利用python进行数据分析 第九章 9.2 使用pandas和seaborn绘图

matplotlib实际上是一种比较低级的工具。要绘制一张图表,你组装一些基本组件就行:数据展示
(即图表类型:线型图、柱状图、盒形图、散布图、等值线图等)、图例、标题、刻度标签以及其
他注解型信息。
在pandas中,我们有多列数据,还有行和列标签。pandas自身就有内置的方法,用于简化从
DataFrame和Series绘制图形。另一个库seaborn( https://seaborn.pydata.org/),由Michael
Waskom创建的静态图形库。Seaborn简化了许多常见可视类型的创建。
ᨀ 示:引入seaborn会修改matplotlib默认的颜色方案和绘图类型,以ᨀ 高可读性和美观度。
即使你不使用seaborn API,你可能也会引入seaborn,作为ᨀ 高美观度和绘制常见matplotlib
图形的简化方法。

线型图

Series和DataFrame都有一个用于生成各类图表的plot方法。默认情况下,它们所生成的是线型图 (如图9-13所示):
In [60]: s = pd.Series(np.random.randn(10).cumsum(), index=np.arange(0, 100, 10))
In [61]: s.plot()

该Series对象的索引会被传给matplotlib,并用以绘制X轴。可以通过use_index=False禁用该功
能。X轴的刻度和界限可以通过xticks和xlim选项进行调节,Y轴就用yticks和ylim。plot参数的完整
列表请参见表9-3。我只会讲解其中几个,剩下的就留给读者自己去研究了。
pandas的大部分绘图方法都有一个可选的ax参数,它可以是一个matplotlib的subplot对象。这使你
能够在网格布局中更为灵活地处理subplot的位置。
DataFrame的plot方法会在一个subplot中为各列绘制一条线,并自动创建图例(如图9-14所示):
In [62]: df = pd.DataFrame(np.random.randn(10, 4).cumsum(0),
....: columns=['A', 'B', 'C', 'D'],
....: index=np.arange(0, 100, 10))
In [63]: df.plot()
plot属性包含一批不同绘图类型的方法。例如,df.plot()等价于df.plot.line()。后面会学习这些方
法。
笔记:plot的其他关键字参数会被传给相应的matplotlib绘图函数,所以要更深入地自定义图
表,就必须学习更多有关matplotlib API的知识。
DataFrame还有一些用于对列进行灵活处理的选项,例如,是要将所有列都绘制到一个subplot中
还是创建各自的subplot。详细信息请参见表9-4
注意: 有关时间序列的绘图,请见第11章。

柱状图

plot.bar()和plot.barh()分别绘制水平和垂直的柱状图。这时,Series和DataFrame的索引将会被用
作X(bar)或Y(barh)刻度(如图9-15所示):
In [64]: fig, axes = plt.subplots(2, 1)
In [65]: data = pd.Series(np.random.rand(16), index=list('abcdefghijklmnop'))
In [66]: data.plot.bar(ax=axes[0], color='k', alpha=0.7)
Out[66]: <matplotlib.axes._subplots.AxesSubplot at 0x7fb62493d470>
In [67]: data.plot.barh(ax=axes[1], color='k', alpha=0.7)
color='k'和alpha=0.7设定了图形的颜色为黑色,并使用部分的填充透明度。对于DataFrame,柱
状图会将每一行的值分为一组,并排显示,如图9-16所示:
注意,DataFrame各列的名称"Genus"被用作了图例的标题。
设置stacked=True即可为DataFrame生成堆积柱状图,这样每行的值就会被堆积在一起(如图9-
17所示):
In [73]: df.plot.barh(stacked=True, alpha=0.5)

笔记:柱状图有一个非常不错的用法:利用value_counts图形化显示Series中各值的出现频
率,比如s.value_counts().plot.bar()。
再以本书前面用过的那个有关小费的数据集为例,假设我们想要做一张堆积柱状图以展示每天各种
聚会规模的数据点的百分比。我用read_csv将数据加载进来,然后根据日期和聚会规模创建一张
交叉表:
In [75]: tips = pd.read_csv('examples/tips.csv')
In [76]: party_counts = pd.crosstab(tips['day'], tips['size'])
In [77]: party_counts
Out[77]:
size 1 2 3 4 5 6
day
Fri 1 16 1 1 0 0
Sat 2 53 18 13 1 0
Sun 0 39 15 18 3 1
Thur 1 48 4 5 1 3
# Not many 1- and 6-person parties
In [78]: party_counts = party_counts.loc[:, 2:5]

然后进行规格化,使得各行的和为1,并生成图表(如图9-18所示):

# Normalize to sum to 1
In [79]: party_pcts = party_counts.div(party_counts.sum(1), axis=0)
In [80]: party_pcts
Out[80]:
size 2 3 4 5
day
Fri 0.888889 0.055556 0.055556 0.000000
Sat 0.623529 0.211765 0.152941 0.011765
Sun 0.520000 0.200000 0.240000 0.040000
Thur 0.827586 0.068966 0.086207 0.017241

In [81]: party_pcts.plot.bar()

注意,DataFrame各列的名称"Genus"被用作了图例的标题。
设置stacked=True即可为DataFrame生成堆积柱状图,这样每行的值就会被堆积在一起(如图9-
17所示):
In [73]: df.plot.barh(stacked=True, alpha=0.5)
笔记:柱状图有一个非常不错的用法:利用value_counts图形化显示Series中各值的出现频
率,比如s.value_counts().plot.bar()。
再以本书前面用过的那个有关小费的数据集为例,假设我们想要做一张堆积柱状图以展示每天各种
聚会规模的数据点的百分比。我用read_csv将数据加载进来,然后根据日期和聚会规模创建一张
交叉表:
In [75]: tips = pd.read_csv('examples/tips.csv')
In [76]: party_counts = pd.crosstab(tips['day'], tips['size'])
In [77]: party_counts
Out[77]:
size 1 2 3 4 5 6
day
Fri 1 16 1 1 0 0
Sat 2 53 18 13 1 0
Sun 0 39 15 18 3 1
Thur 1 48 4 5 1 3
# Not many 1- and 6-person parties
In [78]: party_counts = party_counts.loc[:, 2:5]
然后进行规格化,使得各行的和为1,并生成图表(如图9-18所示):
# Normalize to sum to 1
In [79]: party_pcts = party_counts.div(party_counts.sum(1), axis=0)
In [80]: party_pcts
Out[80]:
size 2 3 4 5
day
Fri 0.888889 0.055556 0.055556 0.000000
Sat 0.623529 0.211765 0.152941 0.011765
Sun 0.520000 0.200000 0.240000 0.040000
Thur 0.827586 0.068966 0.086207 0.017241
In [81]: party_pcts.plot.bar()
于是,通过该数据集就可以看出,聚会规模在周末会变大。
对于在绘制一个图形之前,需要进行合计的数据,使用seaborn可以减少工作量。用seaborn来看
每天的小费比例(图9-19是结果):
In [83]: import seaborn as sns
In [84]: tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip'])
In [85]: tips.head()
Out[85]:
total_bill tip smoker day time size tip_pct
0 16.99 1.01 No Sun Dinner 2 0.063204
1 10.34 1.66 No Sun Dinner 3 0.191244
2 21.01 3.50 No Sun Dinner 3 0.199886
3 23.68 3.31 No Sun Dinner 2 0.162494
4 24.59 3.61 No Sun Dinner 4 0.172069
In [86]: sns.barplot(x='tip_pct', y='day', data=tips, orient='h')
seaborn的绘制函数使用data参数,它可能是pandas的DataFrame。其它的参数是关于列的名字。
因为一天的每个值有多次观察,柱状图的值是tip_pct的平均值。绘制在柱状图上的黑线代表95%置
信区间(可以通过可选参数配置)。
seaborn.barplot有颜色选项,使我们能够通过一个额外的值设置(见图9-20):
In [88]: sns.barplot(x='tip_pct', y='day', hue='time', data=tips, orient='h')
注意,seaborn已经自动修改了图形的美观度:默认调色板,图形背景和网格线的颜色。你可以用
seaborn.set在不同的图形外观之间切换:
In [90]: sns.set(style="whitegrid")

直方图和密度图

直方图(histogram)是一种可以对值频率进行离散化显示的柱状图。数据点被拆分到离散的、间
隔均匀的面元中,绘制的是各面元中数据点的数量。再以前面那个小费数据为例,通过在Series使
用plot.hist方法,我们可以生成一张“小费占消费总额百分比”的直方图(如图9-21所示):
In [92]: tips['tip_pct'].plot.hist(bins=50)

与此相关的一种图表类型是密度图,它是通过计算“可能会产生观测数据的连续概率分布的估计”而
产生的。一般的过程是将该分布近似为一组核(即诸如正态分布之类的较为简单的分布)。因此,
密度图也被称作KDE(Kernel Density Estimate,核密度估计)图。使用plot.kde和标准混合正态
分布估计即可生成一张密度图(见图9-22):
In [94]: tips['tip_pct'].plot.density()
seaborn的distplot方法绘制直方图和密度图更加简单,还可以同时画出直方图和连续密度估计图。
作为例子,考虑一个双峰分布,由两个不同的标准正态分布组成(见图9-23):
In [96]: comp1 = np.random.normal(0, 1, size=200)
In [97]: comp2 = np.random.normal(10, 2, size=200)
In [98]: values = pd.Series(np.concatenate([comp1, comp2]))
In [99]: sns.distplot(values, bins=100, color='k')

散布图或点图

点图或散布图是观察两个一维数据序列之间的关系的有效手段。在下面这个例子中,我加载了来自
statsmodels项目的macrodata数据集,选择了几个变量,然后计算对数差:
In [100]: macro = pd.read_csv('examples/macrodata.csv')
In [101]: data = macro[['cpi', 'm1', 'tbilrate', 'unemp']]
In [102]: trans_data = np.log(data).diff().dropna()
In [103]: trans_data[-5:]
Out[103]:
cpi m1 tbilrate unemp
198 -0.007904 0.045361 -0.396881 0.105361
199 -0.021979 0.066753 -2.277267 0.139762
200 0.002340 0.010286 0.606136 0.160343
201 0.008419 0.037461 -0.200671 0.127339
202 0.008894 0.012202 -0.405465 0.042560

然后可以使用seaborn的regplot方法,它可以做一个散布图,并加上一条线性回归的线(见图9-
24):
In [105]: sns.regplot('m1', 'unemp', data=trans_data)
Out[105]: <matplotlib.axes._subplots.AxesSubplot at 0x7fb613720be0>
In [106]: plt.title('Changes in log %s versus log %s' % ('m1', 'unemp'))
在探索式数据分析工作中,同时观察一组变量的散布图是很有意义的,这也被称为散布图矩阵
(scatter plot matrix)。纯手工创建这样的图表很费工夫,所以seabornᨀ 供了一个便捷的pairplot
函数,它支持在对角线上放置每个变量的直方图或密度估计(见图9-25):
In [107]: sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha': 0.2})
你可能注意到了plot_kws参数。它可以让我们传递配置选项到非对角线元素上的图形使用。对于更
详细的配置选项,可以查阅seaborn.pairplot文档字符串。
分面网格( facet grid )和类型数据
要是数据集有额外的分组维度呢?有多个分类变量的数据可视化的一种方法是使用小面网格。
seaborn有一个有用的内置函数factorplot,可以简化制作多种分面图(见图9-26):
In [108]: sns.factorplot(x='day', y='tip_pct', hue='time', col='smoker',
.....: kind='bar', data=tips[tips.tip_pct < 1])
除了在分面中用不同的颜色按时间分组,我们还可以通过给每个时间值添加一行来扩展分面网格:
In [109]: sns.factorplot(x='day', y='tip_pct', row='time',
.....: col='smoker',
.....: kind='bar', data=tips[tips.tip_pct < 1])
factorplot支持其它的绘图类型,你可能会用到。例如,盒图(它可以显示中位数,四分位数,和
异常值)就是一个有用的可视化类型(见图9-28):
In [110]: sns.factorplot(x='tip_pct', y='day', kind='box',
.....: data=tips[tips.tip_pct < 0.5])
使用更通用的seaborn.FacetGrid类,你可以创建自己的分面网格。请查阅seaborn的文档
https://seaborn.pydata.org/)。

9.3 其它的Python可视化工具

与其它开源库类似,Python创建图形的方式非常多(根本罗列不完)。自从2010年,许多开发工
作都集中在创建交互式图形以便在Web上发布。利用工具如
Boken( https://bokeh.pydata.org/en/latest/)和Plotly(https://github.com/plotly/plotly.py),现在
可以创建动态交互图形,用于网页浏览器。
对于创建用于打印或网页的静态图形,我建议默认使用matplotlib和附加的库,比如pandas和
seaborn。对于其它数据可视化要求,学习其它的可用工具可能是有用的。我鼓励你探索绘图的生
态系统,因为它将持续发展。

9.4 总结

本章的目的是熟悉一些基本的数据可视化操作,使用pandas,matplotlib,和seaborn。如果视觉
显示数据分析的结果对你的工作很重要,我鼓励你寻求更多的资源来了解更高效的数据可视化。这
是一个活跃的研究领域,你可以通过在线和纸质的形式学习许多优秀的资源。
下一章,我们将重点放在pandas的数据聚合和分组操作上。
  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值