全文共3576
字,預計學習時長10
分鐘或更長

圖片來源:Pexels
Seaborn和Matplotlib是Python最強大的兩個可視化庫。Seaborn其默認主題讓人驚訝,而Matplotlib可以通過其多個分類為用戶打造專屬功能。
Python提供了各種用于繪制數據的包。本教程將使用以下兩種包來演示Python的繪圖功能:
· Matplotlib
· Seaborn
Matplotlib
importmatplotlib.pyplot as plt
%matplotlib inline
import numpy as np
在上面的代碼塊中,將Pyplot模塊調整為plt格式并導入Matplotliib庫。這樣做可以簡化執行命令的過程,具體內容會在本篇教程中看到。PyPlot包含創建和編輯繪圖所需的一系列命令。操作時同時運行%matplotlibinline,那么繪圖下方就能自動顯示代碼塊,否則用戶每次繪圖時都需要輸入plt.show()來創建新圖。此功能是Jupyter Notebook / IPython獨有的。Matplotlib擁有定制的代碼塊結構,這使得它比其他繪圖庫更先進。接下來看看如何使用matploblib生成散點圖。
提示:當使用matplotlib時,文本輸出無法帶來視覺上的吸引力。為了解決這個問題,我們在執行代碼塊生成圖片時會在每一行代碼末端添加分號“;”。
我們使用的數據庫是UCI機器學習庫中的共享單車數據集。
Matplotlib: 散點圖
散點圖是各種示意圖中影響力最廣、信息量最大、功能最多的一類圖。它可以直接向用戶傳遞信息,無需太多額外工作(如下圖所示)。
· plt.scatter()將輸入的散點圖上的數據作為初始參數,其中temp指x軸,cnt指y軸。
· c指的是不同數據點的顏色。輸入一個字符串“季節”,它也表示數據幀中的一列,不同顏色對應不同季節。該方法用可視化方法對數據分組,十分簡單便捷。
plt.scatter('temp','cnt', data=day, c='season')
plt.xlabel('NormalizedTemperature', fontsize='large')
plt.ylabel('Countof Total Bike Rentals', fontsize='large');
圖上信息顯示:
· 某些時間點的自行車租賃量超過8000輛。
· 標準溫度超過0.8。
· 自行車租賃量與溫度或季節無關。
· 自行車租賃量與標準溫度之間含有正線性關系。
這個圖的確含有大量信息,然而圖表并不能產生圖例,因此我們很難對各組季節數據進行破譯。這是因為用散點圖繪圖時,Matplotlib無法根據繪圖制作圖例。下一節中,我們將會看到該圖如何隱藏信息,甚至誤導讀者。
看看經過徹底編輯后的繪圖。該圖旨在根據不同組別繪制圖例,并進行破譯。
plt.rcParams['figure.figsize']= [15, 10]
fontdict={'fontsize':18,
'weight' : 'bold',
'horizontalalignment': 'center'}
fontdictx={'fontsize':18,
'weight' : 'bold',
'horizontalalignment': 'center'}
fontdicty={'fontsize':16,
'weight' : 'bold',
'verticalalignment': 'baseline',
'horizontalalignment': 'center'}
spring =plt.scatter('temp', 'cnt', data=day[day['season']==1], marker='o',color='green')
summer =plt.scatter('temp', 'cnt', data=day[day['season']==2], marker='o', color='orange')
autumn =plt.scatter('temp', 'cnt', data=day[day['season']==3], marker='o',color='brown')
winter =plt.scatter('temp', 'cnt', data=day[day['season']==4], marker='o',color='blue')
plt.legend(handles=(spring,summer,autumn,winter),
labels=('Spring', 'Summer','Fall/Autumn', 'Winter'),
title='Season',title_fontsize=16,
scatterpoints=1,
bbox_to_anchor=(1, 0.7), loc=2,borderaxespad=1.,
ncol=1,
fontsize=14)
plt.title('BikeRentals at Different Temperatures\nBy Season', fontdict=fontdict,color='black')
plt.xlabel('Normalizedtemperature', fontdict=fontdictx)
plt.ylabel('Countof Total Rental Bikes', fontdict=fontdicty);

