1. 程式人生 > >利用Python進行資料分析——第8章繪圖及視覺化——學習筆記Python3 5.0.0

利用Python進行資料分析——第8章繪圖及視覺化——學習筆記Python3 5.0.0

matplotlib API 入門

matplotlib API 函式(如plot和close)都位於matplotlib.pyplot模組中,通常的引入方式如下:

import matplotlib.pyplot as plt

Figure和Subplot

matplotlib的影象都位於Figure物件中。可以用plt.figure建立一個新的Figure.

fig=plt.figure()

這時會彈出一個空視窗。當Spyder不能彈出一個空視窗時,選擇Spyder的tools下拉選單preferences,選擇IPython console視窗中Graphics,將Backend從Inline改成Qt5,注意:應用後,要重啟Spyder

plt.figure有一些選項,特別是figsize,它用於確保當圖片儲存到磁碟時具有一定的大小和縱橫比。
不能通過空Figure繪圖。必須用add_subplot建立一個(add_subplot(1,1,1))或多個subplot才行。

ax1=fig.add_subplot(2,2,1)#影象是2x2的,當前選中的是4個subplot中的第一個(編號從1開始)
ax2=fig.add_subplot(2,2,2)
ax3=fig.add_subplot(2,2,3)
#這段程式碼需要在fig=plt.figure()的基礎上繪製圖像,也就是說不要把fig=plt.figure()建立的空視窗關閉


如果這時發出一條繪圖命令(如plt.plot([1.5,3.5,-2,1.6])),matplotlib就會在最後一個用過的subplot上進行繪製。

from numpy.random import randn
plt.plot(randn(50).cumsum(),'k--')#“k--”是一個線型選項,用於告訴matplotlib繪製黑色虛線圖
#為當前影象或最後一個使用的subplot物件繪製,所以圖出現在第3個subplot中

上面那些由fig.add_subplot所返回的物件是AxesSubplot物件

_=ax1.hist(randn(100),bins=20,color='k',alpha=0.3)
ax2.scatter(np.arange(30),np.arange(30)+3*randn(30))#指定某個影象物件,進行繪製

plt.subplot方法可以建立一個新的Figure,並返回一個含有已建立的subplot物件的NumPy陣列
fig,axes=plt.subplots(2,3)
In [6]: axes     #這個和書上的返回結果不同
Out[6]: 
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x000000000E8CB9B0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x000000000D73FD30>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x000000000D772E80>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x000000000D7AAFD0>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x000000000D7EE048>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x000000000E91CF60>]], dtype=object)

可以像對二維陣列一樣,對axes陣列進行索引,例如axes[0,1],代表第1行第2個axes物件.可以通過sharex和sharey指定subplot應該具有相同的X軸或Y軸。


調整subplot周圍的間距

預設情況下,matplotlib會在subplot外圍留下一定的邊距,並在subplot之間留下一定的間距。間距和影象的高度和寬度有關。利用Figure的subplots_adjust方法可以修改間距。

subplots_adjust(left=None,bottom=None,right=None,wspace=None,hspace=None)

wspace和hspace用於控制寬度和高度的百分比,可以用作subplot之間的間距。

fig,axes=plt.subplots(2,2,sharex=True,sharey=True)#產生兩行兩列共4個空白子圖
for i in range(2):
    for j in range(2):
        axes[i,j].hist(randn(500),bins=50,color='k',alpha=0.5)


plt.subplots_adjust(wspace=0,hspace=0)#各subplot之間沒有間距,且標籤重疊了

顏色、標記和線型

matplotlib的plot函式接受一組X和Y座標,還可以接受一個表示顏色和線型的字串縮寫。例如,要根據x和y繪製綠色虛線。

