使用pandas和seaborn绘图
matplotlib
实际上是一种比较低级的工具。要绘制一张图表,你组装一些基本组件就行:数据展示 (即图表类型:线型图、柱状图、盒形图、散布图、等值线图等)、图例、标题、刻度标签以及其他注解型信息。
在pandas
中,我们有多列数据,还有行和列标签。pandas自身就有内置的方法,用于简化从DataFrame和Series
绘制图形。另一个库seaborn
(https://seaborn.pydata.org/),由Michael Waskom创建的静态图形库。Seaborn
简化了许多常见可视类型的创建。
提示:引入
seaborn
会修改matplotlib
默认的颜色方案和绘图类型,以提高可读性和美观度。 即使你不使用seaborn API,你可能也会引入seaborn
,作为提高美观度和绘制常见matplotlib
图形的简化方法。
线型图
Series
和DataFrame
都有一个用于生成各类图表的plot
方法。默认情况下,它们所生成的是线型图 ,如下图所示:
import pandas as pd
import numpy as np
s = pd.Series(np.random.randn(10).cumsum(), index=np.arange(0, 100, 10))
s.plot()
该Series
对象的索引会被传给matplotlib
,并用以绘制X
轴。可以通过use_index=False
禁用该功 能。X
轴的刻度和界限可以通过xticks
和xlim
选项进行调节,Y
轴就用yticks
和ylim
。plot
参数的完整列表 请参见下表:
参数 | 说明 |
---|---|
label | 用于图例的标签 |
ax | 要在其上进行绘制的matplotlib subplot对象,如果没有设置,则使用当前matplotlib subplot |
style | 将要传给matplotlib的风格字符串(如“ko-- ”) |
alpha | 图表的填充不透明度(0到1之间) |
kind | 可以使"line "、“bar ”、“barh ”、“kde ” |
logy | 在Y轴上使用对数标尺 |
use_index | 将对象的索引用作刻度标签 |
rot | 旋转刻度标签(0到360) |
xticks | 用作X轴刻度的值 |
yticks | 用作Y轴刻度的值 |
xlim | X轴的界限(例如[0,10]) |
ylim | Y轴的界限 |
grid | 显示轴网格线(默认打开) |
pandas的大部分绘图方法都有一个可选的ax参数,它可以是一个matplotlib的subplot对象。这使 你能够在网格布局中更为灵活地处理subplot的位置。
DataFrame的plot方法会在一个subplot中为各列绘制一条线,并自动创建图例,如下图所示:
df = pd.DataFrame(np.random.randn(10, 4).cumsum(0), columns=['A', 'B', 'C', 'D'], index=np.arange(0, 100, 10))
df.plot()
plot属性包含一批不同绘图类型的方法。例如,df.plot()等价于df.plot.line()。plot的其他关键字参数会被传给相应的matplotlib绘图函数,所以要更深入地自定义图 表,就必须学习更多有关matplotlib API的知识。
DataFrame还有一些用于对列进行灵活处理的选项,例如,是要将所有列都绘制到一个subplot中还是创建各自的subplot。详细信息请参见下表。
参数 | 说明 |
---|---|
subplots | 将各个DataFrame列绘制到单独的subplot中 |
sharex | 如果subplots=True,则共用一个X轴,包括刻度和界限 |
sharey | 如果subplots=True,则共用一个Y轴 |
figsize | 表示图像大小的元组 |
title | 表示图像标题的字符串 |
legend | 添加一个subplot图例(默认为True) |
sort_columns | 以字母表顺序绘制各列,默认使用当前列顺序 |
柱状图
plot.bar()
和plot.barh()
分别绘制水平和垂直的柱状图。这时,Series
和DataFrame
的索引将会被用 作X(bar)
或Y(barh)
刻度,如下图所示:
fig, axes = plt.subplots(2, 1)
data = pd.Series(np.random.rand(16), index=list('abcdefghijklmnop'))
data.plot.bar(ax=axes[0], color='k', alpha=0.7)
data.plot.barh(ax=axes[1], color='k', alpha=0.7)
color='k'
和alpha=0.7
设定了图形的颜色为黑色,并使用部分的填充透明度。对于DataFrame,柱状图会将每一行的值分为一组,并排显示,如下图所示:
df = pd.DataFrame(np.random.rand(6, 4),
index=['one', 'two', 'three', 'four', 'five',
'six'],
columns=pd.Index(['A', 'B', 'C', 'D'],
name='Genus'))
df.plot.bar()
注意,DataFrame各列的名称"Genus"被用作了图例的标题。设置stacked=True
即可为DataFrame生成堆积柱状图,这样每行的值就会被堆积在一起,如下图所示:
df.plot.barh(stacked=True, alpha=0.5)
笔记:柱状图有一个非常不错的用法:利用value_counts图形化显示Series中各值的出现频率,比如
s.value_counts().plot.bar()
。
以一个有关小费的数据集为例,假设我们想要做一张堆积柱状图以展示每天各种聚会规模的数据点的百分比。我用read_csv将数据加载进来,然后根据日期和聚会规模创建一张交叉表,并进行规格化,使得各行的和为1,并生成图表,如下图所示:
tips = pd.read_csv("../data/tips.csv")
party_counts = pd.crosstab(tips['day'], tips['size'])
party_counts = party_counts.loc[:, 2:5]
party_pcts = party_counts.div(party_counts.sum(1), axis=0)
party_pcts.plot.bar()
通过该数据集就可以看出,聚会规模在周末会变大。
对于在绘制一个图形之前,需要进行合计的数据,使用seaborn可以减少工作量。用seaborn来看每天的小费比例,如下图所示。
import seaborn as sns
tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip'])
sns.barplot(x='tip_pct', y='day', data=tips, orient='h')
seaborn
的绘制函数使用data
参数,它可能是pandas
的DataFrame
。其它的参数是关于列的名字。 因为一天的每个值有多次观察,柱状图的值是tip_pct
的平均值。绘制在柱状图上的黑线代表95%置信区间(可以通过可选参数配置)。
seaborn.barplot
有颜色选项,使我们能够通过一个额外的值设置,如下图所示。
sns.barplot(x='tip_pct', y='day', hue='time', data=tips, orient='h')
注意,seaborn已经自动修改了图形的美观度:默认调色板,图形背景和网格线的颜色。你可以用 seaborn.set在不同的图形外观之间切换,例如:
sns.set(style="whitegrid")
直方图和密度图
直方图(histogram)是一种可以对值频率进行离散化显示的柱状图。数据点被拆分到离散的、间 隔均匀的面元中,绘制的是各面元中数据点的数量。再以前面那个小费数据为例,通过在Series使用 plot.hist方法,我们可以生成一张“小费占消费总额百分比”的直方图,如下图所示。
tips['tip_pct'].plot.hist(bins=50)
与此相关的一种图表类型是密度图,它是通过计算“可能会产生观测数据的连续概率分布的估计”而 产生的。一般的过程是将该分布近似为一组核(即诸如正态分布之类的较为简单的分布)。因此,密度 图也被称作KDE(Kernel Density Estimate,核密度估计)图。使用plot.kde和标准混合正态分布估计 即可生成一张密度图,如下图所示。
tips['tip_pct'].plot.density()
seaborn
的distplot
方法绘制直方图和密度图更加简单,还可以同时画出直方图和连续密度估计图。 作为例子,考虑一个双峰分布,由两个不同的标准正态分布组成,如下图所示。
comp1 = np.random.normal(0,1,size=200)
comp2 = np.random.normal(10, 2, size=200)
values = pd.Series(np.concatenate([comp1, comp2]))
sns.distplot(values, bins=100, color='k')
散点图
散点图是观察两个一维数据序列之间的关系的有效手段。在下面这个例子中,我加载了来自statsmodels
项目的macrodata
数据集,选择了几个变量,然后计算对数差。
import statsmodels.api as sm
macro = sm.datasets.macrodata.data._get_data()
macro.head()
data = macro[['cpi', 'm1', 'tbilrate', 'unemp']]
trans_data = np.log(data).diff().dropna()
然后可以使用seaborn
的regplot
方法,它可以做一个散点图,并加上一条线性回归的线,如下图所示。
在探索式数据分析工作中,同时观察一组变量的散布图是很有意义的,这也被称为散布图矩阵(scatter plot matrix)。纯手工创建这样的图表很费工夫,所以seaborn提供了一个便捷的pairplot
函 数,它支持在对角线上放置每个变量的直方图或密度估计,如下图所示。
sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha': 0.2})
你可能注意到了plot_kws
参数。它可以让我们传递配置选项到非对角线元素上的图形使用。对于更详细的配置选项,可以查阅seaborn.pairplot
文档字符串。
分面网格(facet grid)和类型数据
要是数据集有额外的分组维度呢?有多个分类变量的数据可视化的一种方法是使用小面网格。seaborn
有一个有用的内置函数factorplot
,可以简化制作多种分面图,如下图所示。
sns.factorplot(x='day', y='tip_pct', hue='time', col='smoker', kind='bar', data=tips[tips.tip_pct < 1])
除了在分面中用不同的颜色按时间分组,我们还可以通过给每个时间值添加一行来扩展分面网格:
sns.factorplot(x='day', y='tip_pct', row='time', col='smoker', kind='bar', data=tips[tips.tip_pct < 1])
factorplot
支持其它的绘图类型,你可能会用到。例如,盒图(它可以显示中位数,四分位数,和异 常值)就是一个有用的可视化类型,如下图所示。