2.簡單散點圖
接着上一章講的,另一種常用的圖表類型是簡單散點圖,它是折線圖的近親。不像折線圖,圖中的點連接起來組成連線,散點圖中的點都是獨立分布的點狀、圓圈或其他形狀。本節開始我們也是首先將需要用到的圖表工具和函數導入到 Pycharm 中:
import matplotlib.pyplot as plt plt.style.use('seaborn-whitegrid') import numpy as np
使用 plt.plot
繪制散點圖
在上一節中,我們介紹了plt.plot
/ax.plot
方法繪制折線圖。這兩個方法也可以同樣用來繪制散點圖:
x = np.linspace(0, 10, 30) y = np.sin(x) plt.plot(x, y, 'o', color='black'); plt.show()
傳遞給函數的第三個參數是使用一個字符代表的圖表繪制點的類型。就像你可以使用'-'
或'--'
來控制線條的風格那樣,點的類型風格也可以使用短字符串代碼來表示。所有可用的符號可以通過plt.plot
文檔或 Matplotlib 在線文檔進行查閱。大多數的代碼都是非常直觀的,我們使用下面的例子可以展示那些最通用的符號(將上面第1-3行代碼改為以下,並開頭加上庫函數,結尾plt.show()即可):
rng = np.random.RandomState(0) for marker in ['o', '.', ',', 'x', '+', 'v', '^', '<', '>', 's', 'd']: plt.plot(rng.rand(5), rng.rand(5), marker, label="marker='{0}'".format(marker)) plt.legend(numpoints=1) plt.xlim(0, 1.8);
plt.plot(x, y, '-p', color='gray', markersize=15, linewidth=4, markerfacecolor='white', markeredgecolor='gray', markeredgewidth=2) plt.ylim(-1.2, 1.2);
而且這些符號代碼可以和線條、顏色代碼一起使用,這會在折線圖的基礎上繪制出散點:
plt.plot(x, y, '-ok');
plt.plot
還有很多額外的關鍵字參數用來指定廣泛的線條和點的屬性:
plt.plot(x, y, '-p', color='gray', markersize=15, linewidth=4, markerfacecolor='white', markeredgecolor='gray', markeredgewidth=2) plt.ylim(-1.2, 1.2);
plt.plot
函數的這種靈活性提供了很多的可視化選擇。查閱plt.plot
幫助文檔獲得完整的選項說明。
使用plt.scatter
繪制散點圖
第二種更強大的繪制散點圖的方法是使用plt.scatter
函數,它的使用方法和plt.plot
類似:
plt.scatter(x, y, marker='o');
plt.scatter
和plt.plot
的主要區別在於,plt.scatter
可以針對每個點設置不同屬性(大小、填充顏色、邊緣顏色等),還可以通過數據集合對這些屬性進行設置。
讓我們通過一個隨機值數據集繪制不同顏色和大小的散點圖來說明。為了更好的查看重疊的結果,我們還使用了alpha
關鍵字參數對點的透明度進行了調整:
rng = np.random.RandomState(0) x = rng.randn(100) y = rng.randn(100) colors = rng.rand(100) sizes = 1000 * rng.rand(100) plt.scatter(x, y, c=colors, s=sizes, alpha=0.3, cmap='viridis') plt.colorbar(); # 顯示顏色對比條
注意圖表右邊有一個顏色對比條(這里通過colormap()
函數輸出),圖表中的點大小的單位是像素。使用這種方法,散點的顏色和大小都能用來展示數據信息,在希望展示多個維度數據集合的情況下很直觀。
例如,當我們使用 Scikit-learn 中的鳶尾花數據集,里面的每個樣本都是三種鳶尾花中的其中一種,並帶有仔細測量的花瓣和花萼的尺寸數據:
from sklearn.datasets import load_iris iris = load_iris() features = iris.data.T plt.scatter(features[0], features[1], alpha=0.2, s=100*features[3], c=iris.target, cmap='viridis') plt.xlabel(iris.feature_names[0]) plt.ylabel(iris.feature_names[1]);
我們可以從上圖中看出,可以通過散點圖同時展示該數據集的四個不同維度:圖中的(x, y)位置代表每個樣本的花萼的長度和寬度,散點的大小代表每個樣本的花瓣的寬度,而散點的顏色代表一種特定的鳶尾花類型。如上圖的多種顏色和多種屬性的散點圖對於我們分析和展示數據集時都非常有幫助。
plot
和 scatter
對比:性能提醒
除了上面說的plt.plot
和plt.scatter
對於每個散點不同屬性的支持不同之外,還有別的因素影響對這兩個函數的選擇嗎?對於小的數據集來說,兩者並無差別,當數據集增長到幾千個點時,plt.plot
會明顯比plt.scatter
的性能要高。造成這個差異的原因是plt.scatter
支持每個點使用不同的大小和顏色,因此渲染每個點時需要完成更多額外的工作。而plt.plot
來說,每個點都是簡單的復制另一個點產生,因此對於整個數據集來說,確定每個點的展示屬性的工作僅需要進行一次即可。對於很大的數據集來說,這個差異會導致兩者性能的巨大區別,因此,對於大數據集應該優先使用plt.plot
函數。
3.誤差可視化
對於任何的科學測量來說,精確計算誤差與精確報告測量值基本上同等重要,如果不是更加重要的話。例如,設想我正在使用一些天文物理學觀測值來估算哈勃常數,即本地觀測的宇宙膨脹系數。我從一些文獻中知道這個值大概是 71 (km/s)/Mpc,而我測量得到的值是 74 (km/s)/Mpc,。這兩個值是否一致?在僅給定這些數據的情況下,這個問題的答案是,無法回答。
Mpc(百萬秒差距)參見秒差距
如果我們將信息增加一些,給出不確定性:最新的文獻表示哈勃常數的值大約是 71 2.5 (km/s)/Mpc,我的測量值是 74 5 (km/s)/Mpc。這兩個值是一致的嗎?這就是一個可以准確回答的問題了。
在數據和結果的可視化中,有效地展示這些誤差能使你的圖表涵蓋和提供更加完整的信息。
基礎誤差條
調用一個 Matplotlib 函數就能創建一個基礎的誤差條:
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
import numpy as np
x = np.linspace(0, 10, 50)
dy = 0.8
y = np.sin(x) + dy * np.random.randn(50)
plt.errorbar(x, y, yerr=dy, fmt='.k');
plt.show()
這里的fmt
參數是用來控制線條和點風格的代碼,與plt.plot
有着相同的語法,參見[簡單的折線圖]和[簡單的散點圖]。
除了上面的基本參數,errorbar
函數還有很多參數可以用來精細調節圖表輸出。使用這些參數你可以很容易的個性化調整誤差條的樣式。作者發現通常將誤差線條顏色調整為淺色會更加清晰,特別是在數據點比較密集的情況下:
plt.errorbar(x, y, yerr=dy, fmt='o', color='black', ecolor='lightgray', elinewidth=3, capsize=0);
除了上面介紹的參數,你還可以指定水平方向的誤差條(xerr
),單邊誤差條和其他很多的參數。參閱plt.errorbar
的幫助文檔獲得更多信息。
連續誤差
在某些情況下可能需要對連續值展示誤差條。雖然 Matplotlib 沒有內建的函數能直接完成這個任務,但是你可以通過簡單將plt.plot
和plt.fill_between
函數結合起來達到目標。
這里我們會采用簡單的高斯過程回歸方法,Scikit-Learn 提供了 API。這個方法非常適合在非參數化的函數中獲得連續誤差。我們在這里不會詳細介紹高斯過程回歸,僅僅聚焦在如何繪制連續誤差本身:
譯者注:新版的 sklearn 修改了高斯過程回歸實現方法,下面代碼做了相應修改。
from sklearn.gaussian_process import GaussianProcessRegressor # 定義模型和一些符合模型的點 model = lambda x: x * np.sin(x) xdata = np.array([1, 3, 5, 6, 8]) ydata = model(xdata) # 計算高斯過程回歸,使其符合 fit 數據點 gp = GaussianProcessRegressor() gp.fit(xdata[:, np.newaxis], ydata) xfit = np.linspace(0, 10, 1000) yfit, std = gp.predict(xfit[:, np.newaxis], return_std=True) dyfit = 2 * std # 兩倍sigma ~ 95% 確定區域
我們現在有了xfit
、yfit
和dyfit
,作為對我們數據的連續擬合值以及誤差限。當然我們也可以像上面一樣使用plt.errorbar
繪制誤差條,但是事實上我們不希望在圖標上繪制 1000 個點的誤差條。於是我們可以使用plt.fill_between
函數在誤差限區域內填充一道淺色的誤差帶來展示連續誤差:
# 可視化結果 plt.plot(xdata, ydata, 'or') plt.plot(xfit, yfit, '-', color='gray') plt.fill_between(xfit, yfit - dyfit, yfit + dyfit, color='gray', alpha=0.2) plt.xlim(0, 10);
總代碼如下:
import matplotlib.pyplot as plt plt.style.use('seaborn-whitegrid') import numpy as np from sklearn.gaussian_process import GaussianProcessRegressor # 定義模型和一些符合模型的點 model = lambda x: x * np.sin(x) xdata = np.array([1, 3, 5, 6, 8]) ydata = model(xdata) # 計算高斯過程回歸,使其符合 fit 數據點 gp = GaussianProcessRegressor() gp.fit(xdata[:, np.newaxis], ydata) xfit = np.linspace(0, 10, 1000) yfit, std = gp.predict(xfit[:, np.newaxis], return_std=True) dyfit = 2 * std # 兩倍sigma ~ 95% 確定區域 # 可視化結果 plt.plot(xdata, ydata, 'or') plt.plot(xfit, yfit, '-', color='gray') plt.fill_between(xfit, yfit - dyfit, yfit + dyfit, color='gray', alpha=0.2) plt.xlim(0, 10); plt.show()
注意上面我們調用fill_between
函數:我們傳遞了的參數包括 x 值,y 值的低限,然后是 y 值的高限,結果是圖表中介於低限和高限之間的區域會被填充。
上圖為我們提供了一個非常直觀的高斯過程回歸展示:在觀測點的附近,模型會被限制在一個很小的區域內,反映了這些數據的誤差比較小。在遠離觀測點的區域,模型開始發散,反映了這時的數據誤差比較大。
如果需要獲得plt.fill_between
(以及類似的plt.fill
函數)更多參數的信息,請查閱函數的幫助文檔或 Matplotlib 在線文檔。