ax.plot(x,y,'g--')   #這裡的ax表示某個影象物件,比如上文的as1,as2,as3
通過下面這種更為明確的方式也能得到同樣的效果:
ax.plot(x,y,linestyle='--',color='g') #linestyle用於指明線型
常用的顏色都有一個縮寫詞,要使用其他任意顏色可以通過指定其RGB值的形式使用(例如,‘#CECECE’)。
b: blue #藍色
g: green #綠色
r: red #紅色
c: cyan #青色
m: magenta #洋紅或紫紅
y: yellow #黃色
k: black #黑色
w: white #白色
線型圖還可以加上一些標記(marker),以強調實際的資料點。由於matplotlib建立的是連續的線形圖(點與點之間的插值),因此有時可能看不出真實資料點的位置。標記也可以放到格式字串中,但標記型別和線型必須放在顏色後面。
plt.plot(randn(30).cumsum(),'ko--')
plt.plot(randn(30).cumsum(),color='k',linestyle='dashed',marker='o') #dashed表示虛線,兩種表達方式意思相同
data=randn(30).cumsum()
fig,axes=plt.subplots(3,3)
axes[0,0].plot(data,'g+-')#綠色的+形
axes[0,1].plot(data,'c*-')#青色的*形
axes[0,2].plot(data,'ms-')#洋紅色的正方形
axes[1,0].plot(data,'rh--')#紅色的六邊形
axes[1,1].plot(data,'kD--')#黑色的菱形
axes[1,2].plot(data,'b^--')#藍色的一角向上三角形
axes[2,0].plot(data,'y<:')#黃色的一角向左三角形,所以>表示一角向右三角形
axes[2,1].plot(data,color='#800080',linestyle=':',marker='x') #purple紫色的x形
axes[2,2].plot(data,color='#FF8C00',linestyle='-.',marker='o')#darkorange深橘色的圓形

線上型圖中,非實際資料點預設是按線性方式插值的。可以通過drawstyle選項修改。

data=randn(30).cumsum()
plt.plot(data,'k--',label='Default')
plt.plot(data,'k-',drawstyle='steps-post',label='steps-post')
plt.legend(loc='best')#放置圖例,最佳(best)位置

刻度、標籤和圖例

pyplot介面的設計目的就是互動式使用,含有諸如xlim、xticks和xticklabels之類的方法。分別控制圖表的範圍、刻度位置、刻度標籤等。其使用方式有以下兩種:

  • 呼叫時不帶引數,則返回當前的引數值。例如plt.xlim()返回當前X軸繪圖範圍
  • 呼叫時帶引數,則設定引數值。因此plt.xlim([0,10])會將X軸的範圍設定為0到10
In [22]: plt.xlim()
Out[22]: (-1.4500000000000002, 30.449999999999999)
In [23]: plt.xlim([0,10])
Out[23]: (0, 10)

所有這些方法都是對當前或最近建立的AxesSubplot起作用。它們各自對應subplot物件上的兩種方法,以xlim為例,就是ax.get_xlim和ax.set_xlim。

設定標題、軸標籤、刻度、以及刻度標籤

fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot(randn(1000).cumsum())

要修改X軸的刻度,最簡單的辦法是使用set_xticks和set_xticklabels。前者告訴matplotlib要將刻度放在資料範圍中的哪些位置,預設情況下,這些位置也就是刻度標籤。也可以通過set_xticklabels設定其他標籤。
ticks=ax.set_xticks([0,250,500,750,1000]) #標籤的位置。預設情況下,這些數字就是標籤
labels=ax.set_xticklabels(['one','two','three','four','five']) #在上面的位置上,增添標籤
labels=ax.set_xticklabels(['one','two','three','four','five'],rotation=30,fontsize='small')#rotation旋轉角度
ax.set_title('My first matplotlib plot')#設定標題
ax.set_xlabel('Stages')#設定X軸標籤
ax.set_ylabel('Cumsum')#設定Y軸標籤



新增圖例

圖例(legend)是另一種用於標識圖表元素的重要工具。最簡單的是在新增subplot的時候傳入label引數,然後可以呼叫ax.legend()或plt.legend()來自動建立圖例。

fig=plt.figure()
ax=fig.add_subplot(1,1,1)
ax.plot(randn(1000).cumsum(),'k',label='one')
ax.plot(randn(1000).cumsum(),'k--',label='two')
ax.plot(randn(1000).cumsum(),'k.',label='three')
ax.legend(loc='best')

loc告訴matplotlib要將圖例放在哪,'best'表示一個合適的位置。要從圖例中去除一個或多個元素,不傳入label或傳入label='_nolegend_'即可

註解以及在Subplot上繪圖

註解可以通過text、arrow和annotate等函式進行新增。text可以將文字繪製在圖表的指定座標(x, y),還可以加上自定義的格式。

ax.text(x,y,'Hello world!',family='monospace',fontsize=10)

註釋中可以既含有文字又含有箭頭。在annotate函式中,xy=(x, y)表示被註釋的地方,也就是箭頭指向的位置;xytext=(x, y)表示插入文字的地方,也就是註釋內容顯示的起始位置;label表示新增的內容,如‘peak of the market’;arrowprops用來設定箭頭,facecolor設定箭頭的顏色,headlength箭頭的寬度,width箭身的寬度。

from datetime import datetime
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
data=pd.read_csv('spx.csv',index_col=0,parse_dates=True)
spx=data['SPX']
spx.plot(ax=ax,style='k-')
crisis_data=[(datetime(2007,10,11),'Peak of bull market'),
            (datetime(2008,3,12),'Bear Stearns Fails'),
            (datetime(2008,9,15),'Lehman Bankruptcy')]
for date,label in crisis_data:
    ax.annotate(label,xy=(date,spx.asof(date)+50),xytext=(date,spx.asof(date)+200),
                arrowprops=dict(facecolor='black'),horizontalalignment='left',verticalalignment='top')
ax.set_xlim(['1/1/2007','1/1/2011'])#放大到2007-2010
ax.set_ylim([600,1800])
ax.set_title('Important dates in 2008-2009 financial crisis')

圖形的繪製。matplotlib有一些表示常見圖形的物件。這些物件被稱為塊(patch)。其中有些可以在matplotlib.pyplot中找到(如Rectangle和Circle),但完整集合位於matplotlib.patches。

要在圖表中新增一個圖形,需要建立一個塊物件shp,然後通過ax.add_patch(shp)將其新增到subplot中。

fig=plt.figure()
ax=fig.add_subplot(1,1,1)
rect=plt.Rectangle((0.2,0.75),0.4,0.15,color='k',alpha=0.3)
circ=plt.Circle((0.7,0.2),0.15,color='b',alpha=0.3)
pgon=plt.Polygon([[0.15,0.15],[0.35,0.4],[0.2,0.6]],color='g',alpha=0.5)
ax.add_patch(rect)
ax.add_patch(circ)
ax.add_patch(pgon)

將圖表儲存到檔案

利用plt.savefig可以將當前圖表儲存到檔案。該方法相當於Figure物件的例項方法savefig。例如,要將圖表儲存為SVG檔案,只需輸入:

plt.savefig('figpath.svg')

檔案型別是通過副檔名推斷出來的。因此,如果你使用的是.pdf,就會得到一個PDF檔案。有兩個重要的選項是dpi(控制“每英寸點數”解析度)和bbox_inches(可以剪除當前圖表周圍的空白部分)。要得到一張帶有最小白邊且解析度為400DPI的PNG圖片,可以:

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

savefig並非一定要寫入磁碟,也可以寫入任何檔案型的物件,比如SrtingIO,這對在Web上提供動態生成的圖片很實用

from io import StringIO  #沒試驗成功
buffer=StringIO()
plt.savefig(buffer)
plot_data=buffer.getvalue()

matplotlib配置

matplotlib自帶一些配色方案,以及為生成出版質量的圖片而設定的預設配置資訊。幾乎所有預設行為都能通過一組全域性引數進行自定義,他們可以管理影象大小、subplot邊距、配色方案、字型大小、網格型別等。操作matplotlib配置系統的方式主要有兩種。第一種是Python程式設計方式,即利用rc方法。比如說要將全域性的影象預設大小設定為10x10.

plt.rc('figure',figsize=(10,10))
rc的第一個引數是希望自定義的物件,如'figure'、'aaxes'、'xtick'、'ytick'、'grid'、'legend'等。其後可以跟上一系列的關鍵字引數。最簡單的方法是將這些選項寫成一個字典:
font_options={'family':'monospace','weight':'bold','size':'small'}
plt.rc('font',**font_options)

pandas中的繪圖函式

線型圖

Series和DataFrame都有一個用於生成各類圖表的plot方法。預設情況下,它們生成的是線型圖。

s=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。



pandas的大部分繪圖方法都有一個可選ax引數,它可以是一個matplotlib的subplot物件,能夠在網格佈局中更為靈活的處理subplot的位置。

DataFrame的plot方法會在一個subplot中為各列繪製一條線,並自動建立圖例。

df=DataFrame(np.random.randn(10,4).cumsum(0),columns=['A','B','C','D'],index=np.arange(0,100,10))
df.plot()


DataFrame還有一些用於對列進行靈活處理的選項,例如,是要將所有列都繪製到一個subplot中還是建立各自的subplot。

DataFrame.plot(x=None, y=None,kind='line', ax=None, subplots=False, sharex=None,sharey=False,layout=None,
figsize=None, use_index=True, title=None, grid=None, legend=True, style=None,logx=False,logy=False,loglog=False
xticks=None, yticks=None, xlim=None, ylim=None,rot=None,fontsize=None,colormap=None,table=False, yerr=None, xerr=None, secondary_y=False, sort_columns=False, **kwds)


柱狀圖

在生成線型圖的程式碼中加上kind='bar'(垂直柱狀圖)或kind='barh'(水平柱狀圖)即可生成柱狀圖。這時,Series和DataFrame的索引將會被用作X(bar)或Y(barh)刻度。

fig,axes=plt.subplots(2,1)  #生成兩行一列的影象
data=Series(np.random.rand(16),index=list('abcdefghijklmnop'))
data.plot(kind='bar',ax=axes[0],color='k',alpha=0.7)#axes[0]表示第一個影象物件
data.plot(kind='barh',ax=axes[1],color='k',alpha=0.7)


對於DataFrame,柱狀圖會將每一行的值分為一組。DataFrame各列的名稱“Genus”被用作了圖例的標題。

df=DataFrame(np.random.rand(6,4),index=['one','two','three','four','five','six'],
columns=pd.Index(['A','B','C','D'],name='Genus'))
df.plot(kind='bar')
#設定stacked=True即可為DataFrame生成堆積柱狀圖,這樣每行的值就會被堆積在一起。
df.plot(kind='barh',stacked=True,alpha=0.5)


柱狀圖有一個不錯的用法,利用value_counts圖形化顯示Series中各值的出現頻率,比如s.value_counts().plot(kind='bar').

s=Series([1,2,1,3,4,5,6,4,3,3,2,2,2])
s.value_counts().plot(kind='bar')

關於小費的堆積柱狀圖

tips=pd.read_csv('tips.csv')
party_counts=pd.crosstab(tips['day'],tips['size']) 
#crosstab第一個引數指定index,第二個引數指定columns,按照指定的行和列統計分組頻數
#書上原文是party_counts=pd.crosstab(tips.day,tips.size)
#按照書上的程式碼會得到一個彙總的資料
In [110]: pd.crosstab(tips['day'],tips['size']) 
Out[110]: 
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 [117]: pd.crosstab(tips.day,tips.size)
Out[117]: 
col_0  1464
day        
Fri      19
Sat      87
Sun      76
Thur     62
party_counts=party_counts.ix[:,2:5]
party_pcts=party_counts.div(party_counts.sum(1).astype(float),axis=0)
#按行歸一,即先對一行資料求和,得到一個sum值,然後用該行的每一個數據去除這個sum值,得到一個比值
In [115]: party_pcts
Out[115]: 
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
party_pcts.plot(kind='bar',stacked=True)

直方圖是一種可以對值頻率進行離散化顯示的柱狀圖。資料點被拆分到離散的、間隔均勻的面元中,繪製的是各面元中資料點的數量。

小費佔消費總額百分比的直方圖

tips['tip_pct']=tips['tip']/tips['total_bill']
#新增一列tip_pct,tip_pct的數值是tip列除以total_bill列
tips['tip_pct'].hist(bins=50)
#分成面元數為50

密度圖通過計算“可能會產生觀測資料的連續概率分佈的估計”而產生的。一般的過程是將該分佈近似為一組核(即諸如正態(高斯)分佈之類較為簡單的分佈)。因此,密度圖也被稱為KDE(核密度估計)圖。呼叫plot時加上kind=‘kde’即可生成一張密度圖(標準混合正態分佈KDE)。

這兩種圖常常會被畫在一起。直方圖以規格化形式給出(以便給出面元化密度),然後再在其上繪製核密度估計。

一個由兩個不同的標準正態分佈組成的雙峰分佈。

comp1=np.random.normal(0,1,size=200)#N(0,1)
comp2=np.random.normal(10,2,size=200)#(10,4)
values=Series(np.concatenate([comp1,comp2]))
values.hist(bins=100,alpha=0.3,color='k',normed=True)
values.plot(kind='kde',style='k--')

散佈圖(scatter plot)是觀察兩個一維資料序列之間的關係的有效手段。matplotlib的scatter方法是繪製散佈圖的主要方法。

macro=pd.read_csv('macrodata.csv')
data=macro[['cpi','m1','tbilrate','unemp']]#從macro中選出四列資料
trans_data=np.log(data).diff().dropna()#np.log()取對數,diff()一階差分
trans_data[-5:]
In [139]: trans_data[-5:]
Out[139]: 
          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
plt.scatter(trans_data['m1'],trans_data['unemp'])
plt.title('Changes in log %s vs. log %s' %('m1','unemp'))

散佈圖矩陣(scatter plot matrix),可以同時觀察一組變數的散佈圖。pandas提供了一個能從DataFrame建立散佈圖矩陣的scatter_matrix函式。他還支援在對角線上放置各變數的直方圖或密度圖。

pd.scatter_matrix(trans_data,diagonal='kde',color='k',alpha=0.3)