半小時學完視覺化利器Matplotlib
學ML那麼常用工具庫Numpy,Pandas,Matplotlib和Scipe等肯定是要用到的,磨刀不誤砍柴工,所以先學一些是有必要的,這裡先學習下Matplotlib,由於是程式碼+圖的學習,所以半小時是夠的。
Matplotlib是資料科學領域流行的Python底層繪相簿,主要做資料視覺化圖表,看名字感覺就很像Matlab,所以你用過Matlab畫圖的話那麼使用Matplotlib就會很熟練。
文章首先會介紹怎樣簡陋的折線圖,然後一步步完善。最後會畫直方圖,條形圖,散點圖。關於更多圖的畫法去看官方文件更多圖
1、首先來畫個一天的氣溫隨時間的變化圖,時間間隔是2小時。
from matplotlib import pyplot as plt #導包 x = range(2,26,2) #橫座標,時間間隔兩小時 y = [15,13,14,17,20,25,26,26,24,22,19,15] #溫度 plt.plot(x,y) #畫折線圖,注意x和y的元素個數必須相同 plt.show() #展示
效果如下
現在我們來完善這個圖。
- 圖片有點小
- 缺少描述資訊,比如橫縱座標,圖的意義
- 橫縱軸間距過大(圖中是系統給我們自動調整的)
- 線條的樣式,比如顏色和透明度
- 將圖片儲存
from matplotlib import pyplot as plt #導包 #設定圖片寬高,畫素 注意:要放在開頭 plt.figure(figsize=(20,8),dpi=80) x = range(2,26,2)#橫座標,時間間隔兩小時 y = [15,13,14,17,20,25,26,26,24,22,19,15] #溫度 plt.plot(x,y) #畫折線圖,注意x和y的元素個數必須相同 _tick_lable = [i/2 for i in range(4,49)] plt.xticks(_tick_lable) # plt.xticks(x) plt.yticks(range(min(y),max(y)+1))#max(y)是取不到的所以+1 plt.savefig("./t1.png") #儲存圖片 plt.show() #展示
效果展示
上面的5個問題解決了3個。
再看一個例子:如果列表a表示10點到12點的每一分鐘的氣溫,如何繪製折線圖觀察每分鐘氣溫的變化情況?
from matplotlib import pyplot as plt import random #解決中文顯示問題,mat是不顯示中文的 plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤 plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號 #1、準備資料 x = list(range(0,120)) #轉list是為了後面取步長 y = [random.randint(18,33) for i in range(120)] #2、設定大小並繪圖 plt.figure(figsize=(20,8),dpi=80) plt.plot(x,y) #3、設定x刻度與表示 我們要顯示的是幾點幾分而不是數字 _x_labels = ["10點{}分".format(i) for i in range(0,60)] _x_labels += ["11點{}分".format(i) for i in range(0,60)] #前面兩個會一一對應,也就是原本的數字會被字串幾點幾分給替換掉,rotation表示旋轉度數,如果不旋轉那麼會擠壓到一起,可以自己嘗試下 plt.xticks(x[::3],_x_labels[::3],rotation = 270) #4、設定描述資訊x,y軸,已經圖形 plt.xlabel("時間 min") plt.ylabel("溫度 單位(攝氏度)") plt.title("10點到12點溫度隨時間變化圖") #5、繪製網格,設定透明度 plt.grid(alpha = 0.3) #6、展示 plt.show()
到這裡一個散點圖也就繪製的有模有樣了。有時候需要將兩個或者多個折線圖繪在一起,這樣可以更直觀的進行比較,怎麼做呢,其實很簡單,看下面例子。
現在假設要繪製你和你室友,11到30這20年來交往的女友數量,看誰xxx。
from matplotlib import pyplot as plt
#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號
#1、準備資料,y_1是你,y_2是你室友
x=range(11,31)
y_1 = [1,0,1,1,2,4,3,2,3,4,4,5,6,5,4,3,3,1,1,1]
y_2 = [1,0,3,1,2,2,3,3,2,1 ,2,1,1,1,1,1,1,1,1,1]
#2、設定圖片大小並繪圖
plt.figure(figsize=(20,8),dpi=80)
plt.plot(x,y_1)
plt.plot(x,y_2) #注意這裡
#3、設定x,y軸刻度
_x_labels = ["{}歲".format(i) for i in range(11,31)]
_y_labels = range(0,9)
plt.xticks(x,_x_labels)
plt.yticks(_y_labels)
#4、設定描述資訊x,y軸,以及圖形
plt.xlabel("年齡")
plt.ylabel("女友數量")
plt.title("女友數量隨時間變化圖")
#5、繪製網格,設定透明度
plt.grid(alpha = 0.3)
#6、展示
plt.show()
看效果圖
注意上面的程式碼,除了多了個y_2資料外,也就多了個繪圖程式碼plt.plot(x,y_2)。
補充:線條顏色是mat自動幫我們決定的,但是我們也可以自己決定。另外別人根本不知道那條線是你的哪條是你室友的,所以需要標註,最後線條的形狀也可以自己決定。如何改,下面已經標註了。
到這裡,折線圖就完全繪製完了,那麼下面繪製的散點圖,直方圖,條形圖的例子就很簡單了。其他圖的繪製連結已經在上面給出了。
2、繪製散點圖,主要在於繪圖方法不同,使用plt.scatter(x,y),下面會將兩組資料繪製在一起。
先還是畫個簡陋的,然後來調整
from matplotlib import pyplot as plt
#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號
x_3 = range(1,32)
x_10 = range(41,72) #給10間隔是為了不會連在一起
y_3 = [11,17,16,11,12,11,12,6,6,7,8,9,12,15,14,17,18,21,16,17,20,14,15,15,15,19,21,22,22,22,23]
y_10 = [26,26,28,19,21,17,16,19,18,20,20,19,22,23,17,20,21,20,22,15,11,15,5,13,17,10,11,13,12,13,6]
#注意:跟折線圖區別就是這裡
plt.scatter(x_3,y_3,label = "3月份",color = "r")
plt.scatter(x_10,y_10,label = "10月分",color = "y")
plt.legend(loc = "upper left")
plt.show()
來看效果圖
發現還是挺好看的,但是橫縱並不是我們想要的,下面進行調整並展示
from matplotlib import pyplot as plt
#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號
x_3 = range(1,32)
x_10 = range(41,72) #給10間隔是為了不會連在一起
y_3 = [11,17,16,11,12,11,12,6,6,7,8,9,12,15,14,17,18,21,16,17,20,14,15,15,15,19,21,22,22,22,23]
y_10 = [26,26,28,19,21,17,16,19,18,20,20,19,22,23,17,20,21,20,22,15,11,15,5,13,17,10,11,13,12,13,6]
plt.figure(figsize=(20,8),dpi=100)
plt.scatter(x_3,y_3,label = "3月份",color = "r")
plt.scatter(x_10,y_10,label = "10月分",color = "y")
_x = list(x_3) + list(x_10)
_x_labels = ["3月{}日".format(i) for i in x_3]
_x_labels += ["10月{}日".format(i-40) for i in x_10]
plt.xticks(_x[::3],_x_labels[::3],rotation=45)
plt.xlabel("月份")
plt.ylabel("溫度 單位(攝氏度)")
plt.title("3,10月溫度隨時間變化圖")
plt.legend(loc = "upper left")
plt.show()
到這裡就畫完了散點圖了,以後聚類會用到的,接下來畫條形圖。
3、條形圖示例
假設你獲取到了2017年內地電影票房前20的電影(列表a)和電影票房資料(列表b),那麼如何更加直觀的展示該資料?
a = [“戰狼2”,“速度與激情8”,“功夫瑜伽”,“西遊伏妖篇”,“變形金剛5:最後的騎士”,“摔跤吧!爸爸”,“加勒比海盜5:死無對證”,“金剛:骷髏島”,“極限特工:終極迴歸”,“生化危機6:終章”,“乘風破浪”,“神偷奶爸3”,“智取威虎山”,“大鬧天竺”,“金剛狼3:殊死一戰”,“蜘蛛俠:英雄歸來”,“悟空傳”,“銀河護衛隊2”,“情聖”,“新木乃伊”,]
b=[56.01,26.94,17.53,16.49,15.45,12.96,11.8,11.61,11.28,11.12,10.49,10.3,8.75,7.55,7.32,6.99,6.88,6.86,6.58,6.23] 單位:億
照舊,先畫個簡陋的,跟折線圖比,同樣也只是畫圖方法不同plt.bar
from matplotlib import pyplot as plt
#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號
a = ["戰狼2","速度與激情8","功夫瑜伽","西遊伏妖篇","變形金剛5:最後的騎士","摔跤吧!爸爸","加勒比海盜5:\n死無對證","金剛:骷髏島","極限特工:終極迴歸","生化危機6:終章","乘風破浪","神偷奶爸3","智取威虎山","大鬧天竺","金剛狼3:殊死一戰","蜘蛛俠:英雄歸來","悟空傳","銀河護衛隊2","情聖","新木乃伊"]
b=[56.01,26.94,17.53,16.49,15.45,12.96,11.8,11.61,11.28,11.12,10.49,10.3,8.75,7.55,7.32,6.99,6.88,6.86,6.58,6.23]
plt.figure(figsize=(20,8),dpi=100)
plt.bar(range(len(a)),b,width = 0.3)#可以直接寫成plt.bar(a,b),此時下面那句只需要旋轉90度即可。
#對應字元到x軸上,一定要旋轉90度,不然就擠到一起了
plt.xticks(range(len(a)),a,rotation = 90)
plt.show()
來看效果圖
是不是看著有些彆扭,那麼橫過來吧,使用方法plt.barh()
實際上我們平常看到的都是多個條形圖放一起的,下面就來放到一起。
假設你知道了列表a中電影分別在2017-09-14(b_14), 2017-09-15(b_15), 2017-09-16(b_16)三天的票房,為了展示列表中電影本身的票房以及同其他電影的資料對比情況,應該如何更加直觀的呈現該資料?
a = [“猩球崛起3:終極之戰”,“敦刻爾克”,“蜘蛛俠:英雄歸來”,“戰狼2”]
b_16 = [15746,312,4497,319]
b_15 = [12357,156,2045,168]
b_14 = [2358,399,2358,362]
資料來源: http://www.cbooo.cn/movieday
from matplotlib import pyplot as plt
#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號
a = ["猩球崛起3:終極之戰","敦刻爾克","蜘蛛俠:英雄歸來","戰狼2"]
b_14 = [2358,399,2358,362]
b_15 = [12357,156,2045,168]
b_16 = [15746,312,4497,319]
plt.figure(figsize=(20,8),dpi=100)
wid_bar = 0.2 #不要設定太大,否則就擠到一起了,甚至重疊
x_14 = range(len(a))
x_15 = [i + wid_bar for i in x_14]
x_16 = [i + wid_bar for i in x_15]
#注意:width必須為wid_bar,否則會發生重疊,上面的處理也正是為了解決這個問題
plt.bar(x_14,b_14,width=wid_bar,label = "9月14日")
plt.bar(x_15,b_15,width=wid_bar,label = "9月15日")
plt.bar(x_16,b_16,width=wid_bar,label = "9月16日")
plt.xticks(x_15,a)
plt.legend(loc = "upper right")
plt.show()
來看效果圖
4、直方圖
直方圖通常來統計連續區間上的頻數或者頻率,這裡就只展示一個例子了。注意:直方圖的資料是未經處理的,組數=極差/組距離,要求能整除,否則會錯位。
假設你獲取了250部電影的時長(列表a中),希望統計出這些電影時長的分佈狀態(比如時長為100分鐘到120分鐘電影的數量,出現的頻率)等資訊,你應該如何呈現這些資料?
a=[131, 98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130, 124, 101, 110, 116, 117, 110, 128, 128, 115, 99, 136, 126, 134, 95, 138, 117, 111,78, 132, 124, 113, 150, 110, 117, 86, 95, 144, 105, 126, 130,126, 130, 126, 116, 123, 106, 112, 138, 123, 86, 101, 99, 136,123, 117, 119, 105, 137, 123, 128, 125, 104, 109, 134, 125, 127,105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120, 114,105, 115, 132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134,156, 106, 117, 127, 144, 139, 139, 119, 140, 83, 110, 102,123,107, 143, 115, 136, 118, 139, 123, 112, 118, 125, 109, 119, 133,112, 114, 122, 109, 106, 123, 116, 131, 127, 115, 118, 112, 135,115, 146, 137, 116, 103, 144, 83, 123, 111, 110, 111, 100, 154,136, 100, 118, 119, 133, 134, 106, 129, 126, 110, 111, 109, 141,120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126,114, 140, 103, 130, 141, 117, 106, 114, 121, 114, 133, 137, 92,121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113,134, 106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110,105, 129, 137, 112, 120, 113, 133, 112, 83, 94, 146, 133, 101,131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111,111, 133, 150]
from matplotlib import pyplot as plt
#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號
a=[131, 98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107,
114, 119, 128, 121, 142, 127, 130, 124, 101, 110, 116, 117, 110, 128, 128,
115, 99, 136, 126, 134, 95, 138, 117, 111,78, 132, 124, 113, 150, 110,
117, 86, 95, 144, 105, 126, 130,126, 130, 126, 116, 123, 106, 112, 138,
123, 86, 101, 99, 136,123, 117, 119, 105, 137, 123, 128, 125, 104, 109,
134, 125, 127,105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120,
114,105, 115, 132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134,156, 106,
117, 127, 144, 139, 139, 119, 140, 83, 110, 102,123,107, 143, 115, 136,
118, 139, 123, 112, 118, 125, 109, 119, 133,112, 114, 122, 109, 106, 123,
116, 131, 127, 115, 118, 112, 135,115, 146, 137, 116, 103, 144, 83, 123,
111, 110, 111, 100, 154,136, 100, 118, 119, 133, 134, 106, 129, 126, 110,
111, 109, 141,120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126,114, 140, 103, 130, 141,
117, 106, 114, 121, 114, 133, 137, 92,121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113,134,
106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110,105, 129, 137, 112, 120, 113, 133, 112, 83,
94, 146, 133, 101,131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111,111, 133, 150]
d = 3
bins = (max(a)-min(a))//d
plt.figure(figsize=(20,8),dpi=100)
plt.hist(a,bins)
#設定x的刻度
plt.xticks(range(min(a),max(a)+d,d))
plt.yticks(range(0,26,2))
plt.grid(alpha=0.4)
plt.show()
來看效果圖