· plt.rcParams['figure.figsize']= [15, 10]限定了整張圖的大小,這個代碼對應的是一個長15厘米*寬10厘米的圖。
· Fontdict是一個包含許多參數的字典,可以用于標記不同的軸,其中標題為fontdict,x軸為fontdictx,y軸為fontdicty。
· 如今有四個plt.scatter()函數,對應四個不同的季節,這一點在數據參數中再次出現,而這些數據參數已被子集化以對應不同單一季節。“o”表示不同的標記和顏色參數,這可以直觀地顯示數據點的位置以及其顏色。
· 在plt.legend()中輸入參數形成圖例。前兩個參數是句柄:圖例和標簽會展示真正的散點圖;而于各個圖對應的名字也會在圖例中出現。圖上大小不一的標記代表散點,它們最終組合為一個散點圖。bbox_to_anchor=(1, 0.7), loc=2, borderaxespad=1。這三個參數串聯使用,來對照圖例位置。點擊這句話開頭的鏈接,可以發現這些參數的本質。
現在可以通過區分不同季節來發現更多隱藏信息。但即使已經添加了額外的圖層,散點圖依然可以隱藏信息并帶來誤解。
該散點圖:
· 數據中有重復部分。
· 分布混亂。
· 未顯示自行車租賃在不同季節之間的明顯差別。
· 隱藏信息,如:春夏氣溫上升時自行車出租量會增加。
· 表示自行車租賃量與氣溫呈正比關系。
· 并未清楚顯示最低溫出現在哪一季節。
子圖
創建子圖可能是業界最具吸引力也是最專業的圖表技術之一。當單一的圖信息過多時,人們難以評估,子圖就變得十分重要。
分面就是在同一個軸上繪制多個不同的圖。分面是數據可視化中功能最多的技術之一。分面可以從多個角度展示信息,也可以揭露隱藏內容。
· 如前所述,plt.figure()將用于創建新的繪圖畫布。最終會保存為圖畫格式。
· 重復運行fig.add_subplot()代碼4次,分別對應四個季節的子圖。其參數則對應nrows,ncols和index。比方說axl對應圖表上第一個繪圖(索引在左上角從1開始,向右遞增)。
· 余下的函數調用可以自我解釋或被覆蓋。
fig = plt.figure()
plt.rcParams['figure.figsize']= [15,10]
plt.rcParams['font.weight']= 'bold'
fontdict={'fontsize':25,
'weight' : 'bold'}
fontdicty={'fontsize':18,
'weight' : 'bold',
'verticalalignment': 'baseline',
'horizontalalignment': 'center'}
fontdictx={'fontsize':18,
'weight' : 'bold',
'horizontalalignment': 'center'}
plt.subplots_adjust(wspace=0.2,hspace=0.2)
fig.suptitle('BikeRentals at Different Temperatures\nBy Season',fontsize=25,fontweight='bold', color='black',
position=(0.5,1.01))
ax1 =fig.add_subplot(221)
ax1.scatter('temp','cnt', data=day[day['season']==1], c='green')
ax1.set_title('Spring',fontdict=fontdict, color='green')
ax1.set_ylabel('Countof Total Rental Bikes', fontdict=fontdicty, position=(0,-0.1))
ax2 =fig.add_subplot(222)
ax2.scatter('temp','cnt', data=day[day['season']==2], c='orange')
ax2.set_title('Summer',fontdict=fontdict, color='orange')
ax3 =fig.add_subplot(223)
ax3.scatter('temp','cnt', data=day[day['season']==3], c='brown')
ax3.set_title('Fallor Autumn', fontdict=fontdict, color='brown')
ax4 =fig.add_subplot(224)
ax4.scatter('temp','cnt', data=day[day['season']==4], c='blue')
ax4.set_title('Winter',fontdict=fontdict, color='blue')
ax4.set_xlabel('Normalizedtemperature', fontdict=fontdictx, position=(-0.1,0));

