统计检验——卡方检验分析分类变量间的显著性差异
什么是卡方检验
卡方检验是一种统计检验方法,用于判断观察到的数据与期望数据之间的差异是否具有统计显著性,它主要用于分类数据的分析,常见类型为:卡方独立性检验、卡方适合度检验
卡方独立性检验
实现步骤
提出假设
原假设 :两个分类变量相互独立
备择假设 :两个分类变量不独立
构建列联表
构建一个列联表,记录每个分类组合的观测频数
计算期望频数
期望频数计算公式:
其中, 为第 R行第 C列的期望频数, 为第 R行的总数, 为第 C列的总数, E为总样本量
计算卡方统计量
卡方统计量计算公式:
其中, O为第 i行第 j列的观测频数, E为第 i行第 i列的期望频数
确定自由度
自由度计算公式:
其中, 为行数, 为列数
确定 K值
根据卡方统计量和自由度,查卡方分布表或使用统计软件计算 值
结论
如果 值小于显著性水平(例如 ),拒绝原假设,认为两个分类变量之间存在显著关联
使用场景
用于检验两个分类变量是否独立(案例:性别-男性和女性,是否影响一个人是否吸烟-吸烟或不吸烟,验证性别和吸烟习惯之间是否存在关联)
注意事项
- 观测频数必须是独立的
- 每个单元格中的期望频数应不小于5,如果有很多单元格的期望频数小于5,卡方检验可能不适用,可以考虑合并分类或使用Fisher精确检验
代码实现
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from scipy.stats import chi2_contingency
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
# 生成数据
np.random.seed(0)
products = np.random.choice(['Electronics', 'Clothing', 'Home Decor'], size=100)
regions = np.random.choice(['North', 'South', 'East', 'West'], size=100)
# 创建一个新的数据集
data = {'Product_Category': products, 'Sales_Region': regions}
df = pd.DataFrame(data)
# 创建交叉表
contingency_table = pd.crosstab(df['Product_Category'], df['Sales_Region'])
# 进行卡方独立性检验
chi2, p, dof, expected = chi2_contingency(contingency_table)
print("Chi2 Statistic:", chi2)
print("p-value:", p)
print("Degrees of Freedom:", dof)
# 可视化实际频数的交叉表
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
sns.heatmap(contingency_table, annot=True, fmt='d', cmap='YlGnBu')
plt.title('实际频数的交叉表')
# 可视化期望频数的交叉表
plt.subplot(1, 2, 2)
sns.heatmap(expected, annot=True, fmt='.2f', cmap='YlGnBu')
plt.title('期望频数的交叉表')
plt.tight_layout()
plt.show()
在这里我们生成数据来分析不同产品类别在不同销售区域的分布情况,并通过卡方检验来判断产品类别和销售区域之间是否存在显著关联,这里 在显著性水平0.05下,我们无法拒绝原假设,说明根据现有数据,没有足够的证据表明产品类别和销售区域之间存在显著的关联性
卡方适合度检验
实现步骤
提出假设原假设 :观测数据与理论分布一致
备择假设 :观察数据与理论分布不一致
收集数据
收集观测数据和相应的理论频数
计算期望频数
根据理论分布计算期望频数
计算卡方统计量
其中, 为第 类观测频数, 为第 类的期望频数
确定自由度
其中, k为分类数
确定p 值
根据卡方统计量和自由度,查卡方分布表或使用统计软件计算 值
结论
如果 p值小于显著性水平(例如a=0.05 ),拒绝原假设,认为观测数据与理论分布不一致
代码实现
from scipy.stats import chisquare
# 观察到的频数
observed = np.array([16, 18, 16, 14, 12, 14])
# 期望频数(假设是公平的骰子)
expected = np.array([15, 15, 15, 15, 15, 15])
# 卡方适合度检验
chi2, p = chisquare(observed, f_exp=expected)
# 输出结果
print(f"Chi2 Statistic: {chi2}")
print(f"P-value: {p}")
# 创建DataFrame用于可视化
df = pd.DataFrame({
'Side': ['1', '2', '3', '4', '5', '6'],
'Observed': observed,
'Expected': expected
})
# 可视化实际频数和期望频数
fig, ax = plt.subplots(figsize=(10, 6))
# 观察到的频数柱状图
sns.barplot(x='Side', y='Observed', data=df, color='blue', label='观察到的', ax=ax)
# 期望频数柱状图
sns.barplot(x='Side', y='Expected', data=df, color='orange', label='期望的', ax=ax, alpha=0.5)
ax.set_title('观察到的 vs 期望的频数')
ax.legend()
plt.show()
假设我们在一个实验中投掷了一个六面骰子100次,然后统计了每个面出现的次数,在理想情况下,如果骰子是公平的,每个面应该均匀地出现约15次,这里的代码模拟了这样的情景,并进行了卡方适合度检验,来验证观察到的频数是否与期望的频数(即公平骰子的预期结果)相符,根据这个卡方适合度检验的结果P=0.916884在显著性水平0.05下,可以得出结论:在这个实验中,投掷的六面骰子的观察结果与预期的公平骰子模型一致,没有足够的证据表明骰子不是公平的