信息可視化(也叫繪圖)是數(shù)據(jù)分析中最重要的工作之一。它可能是探索過程的一部分愚争,例如映皆,幫助我們找出異常值挤聘、必要的數(shù)據(jù)轉(zhuǎn)換、得出有關(guān)模型的idea等捅彻。另外组去,做一個可交互的 數(shù)據(jù)可視化也許是工作的最終目標。
matplotlib是一個用于創(chuàng)建出版質(zhì)量圖表的桌面繪圖包(主要是2D方面)步淹。
matplotlib支持各種操作系統(tǒng)上許多不同的GUI后端从隆,而且還能將圖片導出為各種常見的矢量 (vector)和光柵(raster)圖:PDF、SVG缭裆、JPG键闺、PNG、BMP澈驼、GIF等辛燥。
matplotlib API入門
matplotlib的通常引入約定是:
import matplotlib.pyplot as plt
在Jupyter中運行%matplotlib notebook 或在IPython中運行%matplotlib
IPython中進行簡單的應(yīng)用
Figure和Subplot
matplotlib的圖像都位于Figure對象中。你可以用plt.figure創(chuàng)建一個新的Figure
fig = plt.figure()
不能通過空Figure繪圖缝其。必須用add_subplot創(chuàng)建一個或多個subplot才行
# 圖像應(yīng)該是2×2的(即最多4張圖)挎塌,且當前選中的是4個subplot中的第?一個(編號從1開始)
ax1 = fig.add_subplot(2, 2, 1)
matplotlib會在最后一個用過的subplot(如果沒有則創(chuàng)建一個)上進行繪制
# bins 設(shè)置劃分面元(繪制柱狀圖)
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漠其,它可以創(chuàng)建一個新的Figure嘴高,并返回一個含有已創(chuàng)建的subplot對象的NumPy數(shù)組
調(diào)整subplot周圍的間距默認情況下,matplotlib會在subplot外圍留下一定的邊距辉懒,并在subplot之間留下一定的間距阳惹。間距跟圖像的高度和寬度有關(guān),因此如果你調(diào)整了圖像大锌袅(不管是編程還是手工)莹汤, 間距也會自動調(diào)整。利用Figure的subplots_adjust方法可以輕而易舉地修改間距:
wspace和hspace用于控制寬度和高度的百分比颠印,可以用作subplot之間的間距纲岭。下面是一個簡單的例子,將間距收縮到了0
顏色线罕、標記和線型
matplotlib的plot函數(shù)接受一組X和Y坐標止潮,還可以接受一個表示顏色和線型的字符串縮寫。
簡便方法
plt.plot(np.random.randn(30).cumsum(), color='k', linestyle='dashed', marker='i')
非實際數(shù)據(jù)點默認是按線性方式插值的喇闸。可以通過drawstyle選項修改在線型圖中,非實際數(shù)據(jù)點默認是按線性方式插值的燃乍∷舴可以通過drawstyle選項修改:
data = np.random.randn(30).cumsum()
plt.plot(data, 'k--', label='Default')
plt.plot(data, 'k-', drawstyle='steps-post', label='steps-post')
設(shè)置標題、軸標簽刻蟹、刻度以及刻度標簽
fig = plt.figure()
fig.add_subplot(1, 1, 1)
plt.plot(np.random.randn(1000).cumsum())
要改變x軸刻度逗旁,最簡單的辦法是使用set_xticks和set_xticklabels。前者告訴matplotlib要將刻度放在數(shù)據(jù)范圍中的哪些位置舆瘪,默認情況下片效,這些位置也就是刻度標簽。但我們可以通過 set_xticklabels將任何其他的值用作標簽
# 設(shè)置軸標簽
plt.xticks([0, 250, 500, 750, 1000], ['one', 'two', 'three', 'four', 'five'], rotation=30, fontsize='small')
# 設(shè)置標題
plt.title('My first matplotlib plot')
# 設(shè)置圖名
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()來自動創(chuàng)建圖例
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簡化了許多常見可視類型的創(chuàng)建
線型圖
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選項進行調(diào)節(jié)某残,Y軸就用yticks和ylim。
DataFrame的plot方法會在一個subplot中為各列繪制一條線陵吸,并自動創(chuàng)建圖例:
df = pd.DataFrame(np.random.randn(10, 4).cumsum(0),
columns=['A', 'B', 'C', 'D'],
index=np.arange(0, 100, 10))
df.plot()
柱狀圖
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()
設(shè)置stacked=True即可為DataFrame生成堆積柱狀圖,這樣每行的值就會被堆積在一起饶唤。
柱狀圖有一個非常不錯的用法:利用value_counts圖形化顯示Series中各值的出現(xiàn)頻率徐伐,比如s.value_counts().plot.bar()
以有關(guān)小費的數(shù)據(jù)集為例, 假設(shè)我們想要做一張堆積柱狀圖以展示每天各種聚會規(guī)模的數(shù)據(jù)點 的百分比。用read_csv將數(shù)據(jù)加載進來募狂,然后根據(jù)日期和聚會規(guī)模創(chuàng)建一張交叉表:
# 加載數(shù)據(jù)
tips = pd.read_csv('tips.csv')
#獲取關(guān)鍵字段
party_counts = pd.crosstab(tips['day'], tips['size'])
# 截取繪圖數(shù)據(jù)
party_counts = party_counts.loc[:, 2:5]
然后進行規(guī)格化办素,使得各行的和為1,并生成圖表:
party_pcts = party_counts.div(party_counts.sum(1), axis=0)
party_pcts.plot.bar()
通過該數(shù)據(jù)集就可以看出祸穷,聚會規(guī)模在周末會變大性穿。
使用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%置信區(qū)間
直方圖和密度圖
直方圖(histogram)是一種可以對值頻率進行離散化顯示的柱狀圖雷滚。數(shù)據(jù)點被拆分到離散的需曾、間隔均勻的面元中,繪制的是各?面元中數(shù)據(jù)點的數(shù)量。再以前面那個小費數(shù)據(jù)為例呆万,通過在Series使用plot.hist方法刻蚯,我們可以生成一張“小費占消費總額百分比”的直方圖
tips['tip_pct'].plot.hist(bins=50)
與此相關(guān)的一種圖表類型是密度圖,它是通過計算“可能會產(chǎn)生觀測數(shù)據(jù)的連續(xù)概率分布的估計”而產(chǎn)生的桑嘶。一般的過程是將該分布近似為一組核(即諸如正態(tài)分布之類的較為簡單的分布)炊汹。因此,密度圖也被稱作KDE(Kernel Density Estimate逃顶,核密度估計)圖讨便。
用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')
點圖或散布圖是觀察兩個一維數(shù)據(jù)序列之間的關(guān)系的有效手段
加載了來自statsmodels項目的macrodata數(shù)據(jù)集,選擇了幾個變量以政,然后計算對數(shù)差
macro = pd.read_csv('macrodata.csv')
data = macro[['cpi', 'm1', 'tbilrate', 'unemp']]
# 對數(shù)差
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函數(shù)盈蛮,它支持在對角線上放置每個變量的直方圖或密度估計
sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha': 0.2})
分面網(wǎng)格(facet grid)和類型數(shù)據(jù)
數(shù)據(jù)集有額外的分組維度, seaborn有一個有用的內(nèi)置函數(shù)factorplot废菱,可以簡化制作多種分面圖
sns.factorplot(x='day', y='tip_pct', hue='time', col='smoker', kind='bar', data=tips[tips.tip_pct < 1])
除了在分面中用不同的顏色按時間分組,我們還可以通過給每個時間值添加一行來擴展分面網(wǎng)格
sns.factorplot(x='day', y='tip_pct', row='time',col='smoker', kind='bar', data=tips[tips.tip_pct < 1])
factorplot支持其它的繪圖類型抖誉,你可能會用到殊轴。例如,盒圖(它可以顯示中位數(shù)袒炉,四分位數(shù)旁理,和異常值)就是一個有用的可視化類型
sns.factorplot(x='tip_pct', y='day', kind='box',data=tips[tips.tip_pct < 0.5])