首页 > 亿信 > 行业资讯 > 数据可视化

使用pandas和seaborn制作炫酷图表:数据可视化干货

时间:2018-09-26  来源:华章科技  浏览数:283

导读:我们介绍过用matplotlib制作图表的一些tips,感兴趣的同学可以戳→纯干货:手把手教你用Python做数据可视化(附代码)。matplotlib是一个相当底层的工具。你可以从其基本组件中组装一个图表:数据显示(即绘图的类型:线、条、框、散点图、轮廓等)、图例、标题、刻度标记和其他注释。

在pandas中,我们可能有多个数据列,并且带有行和列的标签。pandas自身有很多内建方法可以简化从DataFrame和Series对象生成可视化的过程。另一个是seaborn,它是由Michael Waskom创建的统计图形库。seaborn简化了很多常用可视化类型的生成。

导入seaborn会修改默认的matplotlib配色方案和绘图样式,这会提高图表的可读性和美观性。即使你不适用seaborn的API,你可能更喜欢导入seaborn来为通用matplotlib图表提供更好的视觉美观度。

作者:Wes McKinney

本文摘编自《利用Python进行数据分析》(原书第2版),如需转载请联系我们

01 折线图

Series和DataFrame都有一个plot属性,用于绘制基本的图型。默认情况下,plot()绘制的是折线图(见图9-13):

In [60]: s = pd.Series(np.random.randn(10).cumsum(), index=np.arange(0, 100, 10))

In [61]: s.plot()

 

▲图9-13 简单序列图形

Series对象的索引传入matplotlib作为绘图的x轴,你可以通过传入use_index=False来禁用这个功能。x轴的刻度和范围可以通过xticks和xlim选项进行调整,相应地y轴使用yticks和ylim进行调整。表9-3是plot的全部选项列表。本节我会介绍这些选项中的一些,其余你可以自行探索。

大部分pandas的绘图方法,接收可选的ax参数,该参数可以是一个matplotlib子图对象。这使你可以更为灵活的在网格布局中放置子图。

DataFrame的plot方法在同一个子图中将每一列绘制为不同的折线,并自动生成图例(见图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()

 

▲图9-14 简单DataFrame绘图

plot属性包含了不同绘图类型的方法族。例如,df.plot( )等价于df.plot.line( )。我们之后将会探索这些方法中的一部分。

要绘制的其他关键字参数会传递到相应的matplotlib绘图函数,因此你可以通过了解更多的matplotlib的 API信息来进一步定制这些图表。

数据可视化干货:使用pandas和seaborn制作炫酷图表(附代码)

▲表9-3 Series.plot方法参数

DataFrame拥有多个选项,允许灵活地处理列;例如,是否将各列绘制到同一个子图中,或为各列生成独立的子图。参考表9-4了解更多选项。

数据可视化干货:使用pandas和seaborn制作炫酷图表(附代码)

▲表9-4

02 柱状图

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)

数据可视化干货:使用pandas和seaborn制作炫酷图表(附代码)

▲图9-15 水平柱状图和垂直柱状图

选项color='k'和alpha=0.7将柱子的颜色设置为黑色,并将图像的填充色设置为部分透明。

在DataFrame中,柱状图将每一行中的值分组到并排的柱子中的一组。参考图9-16:

In [69]: df = pd.DataFrame(np.random.rand(6, 4),

....: index=['one', 'two', 'three', 'four', 'five', 'six'],

....: columns=pd.Index(['A', 'B', 'C', 'D'], name='Genus'))

In [70]: df

Out[70]:

Genus A B C D

one 0.370670 0.602792 0.229159 0.486744

two 0.420082 0.571653 0.049024 0.880592

three 0.814568 0.277160 0.880316 0.431326

four 0.374020 0.899420 0.460304 0.100843

five 0.433270 0.125107 0.494675 0.961825

six 0.601648 0.478576 0.205690 0.560547

