9.1 简明matplotlib API入门
在使用matplotlib时,我们使用以下的导入惯例:
In [1]: import matplotlib.pyplot as plt
在Jupyter中运行%matplotlib notebook(或在Ipython中运行%matplotlib),我们就可以尝试生成一个简单的图形。如果所有的设置都正确,输入以下代码就会生成一张线形图。
In [1]: import matplotlib.pyplot as plt
In [2]:
In [2]: import numpy as np
In [3]: data = np.arange(10)
In [4]: data
Out[4]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
尽管seaborn等库和pandas内建的绘图函数可以处理大部分绘图的普通细节,但如果你想在提供的函数选项之外进行定制则需要学习一些matplotlib的API。
9.1.1 图片与子图
matplotlib所绘制的图位于图片(Figure)对象中。你可以使用plt.figure生成一个新的图片:
In [9]: fig = plt.figure()
在IPython中,一个空白的绘图窗口就会出现,但在Jupyter中则没有任何显示,直到我们使用一些其他命令。plt.figure有一些选项,比如figsize是确保图片有一个确定的大小以及存储到硬盘时的长宽比。
你不能使用空白的图片进行绘图。你需要使用add_subplot创建一个或多个子图(subplot):
In [10]: ax1 = fig.add_subplot(2,2,1)
上面代码的意思是图片应该是2X2的(最多四个图形),并且我们选择了四个图形中的第一个(序号从1开始)。如果你接着创建了两个子图,你将会获得看上去类似于下图的可视化:
In [11]: ax2 = fig.add_subplot(2,2,2)
In [12]: ax3 = fig.add_subplot(2,2,3)
使用Jupyter notebook 时有个细节需要注意,在每个单元格运行后,图表被重置,因此对于更复杂的图标,你必须将所有的绘图命令放在单个的notebook单元格中。
当你输入绘图命令plt.plot([1.55,3.5,-2,1.6]),matplotlib会在最后一个图片和子图(如果需要的话就创建一个)上进行绘制,从而隐藏图片和子图的创建。因此,如果我们添加了下面的代码,你会得到下图的可视化:
'k--'是用于绘制黑色分段线的style选项。fig.add_subplot返回的对象是Axes Subplot对象,使用这些对象你可以直接在其他空白的子图上调用对象的实例方法进行绘图。
使用子图网格创建图片是非常常见的任务,所以matplotlib包含了一个便捷方法plt.subplots,它创建一个新的图片,然后返回包含了已生成子图对象的Numpy数组:
In [8]: fig , axes = plt.subplots(2,3)
In [9]: axes
Out[9]:
array([[<AxesSubplot:>, <AxesSubplot:>, <AxesSubplot:>],
[<AxesSubplot:>, <AxesSubplot:>, <AxesSubplot:>]], dtype=object)
这是非常有用的,因为数组axes可以像二维数组那样方便的进行索引,例如axes[0,1]。你也可以通过使用sharex和sharey来表明子图分别拥有相同的X轴或Y轴。当你在相同的比例下进行数据对比时,sharex和sharey会非常有用;此外,matplotlib还可以独立地缩放图像的界限。
9.1.1.1 调整子图周围的间距
默认情况下,matplotlib会在子图的外部和子图之间留出一定的间距。这个间距都是相对于图的高度和宽度来指定的,所以如果你通过编程或手动使用GUI窗口来调整图的大小,那么图就会自动调整。你可以使用图对象上的subplots_adjust方法更改间距,也可以用作顶层函数:
In [12]: plt.subplots_adjust(left=None,bottom=None,right=None,top=None,wspace=None,hspace=None)
wspace和hapace分别控制的是图片的宽度和高度百分比,以用作子图间的间距。下面是一个小例子,我将这个间距一直缩小到零:
In [14]: fig,axes = plt.subplots(2,2,sharex=True,sharey=True)
In [15]: for i in range(2):
...: for j in range(2):
...: axes[i,j].hist(np.random.randn(500),bins=50,color='k',alpha=0.5)
...: plt.subplot_adjust(wspace=0,hspace=0)
如果你发现提示报错:AttributeError: module ‘matplotlib.pyplot’ has no attribute ‘
那么通过 !pip uninstall matplotlib 卸载,再重新安装。
你可能会注意到轴标签是存在重叠的。matplotlib并不检查标签是否重叠,因此在类似情况下你需要通过显式指定刻度位置和刻度标签的方式来修复轴标签。
9.1.2 颜色、标记和线类型
matplotlib的主函数plot接收带有x和y轴的数组以及一些可选的字符串缩写参数来指明颜色和线类型。例如,要用绿色破折号绘制x对y的线,你需要执行:
ax.plot(x,y,’g–‘)
这种在字符串中指定颜色和线条样式的方式是方便的。在实践中,如果你以变成方式创建绘图,则可能不希望将字符串混合在一起以创建具有所需样式的图标。同样的图表可以使用更为显式的方式来表达:
ax.plot(x,y,linestyle=’–‘,color=’g’)
有 很多颜色缩写被用于常用颜色,但是你可以通过指定十六进制颜色代码的方式来制定任何颜色(例如‘#CECECE’)。参考plot函数的文档字符串可以看到全部的线类型(在ipython或jupyter中使用plot?)
折线图还可以有标记来凸显实际的数据点。由于matplotlib创建了一个连续性折线图,插入点之间有时并不清除点在哪。标记可以是样式字符串的一部分,样式字符串中线类型,标记类型必须跟在颜色后面:
In [14]: from numpy.random import randn
In [18]: plt.plot(randn(30).cumsum(),’ko–‘)
上面的代码可以写得更为显式:
In [20]: plt.plot(randn(30).cumsum(),color='k',linestyle='dashed',marker='o')
对于折线图,你会注意到后续的点默认都是线性内插的。你可以通过drawstyle选项进行更改:
In [25]: data = np.random.randn(30).cumsum()
In [26]: plt.plot(data,'k--',label='Default')
In [28]: plt.plot(data,'k--',drawstyle='steps-post',label='steps-post')
Out[28]: [<matplotlib.lines.Line2D at 0x7fe8c8ea77c0>]
In [29]: plt.legend(loc='best')
Out[29]: <matplotlib.legend.Legend at 0x7fe899bcd6a0>
你可能会注意到在运行代码后会有像
Out[37]: [<matplotlib.lines.Line2D at 0x7fe8a014eca0>]
这样的输出。matplotlib返回的对象引用了刚刚添加的图表子组件。很多时候你可以安全地忽略这些输出。这里,由于我们向plot传递了laber,我们可以使用plt.legend为每条线生成一个用于区分的图例。
无论你在用数据绘图时是否传递了laber选项,你都必须调用plt.legend(如果你有轴的引用,也可以用ax.legend)来生成图例。
9.1.3 刻度、标签和图例
对于大多数图标修饰工作,有两种主要的方式:使用程序性的pyplot接口(即matplotlib.pyplot)和更多面向对象的原生matplotlib API。
pyplot 接口设计为交互式使用,你包含了像xlim、xticks和xticklabels等方法。这些方法分别控制了绘图范例,刻度位置以及刻度标签。我们可以在两种方式中使用:
1、在没有函数参数的情况下调用,返回当前的参数值(例如plt.xlim()返回当前的x轴绘图范围)。
2、传入参数的情况下调用,并设置参数值(例如plt.xlim([0,10])会将x轴的范围设置为0到10)。
所有的这些方法都会在当前活动的或最近创建的AxesSubplot上生效。这些方法的每一个对应于子图自身的两个方法。比如xlim对应于ax.get_lim和ax.set_lim。我更倾向于使用subplot的实例方法,因为这样更为显式(尤其是在处理多个子图时),但你当然可以使用你觉得更方便的方式。
9.1.3.1 设置标题、轴标签、刻度和刻度标签
为了讲解轴的自定义,我会生成一个简单图表,并绘制随机漫步:
In [39]: fig = plt.figure() # 生成一个空白图
In [40]: ax = fig.add_subplot(1,1,1) # 一行一列这是一个图
In [41]: ax.plot(np.random.randn(1000).cumsum()) # 生成一千个符合正态分布的随机数字,cumsum返回沿着指定轴的元素累加和所组成的数组
Out[41]: [<matplotlib.lines.Line2D at 0x7fe8e8ed64c0>]
要改变x轴刻度,最简单的方式是使用set_xticks和set_xticklabels。set_xticks表示在数据范围内设定刻度的位置,默认情况下,这些刻度也有标签。但是我们可以使用set_xticklabels为标签赋值:
In [44]: ticks = ax.set_xticklabels([0,250,500,750,1000])
<ipython-input-44-4187d0f80e04>:1: UserWarning: FixedFormatter should only be used together with FixedLocator
ticks = ax.set_xticklabels([0,250,500,750,1000])
In [45]: labels = ax.set_xticklabels(['one','two','three','four','five'],rotation=30,fontsize='small')
<ipython-input-45-cf1fac8a7366>:1: UserWarning: FixedFormatter should only be used together with FixedLocator
labels = ax.set_xticklabels(['one','two','three','four','five'],rotation=30,fontsize='small')
rotation选项会将x轴刻度标签旋转30度。最后,set_xlabel会给x轴一个名称,set_titel会给子图一个标题:
In [46]: ax.set_title('MY first matplotlib plot')
Out[46]: Text(0.5, 1.0, 'MY first matplotlib plot')
In [47]: ax.set_xlabel('Stages')
Out[47]: Text(0.5, 24.438360157402354, 'Stages')
修改y轴坐标是相同过程,将上面示例中的x替换成y即可。轴的类型拥有一个set方法,允许批量设置绘图属性。根据之前的示例,我们可以写如下代码:
In [53]: props = {'title':'My','xlabel':'stages'}
In [54]: ax.set(**props)
Out[54]: [Text(0.5, 1.0, 'My'), Text(0.5, 24.438360157402354, 'stages')]
我们修改下y轴刻度:
In [61]: labels = ax.set_yticklabels(['xinyuan','jieyi','changze','yamei','piaoxiaomin'],rotation=30,fontsize='small')
<ipython-input-61-d3585363d156>:1: UserWarning: FixedFormatter should only be used together with FixedLocator
labels = ax.set_yticklabels(['xinyuan','jieyi','changze','yamei','piaoxiaomin'],rotation=30,fontsize='small')
9.1.3.2 添加图例
图例是用来区分绘图元素的另一个重要内容。有多重方式可以添加图例。最简单的方式是在添加每个图表时传递label参数:
In [63]: ax.plot(randn(1000).cumsum(),'k',label='one')
Out[63]: [<matplotlib.lines.Line2D at 0x7fe899e0efa0>]
In [64]: ax.plot(randn(1000).cumsum(),'k--',label='two')
Out[64]: [<matplotlib.lines.Line2D at 0x7fe8b85fcbe0>]
In [65]: ax.plot(randn(1000).cumsum(),'k.',label='three')
Out[65]: [<matplotlib.lines.Line2D at 0x7fe899e0ea30>]
一旦你运行了上面的代码,你也可以调用ax.legend()或plt.legend自动生成图例。
legend方法有多个其他的位置参数loc。参考文档字符串(使用ax.legend?命令)获取更多信息。
loc参数告诉matplotlib在哪里放置图标。如果你不挑剔,‘best’是一个好选项,它会自动选择最适合的位置。如果取消图例中的元素,不要传入label参数或者传入label='_nolegend_'。
9.1.4 注释与子图加工
除了标准的绘图类型,你可能还会想在图表上绘制自己的注释,而且注释中可能会包含文本、箭头以及其他图形。你可以使用text、arrow和annote方法来添加注释和文本。text在图标上给定的坐标(x,y),根据可选的定制样式绘制文本:
In [70]: ax.text(x,y,'hello world',family='monispace',fontsize=10)
注释可以通过绘制文本和箭头。作为一个例子,让我们绘制标普500指数从2007年以来的收盘价,并在图表中标注从2008年到2009年金融危机中的重要日期。你可以在jupyter note的一个单元格复现这些代码。
In [71]: from datetime import datetime
In [72]: fig = plt.figure()
In [73]: ax = fig.add_subplot(1,1,1)
In [74]: data = pd.read_csv('examples/spx.csv',index_col=0,parse_dates=True)
In [77]: spx = data['SPX']
In [78]: spx.plot(ax=ax,style='k-')
Out[78]: <AxesSubplot:xlabel='Date'>
In [85]: for date,label in crisis_data:
...: ax.annotate(label,xy=(date,spx.asof(date)+75),xytext=(date,spx.asof(date)+225),arrowprops=dict(facecolor='black',head
...: width=4,width=2,headlength=4),horizontalalignment='left',verticalalignment='top')
In [86]: # 放大2007年~ 2010年
In [87]: ax.set_xlim(['1/1/2007','1/1/2011'])
Out[87]: (13514.0, 14975.0)
In [88]: ax.set_ylim([600,1800])
Out[88]: (600.0, 1800.0)
In [90]: ax.set_title('wo suibian quge mingzi')
Out[90]: Text(0.5, 1.0, 'wo suibian quge mingzi')
在图表中有一些重要点需要凸显:ax.annotate方法可以在指定的x和y坐标上绘制标签。我们可以使用set_xlim和set_ylim方法手动设置图表的边界,而不是使用matplotlib的默认设置。最后,ax.set_title给图表添加了一个主标题。
参考在线的matplotlib展览馆,可以学习更多注释的范例。
绘制图形时有更多需要注意的地方。matplotlib含有表示多种常见图形的对象,这些对象的引用是patches。一些图形,比如rectangle(矩形)和circle(圆形),可以在matplotlib.pyplot中找到,但图形的全集位于matplotlib.patches。
想在图表中添加图形时,你需要生成patch对象shp,并调用ax.add_patch(shp)将它加入到子图中:
In [91]: fig = plt.figure()
In [92]: ax = fig.add_subplot(1,1,1)
In [93]: rect = plt.Rectangle((0.2,0.75),0.4,0.15,color='k',alpha=0.3)
# alpha 是透明度的意思
In [95]: circ = plt.Circle((0.7,0.2),0.15,color='b',alpha=0.3)
In [96]: pgon = plt.Polygon([[0.15,0.15],[0.35,0.4],[0.2,0.6]],color='g',alpha=0.5)
In [98]: ax.add_patch(rect)
Out[98]: <matplotlib.patches.Rectangle at 0x7fe89b193be0>
In [99]: ax.add_patch(circ)
Out[99]: <matplotlib.patches.Circle at 0x7fe8c9ed5760>
In [100]: ax.add_patch(pgon)
Out[100]: <matplotlib.patches.Polygon at 0x7fe8c9ee96a0>
当你看到很多常见绘图类型的实现时,你会发现他们都是patches组装而来。
9.1.5 将图片保存到文件
你可以使用plt.savefig将活动图片保存到文件。这个方法等价于图片对象的savefig实例方法。例如将图片保存为png,你只需要输入以下代码:
plt.savefig(‘figpath.png’)
文件类型是从文件扩展名中推断出来的。所以如果你使用.pdf,则会得到一个PDF。我常常使用几个重要的选项来发布图形:dpi,它控制每英寸点数的分辨率;bbo_xinches,可以修剪实际图形的空白。为了得到同样一个PNG图片,且使用最小的空白,拥有400DPI,你需要运行以下代码:
plt.save(‘figpath.png’,dpi=400,bbox_inches=’tight’)
savefig并非一定是邪道硬盘的,它可以将图片邪道所有的文件型对象中,例如BytesIO:
from io import BytesIO
buffer = BytesIO
plt.savefig(buffer)
plot_data = buffer.getvalue()
9.1.6 matplotlib 设置
matplotlib配置了配色方案和默认设置,主要用来准备用于发布的图片。幸运的是,几乎所有的默认行为都可以通过广泛的全局参数来定制,包括图形大小、子图间距、颜色、字体大小和网格样式等等。使用rc方法是使用python变成修改配置的一种方式,例如,要将全局默认数字大小设置为10X10,你可以输入:
In [103]: plt.savefig('figpath.png',dpi=400,bbox_inches='tight')
In [104]: plt.rc('figure',figsize=(10,10))
rc的第一个参数是你想要自定义的组件,比如‘figure’、‘axes’、‘xtick’、‘ytick’、‘grid’、‘legend’等等。之后,可以按照关键字参数的序列指定新参数。字典是一种在程序中设置选项的简单方式:
In [111]: font_options = {'family':'monospace',
...: 'weight':'bold'
...: }
In [112]: plt.rc('font',**font_options)
如果需要更深入的定制和参看全景选项,可以参考matplotlib的设置文件matplotlibrc,该文件位于matplotlib/mpl-data路径。如果你制定了这个文件,并将它放置在home路径下并且文件名为.matplotlibrc,则每次你使用matplotlib时都会读取该文件。
这里说明一下,原文里的字典还包含‘font’:‘small’,但是一旦这么输入就会报错,错误信息为:
ValueError: Key font.size: Could not convert ‘small’ to float
自神仔不做这本书,这种奇怪的问题我就不知道找谁解决了,放着吧,阿门。
9.2 使用pandas和seaborn绘图
matplotlib是一个相当底层的工具。你可以从其基本组件中组装一个图标:数据显示(即绘图的类型;线、条、框、散点图、轮廓等)、图例、标题、刻度标记和其他注释。
在pandas中,我们可能有多个数据列,并且带有行和列的标签。pandas自身有很多内建方法可以简化从DataFrame和Series对象生成可视化过程。另一个库是seaborn,它是由Michael Waskom创建的统计图形库。seaborn简化了很多常用可视化类型的生成。
导入seaborn会修改默认的matplotlib配色方案和绘图样式,这会提高图标的可读性和美观性。即使你不使用seaborn的API,你可能更喜欢导入seaborn来为通用matplotlib图标提供更好的视觉美观度。
9.2.1 折线图
Series和DataFrame都有一个plot属性,用于绘制基本的图形。默认情况下,plot()绘制的是折线图:
In [113]: s = pd.Series(np.random.randn(10).cumsum(),index=np.arange(0,100,10))
In [114]: s.plot()
Out[114]: <AxesSubplot:>
Series 对象的索引传入matplotlib作为绘图的x轴,你可以通过传入use_index=False来禁用这个功能。x轴的刻度和范围可以通过xticks和xlim选项进行调整,相应地y轴使用yticks和ylim进行调整。
大部分pandas的绘图方式,接收可选的ax参数,该参数可以是一个matplotlib子图对象。这使你可以更为灵活地在网格不居中放置子图。
DataFrame 的plot方法在同一个子图中将每一列绘制为不同的折线,并自动生成图例:
In [115]: df = pd.DataFrame(np.random.randn(10,4).cumsum(0),columns=['A','B','C','D'],index=np.arange(0,100,10))
In [116]: df.plot()
Out[116]: <AxesSubplot:>
plot属性包含了不同绘图类型的方法族。例如,df.plot()等价于df.plot.line()。
plot的其他关键字参数会传递到响应的matplotlib绘图函数,因此你可以通过了解更多的matplotlib的API信息来进一步定制这些图标。
9.2.2 柱状图
plot.bar()和plot.barh()可以分别绘制垂直和水平的柱状图。在绘制柱状图时,Series或DataFrame的索引将会被用作X轴刻度(bar)或Y轴刻度(barh):
In [119]: fig,axes = plt.subplots(2,1)
In [121]: data = pd.Series(np.random.randn(16),index=list('abcdefghijklmnop'))
In [123]: data.plot.bar(ax=axes[0],color='k',alpha=0.7)
Out[123]: <AxesSubplot:>
选项color='k'和alpha=0.7将柱子的颜色设置为黑色,并将图像的填充色设置为部分透明。
在DataFrame中,柱状图将每一行的值分组到并排的柱子中的一组。
In [125]: df = pd.DataFrame(np.random.rand(6,4),
...: index=['one','two','three','four','five','six'],
...: columns=pd.Index(['A','B','C','D'],name='Genus')) # 生成四组,每组六个0-1之间的浮点数
In [126]: df
Out[126]:
Genus A B C D
one 0.734436 0.593354 0.563317 0.595107
two 0.405626 0.080266 0.598416 0.486880
three 0.502516 0.478946 0.598374 0.544180
four 0.542656 0.765685 0.154775 0.799048
five 0.376769 0.938997 0.326813 0.420403
six 0.405602 0.708587 0.016057 0.458708
In [127]: df.plot.bar()
Out[127]: <AxesSubplot:>
请注意DataFrame的列名称“Genus”被用作了图例标题。我们可以通过传递stacked = True来生成堆积柱状图,这会使得每一行的值堆积在一起。
使用value_counts:s.value_counts().plot.bar()可以有效地对Series值频率进行可视化。
回到本书之前使用的数据集,假设我们想要绘制一个堆积柱状图,用于展示每个派对在每天的数据点占比。使用read_csv载入数据,并根据星期日期和派对规模形成交叉表:
In [134]: tips = pd.read_csv('examples/tips.csv')
In [135]: party = pd.crosstab(tips['day'],tips['size'])
In [136]: party
Out[136]:
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
In [137]: # 没有太多的1人和6人派对
In [138]: party = party.loc[:,2:5]
之后,进行标准化以确保每一行的值和为1,然后进行绘图:
In [139]: party_pcts = party.div(party.sum(1),axis=0)
In [140]: party_pcts
Out[140]:
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
你可以看到本数据集中的排队数量在周末会增加。
对于在会图签需要聚合或汇总的数据,使用seaborn包会使工作更为简单。现在让我们看下使用seaborn进行按星期日期计算小费百分比:
In [142]: import seaborn as sns
In [145]: tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip'])
In [146]: tips.head()
Out[146]:
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
seaborn中的绘图函数使用data参数,这个参数可以是pandas的DataFrame。其他的参数则与列名有关。因为day列中有多个观测值,柱子的值是tip_pct的平均值。柱子上画出的黑线代表的是95%的置信区间(置信区间可以通过可选参数进行设置)。
seaborn.barplot 拥有一个hue选项,允许我们通过一个额外的分类值将数据分离:
In [150]: sns.barplot(x='tip_pct',y='day',hue='time',data=tips,orient='h')
Out[150]: <AxesSubplot:xlabel='tip_pct', ylabel='day'>
请注意seaborn自动改变了图表的美观性:默认的调色板、图北京和网格线条颜色。你可以使用seaborn.set在不同的绘图外观中进行切换:
In [151]: sns.set(style='whitegrid')
9.2.3 直方图和密度图
直方图是一种条形图,用于给出值频率的离散显示。数据点被分成离散的,均匀间隔的箱,并且绘制每个箱中的数据点的数量。使用之前的消费数据,我们可以使用Series的plot.hist方法制作消费占总费用百分比的直方图:
In [153]: tips['tip_pct'].plot.hist(bins=50)
Out[153]: <AxesSubplot:ylabel='Frequency'>
密度图是一种与直方图相关的图标类型,它通过计算可能产生观测数据的连续概率分部估计而产生。通常的做法是将这种分布近似为“内核”的混合,也就是像正态分布那样的简单的分布。因此,密度图也被成为内核密度估计图(KDE)。plot.kde使用传统法定混合法估计绘制密度图:
In [156]: tips['tip_pct'].plot.density()
Out[156]: <AxesSubplot:xlabel='tip_pct', ylabel='Density'>
distplot 方法可以绘制直方图和连续密度估计,通过distplot方法seaborn使直方图和密度图的绘制更为简单。作为例子,考虑由两个不同的标准正态分布组成的双峰分布:
In [158]: comp1 = np.random.normal(0,1,size=200)
In [159]: comp2 = np.random.normal(10,2,size=200)
In [160]: values = pd.Series(np.concatenate([comp1,comp2]))
In [161]: sns.displot(values,bins=100,color='k')
Out[161]: <seaborn.axisgrid.FacetGrid at 0x7fe89a01af70>
9.2.4 散点图或点图
点图或散点图可以用于检测两个一维数据序列之间的关系。例如,这里我们从statsmodels项目中载入了macrodata数据集,并选择了一些变量,之后计算对数差:
In [163]: macro = pd.read_csv('examples/macrodata.csv')
In [164]: data = macro[['cpi','m1','tbilrate','unemp']]
In [165]: trans_data = np.log(data).diff().dropna() # log计算x的自然对数,diff是沿着指定轴计算第N维的离散差值,dropna过滤缺失数据
In [166]: trans_data[-5:]
Out[166]:
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方法,该方法可以绘制散点图,并拟合出一条线性回归线:
In [170]: sns.regplot('m1','unemp',data=trans_data)
In [168]: plt.title('ohoho')
在探索性数据分析中,能够查看一组变量中的所有散点图是有帮助的,这被称为成对图或散点图矩阵。从头开始绘制这样一个图是有点工作量的,所以seaborn有一个方便的pairplot函数,它支持在对角线上放置每个变量的直方图或密度估计值:
In [174]: sns.pairplot(trans_data,diag_kind='kde',plot_kws={'alpha':0.2})
Out[174]: <seaborn.axisgrid.PairGrid at 0x7fe8d8e549d0>
你可能会注意到plot_ksw参数,这个参数使我们能够将配置选项传递给非对角元素上的各个绘图调用。参考seaborn.pairplot的文档字符串可以看到更多细节的设置选项。
9.2.5 分面网格和分类数据
如果数据集有额外的分组维度怎么办?使用分面网格是利用多种分组变量对数据进行可视化的方式。seaborn拥有一个有效的内建函数factorplot,它可以简化多种分面绘图:
In [176]: sns.factorplot(x='day',y='tip_pct',hue='time',col='smoker',kind='bar',data=tips[tips.tip_pct < 1])
除了根据‘time’在一个面内将不同的柱分组为不同的颜色,我们还可以通过每个时间值添加一行来扩展分面网络:
In [177]: sns.factorplot(x='day',y='tip_pct',row='time',col='smoker',kind='bar',data=tips[tips.tip_pct < 1])
factorplot 支持其他可能有用的图类型,具体取决于你要显示的内容。例如,箱型图(显示中位值、四分位数和异常值)可以是有效的可视化类型:
In [178]: sns.factorplot(x='tip_pct',y='day',kind='box',data=tips[tips.tip_pct < 0.5])
你可以使用更通用更多seaborn.FaceetGrid类创建自己的分面网格图。具体可查看https://seaborn.pydata.org
9.3 其他Python可视化工具
和开源代码一样,在Python语言下创建图形的选择有很多。自2010年以来,很多开发工作都集中在创建web交互式图形上。借助想Bokeh和plotly这样的工具,在web浏览器中创建动态的、交互式图像现在已经可以实现。
如果是创建用于印刷或网页的静态图形,我建议根据你的需要使用默认的matplotlib以及像pandas和seaborn这样的附加库。对于其他数据可视化要求,学习其他可用工具之一可能是有用的。
本章及后面的内容,我觉得吧,更多是混个脸熟(包括本书前面的内容也一样),以后实际用到了,知道去哪翻书(望天)。
胭惜雨
2021年04月13日