現在分別分析各組,效果也會更加顯著。首先要注意到在不同季節里,自行車租賃量與氣溫的關系存在差異:
· 它們在春天呈現正線性關系。
· 它們在冬天和夏天呈二次非線性關系。
· 在秋天它們的正線性關系十分不明顯。
但是,這些圖依然有可能誤導讀者,原因也并不明顯。四張圖中,所有的軸都不一樣。如果人們沒有留意到這一點,那么他們很有可能會誤解這些圖。請參閱下文,了解如何解決該問題。
fig = plt.figure()
plt.rcParams['figure.figsize']= [12,12]
plt.rcParams['font.weight']= 'bold'
plt.subplots_adjust(hspace=0.60)
fontdicty={'fontsize':20,
'weight' : 'bold',
'verticalalignment': 'baseline',
'horizontalalignment': 'center'}
fontdictx={'fontsize':20,
'weight' : 'bold',
'horizontalalignment': 'center'}
fig.suptitle('BikeRentals at Different Temperatures\nBy Season',fontsize=25,fontweight='bold', color='black',
position=(0.5,1.0))
#ax2 is definedfirst because the other plots are sharing its x-axis
ax2 =fig.add_subplot(412, sharex=ax2)
ax2.scatter('temp','cnt', data=day.loc[day['season']==2], c='orange')
ax2.set_title('Summer',fontdict=fontdict, color='orange')
ax2.set_ylabel('Countof Total Rental Bikes', fontdict=fontdicty, position=(-0.3,-0.2))
ax1 =fig.add_subplot(411, sharex=ax2)
ax1.scatter('temp','cnt', data=day.loc[day['season']==1], c='green')
ax1.set_title('Spring',fontdict=fontdict, color='green')
ax3 =fig.add_subplot(413, sharex=ax2)
ax3.scatter('temp','cnt', data=day.loc[day['season']==3], c='brown')
ax3.set_title('Fallor Autumn', fontdict=fontdict, color='brown')
ax4 =fig.add_subplot(414, sharex=ax2)
ax4.scatter('temp','cnt', data=day.loc[day['season']==4], c='blue')
ax4.set_title('Winter',fontdict=fontdict, color='blue')
ax4.set_xlabel('Normalizedtemperature', fontdict=fontdictx);

如今繪圖網格重新調整,所有圖的x軸都與夏天圖的x軸一致(選擇夏天的x軸為標準是因為它的溫度范圍更廣)。現在可以從數據中找到一些更有趣的發現:
· 最低溫度出現在春天。
· 最高溫度出現在秋天。
· 在夏天和秋天,自行車租賃量和溫度似乎呈二次關系。
· 不考慮季節因素時,溫度越低,自行車租賃量越少。
· 春天的自行車租賃量和溫度呈明顯的正線性關系。
· 秋天的自行車租賃量和溫度呈輕度的負線性關系。
fig = plt.figure()
plt.rcParams['figure.figsize']= [10,10]
plt.rcParams['font.weight']= 'bold'
plt.subplots_adjust(wspace=0.5)
fontdicty1={'fontsize':18,
'weight' : 'bold'}
fontdictx1={'fontsize':18,
'weight' : 'bold',
'horizontalalignment': 'center'}
fig.suptitle('BikeRentals at Different Temperatures\nBy Season',fontsize=25,fontweight='bold', color='black',
position=(0.5,1.0))
ax3 =fig.add_subplot(143, sharey=ax3)
ax3.scatter('temp','cnt', data=day.loc[day['season']==3], c='brown')
ax3.set_title('Fallor Autumn', fontdict=fontdict,color='brown')
ax1 =fig.add_subplot(141, sharey=ax3)
ax1.scatter('temp','cnt', data=day.loc[day['season']==1], c='green')
ax1.set_title('Spring',fontdict=fontdict, color='green')
ax1.set_ylabel('Countof Total Rental Bikes', fontdict=fontdicty1, position=(0.5,0.5))
ax2 =fig.add_subplot(142, sharey=ax3)
ax2.scatter('temp','cnt', data=day.loc[day['season']==2], c='orange')
ax2.set_title('Summer',fontdict=fontdict, color='orange')
ax4 =fig.add_subplot(144, sharey=ax3)
ax4.scatter('temp','cnt', data=day.loc[day['season']==4], c='blue')
ax4.set_title('Winter',fontdict=fontdict, color='blue')
ax4.set_xlabel('Normalizedtemperature', fontdict=fontdictx, position=(-1.5,0));

