【機(jī)器學(xué)習(xí)基礎(chǔ)】如何檢測(cè)兩組數(shù)據(jù)是否同分布?
點(diǎn)擊關(guān)注公眾號(hào),干貨及時(shí)送達(dá)
一個(gè)模型中,很重要的技巧就是要確定訓(xùn)練集與測(cè)試集特征是否同分布,這也是機(jī)器學(xué)習(xí)的一個(gè)很重要的假設(shè),但很多時(shí)候我們默認(rèn)這個(gè)道理,卻很難有方法來(lái)保證數(shù)據(jù)同分布。
T檢驗(yàn)(Binary)
T檢驗(yàn)是一種適合小樣本的統(tǒng)計(jì)分析方法,通過(guò)比較不同數(shù)據(jù)的均值,研究?jī)山M數(shù)據(jù)是否存在差異。
我們參考《python科學(xué)計(jì)算第二版》:
https://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s/sv5QipNA6QPWgDC3R8DuAQ
單樣本t檢驗(yàn)
單樣本t檢驗(yàn)是樣本均值與總體均值的比較問(wèn)題。其中總體服從正態(tài)分布,從正態(tài)總體中抽樣得到n個(gè)個(gè)體組成抽樣樣本,計(jì)算抽樣樣本均值和標(biāo)準(zhǔn)差,判斷總體均值與抽樣樣本均值是否相同。
from scipy.stats import ttest_1samp
import numpy as np
print("Null Hypothesis:μ=μ0=30,α=0.05")
ages = [25,36,15,40,28,31,32,30,29,28,27,33,35]
t = (np.mean(ages)-30)/(np.std(ages,ddof=1)/np.sqrt(len(ages)))
ttest,pval = ttest_1samp(ages,30)
print(t,ttest)
if pval < 0.05:
print("Reject the Null Hypothesis.")
else:
print("Accept the Null Hypothesis.")
配對(duì)樣本t檢驗(yàn)
配對(duì)樣本主要是同一實(shí)驗(yàn)前后效果的比較,或者同一樣品用兩種方法檢驗(yàn)結(jié)果的比較。可以把配對(duì)樣本的差作為變量,差值的總體均數(shù)為0,服從正態(tài)分布。
from scipy.stats import ttest_rel
s1 = [620.16,866.50,641.22,812.91,738.96,899.38,760.78,694.95,749.92,793.94]
s2 = [958.47,838.42,788.90,815.20,783.17,910.92,758.49,870.80,826.26,805.48]
print("Null Hypothesis:mean(s1)=mean(s2),α=0.05")
ttest,pval = ttest_rel(s1,s2)
if pval < 0.05:
print("Reject the Null Hypothesis.")
else:
print("Accept the Null Hypothesis.")
獨(dú)立樣本t檢驗(yàn)
對(duì)于第三個(gè)問(wèn)題獨(dú)立樣本t檢驗(yàn),比較兩個(gè)樣本所代表的兩個(gè)總體均值是否存在顯著差異。除了要求樣本來(lái)自正態(tài)分布,還要求兩個(gè)樣本的總體方差相等“方差齊性”。
from scipy.stats import ttest_ind,norm,f
import numpy as np
def ftest(s1,s2):
'''F檢驗(yàn)樣本總體方差是否相等'''
print("Null Hypothesis:var(s1)=var(s2),α=0.05")
F = np.var(s1)/np.var(s2)
v1 = len(s1) - 1
v2 = len(s2) - 1
p_val = 1 - 2*abs(0.5-f.cdf(F,v1,v2))
print(p_val)
if p_val < 0.05:
print("Reject the Null Hypothesis.")
equal_var=False
else:
print("Accept the Null Hypothesis.")
equal_var=True
return equal_var
def ttest_ind_fun(s1,s2):
'''t檢驗(yàn)獨(dú)立樣本所代表的兩個(gè)總體均值是否存在差異'''
equal_var = ftest(s1,s2)
print("Null Hypothesis:mean(s1)=mean(s2),α=0.05")
ttest,pval = ttest_ind(s1,s2,equal_var=equal_var)
if pval < 0.05:
print("Reject the Null Hypothesis.")
else:
print("Accept the Null Hypothesis.")
return pval
np.random.seed(42)
s1 = norm.rvs(loc=1,scale=1.0,size=20)
s2 = norm.rvs(loc=1.5,scale=0.5,size=20)
s3 = norm.rvs(loc=1.5,scale=0.5,size=25)
ttest_ind_fun(s1,s2)
ttest_ind_fun(s2,s3)
KS檢驗(yàn)(Numerical)
KS檢驗(yàn)是一種統(tǒng)計(jì)檢驗(yàn)方法,其通過(guò)比較兩樣本的頻率分布、或者一個(gè)樣本的頻率分布與特定理論分布(如正態(tài)分布)之間的差異大小來(lái)推論兩個(gè)分布是否來(lái)自同一分布。
KS檢驗(yàn)與t-檢驗(yàn)之類的其他方法不同是KS檢驗(yàn)不需要知道數(shù)據(jù)的分布情況,可以算是一種非參數(shù)檢驗(yàn)方法。當(dāng)然這樣方便的代價(jià)就是當(dāng)檢驗(yàn)的數(shù)據(jù)分布符合特定的分布事,KS檢驗(yàn)的靈敏度沒(méi)有相應(yīng)的檢驗(yàn)來(lái)的高。在樣本量比較小的時(shí)候,KS檢驗(yàn)最為非參數(shù)檢驗(yàn)在分析兩組數(shù)據(jù)之間是否不同時(shí)相當(dāng)常用。
PS:t-檢驗(yàn)的假設(shè)是檢驗(yàn)的數(shù)據(jù)滿足正態(tài)分布,否則對(duì)于小樣本不滿足正態(tài)分布的數(shù)據(jù)用t-檢驗(yàn)就會(huì)造成較大的偏差,雖然對(duì)于大樣本不滿足正態(tài)分布的數(shù)據(jù)而言t-檢驗(yàn)還是相當(dāng)精確有效的手段。
判斷是否符合正態(tài)分布
KS函數(shù)說(shuō)明文檔:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.kstest.html
import numpy as np
import pandas as pd
from scipy import stats
data = [87,77,92,68,80,78,84,77,81,80,80,77,92,86,
76,80,81,75,77,72,81,72,84,86,80,68,77,87,
76,77,78,92,75,80,78]
# 樣本數(shù)據(jù),35位健康男性在未進(jìn)食之前的血糖濃度
df = pd.DataFrame(data, columns =['value'])
e = df['value'].mean() # 計(jì)算均值
std = df['value'].std() # 計(jì)算標(biāo)準(zhǔn)差
stats.kstest(df['value'], 'norm', (e, std))
# .kstest方法:KS檢驗(yàn),參數(shù)分別是:待檢驗(yàn)的數(shù)據(jù),檢驗(yàn)方法(這里設(shè)置成norm正態(tài)分布),均值與標(biāo)準(zhǔn)差
# 結(jié)果返回兩個(gè)值:statistic → D值,pvalue → P值
# p值大于0.05,為正態(tài)分布
#KstestResult(statistic=0.1590180704824098, pvalue=0.3066297258358026)
# p值大于0.05,不拒絕原假設(shè),因此上面的數(shù)據(jù)服從正態(tài)分布。
#且一般情況下, stats.kstest(df[‘value’], ‘norm’, (u, std))一條語(yǔ)句就得到p值的結(jié)果。
#from scipy import stats
#stats.kstest(rvs, cdf, args=(),…)
#其中rvs可以是數(shù)組、生成數(shù)組的函數(shù)或者scipy.stats里面理論分布的名字
#cdf可以與rvs一致。若rvs和cdf同是數(shù)組,則是比較兩數(shù)組的分布是否一致;一個(gè)是數(shù)組,另一個(gè)是理論分布的名字,則是看樣本是否否和理論分布
#args是一個(gè)元組,當(dāng)rvs或者cds是理論分布時(shí),這個(gè)參數(shù)用來(lái)存儲(chǔ)理論分布的參數(shù),如正態(tài)分布的mean和std。
KL Divergence
KL 散度是一種衡量?jī)蓚€(gè)概率分布的匹配程度的指標(biāo),兩個(gè)分布差異越大,KL散度越大。注意如果要查看測(cè)試集特征是否與訓(xùn)練集相同,P代表訓(xùn)練集,Q代表測(cè)試集,這個(gè)公式對(duì)于P和Q并不是對(duì)稱的。
計(jì)算公式為:
對(duì)于離散分布
對(duì)于連續(xù)分布
import numpy as np
import scipy.stats
# 隨機(jī)生成兩個(gè)離散型分布
x = [np.random.randint(1, 11) for i in range(10)]
print(x)
print(np.sum(x))
px = x / np.sum(x)
print(px)
y = [np.random.randint(1, 11) for i in range(10)]
print(y)
print(np.sum(y))
py = y / np.sum(y)
print(py)
# 利用scipy API進(jìn)行計(jì)算
# scipy計(jì)算函數(shù)可以處理非歸一化情況,因此這里使用
# scipy.stats.entropy(x, y)或scipy.stats.entropy(px, py)均可
KL = scipy.stats.entropy(x, y)
print(KL)
# 實(shí)現(xiàn)
KL = 0.0
for i in range(10):
KL += px[i] * np.log(px[i] / py[i])
# print(str(px[i]) + ' ' + str(py[i]) + ' ' + str(px[i] * np.log(px[i] / py[i])))
print(KL)
機(jī)器學(xué)習(xí)模型檢測(cè)
用特征訓(xùn)練模型來(lái)分辨測(cè)試集與測(cè)試集,若模型效果好的話代表訓(xùn)練集和測(cè)試集存在較大差異,否則代表訓(xùn)練集和測(cè)試集分布比較相似。
具體做法是構(gòu)建一個(gè)二分類模型,對(duì)訓(xùn)練集打上0,測(cè)試集打上1,然后shuffle一下進(jìn)行訓(xùn)練,若分類效果好,代表訓(xùn)練集和測(cè)試集區(qū)分度很高,那么分布差異就較大。
