老饼讲解:一步一步上手学习
卡方独立检验是卡方检验(chi-square Test)的一种,它属于一种用来检验两组数据的分布差异是否显著的假设检验,在机器学习中一般用来检验变量的相关性,例如男、女两组身高数据的分布如果差异大,则说明性别对身高有影响。好了,下面我们就来详细说说卡方独立检验的原理、流程和代码实现。
卡方检验包括独立检验和拟合性检验,它们都是基于卡方值的检验方法,但是它们用于解决不同的问题。卡方拟合性检验可参考文章《卡方检验-拟合性检验》,今天我们只说卡方独立检验。
卡方-独立检验解决的问题如下:

事件发生有n种可能: ,A组 和 B组在 上的分布现在表现出来的分别是:
、
我们想知道A组与B组在取值分布上有没有区别。
我们先来看看卡方-独立检验的思路与流程,后面再来详细说它的具体操作。
卡方-独立检验的思路与流程如下:

一、假设没区别,算出期望值
卡方检验先假设A组与B组没有区别,在这假设下,算出A组与B组的期望值。
二、计算期望值与事实值差异的概率
计算事实值与期望值的差异(该差异构造成服从卡方分布)。
由于差异值服从卡方分布,所以可进一步计算出差异值出现的概率。
三、根据概率,确定假设成不成立
根据差异值出现的概率,从而确定假设合不合理。
如果概率很小,说明当前是个小概率事件,则假设不合理,即A组与B组没有区别。
好了,下面我们先来说说卡方独立检验的计算流程和步骤,后面再来说这些公式怎么得出来的。
我们先来认识一下事实表,事实表是指各组当前观察到的取值,它的格式如下:

一般将事实表记为A,然后现在要判断A中的组1与组2有没有区别。
好了,下面我们来看看卡方独立检验的详细步骤。
首先假设两组没有区别,然后计算"没有区别"的概率,如下:
Step-1:计算期望表
期望表 E 的计算公式为:
其中,为A第i行求和,为A第j列求和,为总样本数。
Step-2:计算卡方值
卡方值计算公式为:
Step-3:计算p值
p值如下计算:
其中, :自由度,, r为A的行数,c为A列数
:自由度df的卡方累积分布函数
备注:卡方累积分布函数一般由计算机或查表得到,没有显式公式。
得到p值后,进行判断就可以了,如果概率很小,就拒绝"没有区别"的假设,否则接受假设。
好了,下面我们用一个实例,来更具体的看看卡方独立检验的检验过程。
设现在有男女两组身高的分布,如下:

现问性别对身高有没有影响,那么先假设"男女两组的身高没有区别",然后计算它的概率,如下:
Step-1:计算期望表
1. 在计算期望表前,先对事实表进行行列汇总,如下:

2. 使用公式 计算期望表, 可得到结果:

即:

Step-2:计算卡方值
根据公式计算卡方值,如下:
这里的卡方值,就是事实与期望差异的度量。
Step-3:计算p值
1. 计算自由度
根据公式计算自由度
2. 计算p值
由 服从自由度为 2 的卡方分布,即可知
其中, 是自由度为2的卡方累积分布函数
使用 python的scipy.stats.chi2.cdf进行计算卡方值, 现 , 自由度 , 则代码如下:

即可得到:p = 0.17728440996987782。
一般p<0.05时我们会拒绝"没有区别"的假设,而这里p = 0.177,所以我们接受假设,也就是两组没有区别。
在上面的卡方独立检验中计算过程中,期望表、卡方值与p值的计算都使用了公式,下面我们就来说说这些计算公式是怎么推导出来的。
先来说说期望表的计算公式是怎么推导出来的,设事实表A与它的汇总数据如下所示:

其中,是第i行求和,是第列求和,是总和
如果组1、组2没有区别,那么它们的分布的期望应该与总体保持一致,所以组1、组2在各个取值上的分布占比,此时都应该为:
由于组1的总样本数为,故组1的期望取值为:
同理,组2的总样本数为,组2的期望取值为:
通过观察就可以得到,期望表的取值为:
好了,下面再来说说卡方值与p值的公式是怎么一回事。
由于每一个事实值都与期望值有所差异,不妨用 来量化这个差异,则总的差异为:
设 是服从正态分布的随机变量,则由统计学知识可知: 是服从标准正态分布的随机变量,从而服从自由度为的卡方分布。因此,差异的概率为:
其中, 是自由度为的卡分累积分布函数
这样就得到了在"组1、组2没区别"的假设下,样本出现当前差异的概率,如果概率过小,则拒绝假设,认为组1、组2存在区别,即p越小,代表两组别的分布区别越大。
下面我们先通过scipy的函数来做卡方独立检验,然后再自己按公式来自实现卡方独立检验。
在python中要实现卡方独立检验,可以直接调用scipy的chi2_contingency函数,具体代码如下:
'''
本代码用于展示如何使用scipy来计算卡方独立检验
本代码来自《老饼讲解-机器学习》www.bbblearn.com
'''
import numpy as np
import scipy
A = np.array([[8,11,1],[3,18,9]]) # 事实表,包含两个组别在3个类别上的样本数
chi2_value,p_value,free_n,ex = scipy.stats.chi2_contingency(A) # 调用scipy的函数计算卡方值与P值
print('\n卡方值chi2 =',chi2_value,',p =',p_value) # 打印卡方值与P值代码运行结果如下:

从以上结果可以看到,p值相对较小,如果置信水平设为0.05,由于p<0.05,所以拒绝假设,认为两个组别存在区别。
好了,为了加深对卡方独立检验的理解,我们不妨自己实现一下卡方独立检验,这也是很简单的,只需按照上面所说的步骤进行实现就可以了,具体代码如下:
'''
本代码用于展示如何自实现卡方独立检验
本代码来自《老饼讲解-机器学习》www.bbblearn.com
'''
import numpy as np
import scipy
def cal_chi2(pair):
pair[pair==0] = 1 # 避免为0,将0置1
class_rate = pair.sum(axis=1)/pair.sum().sum() # 两类样本的占比
col_sum = pair.sum(axis=0) # 各组别的样本个数
ex = np.dot(np.array([class_rate]).T,np.array([col_sum])) # 计算期望值
chi2 = (((pair - ex)**2/ex)).sum() # 计算卡方值
df = (pair.shape[0]-1)*(pair.shape[1]-1) # 计算自由度
p = 1-scipy.stats.chi2.cdf(df=df, x=chi2) # 计算p值
return chi2,p # 返回卡方值与p值
# 调用自实现函数计算卡方值与P值
A = np.array([[8,11,1],[3,18,9]]) # 事实表:两组别在3个类别上的样本数
chi2,p = cal_chi2(A) # 调用自实现函数计算卡方值与P值
print('卡方值chi2 =',chi2,',p =',p) # 打印卡方值与P值代码运行结果如下:

可以看到,自写代码计算的卡方值与scipy的函数计算结果是一致的。
卡方独立检验的用途就是检验两个组别的分布是否有没有区别,也就是两组数据是否来自同一分布。它主要先假设没有区别,然后计算出"没有区别"时的期望与事实值的差异出现的概率,如果概率过小,说明"没有区别"是小概率事件,则拒绝假设,否则接受假设。
评论