In [71]: df.plot.bar()

数据可视化干货:使用pandas和seaborn制作炫酷图表(附代码)

▲图9-16 DataFrame柱状图

请注意DataFrame的列名称"Genus"被用作了图例标题。我们可以通过传递stacked=True来生成堆积柱状图,会使得每一行的值堆积在一起(参考图9-17):

In [73]: df.plot.barh(stacked=True, alpha=0.5)

数据可视化干货:使用pandas和seaborn制作炫酷图表(附代码)

▲图9-17 DataFrame堆积柱状图

使用value_counts: s.value_counts().plot.bar()可以有效的对Series值频率进行可视化。

回到本书之前使用的数据集,假设我们想要绘制一个堆积柱状图,用于展示每个派对在每天的数据点占比。使用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

# 没有太多的1人和6人派对

In [78]: party_counts = party_counts.loc[:, 2:5]

之后,进行标准化以确保每一行的值和为1,然后进行绘图(见图9-18):

# 标准化至和为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()

数据可视化干货:使用pandas和seaborn制作炫酷图表(附代码)

▲图9-18 每天派对数量的百分比

你可以看到本数据集中的派对数量在周末会增加。

对于在绘图前需要聚合或汇总的数据,使用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')

数据可视化干货:使用pandas和seaborn制作炫酷图表(附代码)

▲图9-19 用错误栏按天显示小费百分比

seaborn中的绘图函数使用一个data参数,这个参数可以是pandas的DataFrame。其他的参数则与列名有关。因为day列中有多个观测值,柱子的值是tip_pct的平均值。柱子上画出的黑线代表的是95%的置信区间(置信区间可以通过可选参数进行设置)。

seaborn.barplot拥有一个hue选项,允许我们通过一个额外的分类值将数据分离:

In [88]: sns.barplot(x='tip_pct', y='day', hue='time', data=tips, orient='h')

数据可视化干货:使用pandas和seaborn制作炫酷图表(附代码)

▲图9-20 根据星期几数值和时间计算的小费百分比

请注意seaborn自动改变了图表的美观性:默认的调色板、图背景和网格线条颜色。你可以使用seaborn.set在不同的绘图外观中进行切换:

In [90]: sns.set(style="whitegrid")

03 直方图和密度图

直方图是一种条形图,用于给出值频率的离散显示。数据点被分成离散的,均匀间隔的箱,并且绘制每个箱中数据点的数量。使用之前的小费数据,我们可以使用Series的plot.hist方法制作小费占总费用百分比的直方图(见图9-21):

In [92]: tips['tip_pct'].plot.hist(bins=50)

数据可视化干货:使用pandas和seaborn制作炫酷图表(附代码)

▲图9-21 小费百分比的直方图

密度图是一种与直方图相关的图表类型,它通过计算可能产生观测数据的连续概率分布估计而产生。通常的做法是将这种分布近似为“内核”的混合,也就是像正态分布那样简单的分布。因此,密度图也被成为内核密度估计图(KDE)。plot.kde使用传统法定混合法估计绘制密度图(见图9-22):

In [94]: tips['tip_pct'].plot.density()

数据可视化干货:使用pandas和seaborn制作炫酷图表(附代码)

▲图9-22 小费百分比密度图

distplot方法可以绘制直方图和连续密度估计,通过distplot方法seaborn使直方图和密度图的绘制更为简单。作为例子,考虑由两个不同的标准正态分布组成的双峰分布(见图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')

数据可视化干货:使用pandas和seaborn制作炫酷图表(附代码)

▲图9-23 正态混合的标准化直方图与密度估计

04 散点图或点图

点图或散点图可以用于检验两个一维数据序列之间的关系。例如,这里我们从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

联系
电话

您好,商务咨询请联系

渠道咨询电话:137-0121-6790

直销热线电话:137-0121-6791

技术
支持

您好,技术支持请联系

QQ:400-0011-866

(工作日9:00-18:00)