為什么要叫“卡方”?因?yàn)樵恰癱hi-squared”,一半是音譯,一半是意譯。其中,chi 是希臘字母 的讀音,其實(shí)讀音更像是“開(kāi)”,而不是“卡”。square表示平方,因此在英語(yǔ)中,卡方分布寫(xiě)作 distribution。
成都創(chuàng)新互聯(lián)公司是一家以網(wǎng)絡(luò)技術(shù)公司,為中小企業(yè)提供網(wǎng)站維護(hù)、網(wǎng)站設(shè)計(jì)、做網(wǎng)站、網(wǎng)站備案、服務(wù)器租用、域名注冊(cè)、軟件開(kāi)發(fā)、小程序設(shè)計(jì)等企業(yè)互聯(lián)網(wǎng)相關(guān)業(yè)務(wù),是一家有著豐富的互聯(lián)網(wǎng)運(yùn)營(yíng)推廣經(jīng)驗(yàn)的科技公司,有著多年的網(wǎng)站建站經(jīng)驗(yàn),致力于幫助中小企業(yè)在互聯(lián)網(wǎng)讓打出自已的品牌和口碑,讓企業(yè)在互聯(lián)網(wǎng)上打開(kāi)一個(gè)面向全國(guó)乃至全球的業(yè)務(wù)窗口:建站服務(wù)電話(huà):028-86922220
在理解卡方檢驗(yàn)之前,應(yīng)當(dāng)理解卡方分布??ǚ椒植际且环N連續(xù)概率分布。
如果一個(gè)隨機(jī)變量 服從標(biāo)準(zhǔn)正態(tài)分布,即 ,那么 就服從自由度為1的卡方分布。記作 或者
而如果 都服從標(biāo)準(zhǔn)正態(tài)分布,那么它們的平方和服從自由度為 的卡方分布,記作:
或者寫(xiě)作 。
對(duì)于非負(fù)自變量 的自由度為 的卡方分布的概率密度函數(shù) (簡(jiǎn)稱(chēng)"pdf"):
(1)為什么 非負(fù)?因?yàn)楦鶕?jù)定義,卡方分布的自變量是一個(gè)平方和。
(2)這里的 是一個(gè)函數(shù)。關(guān)于這個(gè)函數(shù)具體是什么,以及上門(mén)的概率密度函數(shù)如何推導(dǎo),這里不展開(kāi),只需要知道有這么個(gè)函數(shù)即可。實(shí)在是好奇的,可以 參考這里 。
(3)卡方分布的均值為 ,而標(biāo)準(zhǔn)差為 。
(4)自由度越大,該函數(shù)圖像越對(duì)稱(chēng)。
(5)為什么這里 需要正態(tài)分布,我的理解是,如果零假設(shè)為真,那么觀測(cè)值和期望值之間的波動(dòng)程度,應(yīng)該是正態(tài)分布的,或者說(shuō)“噪聲”應(yīng)該是正態(tài)分布的。
卡方檢驗(yàn)有兩個(gè)用途:
擬合優(yōu)度檢驗(yàn) chi-squared test goodness of fit
獨(dú)立性檢驗(yàn) chi-squared test of independence
某新聞?wù)f某個(gè)籃球明星的原地兩連投的單次命中率是0.8,根據(jù)歷次比賽的數(shù)據(jù)匯總得到下面的表格:
意思是說(shuō),在比賽中,有5次兩連投是一次都沒(méi)中,有82次是在兩連投中命中1次。現(xiàn)在,我們來(lái)用卡方檢驗(yàn)驗(yàn)證新聞?wù)f的0.8的命中率是否正確。零假設(shè)如下:
:兩連投的成功次數(shù)符合二項(xiàng)分布,且概率為
(1)先根據(jù)零假設(shè)計(jì)算“期望”的命中次數(shù)分布:
由于總的觀察次數(shù)為 ,于是在 成立的前提下,可以計(jì)算每種兩連投結(jié)果的期望次數(shù):
0次命中:
1次命中:
2次命中:
顯然,期望的觀察次數(shù)和實(shí)際的觀察次數(shù)是有偏差的,那么問(wèn)題在于這個(gè)偏差是否大到具有統(tǒng)計(jì)顯著性,進(jìn)而可以否定零假設(shè)。
(2)我們來(lái)構(gòu)造卡方檢驗(yàn)統(tǒng)計(jì)量(chi-squared test statistic):
這個(gè)值是把表里每個(gè)格子的實(shí)際值和期望值進(jìn)行對(duì)比。為什么要用平方?目的在于規(guī)避正負(fù)號(hào)的影響。為什么要除以期望值?目的在于消除數(shù)量絕對(duì)值的影響。例如你預(yù)算3塊錢(qián)的水,商家加價(jià)50元,那么這個(gè)波動(dòng)是你無(wú)法忍受的,而你預(yù)算20萬(wàn)的車(chē),商家加價(jià)50元,則變得可以忍受。也就是說(shuō),除以期望值目的在于聚焦于變化率,而不是變化量。
之后,把這些“變化率”加總得到 。而計(jì)算自由度有一個(gè)公式:
其中 R 表示行數(shù),C 表示列數(shù)。對(duì)于本例:
從另一個(gè)角度解釋為什么 :前面的定義是如果是 個(gè)符合標(biāo)準(zhǔn)正態(tài)分布的 相加,則自由度是 ,但是這里自有兩個(gè)格子可以自由變化,第三個(gè)格子可以用總觀察數(shù)減出來(lái),例如 。
因此,真正自由的只有2個(gè)格子,所以自由度是2。
好了,將格子的數(shù)據(jù)代入,求出檢驗(yàn)統(tǒng)計(jì)量:
(3)根據(jù)自由度為2的卡方分布,找到檢驗(yàn)統(tǒng)計(jì)量對(duì)應(yīng)的位置:
不難理解,隨著統(tǒng)計(jì)量增大,表示預(yù)期的分布和實(shí)際的分布的差異也就越來(lái)越大。
另外,由于通常意義上,p值是越小越能推翻零假設(shè),那么顯然我們需要用右側(cè)的面積來(lái)表示p值,這里用Python計(jì)算來(lái)代替查表:
輸出:statistic: 17.26, pvalue: 0.0002
由于p值很?。僭O(shè)我們的顯著性水平的0.05),那么我們可以推翻零假設(shè)。
進(jìn)一步的,我們來(lái)探索下,該運(yùn)動(dòng)員的兩連投的成功次數(shù)分?jǐn)?shù)是否真的符合二項(xiàng)分布。零假設(shè):
:兩連投的成功次數(shù)符合二項(xiàng)分布。
既然符合二項(xiàng)分布,那么我們需要先估算一下最合理的 概率,那當(dāng)然是用總命中數(shù)除以總投籃數(shù)來(lái)計(jì)算了:
然后,用該概率值重復(fù)之前的計(jì)算,也就是先計(jì)算出一個(gè)期望的表格:
注意,這里的 ,這是因?yàn)?,我們每從?shù)據(jù)估計(jì)一個(gè)參數(shù),那么我們就損失一個(gè)自由度。這里用了一個(gè)平均命中的概率,因此自由度只有 。
這時(shí)候,在使用 Python 進(jìn)行計(jì)算時(shí),注意調(diào)整默認(rèn)的自由度:
這里的 ddof 就是額外損失的自由度,本意是“delta degree of freedom”
輸出:statistic: 0.34, pvalue: 0.56
可以看到p值很大,因此不足以推翻零假設(shè),也就是說(shuō)該運(yùn)動(dòng)員的投籃命中次數(shù)可能真的是二項(xiàng)分布。
下面表格表示喝酒頻率和與警察發(fā)生麻煩的頻數(shù)。
以第一列為例,表示從不喝酒的人中,4992人不發(fā)生麻煩,71人會(huì)發(fā)生麻煩。
現(xiàn)在的問(wèn)題是,能否從以下數(shù)據(jù)推斷說(shuō)喝酒頻率和與警察發(fā)生麻煩這兩個(gè)事件相互獨(dú)立?
我們的零假設(shè)應(yīng)該如何設(shè)計(jì)?如果要說(shuō)明兩者相互獨(dú)立,那么上表的分布應(yīng)該滿(mǎn)足乘法公式。也就是說(shuō)兩個(gè)獨(dú)立事件一起發(fā)生的概率等于分別發(fā)生的概率之積。
于是我們有:
發(fā)生麻煩的總?cè)藬?shù)除以總?cè)藬?shù)
不喝酒的總?cè)藬?shù)除以總?cè)藬?shù)
進(jìn)一步,根據(jù)總?cè)藬?shù)算出不喝酒而發(fā)生麻煩的人數(shù)的期望(下標(biāo)表示零假設(shè)):
用類(lèi)似的算法,計(jì)算每一個(gè)格子在零假設(shè)成立的情況下的值,寫(xiě)在原表數(shù)據(jù)下的括號(hào)里:
仔細(xì)觀察可以看出,其實(shí)每個(gè)格子就是對(duì)應(yīng)的:
另外可以看到,零假設(shè)下的各個(gè)格子的行列之和與原來(lái)相同。這不是偶然的,我們用字母代替計(jì)算一下就知道了:
于是第一列的兩個(gè)格子應(yīng)該是:
對(duì)于其他格子、行的總和,都一樣,這里不多說(shuō)了。
好,繼續(xù)分析。我們直接用上表計(jì)算卡方統(tǒng)計(jì)量和p值:
這部分計(jì)算方法和擬合優(yōu)度是一樣的,就不贅述了。計(jì)算發(fā)現(xiàn)這個(gè)p值非常小,接近0,因此我們可以推翻零假設(shè)。也就是說(shuō),喝酒的頻率和被警察找麻煩的并不是獨(dú)立的,而是相關(guān)的。
關(guān)于獨(dú)立性檢驗(yàn),有一個(gè)比卡方檢驗(yàn)更精準(zhǔn)的檢驗(yàn),叫 fisher's exact test。它通過(guò)直接計(jì)算否定零假設(shè)的概率,也就直接得到了一個(gè)準(zhǔn)確的p值。有一個(gè)經(jīng)典的女士品茶的統(tǒng)計(jì)學(xué)故事。有一個(gè)女士號(hào)稱(chēng)可以區(qū)分出一杯茶是先倒入了奶還是先倒入了茶。統(tǒng)計(jì)學(xué)家 Fisher 為了驗(yàn)證她的說(shuō)法,做了一個(gè)實(shí)驗(yàn)。拿了8杯茶,4杯是先茶后奶,4杯是先奶后茶。
實(shí)驗(yàn)結(jié)果是全部說(shuō)對(duì)了。那么問(wèn)題是,這是否具有統(tǒng)計(jì)顯著性呢?比如說(shuō)一個(gè)人猜對(duì)了一次硬幣,他的預(yù)測(cè)能力靠譜嗎?
我們假設(shè)女士的判斷是完全隨機(jī)的,這個(gè)是我們的零假設(shè)。那么8杯里面抽中4杯全對(duì)的概率是:
如果顯著性水平是0.01,那么我們不能推翻零假設(shè),即不敢確定這位女士真有這個(gè)識(shí)別能力。如果顯著性水平定在0.05,則我們可以認(rèn)為她確實(shí)有這個(gè)識(shí)別能力。
如果讓實(shí)驗(yàn)結(jié)果有更大的說(shuō)服力呢?一個(gè)簡(jiǎn)單的辦法就是增加茶的數(shù)量,比如我們?cè)O(shè)定為兩種茶各10杯,要求10杯都判斷正確,那么p值為多少呢?
這個(gè)算起來(lái)比較麻煩,這里我寫(xiě)一個(gè) python 腳本來(lái)計(jì)算:
計(jì)算結(jié)果:
這個(gè)p值就小得很夸張了,基本可以斷定零假設(shè)不成立了。
那么,回到實(shí)驗(yàn)本身,如果女士只選對(duì)了三杯,那么在零假設(shè)的前提下,這個(gè)發(fā)生的概率是多少?
這個(gè)概率比較大了,原大于通常使用的顯著性水平 0.05,因此我們沒(méi)有辦法推翻零假設(shè)。為什么要這樣 乘 呢?這個(gè)是因?yàn)橐还灿羞@么多種取法。你把所有可能的取法羅列處理,就是16種,然后除以總的取法數(shù),就是隨機(jī)取到這樣結(jié)果的概率。
比較 Fisher's exact test 和 chi-squared test,可以 參考這篇文章 。
一般來(lái)說(shuō),兩者都適用的情況下,應(yīng)該優(yōu)先選擇 Fisher's exact test,因?yàn)樗蔷_值。如果實(shí)驗(yàn)觀察的數(shù)量很?。ㄐ∮?0),應(yīng)該不使用 chi-squared test。
下面使用一個(gè)腳本來(lái)計(jì)算:
python可以對(duì)大數(shù)據(jù)進(jìn)行卡方檢驗(yàn)
需要澄清兩點(diǎn)之后才可以比較全面的看這個(gè)問(wèn)題:
1. 百萬(wàn)行級(jí)不算大數(shù)據(jù)量,以目前的互聯(lián)網(wǎng)應(yīng)用來(lái)看,大數(shù)據(jù)量的起點(diǎn)是10億條以上。
2. 處理的具體含義,如果是數(shù)據(jù)載入和分發(fā),用python是很高效的;如果是求一些常用的統(tǒng)計(jì)量和求一些基本算法的結(jié)果,python也有現(xiàn)成的高效的庫(kù),C實(shí)現(xiàn)的和并行化的;如果是純粹自己寫(xiě)的算法,沒(méi)有任何其他可借鑒的,什么庫(kù)也用不上,用純python寫(xiě)是自討苦吃。
python的優(yōu)勢(shì)不在于運(yùn)行效率,而在于開(kāi)發(fā)效率和高可維護(hù)性。針對(duì)特定的問(wèn)題挑選合適的工具,本身也是一項(xiàng)技術(shù)能力。
創(chuàng)建結(jié)構(gòu)元素: clear;close all SE = strel('rectangle',[40 30]); %注意:結(jié)構(gòu)元素必須具有適當(dāng)?shù)拇笮?既可以刪電流線又可以刪除矩形.
def calc_chiSquare(sampleSet, feature, target):
'''
計(jì)算某個(gè)特征每種屬性值的卡方統(tǒng)計(jì)量
params:
? ? sampleSet: 樣本集
? ? feature: 目標(biāo)特征
? ? target: 目標(biāo)Y值 (0或1) Y值為二分類(lèi)變量
return:
? ? 卡方統(tǒng)計(jì)量dataframe
? ? feature: 特征名稱(chēng)
? ? act_target_cnt: 實(shí)際壞樣本數(shù)
? ? expected_target_cnt:期望壞樣本數(shù)
? ? chi_square:卡方統(tǒng)計(jì)量
'''
# 計(jì)算樣本期望頻率
target_cnt = sampleSet[target].sum()
sample_cnt = len(sampleSet[target])
expected_ratio = target_cnt * 1.0/sample_cnt
# 對(duì)變量按屬性值從大到小排序
df = sampleSet[[feature, target]]
col_value = list(set(df[feature]))?
# 計(jì)算每一個(gè)屬性值對(duì)應(yīng)的卡方統(tǒng)計(jì)量等信息
chi_list = []; target_list = []; expected_target_list = []
for value in col_value:
? ? df_target_cnt = df.loc[df[feature] == value, target].sum()
? ? df_cnt = len(df.loc[df[feature] == value, target])
? ? expected_target_cnt = df_cnt * expected_ratio
? ? chi_square = (df_target_cnt - expected_target_cnt)**2 / expected_target_cnt
? ? chi_list.append(chi_square)
? ? target_list.append(df_target_cnt)
? ? expected_target_list.append(expected_target_cnt)
# 結(jié)果輸出到dataframe, 對(duì)應(yīng)字段為特征屬性值, 卡方統(tǒng)計(jì)量, 實(shí)際壞樣本量, 期望壞樣本量
chi_stats = pd.DataFrame({feature:col_value, 'chi_square':chi_list,
? ? ? ? ? ? ? ? ? ? ? ? ? 'act_target_cnt':target_list, 'expected_target_cnt':expected_target_list})
return chi_stats[[feature, 'act_target_cnt', 'expected_target_cnt', 'chi_square']]
def chiMerge_maxInterval(chi_stats, feature, maxInterval=5):
'''
卡方分箱合并--最大區(qū)間限制法
params:
? ? chi_stats: 卡方統(tǒng)計(jì)量dataframe
? ? feature: 目標(biāo)特征
? ? maxInterval:最大分箱數(shù)閾值
return:
? ? 卡方合并結(jié)果dataframe, 特征分割split_list
'''
group_cnt = len(chi_stats)
split_list = [chi_stats[feature].min()]
# 如果變量區(qū)間超過(guò)最大分箱限制,則根據(jù)合并原則進(jìn)行合并
while(group_cnt maxInterval):
? ? min_index = chi_stats[chi_stats['chi_square']==chi_stats['chi_square'].min()].index.tolist()[0]
? ? # 如果分箱區(qū)間在最前,則向下合并
? ? if min_index == 0:
? ? ? ? chi_stats = merge_chiSquare(chi_stats, min_index+1, min_index)
? ? # 如果分箱區(qū)間在最后,則向上合并
? ? elif min_index == group_cnt-1:
? ? ? ? chi_stats = merge_chiSquare(chi_stats, min_index-1, min_index)
? ? # 如果分箱區(qū)間在中間,則判斷與其相鄰的最小卡方的區(qū)間,然后進(jìn)行合并
? ? else:
? ? ? ? if chi_stats.loc[min_index-1, 'chi_square'] chi_stats.loc[min_index+1, 'chi_square']:
? ? ? ? ? ? chi_stats = merge_chiSquare(chi_stats, min_index, min_index+1)
? ? ? ? else:
? ? ? ? ? ? chi_stats = merge_chiSquare(chi_stats, min_index-1, min_index)
? ? group_cnt = len(chi_stats)
chiMerge_result = chi_stats
split_list.extend(chiMerge_result[feature].tolist())
return chiMerge_result, split_list
def chiMerge_minChiSquare(chi_stats, feature, dfree=4, cf=0.1, maxInterval=5):
'''
卡方分箱合并--卡方閾值法
params:
? ? chi_stats: 卡方統(tǒng)計(jì)量dataframe
? ? feature: 目標(biāo)特征
? ? maxInterval: 最大分箱數(shù)閾值, default 5
? ? dfree: 自由度, 最大分箱數(shù)-1, default 4
? ? cf: 顯著性水平, default 10%
return:
? ? 卡方合并結(jié)果dataframe, 特征分割split_list
'''
threshold = get_chiSquare_distuibution(dfree, cf)
min_chiSquare = chi_stats['chi_square'].min()
group_cnt = len(chi_stats)
split_list = [chi_stats[feature].min()]
# 如果變量區(qū)間的最小卡方值小于閾值,則繼續(xù)合并直到最小值大于等于閾值
while(min_chiSquare threshold and group_cnt maxInterval):
? ? min_index = chi_stats[chi_stats['chi_square']==chi_stats['chi_square'].min()].index.tolist()[0]
? ? # 如果分箱區(qū)間在最前,則向下合并
? ? if min_index == 0:
? ? ? ? chi_stats = merge_chiSquare(chi_stats, min_index+1, min_index)
? ? # 如果分箱區(qū)間在最后,則向上合并
? ? elif min_index == group_cnt-1:
? ? ? ? chi_stats = merge_chiSquare(chi_stats, min_index-1, min_index)
? ? # 如果分箱區(qū)間在中間,則判斷與其相鄰的最小卡方的區(qū)間,然后進(jìn)行合并
? ? else:
? ? ? ? if chi_stats.loc[min_index-1, 'chi_square'] chi_stats.loc[min_index+1, 'chi_square']:
? ? ? ? ? ? chi_stats = merge_chiSquare(chi_stats, min_index, min_index+1)
? ? ? ? else:
? ? ? ? ? ? chi_stats = merge_chiSquare(chi_stats, min_index-1, min_index)
? ? min_chiSquare = chi_stats['chi_square'].min()
? ? group_cnt = len(chi_stats)
chiMerge_result = chi_stats
split_list.extend(chiMerge_result[feature].tolist())
return chiMerge_result, split_list
def get_chiSquare_distuibution(dfree=4, cf=0.1):
'''
根據(jù)自由度和置信度得到卡方分布和閾值
params:
? ? dfree: 自由度, 最大分箱數(shù)-1, default 4
? ? cf: 顯著性水平, default 10%
return:
? ? 卡方閾值
'''
percents = [0.95, 0.90, 0.5, 0.1, 0.05, 0.025, 0.01, 0.005]
df = pd.DataFrame(np.array([chi2.isf(percents, df=i) for i in range(1, 30)]))
df.columns = percents
df.index = df.index+1
# 顯示小數(shù)點(diǎn)后面數(shù)字
pd.set_option('precision', 3)
return df.loc[dfree, cf]
def merge_chiSquare(chi_result, index, mergeIndex, a = 'expected_target_cnt',
? ? ? ? ? ? ? ? b = 'act_target_cnt', c = 'chi_square'):
'''
params:
? ? chi_result: 待合并卡方數(shù)據(jù)集
? ? index: 合并后的序列號(hào)
? ? mergeIndex: 需合并的區(qū)間序號(hào)
? ? a, b, c: 指定合并字段
return:
? ? 分箱合并后的卡方dataframe
'''
chi_result.loc[mergeIndex, a] = chi_result.loc[mergeIndex, a] + chi_result.loc[index, a]
chi_result.loc[mergeIndex, b] = chi_result.loc[mergeIndex, b] + chi_result.loc[index, b]
chi_result.loc[mergeIndex, c] = (chi_result.loc[mergeIndex, b] - chi_result.loc[mergeIndex, a])**2 /chi_result.loc[mergeIndex, a]
chi_result = chi_result.drop([index])
chi_result = chi_result.reset_index(drop=True)
return chi_result
for col in bin_col:
chi_stats = calc_chiSquare(exp_f_data_label_dr, col, 'label')
chiMerge_result, split_list = chiMerge_maxInterval(chi_stats, col, maxInterval=5)
print(col, 'feature maybe split like this:', split_list)
名稱(chēng)欄目:卡方檢驗(yàn)python函數(shù) 卡方檢驗(yàn)命令
文章來(lái)源:http://muchs.cn/article4/dossdoe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、網(wǎng)站排名、網(wǎng)站建設(shè)、App開(kāi)發(fā)、動(dòng)態(tài)網(wǎng)站、商城網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容