除了使用置换检验之外,还可以执行一种稍微概念上更简单的蒙特卡洛检验。以下是具体实现方法:
首先,我们导入所需的库,并设定一个示例列联表数据:
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
# 示例列联表数据
table = np.asarray([[20, 49, 25, 4],
[35, 54, 43, 12],
[27, 44, 29, 8],
[7, 20, 16, 4]])
# 在零假设(即无关联性)下获取列联表分布
row_totals, col_totals = stats.contingency.margins(table)
null_dist = stats.random_table(row_totals.ravel(), col_totals.ravel())
# 蒙特卡洛零分布:在零假设下随机抽样列联表并计算统计量
n_simulations = 9999
monte_carlo_null_distribution = np.empty(n_simulations, dtype=float)
for i in range(n_simulations):
resampled_table = stats.chi2_contingency(null_dist.rvs())
monte_carlo_null_distribution[i] = resampled_table.statistic
# 将观察到的统计量与蒙特卡洛零分布进行比较
observed_chi2 = stats.chi2_contingency(table)
extreme_count = (monte_carlo_null_distribution >= observed_chi2.statistic).sum()
pvalue_mc = (extreme_count + 1) / (n_simulations + 1) # 0.6534
# 绘制蒙特卡洛零分布和渐近逼近分布
plt.hist(monte_carlo_null_distribution, bins=30, density=True, label='蒙特卡洛')
degrees_of_freedom = table.size - sum(table.shape) + table.ndim - 1
asymptotic_dist = stats.chi2(degrees_of_freedom)
x_axis = np.linspace(0, 40, 300)
plt.plot(x_axis, asymptotic_dist.pdf(x_axis), label='渐近')
plt.legend()
plt.title("卡方检验的零分布")
# 显示图片(对应于WsVk3.png)
# (由于无法实际显示图片,请参照用户上传的WsVk3.png图表)
# 接下来分析临界阈值附近的保守性和安全性
ecdf = stats.ecdf(monte_carlo_null_distribution)
quantiles = ecdf.sf.quantiles[::-1]
prob_mc = ecdf.sf.probabilities[::-1]
prob_asymp = asymptotic_dist.sf(quantiles)
plt.plot(prob_mc, prob_asymp)
plt.xlabel("蒙特卡洛零分布生存概率")
plt.ylabel("渐近零分布生存概率")
plt.plot([0, 1], [0, 1], '--')
plt.xlim(0, 0.1)
plt.ylim(0, 0.1)

它们之间的匹配度非常高,因此至少对于这个列联表来说,采用渐进卡方检验是相当可靠的。