需求描述:想確認手邊資料是否為常態分佈,因為有很多統計方法的前提都是資料為常態分佈時才能用。
結果圖:
Wiki 上面的解釋是:「基於累計分布函數,用以檢驗兩個經驗分布是否不同或一個經驗分布與另一個理想分布是否不同。」相對應的 Python Package 為 scipy.stats.kstest,文件在此。以下操作主要使用 Python Pandas 及 Scipy 來說明。
原本跟這篇 stackoverflow 的發問者犯了一樣的錯誤,用了 default 的 loc=0, scale=1 給 kstest,結果返回了一個 pvalue = 0 給我。回答者解釋,需要先取得手邊資料的 loc 及 scale,也就是資料平均值及標準差。
因此首先從 Pandas 的 DataFrame 取得要檢驗的資料,轉成 numpy array:
data = df['col_name'].values
接著取得 loc 及 scale:
from scipy.stats import normloc, scale = norm.fit(data)
然後根據資料的 loc 跟 scale 建立常態分佈:
n = norm(loc=loc, scale=scale)
最後來視覺化,第一個先來處理實際資料的分佈,畫個柱狀圖:
import matplotlib.pyplot as pltplt.hist( data,
bins=np.arange(data.min(), data.max()+0.2, 0.2),
rwidth=0.5 )
- data:實際手邊資料,型態為 numpy array
- bins:如果給一個整數(int),代表指定圖中柱子要幾根;如果給一個 sequence,例如給 [1, 2, 3, 4] 的話,代表第一根柱子為 1–2,包含 1 不包含 2,第二根柱子為 2–3,包含 2 不包含 3,但最後一根 3–4,則包含 3 也包含 4。
- rwidth:柱子寬度
第二個來畫常態分佈圖,先讓 X 軸能跟柱狀圖的 X 軸對到:
x = np.arange(data.min(), data.max()+0.2, 0.2)plt.plot(x, 1100*n.pdf(x))
Y 為 pdf 為 Probability density function 機率密度函數。Wiki 一下:「連續型隨機變量的機率密度函數是一個描述這個隨機變量的輸出值,在某個確定的取值點附近的可能性的函數。」因為回傳的值太小,為了看清楚它的分佈,在這邊多乘了 1100。
最後把剛才畫個兩個圖 show 出來:
plt.show()
右邊長長的尾巴看起來不是很 fit 常態分佈,接著來做檢驗看看。
from scipy.stats import kstestkstest(data, n.cdf)
cdf 為 Cumulative distribution function 累積分佈函數。 Wiki 一下:「是機率密度函數的積分,能完整描述一個實隨機變量 X 的機率分布。」 kstest 回傳了兩個值 statistic=0.07651554991679332 以及 pvalue=1.6163215356639675e-26,其中 pvalue 為約 1.616 乘以 10 的 -26 次方,p value 愈低代表愈能拒絕虛無假設,其中 KS Test 的虛無假設為假設兩分佈相同,故代表手邊資料的分佈不符合常態分佈。