1. 程式人生 > >前置機器學習(五):30分鐘掌握常用Matplotlib用法

前置機器學習(五):30分鐘掌握常用Matplotlib用法

> Matplotlib 是建立在NumPy基礎之上的Python繪相簿,是在機器學習中用於資料視覺化的工具。 我們在前面的文章講過[NumPy的用法](http://blog.caiyongji.com/2020/12/06/pre-ml-numpy-3.html),這裡我們就不展開討論NumPy的相關知識了。 Matplotlib具有很強的工具屬性,也就是說它只是為我所用的,我們不必花太多的精力去精進它。我們只需要知道它可以做那些事,可以繪製哪些圖形,有一個印象就足夠了。我們在實際使用中用什麼拿什麼,我們用到了自然就熟練了,用不到的功能也就說明它對你沒什麼用。 這就是**按需學習(Learn on Demand)** 。這點我在[《如何成為十倍速程式設計師》](http://blog.caiyongji.com/2017/12/20/how-to-be-10x-programmer.html)裡提到過類似的理念。 # 一、Matplotlib常見用法 ## 1. 繪製簡單影象 我們以機器學習中最常見的啟用函式`sigmoid`舉例,我們來繪製它。 ``` import matplotlib.pyplot as plt import numpy as np x = np.linspace(-10,10,1000) y = 1 / (1 + np.exp(-x)) plt.plot(x,y) plt.show() ``` 其中sigmoid的公式為: $y = f(x) =\frac{1}{1+e^{-x}}$ plot()方法展示變數間的趨勢,show()方法展示影象。 我們得到如圖所示影象: ![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2e43813c398445a8bcc9179d639f6285~tplv-k3u1fbpfcp-watermark.image) ## 2. 新增常用元素 我們新增一些參考元素,各函式的解釋我在程式碼中進行了詳細的標註。 ``` x = np.linspace(-10,10,1000) #寫入公式 y = 1 / (1 + np.exp(-x)) #x軸範圍限制 plt.xlim(-5,5) #y軸範圍限制 plt.ylim(-0.2,1.2) #x軸新增標籤 plt.xlabel("X axis") #y軸新增標籤 plt.ylabel("Y axis") #標題 plt.title("sigmoid function") #設定網格,途中紅色虛線 plt.grid(linestyle=":", color ="red") #設定水平參考線 plt.axhline(y=0.5, color="green", linestyle="--", linewidth=2) #設定垂直參考線 plt.axvline(x=0.0, color="green", linestyle="--", linewidth=2) #繪製曲線 plt.plot(x,y) #儲存影象 plt.savefig("./sigmoid.png",format='png', dpi=300) ``` 以上程式碼包含了限制X、Y軸範圍,新增標題和標籤,設定網格,新增參考線,儲存影象等內容。 繪製圖像如下: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/be1b3d15fa4e4257a95347e3ce93ca9a~tplv-k3u1fbpfcp-watermark.image) ## 3. 繪製多曲線 ``` #生成均勻分佈的1000個數值 x = np.linspace(-10,10,1000) #寫入sigmoid公式 y = 1 / (1 + np.exp(-x)) z = x**2 plt.xlim(-2,2) plt.ylim(0,1) #繪製sigmoid plt.plot(x,y,color='#E0BF1D',linestyle='-', label ="sigmoid") #繪製y=x*x plt.plot(x,z,color='purple',linestyle='-.', label = "y=x*x") #繪製legend,即下圖角落的圖例 plt.legend(loc="upper left") #展示 plt.show() ``` 繪製多影象直接呼叫多個plot()即可。注意:如果不呼叫legend()方法,不會繪製左上角的legend(圖例)。其中`color`引數支援hex表示。 ![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/50d5a87f58d04c35a09bf65cc5b6dbd2~tplv-k3u1fbpfcp-watermark.image) ### 4. 認識figure(畫布) 首先我們認識figure(畫布),比如legend我們在上文中提到過,是線條標籤的展示。grid所圈住的虛線是網格參考線。Title/x axislabel等文字標籤。 這張圖有助於我們對figure有一個值觀的理解。 ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aaa9c8856c4742d0b8af3dbf5abb6240~tplv-k3u1fbpfcp-watermark.image) ### 5. 繪製多影象 一個figure是可以對應多個plot的,現在我們試著在一個figure上繪製多影象。 ``` x = np.linspace(-2*np.pi, 2*np.pi, 400) y = np.sin(x**2) z = 1 / (1 + np.exp(-x)) a = np.random.randint(0,100,400) b = np.maximum(x,0.1*x) #建立兩行兩列的子影象 fig, ax_list = plt.subplots(nrows=2, ncols=2) # 'r-'其中r表示color=red,-表示linestyle='-' ax_list[0][0].plot(x,y,'r-') ax_list[0][0].title.set_text('sin') ax_list[0][1].scatter(x,a,s=1) ax_list[0][1].title.set_text('scatter') ax_list[1][0].plot(x,b,'b-.') ax_list[1][0].title.set_text('leaky relu') ax_list[1][1].plot(x,z,'g') ax_list[1][1].title.set_text('sigmoid') #調整子影象的佈局 fig.subplots_adjust(wspace=0.9,hspace=0.5) fig.suptitle("Figure graphs",fontsize=16) ``` 其中,最關鍵的是`subplots`方法,生成2行2列的子影象,然後我們呼叫ax_list中的各繪圖方法。 其中`'r-'`,`'b-.'`引數為繪圖的縮寫寫法,本文後續引數縮寫段落會單獨講解。 ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/07a254930590455891922bc4e0b5619b~tplv-k3u1fbpfcp-watermark.image) ## 6. 繪製常用圖 我們常用圖來表示資料之間的關係,常見的圖包括直方圖、柱狀圖、餅圖、散點圖等等。 ``` #使繪圖支援中文 plt.rcParams['font.sans-serif']=['Microsoft YaHei'] #建立兩行兩列的子影象 fig, [[ax1,ax2],[ax3,ax4],[ax5,ax6]] = plt.subplots(nrows=3, ncols=2,figsize=(8,8)) #繪製柱狀圖bar value = (2, 3, 4, 1, 2) index = np.arange(5) ax1.bar(index, value,alpha=0.4, color='b') ax1.set_xlabel('Group') ax1.set_ylabel('Scores') ax1.set_title('柱狀圖') #繪製直方圖histogram h = 100 + 15 * np.random.randn(437) ax2.hist(h, bins=50) ax2.title.set_text('直方圖') #繪製餅圖pie labels = 'Frogs', 'Cai', 'Yongji', 'Logs' sizes = [15, 30, 45, 10] explode = (0, 0.1, 0, 0) ax3.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90) ax3.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle. ax3.title.set_text('餅圖') #繪製棉棒圖stem x = np.linspace(0.5, 2*np.pi, 20) y = np.random.randn(20) ax4.stem(x,y, linefmt="-.", markerfmt="o", basefmt='-') ax4.set_title("棉棒圖") #繪製氣泡圖scatter a = np.random.randn(100) b = np.random.randn(100) ax5.scatter(a, b, s=np.power(2*a+4*b,2), c=np.random.rand(100), cmap=plt.cm.RdYlBu, marker="o") #繪製極線圖polar fig.delaxes(ax6) ax6 = fig.add_subplot(236, projection='polar') #ax6 = fig.add_subplot(2,3,6, projection='polar')#2行,3列,第6個圖 r = np.arange(0, 2, 0.01) theta = 2 * np.pi * r ax6.plot(theta, r) ax6.set_rmax(2) ax6.set_rticks([0.5, 1, 1.5, 2]) # Less radial ticks ax6.set_rlabel_position(-22.5) # Move radial labels away from plotted line ax6.grid(True) #調整子影象的佈局 fig.subplots_adjust(wspace=1,hspace=1.2) fig.suptitle("圖形繪製",fontsize=16) ``` 繪製圖像如下: ![](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c736b66374dd4860b007e99f3d48fe4b~tplv-k3u1fbpfcp-watermark.image) ## 7. 引數簡寫 因為matplotlib支援引數的縮寫,所以我認為有必要單獨拿出來講一講各引數縮寫的表示。 ``` x = np.linspace(-10,10,20) y = 1 / (1 + np.exp(-x)) plt.plot(x,y,c='k',ls='-',lw=5, label ="sigmoid", marker="o", ms=15, mfc='r') plt.legend() ``` 繪製圖像如下: ![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ecf1b18bc34449e89077d9f80b355a78~tplv-k3u1fbpfcp-watermark.image) ### 7.1 c代表color(顏色) | 字元 | 顏色 | |:----|----:| |‘b’|blue | |‘g’|green | |‘r’|red | |‘c’|cyan | |‘m’|magenta | |‘y’|yellow | |‘k’|black | |‘w’|white | ### 7.2 ls代表linestyle(線條樣式) | 字元 | 描述 | |:----|----:| |'-' | solid line style | |'--' | dashed line style | |'-.' | dash-dot line style | |':' | dotted line style | |'.' | point marker | |',' | pixel marker | |'o' | circle marker | |'v' | triangle_down marker | |'^' | triangle_up marker | |'<' | triangle_left marker | |'>' | triangle_right marker | |'1' | tri_down marker | |'2' | tri_up marker | |'3' | tri_left marker | |'4' | tri_right marker | |'s' | square marker | |'p' | pentagon marker | |'\*' | star marker | |'h' | hexagon1 marker | |'H' | hexagon2 marker | |'+' | plus marker | |'x' | x marker | |'D' | diamond marker | |'d' | thin_diamond marker | |'\|' | vline marker | |'\_' | hline marker | ### 7.3 marker(記號樣式) 記號樣式展示如下: ![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bccb20a6157f42969c3f0c20c4b69c71~tplv-k3u1fbpfcp-watermark.image) ### 7.4 其他縮寫 1. `lw`代表linewidth(線條寬度),如:lw=2.5 2. `ms`代表markersize(記號尺寸),如:ms=5 3. `mfc`代表markerfacecolor(記號顏色),如:mfc='red' # 二、Matplotlib進階用法 ## 1. 新增文字註釋 我們可以在畫布(figure)上新增文字、箭頭等標註,來讓影象表述更清晰準確。 我們通過呼叫`annotate`方法來繪製註釋。 ``` fig, ax = plt.subplots(figsize=(8, 8)) t = np.arange(0.0, 5.0, 0.01) s = np.cos(2*np.pi*t) # 繪製一條曲線 line, = ax.plot(t, s) #添加註釋 ax.annotate('figure pixels', xy=(10, 10), xycoords='figure pixels') ax.annotate('figure points', xy=(80, 80), xycoords='figure points') ax.annotate('figure fraction', xy=(.025, .975), xycoords='figure fraction', horizontalalignment='left', verticalalignment='top', fontsize=20) #第一個箭頭 ax.annotate('point offset from data', xy=(2, 1), xycoords='data', xytext=(-15, 25), textcoords='offset points', arrowprops=dict(facecolor='black', shrink=0.05), horizontalalignment='right', verticalalignment='bottom') #第二個箭頭 ax.annotate('axes fraction', xy=(3, 1), xycoords='data', xytext=(0.8, 0.95), textcoords='axes fraction', arrowprops=dict(facecolor='black', shrink=0.05), horizontalalignment='right', verticalalignment='top') ax.set(xlim=(-1, 5), ylim=(-3, 5)) ``` 繪製圖像如下: ![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/245e132c9ea94592aa5de845990564cb~tplv-k3u1fbpfcp-watermark.image) ## 2. 繪製3D影象 繪製3D影象需要匯入`Axes3D`庫。 ``` from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt from matplotlib import cm from matplotlib.ticker import LinearLocator, FormatStrFormatter import numpy as np fig = plt.figure(figsize=(15,15)) ax = fig.gca(projection='3d') # Make data. X = np.arange(-5, 5, 0.25) Y = np.arange(-5, 5, 0.25) X, Y = np.meshgrid(X, Y) R = np.sqrt(X**2 + Y**2) Z = np.sin(R) # Plot the surface. surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, linewidth=0, antialiased=False) # Customize the z axis. ax.set_zlim(-1.01, 1.01) ax.zaxis.set_major_locator(LinearLocator(10)) ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f')) # Add a color bar which maps values to colors. fig.colorbar(surf, shrink=0.5, aspect=5) ``` 其中`cmap`意為colormap,用來繪製顏色分佈、漸變色等。`cmap`通常配合`colorbar`使用,來繪製圖像的顏色欄。 ![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9cdd700a98884963bce2422843a4fece~tplv-k3u1fbpfcp-watermark.image) ## 3. 匯入影象(加州房價) 引入`mpimg`庫,來匯入影象。 我們以美國加州房價資料為例,匯入加州房價資料繪製散點圖,同時匯入加州地圖圖片,檢視地圖經緯度對應房價的資料。同時使用顏色欄,繪製熱度影象。 程式碼如下: ``` import os import urllib import numpy as np import pandas as pd import matplotlib.pyplot as plt import matplotlib.image as mpimg #加州房價資料(大家不用在意域名) housing = pd.read_csv("http://blog.caiyongji.com/assets/housing.csv") #加州地圖 url = "http://blog.caiyongji.com/assets/california.png" urllib.request.urlretrieve("http://blog.caiyongji.com/assets/california.png", os.path.join("./", "california.png")) california_img=mpimg.imread(os.path.join("./", "california.png")) #根據經緯度繪製房價散點圖 ax = housing.plot(kind="scatter", x="longitude", y="latitude", figsize=(10,7), s=housing['population']/100, label="Population", c="median_house_value", cmap=plt.get_cmap("jet"), colorbar=False, alpha=0.4, ) plt.imshow(california_img, extent=[-124.55, -113.80, 32.45, 42.05], alpha=0.5, cmap=plt.get_cmap("jet")) plt.ylabel("Latitude", fontsize=14) plt.xlabel("Longitude", fontsize=14) prices = housing["median_house_value"] tick_values = np.linspace(prices.min(), prices.max(), 11) #顏色欄,熱度地圖 cbar = plt.colorbar(ticks=tick_values/prices.max()) cbar.ax.set_yticklabels(["$%dk"%(round(v/1000)) for v in tick_values], fontsize=14) cbar.set_label('Median House Value', fontsize=16) v plt.legend(fontsize=16) ``` 繪製圖像如下: 紅色昂貴,藍色便宜,圓圈大小表示人口多少 ![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2a58d4c795d545e2b6f75c7efa531997~tplv-k3u1fbpfcp-watermark.image) ## 4. 繪製等高線 等高線對於在二維空間內繪製三維影象很有用。 ``` def f(x, y): return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x) x = np.linspace(0, 5, 50) y = np.linspace(0, 5, 40) X, Y = np.meshgrid(x, y) Z = f(X, Y) plt.contourf(X, Y, Z, 20, cmap='RdGy') plt.colorbar() ``` 繪製圖像如下: 黑色地方是峰,紅色地方是谷。 ![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5277014f60cd4ee5839d673757a7f041~tplv-k3u1fbpfcp-watermark.image) ## 繪製動畫 繪製動畫需要引入`animation`庫,通過呼叫`FuncAnimation`方法來實現繪製動畫。 ``` import numpy as np from matplotlib import pyplot as plt from matplotlib import animation fig = plt.figure() ax = plt.axes(xlim=(0, 2), ylim=(-2, 2)) line, = ax.plot([], [], lw=2) # 初始化方法 def init(): line.set_data([], []) return line, # 資料更新方法,週期性呼叫 def animate(i): x = np.linspace(0, 2, 1000) y = np.sin(2 * np.pi * (x - 0.01 * i)) line.set_data(x, y) return line, #繪製動畫,frames幀數,interval週期行呼叫animate方法 anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True) anim.save('ccccc.gif', fps=30) plt.show() ``` 上述程式碼中`anim.save()`方法支援儲存mp4格式檔案。 繪製動圖如下: ![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bac12e88bd2445d4aaaf9dc81342785c~tplv-k3u1fbpfcp-watermark.image) # 結語 到此,前置機器學習系列就結束了,我們已經為上手機器學習做足了準備。檢視完整[《前置機器學習系列》](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzUxMjU4NjI4MQ==&action=getalbum&album_id=1627166768236412929&scene=173&from_msgid=2247484075&from_itemidx=1&count=3#wechat_redirect)請關注公眾號【caiyongji】或訪問我的個人部落格[blog.caiyongji.com](http://blog.caiyongji.com/)同步更新。 大家可能發現了,我的教程中偏向實踐的方向更多。接下來的機器學習系列教程也會更多的偏向於實際使用,而非理論方向。 對數學畏懼的同學不要慌,跟著我慢慢學