將所有繪圖并列放置又有新的發現:
· 所有季節都有超過8000輛自行車出租的時間點。
· 大規模的自行車出租主要出現在春秋兩季。
· 冬夏兩季中自行車租賃量變動較大。
但注意,不要從以上方面來解釋變量之間的關系。盡管春夏兩季中自行車租賃量與氣溫似乎存在負線性關系,但這一解釋實際是錯誤的。從前文的分析中我們發現事實并非如此。
Seaborn
seaborn包是基于Matplotlib庫開發的。它用于創建更具吸引力、信息量更大的統計圖形。雖然seaborn與Matplotlib不一樣,但它創建的圖像一樣具有吸引力。
盡管matplotlib表現不俗,但我們總希望做得更好。運行下面的代碼塊以導入seaborn庫,并創建先前的散點圖,來看看會出現什么。
首先輸入代碼import seaborn assns,將seaborn庫導入。下一行sns.set()將seaborn的默認主題和調色板加載到會話中。運行下面的代碼并觀察圖表中哪些區域或文字發生更改。
import seaborn assns
sns.set()
將seaborn加載到會話中后,當使用Matplotlib生成圖像時,這個庫會添加seaborn的默認自定義項,如圖所示。而最令用戶感到困擾的便是它們的標題有可能會重復——Matplotlib的命名規則讓人困惑,這一點也讓人覺得厭煩。盡管如此,這些視覺效果依然很有吸引力,數據科學家的工作已引入這一技術。
為了使標題更加與時俱進,提高其用戶友好度,需要使用如下代碼。但注意,以下代碼僅適用于散點圖中含有副標題的情況。有的時候副標題也十分重要,因此仍需更好地掌握這種結構。
fig = plt.figure()
fig.suptitle('Seabornwith Python', fontsize='x-large', fontweight='bold')
fig.subplots_adjust(top=0.87)
#This is used forthe main title. 'figure()' is a class that provides all the plotting elementsof a diagram.
#This must be usedfirst or else the title will not show.fig.subplots_adjust(top=0.85) solves ouroverlapping title problem.
ax =fig.add_subplot(111)
fontdict={'fontsize':14,
'fontweight' : 'book',
'verticalalignment': 'baseline',
'horizontalalignment': 'center'}
ax.set_title('PlottingTutorial', fontdict=fontdict)
#This specifieswhich plot to add the customizations. fig.add_sublpot(111) corresponds to topleft plot no.1
#(there is only oneplot).
plt.plot(x, y,'go-', linewidth=1) #linewidth=1 to make it narrower
plt.xlabel('x-axis',fontsize=14)
plt.ylabel('yaxis',fontsize=14);
深入挖掘seaborn的功能后,我們可以用更少的代碼行與類似的語法對自行車租賃量數據集再次創建可視化圖。Seaborn仍然使用Matplotlib語法來生成圖像,盡管新圖與舊圖之間的語法差異很小,但依然十分明顯。
為了簡化視覺效果,我們將對自行車租賃數據集的“季節”列重新命名,并重新標記。
day.rename(columns={'season':'Season'},inplace=True)
day['Season']=day.Season.map({1:'Spring',2:'Summer', 3:'Fall/Autumn', 4:'Winter'})
如今我們已根據喜好重新編輯了“季節”一欄,接下來將用seaborn對先前的繪圖進行可視化。
第一個明顯的區別在于——當默認樣式加入到會話后,seaborn顯示的默認主題不一致。上面顯示的默認主題是在調用sns.set()時在后臺應用sns.set_style('whitegrid')的結果。我們也可以根據喜好用已有主題改變原來的狀態,如下圖所示。
· sns.set_style()標記的是“white”、“dark”、“whitegrid”以及“darkgrid”中的一個。這一代碼控制著整個繪圖區域,比如顏色,網格以及標記的狀態。
· sns.set_context()表示的是“paper”、“notebook”、“talk”和“poster”的內容。這將根據讀取方式控制繪圖的布局。例如,如果內容出現在“poster”上,我們將看到放大的圖像和文字。如果內容出現在 “talk”中,其字體將會加粗。
plt.figure(figsize=(7,6))
fontdict={'fontsize':18,
'weight' : 'bold',
'horizontalalignment': 'center'}
sns.set_context('talk',font_scale=0.9)
sns.set_style('ticks')
sns.scatterplot(x='temp',y='cnt', hue='Season', data=day, style='Season',
palette=['green','orange','brown','blue'], legend='full')
plt.legend(scatterpoints=1,
bbox_to_anchor=(1, 0.7), loc=2,borderaxespad=1.,
ncol=1,
fontsize=14)
plt.xlabel('NormalizedTemperature', fontsize=16, fontweight='bold')
plt.ylabel('Countof Total Bike Rentals', fontsize=16, fontweight='bold')
plt.title('BikeRentals at Different Temperatures\nBy Season', fontdict=fontdict, color='black',
position=(0.5,1));
現在來看一個相同的散點圖,但其輸入代碼為sns.set_context('paper',font_scale=2)和sns.set_style('white')
plt.figure(figsize=(7,6))
fontdict={'fontsize':18,
'weight' : 'bold',
'horizontalalignment': 'center'}
sns.set_context('paper',font_scale=2) #this makes the font and scatterpoints much smaller, hence theneed for size adjustemnts
sns.set_style('white')
sns.scatterplot(x='temp',y='cnt', hue='Season', data=day, style='Season',
palette=['green','orange','brown','blue'],legend='full', size='Season', sizes=[100,100,100,100])
plt.legend(scatterpoints=1,
bbox_to_anchor=(1, 0.7), loc=2,borderaxespad=1.,
ncol=1,
fontsize=14)
plt.xlabel('NormalizedTemperature', fontsize=16, fontweight='bold')
plt.ylabel('Countof Total Bike Rentals', fontsize=16, fontweight='bold')
plt.title('BikeRentals at Different Temperatures\nBy Season', fontdict=fontdict,color='black',
position=(0.5,1));
現在終于用Seaborn重新創建了之前用Matplotlib生成的散點圖。更改后的圖使用的代碼行數更少,分辨率也更高。接下來繼續完成繪圖:
sns.set(rc={'figure.figsize':(20,20)})
sns.set_context('talk',font_scale=2)
sns.set_style('ticks')
g =sns.relplot(x='temp', y='cnt', hue='Season', data=day,palette=['green','orange','brown','blue'],
col='Season', col_wrap=4,legend=False
height=6, aspect=0.5,style='Season', sizes=(800,1000))
g.fig.suptitle('BikeRentals at Different Temperatures\nBy Season' ,position=(0.5,1.05),fontweight='bold', size=18)
g.set_xlabels('NormalizedTemperature',fontweight='bold', size=15)
g.set_ylabels('Countof Total Bike Rentals',fontweight='bold', size=20);
改變圖表形狀需要改變外觀參數。通過增大外觀的數值,圖表形狀會更呈方形。圖像高度也會隨著數值更改發生變化,因此這里需要同時對兩個參數進行試驗。
更改行數和列數需使用col_wrap參數執行此操作。行數和列數會隨著col參數而變化。這種參數可以檢測類比數目,同時可以相應地分配。
sns.set(rc={'figure.figsize':(20,20)})
sns.set_context('talk',font_scale=2)
sns.set_style('ticks')
g =sns.relplot(x='temp', y='cnt', hue='Season',data=day,palette=['green','orange','brown','blue'],
col='Season', col_wrap=2,legend=False
height=4, aspect=1.6,style='Season', sizes=(800,1000))
g.fig.suptitle('BikeRentals at Different Temperatures\nBy Season' ,position=(0.5,1.05),fontweight='bold', size=18)
g.set_xlabels('NormalizedTemperature',fontweight='bold', size=15)
g.set_ylabels('Countof\nTotal Bike Rentals',fontweight='bold', size=20);