Matplotlib 是建立在NumPy基礎之上的Python繪相簿,是在機器學習中用於資料視覺化的工具。
我們在前面的文章講過NumPy的用法,這裡我們就不展開討論NumPy的相關知識了。
Matplotlib具有很強的工具屬性,也就是說它只是為我所用的,我們不必花太多的精力去精進它。我們只需要知道它可以做那些事,可以繪製哪些圖形,有一個印象就足夠了。我們在實際使用中用什麼拿什麼,我們用到了自然就熟練了,用不到的功能也就說明它對你沒什麼用。
這就是按需學習(Learn on Demand) 。這點我在《如何成為十倍速程式設計師》裡提到過類似的理念。
一、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()方法展示影像。
我們得到如圖所示影像:
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軸範圍,新增標題和標籤,設定網格,新增參考線,儲存影像等內容。
繪製影像如下:
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表示。
4. 認識figure(畫布)
首先我們認識figure(畫布),比如legend我們在上文中提到過,是線條標籤的展示。grid所圈住的虛線是網格參考線。Title/x axislabel等文字標籤。
這張圖有助於我們對figure有一個值觀的理解。
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-.'
引數為繪圖的縮寫寫法,本文後續引數縮寫段落會單獨講解。
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)
繪製影像如下:
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()
繪製影像如下:
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(記號樣式)
記號樣式展示如下:
7.4 其他縮寫
lw
代表linewidth(線條寬度),如:lw=2.5ms
代表markersize(記號尺寸),如:ms=5mfc
代表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))
繪製影像如下:
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
使用,來繪製影像的顏色欄。
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)
繪製影像如下:
紅色昂貴,藍色便宜,圓圈大小表示人口多少
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()
繪製影像如下:
黑色地方是峰,紅色地方是谷。
繪製動畫
繪製動畫需要引入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格式檔案。
繪製動圖如下:
結語
到此,前置機器學習系列就結束了,我們已經為上手機器學習做足了準備。檢視完整《前置機器學習系列》請關注公眾號【caiyongji】或訪問我的個人部落格blog.caiyongji.com同步更新。
大家可能發現了,我的教程中偏向實踐的方向更多。接下來的機器學習系列教程也會更多的偏向於實際使用,而非理論方向。
對數學畏懼的同學不要慌,跟著我慢慢學就好。