绘图和可视化

信息可视化(也叫绘图)是数据分析中最重要的工作之一。它可能是探索过程的一部分,例如,帮助我们找出异常值、必要的数据转换、得出有关模型的idea等。另外,做一个可交互的 数据可视化也许是工作的最终目标。

matplotlib是一个用于创建出版质量图表的桌面绘图包(主要是2D方面)。

matplotlib支持各种操作系统上许多不同的GUI后端,而且还能将图片导出为各种常见的矢量 (vector)和光栅(raster)图:PDF、SVG、JPG、PNG、BMP、GIF等。

matplotlib API入门

matplotlib的通常引入约定是:

import matplotlib.pyplot as plt

在Jupyter中运行%matplotlib notebook 或在IPython中运行%matplotlib

连续操作

IPython中进行简单的应用

普通折线图

Figure和Subplot

matplotlib的图像都位于Figure对象中。你可以用plt.figure创建一个新的Figure

fig = plt.figure()

不能通过空Figure绘图。必须用add_subplot创建一个或多个subplot才行

# 图像应该是2×2的(即最多4张图),且当前选中的是4个subplot中的第⼀一个(编号从1开始) 
ax1 = fig.add_subplot(2, 2, 1)

matplotlib会在最后一个用过的subplot(如果没有则创建一个)上进行绘制

# bins 设置划分面元(绘制柱状图)
plt.hist(np.random.randn(100), bins=20, color='k', alpha=0.3)
ax2 = fig.add_subplot(2, 2, 2) 
# 散点图
plt.scatter(np.arange(30), np.arange(30) + 3 * np.random.randn(30))
ax3 = fig.add_subplot(2, 2, 3) 
# 折线图
plt.plot([1.5, 3.5, -2, 1.6])
# cumsum 叠加虚线折线图,同时缩小实线折线图
plt.plot(np.random.randn(50).cumsum(), 'k--')
在一个画布中同时创建柱状图、散点图、折线图(虚线)

“k—“是一个线型选项,用于告诉matplotlib绘制黑色虚线图

plt.subplots,它可以创建一个新的Figure,并返回一个含有已创建的subplot对象的NumPy数组

subplots

调整subplot周围的间距默认情况下,matplotlib会在subplot外围留下一定的边距,并在subplot之间留下一定的间距。间距跟图像的高度和宽度有关,因此如果你调整了图像大小(不管是编程还是手工), 间距也会自动调整。利用Figure的subplots_adjust方法可以轻而易举地修改间距:

subplots_adjust参数及说明

wspace和hspace用于控制宽度和高度的百分比,可以用作subplot之间的间距。下面是一个简单的例子,将间距收缩到了0

将间距收缩到0

颜色、标记和线型

matplotlib的plot函数接受一组X和Y坐标,还可以接受一个表示颜色和线型的字符串缩写。

关闭之前的画图窗口,否则新图会直接画在之前的最后一小部分

简便方法

plt.plot(np.random.randn(30).cumsum(), color='k', linestyle='dashed', marker='i')
简单设置参数

非实际数据点默认是按线性方式插值的。可以通过drawstyle选项修改在线型图中,非实际数据点默认是按线性方式插值的。可以通过drawstyle选项修改:

data = np.random.randn(30).cumsum()

plt.plot(data, 'k--', label='Default')

plt.plot(data, 'k-', drawstyle='steps-post', label='steps-post') 
通过drawstyle选项修改

设置标题、轴标签、刻度以及刻度标签

fig = plt.figure()

fig.add_subplot(1, 1, 1)

plt.plot(np.random.randn(1000).cumsum())
新的画布

要改变x轴刻度,最简单的办法是使用set_xticks和set_xticklabels。前者告诉matplotlib要将刻度放在数据范围中的哪些位置,默认情况下,这些位置也就是刻度标签。但我们可以通过 set_xticklabels将任何其他的值用作标签

# 设置轴标签
plt.xticks([0, 250, 500, 750, 1000], ['one', 'two', 'three', 'four', 'five'], rotation=30, fontsize='small')

# 设置标题
plt.title('My first matplotlib plot') 

# 设置图名
plt.xlabel('Stages')
设置效果

添加图例

plt.plot(randn(1000).cumsum(), 'k', label='one')

plt.plot(randn(1000).cumsum(), 'k--', label='two') 

plt.plot(randn(1000).cumsum(), 'k.', label='three') 

# plt.legend()来自动创建图例
plt.legend(loc='best')
添加图例

读取文件并显示图表

from datetime import datetime

fig = plt.figure() 
fig.add_subplot(1, 1, 1)

data = pd.read_csv('spx.csv', index_col=0, parse_dates=True) 
spx = data['SPX']

plt.plot(spx, 'k-')
读取文件并显示图表

图表保存到文件

plt.savefig('figpath.png', dpi=400, bbox_inches='tight')

使用pandas和seaborn绘图

Seaborn简化了许多常见可视类型的创建

线型图

Series和DataFrame都有一个用于生成各类图表的plot方法。默认情况下,它们所生成的是线型图

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。

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()
DataFrame-线形图

柱状图

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)
垂直和水平柱状图的比较

对于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()
按行分组,并排显示

设置stacked=True即可为DataFrame生成堆积柱状图,这样每行的值就会被堆积在一起。

堆积行值

柱状图有一个非常不错的用法:利用value_counts图形化显示Series中各值的出现频率,比如s.value_counts().plot.bar()以有关小费的数据集为例, 假设我们想要做一张堆积柱状图以展示每天各种聚会规模的数据点 的百分比。用read_csv将数据加载进来,然后根据日期和聚会规模创建一张交叉表:

# 加载数据
tips = pd.read_csv('tips.csv')

#获取关键字段
party_counts = pd.crosstab(tips['day'], tips['size'])

# 截取绘图数据
party_counts = party_counts.loc[:, 2:5]

然后进行规格化,使得各行的和为1,并生成图表:

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')
绘制结果

绘制在柱状图上的黑线代表95%置信区间

细化小费组成

直方图和密度图

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

tips['tip_pct'].plot.hist(bins=50)
绘制直方图

与此相关的一种图表类型是密度图,它是通过计算“可能会产生观测数据的连续概率分布的估计”而产生的。一般的过程是将该分布近似为一组核(即诸如正态分布之类的较为简单的分布)。因此,密度图也被称作KDE(Kernel Density Estimate,核密度估计)图。

KDE

用seaborn绘制

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数据集,选择了几个变量,然后计算对数差

macro = pd.read_csv('macrodata.csv')
data = macro[['cpi', 'm1', 'tbilrate', 'unemp']]
# 对数差
trans_data = np.log(data).diff().dropna()
数据准备

使用seaborn的regplot方法,它可以做一个散布图,并加上一条线性回归的线

sns.regplot('m1', 'unemp', data=trans_data) 

plt.title('Changes in log %s versus log %s' % ('m1', 'unemp'))
散点图+回归线

seaborn提供了一个便捷的pairplot函数,它支持在对角线上放置每个变量的直方图或密度估计

sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha': 0.2})
数据对比

分面网格(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支持其它的绘图类型,你可能会用到。例如,盒图(它可以显示中位数,四分位数,和异常值)就是一个有用的可视化类型

sns.factorplot(x='tip_pct', y='day', kind='box',data=tips[tips.tip_pct < 0.5])
盒图
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容