資料視覺化之 contour ( matplotlib.pyplot ) 教學與用法

本文簡單介紹如何使用 matplotlib 的 contour / contourf 於 Machine Learning 中呈現預測結果 ( 使用 scikit-learn )

Seachaos
tree.rocks

--

前言

資料視覺化 ( Data Visiual ) 對於 Machine Learning 是非常有幫助的方法
特別是一些 Model 結果 ( Predict ) 的呈現

而 python 的 matplotlib 中, pyplot.contour ( contourf ) 可以用來呈現等高線圖,深度 ( Z ) 或是顯示不同的 Y ( output ) 值 ( 意即有多種 Y 輸出 ),我們會透過本文的範例來觀察 ( 使用 sklearn )

本文之教學範例主要使用 Jupyter 來執行,如果是其他方式使用須注意 plt.imshow 之類呼叫

Contour / Contourf 基本介紹

直接先看範例程式

左圖為 contour / 右圖為 contourf

解說

基本上 plt.pyplot 的 contour / contourf 使用上其實是大同小異,主要差別是是否會填滿色塊 ( contour 為線條, contourf 為填滿的色塊),因本人比較喜歡使用 contourf ,故後以 contourf 為主

我們這邊使用上有 X, Y, Z 這三個值,分別是 X 座標,Y 座標,Z 深度(如前述,用來表示等高線很合理)

題外話 : 我們要產生出平面的大量 X, Y 與 Z 其實是很麻煩的,所幸 numpy 有個方法叫做 meshgrid,透過 np.mashgrid ( X, Y ) 就可以得到 contour 所需的座標,可以想像是產生出

p = [
[(0,0), (1,0), (2,0), (3,0)],
[(0,1), (1,1), (2,1), (3,1)],
[(0,2), (1,2), (2,2), (3,2)],
[(0,3), (1,3), (2,3), (3,3)]
]

( 類似這種形式 )
不使用 meshgrid, 要將上述的 p 套用的話還需要以下方法轉換

x, y = zip(*[list(zip(*l)) for l in p])
x = np.array(x)
y = np.array(y)
示意圖

當需要更大個範圍時很麻煩,所以我們使用此方法方便些

回到正題 :

x = range(4)
y = range(4)
x, y = np.meshgrid(x, y)

range(4) 可以看作是解析度,當我們需要更多的描繪點只要改動這邊即可

z 矩陣就是我們的深度 ( 可以是 Y 輸出結果 )
如果不用 contour ,使用單純的 plot 只會得到點,而且還要過濾 Z 值分開上色 ( 如下範例程式與圖 )

z = np.array(z)
for idx, color in [
(z == 0, '#000'),
(z == 1, '#F00')
]:
plt.plot(x[idx], y[idx], '*', color=color)
只使用 plot 不使用 contour

Python Matplotlib 之 Contourf 應用

再暸解基本的 contour / contourf 應用之後,我們搭配 sklearn 來做簡單應用示範,以下皆是亂數即時產生,所以相同的程式碼所產生的圖表不一定會和本文相同

準備資料

這裡我們使用 make_moons 來做資料示範,這可以使用 from sklearn.datasets import make_moons 來產生,此測試資料包含了一個座標系與 0 或 1 的結果 ( x1 + x2 = y )

Model 預測

其實用什麼 Model 都行,我們這邊用 RandomForestClassifier 來做示範

範例程式

直接看以下範例

make_moon 得到的預測圖

解說

import 與 資料準備我們就不多做介紹,我們直接看到這段

resolution = 50
dx = np.linspace(np.min(X[:, 0]), np.max(X[:, 0]), resolution)
dy = np.linspace(np.min(X[:, 1]), np.max(X[:, 1]), resolution)
dx, dy = np.meshgrid(dx, dy)

其實就等同我們上面基本教學的

x = range(4)
y = range(4)
x, y = np.meshgrid(x, y)

只是我們有技巧地透過 numpy min / max 去找出適當的值,resolution 相當於我們基礎教學裡 range 的數值,然後使用 linspace 來做節點分割,大家在跑範例程式時可以改看看 resolution 會發現 contour 精度的變化

再來看 test_x = np.c_[dx.flatten(), dy.flatten()]
其實這是因為 model prdict 需要 x1, x2 ,所以我們將 x, y 合併
然後送入 model ( clf ) 得到 z

最後 z 輸出的 shape 並不符合 contour 使用,所以我們要 reshape
z = z.reshape(dx.shape)

我們就可以畫出簡單的圖

# draw
plt.contourf(dx, dy, z, alpha=0.2)
plt.contourf 結果

然後我們還需要看一下原始資料 ( dataset )
確認我們的 Model 運作是正確的,所以我們使用 plot 來把原本資料繪上

# draw all dataset
colors = ['#FF0', '#000']
for i in [0, 1]:
idx = y == i
plt.plot(X[idx, 0], X[idx, 1], '*', color=colors[i])

就會得到類似這樣的結果

底色就是我們 Model 訓練的分類結果

另外

plot_z = clf.predict(test_x)
colors = ['#F00', '#00F']
for i in [0, 1]:
idx = plot_z == i
plt.plot(test_x[idx, 0], test_x[idx, 1], '*', alpha=0.3, color=colors[i])

也可以將預測結果 plot 在圖上,可以透過配合改變 resolution 來觀看

這是 contour 與 plot 比較

透過降低 resolution ( 下圖降為 10 ) 可以發現, 和單純 plot 將比,contour 明顯在資料視覺化上面容易許多

左圖使用 contour / 右圖單純只用 plt

結語

希望以上教學有幫助到大家

參考資料 : https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.contourf.html
https://www.python-course.eu/matplotlib_contour_plot.php

--

--