HOWTO · Matplotlib
如何在 Matplotlib 直方圖中手動設定 bin 的大小
在 Matplotlib 的一維直方圖中,將資料與邊界序列傳入 `plt.hist(..., bins=...)`,即可設定各分箱的寬度。
本頁內容
在 Matplotlib 的一維直方圖中,將資料與邊界序列傳入 plt.hist(..., bins=...),即可控制分箱寬度。每一對相鄰邊界值會定義一個區間,因此可建立等寬或不等寬的分箱。hist2d() 用於二維直方圖;本文範例使用的是 plt.hist()。
將分箱邊界作為 hist() 函式的參數
如果想自行決定各區間的起點與終點,可以傳入邊界序列。例如,[0, 10, 20, 30, 40, 50, 60, 80, 100] 會建立八個分箱:前六個寬度為 10,最後兩個寬度為 20。分箱數量比邊界值少一個。小於第一個邊界或大於最後一個邊界的值不會計入直方圖,因此請選擇能涵蓋目標觀測值的範圍。
若要讓所有分箱寬度相同,可以使用 np.arange 產生等間距的邊界。下方範例會以相同資料比較自訂邊界與等寬邊界。由於 np.arange(start, stop, step) 會包含 start、排除 stop,因此 stop 值必須大於最大觀測值,才能讓邊界涵蓋該值。
import matplotlib.pyplot as plt
import numpy as np
values = np.array([3, 8, 12, 18, 24, 31, 37, 43, 52, 61, 74, 88, 96])
width = 10
explicit_edges = [0, 10, 20, 30, 40, 50, 60, 80, 100]
equal_edges = np.arange(0, 101, width)
fig, axes = plt.subplots(1, 2, figsize=(10, 4))
axes[0].hist(values, bins=explicit_edges)
axes[0].set_title("Chosen boundaries")
axes[1].hist(values, bins=equal_edges)
axes[1].set_title("Equal-width bins")
for axis in axes:
axis.set_xlabel("Value")
axis.set_ylabel("Count")
fig.tight_layout()
plt.show()
若要根據資料建立等寬分箱,將 max(values) + width 作為 stop 是一種方便的做法。因為 np.arange 不會包含 stop,該值本身不會成為邊界。使用這組數值時,stop 為 106,產生的最後一個邊界是 100,仍可涵蓋最大觀測值 96。如果資料範圍或寬度有所變動,請依目前資料計算邊界,不要沿用固定清單。
根據所需寬度計算分箱數量
如果資料範圍要等到程式執行時才能得知,可以根據觀測值推導第一個與最後一個邊界。此範例會將第一個邊界向下取整至所需寬度的倍數,並將最後一個邊界延伸至大於或等於最大值的倍數。此方法假設資料集非空且包含數值,並且寬度為正數。最外側的分箱可能超出資料範圍,但每對相鄰邊界之間的間距仍是指定的寬度。
import matplotlib.pyplot as plt
import numpy as np
values = np.array([3, 8, 12, 18, 24, 31, 37, 43, 52, 61, 74, 88, 96])
width = 10.0
first_edge = np.floor(values.min() / width) * width
last_edge = np.ceil(values.max() / width) * width
edges = np.arange(first_edge, last_edge + width, width)
plt.hist(values, bins=edges)
plt.xlabel("Value")
plt.ylabel("Count")
plt.title(f"Histogram with bin width {width:g}")
plt.show()
在此例中,最小值為 3,最大值為 96,因此產生的邊界從 0 到 100,間距為 10。觀測值會依這些區間分箱,繪製出的直方圖也會使用指定的寬度。若要使用其他寬度,請更新 width;相同的計算方式會產生相應的邊界序列。如果資料集為空或寬度不是正數,請先處理這些輸入情況,再計算邊界。