最强总结!十大统计检验方法 !!

发布日期:2025-04-13 08:35:18 点击次数:91

哈喽,我是小白~

统计检验方法能够帮助验证模型的性能差异是否具备统计显著性,避免结果偶然。通过这些方法,可以确保实验结果具有可重复性和稳健性,从而支持科学结论的有效性。此外,统计检验还可以帮助发现不同模型、特征或算法改进的真实影响,避免误导性优化。

图片

今天分享的内容,涉及到:

t 检验(t-test)卡方检验(Chi-Square Test)方差分析(ANOVA)Mann-Whitney U 检验Kolmogorov-Smirnov 检验(K-S 检验)Wilcoxon 符号秩检验Kruskal-Wallis 检验Fisher 精确检验McNemar 检验Cochran's Q 检验

一起来看下细节~

1. t 检验(t-test)

t 检验是用于比较两个样本均值的假设检验方法,假设数据服从正态分布。它包括单样本 t 检验、独立样本 t 检验和配对样本 t 检验。

原理

t 检验基于样本均值与总体均值的差异,考虑了样本标准误的影响。其关键思想是,如果两个样本均值的差异在合理范围内,则认为它们来自相同的总体,否则就认为它们有显著差异。

核心公式

独立样本 t 检验的统计量为:

 分别是样本 1 和样本 2 的均值 分别是两个样本的方差 是两个样本的样本数量公式推导

假设两个独立样本来自相同的总体。根据中心极限定理,样本均值近似服从正态分布。假设样本方差未知,我们使用样本方差代替总体方差进行估计。

1. 均值的差异:样本均值的差异为 。

2. 标准误的计算:对于两个样本均值的标准误,公式为

3. t 值计算:将均值差异除以标准误,得到 t 值:

4. t 分布:通过计算得到的 t 值,可以根据 t 分布表来确定 p 值,p 值反映了均值差异的显著性。

5. 自由度:t 分布的自由度为 。

如果计算出的 t 值超过临界值,则拒绝零假设,即认为两个样本的均值显著不同。

Python实现

假设我们想检验一种新的教学方法是否比传统方法更有效。在这个实验中,我们有两个独立的学生组:一个组使用传统教学方法,另一个组使用新的教学方法。我们想比较这两组学生在最终考试中的平均成绩,以确定新的教学方法是否有显著提高学生的成绩。

数据集描述:

传统方法组:学生使用传统教学方法,他们的成绩从某个正态分布中随机生成。新方法组:学生使用新的教学方法,他们的成绩从另一个正态分布中随机生成。

我们将使用两个样本的独立 t 检验来比较这两个组的平均成绩,假设新方法能提高学生的平均分数。

import numpy as npimport matplotlib.pyplot as pltimport seaborn as snsfrom scipy import stats# 设置随机种子,保证结果的可重复性np.random.seed(42)# 生成虚拟数据# 传统方法组,正态分布,均值为70,标准差为10,样本量为50traditional_scores = np.random.normal(loc=70, scale=10, size=50)# 新方法组,正态分布,均值为75,标准差为12,样本量为50new_method_scores = np.random.normal(loc=75, scale=12, size=50)# 独立样本t检验t_stat, p_value = stats.ttest_ind(traditional_scores, new_method_scores)# 打印t检验结果print(f'T-statistic: {t_stat:.3f}, P-value: {p_value:.3f}')# 创建一个图形,包含多个子图plt.figure(figsize=(12, 8))# 1. 箱线图 (Boxplot)plt.subplot(2, 2, 1)sns.boxplot(data=[traditional_scores, new_method_scores], palette='Set2')plt.xticks([0, 1], ['Traditional Method', 'New Method'])plt.title('Boxplot of Scores')# 2. 直方图 (Histogram)plt.subplot(2, 2, 2)sns.histplot(traditional_scores, color='blue', label='Traditional', kde=True, bins=10, stat='density', alpha=0.6)sns.histplot(new_method_scores, color='red', label='New Method', kde=True, bins=10, stat='density', alpha=0.6)plt.legend()plt.title('Histogram of Scores')plt.xlabel('Score')plt.ylabel('Density')# 3. 均值柱状图 (Barplot of Means with Standard Error)means = [np.mean(traditional_scores), np.mean(new_method_scores)]errors = [stats.sem(traditional_scores), stats.sem(new_method_scores)]  # 标准误plt.subplot(2, 1, 2)plt.bar([0, 1], means, yerr=errors, capsize=10, color=['blue', 'red'], alpha=0.7)plt.xticks([0, 1], ['Traditional Method', 'New Method'])plt.title('Mean Scores with Standard Error')plt.ylabel('Mean Score')# 调整布局,防止图像重叠plt.tight_layout()# 展示图形plt.show()

数据生成:我们生成了两组虚拟数据,分别代表传统方法组和新方法组的考试成绩。

t 检验:通过 scipy.stats.ttest_ind 进行独立样本的 t 检验,检验两组平均值是否有显著差异。

图片

箱线图:展示两组的成绩分布,便于观察中位数、四分位距和离群点。可以清晰地展示数据的集中趋势和离散趋势,帮助判断数据的分布和潜在的异常值。直方图:展示两组成绩的频率分布,并叠加核密度估计曲线,帮助观察数据的形态及正态性。结合核密度估计曲线,能够显示数据的分布形状,便于验证假设数据的正态性,这对于 t 检验非常重要。均值柱状图:展示每组的平均分和标准误,直观地比较均值的差异。结合标准误误差条,能直观地展示两组均值的差异及其不确定性,从而帮助评估组间差异的大小。2. 卡方检验(Chi-Square Test)

卡方检验用于判断两个分类变量之间是否存在统计显著的关系。常用于频数数据或分类数据的独立性检验和拟合优度检验。

原理

卡方检验通过比较观测值与期望值,衡量分类变量的独立性。如果实际观测值与期望值的差异很大,则认为变量之间存在关联。

核心公式

卡方统计量的计算公式为:

 是观察值(观测频数) 是期望值(期望频数)公式推导

1. 零假设:假设分类变量是独立的。

2. 期望频数的计算:期望频数  的计算为:

3. 差异计算:计算每个单元格的观测频数  和期望频数  的差异平方。

4. 归一化差异:用期望频数  归一化差异,计算卡方统计量。

5. 卡方分布:最终的卡方统计量服从卡方分布,其自由度为 ,其中  是行数, 是列数。

通过查卡方分布表,若卡方统计量超出临界值,则拒绝零假设,认为两个变量不独立。

Python实现

有一组虚拟数据集,包含两个分类变量:产品类型(A, B, C)和客户满意度(高, 中, 低)。我们想检验产品类型与客户满意度是否存在显著的关联。

import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as snsfrom scipy.stats import chi2_contingencyfrom statsmodels.graphics.mosaicplot import mosaic# 生成虚拟数据np.random.seed(42)data = pd.DataFrame({    'Product_Type': np.random.choice(['A', 'B', 'C'], size=300, p=[0.3, 0.4, 0.3]),    'Customer_Satisfaction': np.random.choice(['High', 'Medium', 'Low'], size=300, p=[0.4, 0.3, 0.3])})# 生成交叉表contingency_table = pd.crosstab(data['Product_Type'], data['Customer_Satisfaction'])# 卡方检验chi2, p, dof, expected = chi2_contingency(contingency_table)# 输出结果print(f'Chi-Square Test Statistic: {chi2}')print(f'P-value: {p}')print(f'Degrees of Freedom: {dof}')print(f'Expected Frequencies: \n{expected}')# 创建图像fig, axes = plt.subplots(2, 2, figsize=(14, 10))# 1. 分组柱状图contingency_table.plot(kind='bar', stacked=False, ax=axes[0, 0], color=['#FF6F61', '#6B5B95', '#88B04B'])axes[0, 0].set_title('Grouped Bar Plot')axes[0, 0].set_ylabel('Count')axes[0, 0].set_xlabel('Product Type')# 2. 热力图显示观察值和期望值的差异sns.heatmap(contingency_table - expected, annot=True, cmap='coolwarm', ax=axes[0, 1])axes[0, 1].set_title('Heatmap of Observed vs Expected')# 3. 马赛克图mosaic(data, ['Product_Type', 'Customer_Satisfaction'], ax=axes[1, 0], title='Mosaic Plot')# 4. 堆积柱状图contingency_table.plot(kind='bar', stacked=True, ax=axes[1, 1], color=['#FFA07A', '#20B2AA', '#9370DB'])axes[1, 1].set_title('Stacked Bar Plot')axes[1, 1].set_ylabel('Count')axes[1, 1].set_xlabel('Product Type')# 调整布局plt.tight_layout()plt.show()

图片

分组柱状图:该图展示了每种产品类型下客户满意度的分布,帮助我们直观比较不同分类的观测频次。

热力图:展示了观察值与期望值之间的差异,颜色鲜明的热力图可以直观地显示是否有显著偏差。

马赛克图:展示了类别之间的相对比例,图形的面积代表不同类别组合的比例,是一个直观的方式来展示两个分类变量之间的关系。

堆积柱状图:展示了不同类别之间的累积分布,便于查看各类别组合的总计情况。

这些数据分析图形综合展示了分类变量的频数分布、期望与实际值的差异,以及两者的关联性。

3. 方差分析(ANOVA)

方差分析用于比较三个或更多样本的均值差异,常用于多组数据的比较。单因素 ANOVA 用于单一因子对响应变量的影响分析。

原理

ANOVA 通过比较组间方差和组内方差,判断组间的均值差异是否显著。组间方差大,说明不同组之间差异显著;组内方差反映了组内个体之间的波动。

核心公式

单因素方差分析的 F 值为:

:组间均方:组内均方:组间平方和:组内平方和公式推导

1. 零假设:假设所有组的均值相等,即 。

2. 组间平方和(SSB):计算各组均值和总体均值的偏差平方:

3. 组内平方和(SSW):计算组内数据和各组均值的偏差平方:

4. 均方计算:组间均方(MSB)和组内均方(MSW)分别为组间平方和和组内平方和除以自由度:

5. F 值计算:F 统计量为组间均方与组内均方的比值:

6. F 分布:F 统计量服从  分布,通过查表判断是否拒绝零假设。

Python实现

使用 ANOVA 来检验不同教学方法的平均成绩是否存在显著差异。为此,我们将生成虚拟数据,并通过可视化展示数据和结果。

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsimport scipy.stats as statsfrom statsmodels.formula.api import olsfrom statsmodels.stats.anova import anova_lmimport statsmodels.api as sm# 设置随机种子,生成可重复的虚拟数据np.random.seed(42)# 创建虚拟数据集:三个教学方法,每个方法下有 30 名学生的成绩n_students = 30method_A = np.random.normal(loc=75, scale=10, size=n_students)  # 方法 A 的成绩method_B = np.random.normal(loc=80, scale=12, size=n_students)  # 方法 B 的成绩method_C = np.random.normal(loc=70, scale=9, size=n_students)   # 方法 C 的成绩# 构造数据集df = pd.DataFrame({    'Score': np.concatenate([method_A, method_B, method_C]),    'Method': ['A']*n_students + ['B']*n_students + ['C']*n_students})# 1. 方差分析(ANOVA)模型model = ols('Score ~ Method', data=df).fit()anova_results = anova_lm(model)# 2. 提取残差和拟合值df['Residuals'] = model.residdf['Fitted'] = model.fittedvalues# 设置绘图风格sns.set(style='whitegrid', palette='Set2')# 创建画布和子图 (3 行 1 列)fig, axes = plt.subplots(3, 1, figsize=(10, 15))# 3. 绘制箱线图(Boxplot):不同教学方法的成绩分布sns.boxplot(x='Method', y='Score', data=df, ax=axes[0], linewidth=2.5, width=0.5)axes[0].set_title('Boxplot of Scores by Teaching Method', fontsize=14)axes[0].set_xlabel('Teaching Method', fontsize=12)axes[0].set_ylabel('Scores', fontsize=12)# 4. 绘制均值和标准误差图mean_se_df = df.groupby('Method').agg(Mean=('Score', 'mean'), SE=('Score', 'sem')).reset_index()axes[1].errorbar(x=mean_se_df['Method'], y=mean_se_df['Mean'],                  yerr=mean_se_df['SE'], fmt='o', ecolor='red', capsize=5, markersize=8, color='blue')axes[1].set_title('Mean and Standard Error of Scores by Teaching Method', fontsize=14)axes[1].set_xlabel('Teaching Method', fontsize=12)axes[1].set_ylabel('Mean Scores', fontsize=12)# 5. 绘制残差图:残差 vs 拟合值sns.residplot(x='Fitted', y='Residuals', data=df, ax=axes[2], lowess=True,               scatter_kws={'color': 'purple'}, line_kws={'color': 'orange', 'lw': 2})axes[2].set_title('Residual Plot', fontsize=14)axes[2].set_xlabel('Fitted Values', fontsize=12)axes[2].set_ylabel('Residuals', fontsize=12)# 调整图形布局plt.tight_layout()plt.show()# 输出方差分析结果print('ANOVA Results:\n', anova_results)

虚拟数据生成:创建了三个不同教学方法的学生成绩数据集,假设方法 A、B 和 C 的成绩分别服从正态分布,均值和标准差不同。

ANOVA 检验:通过 statsmodels 库中的 ols 函数拟合线性模型,使用 anova_lm 进行方差分析。

图片

箱线图:通过箱线图,我们可以看到每个教学方法的成绩分布情况,便于判断是否有极端值以及分布的对称性。均值和标准误图:展示了每组的平均成绩及其误差范围,帮助我们观察不同教学方法的平均成绩是否存在显著差异。残差图:通过残差图,我们可以检查方差分析模型的残差是否均匀分布,从而判断模型拟合的合理性。如果残差不随拟合值的增大而增大,模型拟合是合理的。4. Mann-Whitney U 检验

Mann-Whitney U 检验是一种非参数检验,用于比较两个独立样本的中位数差异。它不要求数据服从正态分布,是 t 检验的非参数替代方法。

原理

该方法基于样本秩的比较,如果两个样本来自同一总体,两个样本的秩序统计量应该混合分布。如果存在中位数差异,则高秩数据偏向某个样本。

核心公式

Mann-Whitney U 检验的 U 值公式为:

 是两个样本的大小 是样本 1 的秩和公式推导

1. 秩赋值:将两个样本数据合并,按大小为它们赋予秩(小值秩小)。 

2. 秩和计算:计算样本 1 和样本 2 的秩和 。 

3. U 值计算:

选择较小的 值,并查表确定其 p 值。Python实现

两个不同的疗法(治疗A和治疗B),用于治疗患者的慢性疼痛。每个疗法的样本量为50人,并测量了在疗法应用后每个患者的疼痛评分。因为数据不是正态分布的,所以我们选择了非参数检验中的Mann-Whitney U检验来比较这两种疗法的疗效是否有显著差异。

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom scipy.stats import mannwhitneyu# 设置随机种子,便于复现np.random.seed(42)# 生成两个虚拟的疼痛评分数据集 (非正态分布)# 疗法A的疼痛评分treatment_A = np.random.beta(a=2, b=5, size=50) * 10  # Beta分布, 放大到0-10范围# 疗法B的疼痛评分treatment_B = np.random.beta(a=2.5, b=4, size=50) * 10# 创建数据框data = pd.DataFrame({    'Pain Score': np.concatenate([treatment_A, treatment_B]),    'Treatment': ['A'] * 50 + ['B'] * 50})# Mann-Whitney U检验stat, p_value = mannwhitneyu(treatment_A, treatment_B)print(f'Mann-Whitney U检验的统计量: {stat}, p值: {p_value}')# 画图plt.figure(figsize=(14, 10))# 子图1:箱线图plt.subplot(2, 2, 1)sns.boxplot(x='Treatment', y='Pain Score', data=data, palette='Set2')plt.title('Boxplot of Pain Scores for Two Treatments', fontsize=14)plt.xlabel('Treatment', fontsize=12)plt.ylabel('Pain Score', fontsize=12)# 子图2:小提琴图plt.subplot(2, 2, 2)sns.violinplot(x='Treatment', y='Pain Score', data=data, palette='Set1')plt.title('Violin Plot of Pain Scores for Two Treatments', fontsize=14)plt.xlabel('Treatment', fontsize=12)plt.ylabel('Pain Score', fontsize=12)# 子图3:累积分布函数(CDF)plt.subplot(2, 1, 2)sns.ecdfplot(treatment_A, label='Treatment A', color='blue', lw=2)sns.ecdfplot(treatment_B, label='Treatment B', color='orange', lw=2)plt.title('Cumulative Distribution Function (CDF)', fontsize=14)plt.xlabel('Pain Score', fontsize=12)plt.ylabel('CDF', fontsize=12)plt.legend(title='Treatment')# 调整布局并展示图形plt.tight_layout()plt.show()

图片

箱线图:通过中位数和四分位数来展示数据集的集中趋势和离散程度,帮助快速发现两个疗法的中心趋势是否存在差异。

小提琴图:相比箱线图,小提琴图增加了数据分布的密度信息,能展示出数据的分布形状和波动情况,帮助发现每组数据的对称性和集中情况。

累积分布函数图(CDF):展示了每个治疗组在特定疼痛评分下的累积概率,可以帮助我们查看两组数据在每个评分区间的累积分布差异。

这些数据分析图形能够从多个角度验证治疗A和治疗B的疼痛评分是否存在显著差异,结合Mann-Whitney U检验的结果,得出统计结论。

5. Kolmogorov-Smirnov 检验(K-S 检验)

Kolmogorov-Smirnov 检验用于比较两个分布的差异,或检验样本是否来自某个已知分布。K-S 检验常用于正态性检验。

原理

K-S 检验基于两个累积分布函数(CDF)之间的最大差异。通过比较样本分布的累积分布函数和理论分布的累积分布函数,计算最大差异值 。

核心公式

K-S 检验统计量为:

 分别为两个分布的累积分布函数公式推导

1. 累积分布函数计算:对于每个样本,计算样本的经验累积分布函数(ECDF)。

2. 最大差异计算:在每个数据点上,计算两个累积分布函数之间的绝对差值,并找到其最大值 。

3. 查表:通过查 Kolmogorov 分布表,判断  值是否显著。

Python实现

生成两个虚拟数据集,一个是正态分布,另一个是指数分布,目的是使用 K-S 检验来判断它们的分布是否显著不同。

数据集 1: 正态分布 (均值为 0, 标准差为 1)数据集 2: 指数分布 (λ = 1)import numpy as npimport matplotlib.pyplot as pltfrom scipy.stats import kstest, norm, expon# 生成虚拟数据np.random.seed(42)sample_size = 1000# 数据集1:正态分布data_norm = np.random.normal(loc=0, scale=1, size=sample_size)# 数据集2:指数分布data_expon = np.random.exponential(scale=1, size=sample_size)# 执行K-S检验ks_stat, p_value = kstest(data_norm, 'expon', args=(0, 1))# 生成x轴x = np.linspace(-2, 8, 1000)# 获取累积分布函数 (CDF)cdf_norm = norm.cdf(x, loc=0, scale=1)cdf_expon = expon.cdf(x, scale=1)# 获取概率密度函数 (PDF)pdf_norm = norm.pdf(x, loc=0, scale=1)pdf_expon = expon.pdf(x, scale=1)# 绘制图形fig, ax = plt.subplots(2, 2, figsize=(12, 10))# 图1:累积分布函数 (CDF)ax[0, 0].plot(x, cdf_norm, color='blue', label='Normal CDF', linewidth=2)ax[0, 0].plot(x, cdf_expon, color='red', label='Exponential CDF', linewidth=2)ax[0, 0].set_title('Cumulative Distribution Function (CDF)', fontsize=14)ax[0, 0].legend()ax[0, 0].grid(True)# 图2:概率密度函数 (PDF)ax[0, 1].plot(x, pdf_norm, color='green', label='Normal PDF', linewidth=2)ax[0, 1].plot(x, pdf_expon, color='orange', label='Exponential PDF', linewidth=2)ax[0, 1].set_title('Probability Density Function (PDF)', fontsize=14)ax[0, 1].legend()ax[0, 1].grid(True)# 图3:经验累积分布 (Empirical CDF)ecdf_norm_x, ecdf_norm_y = np.sort(data_norm), np.arange(1, sample_size+1) / sample_sizeecdf_expon_x, ecdf_expon_y = np.sort(data_expon), np.arange(1, sample_size+1) / sample_sizeax[1, 0].step(ecdf_norm_x, ecdf_norm_y, color='blue', label='Empirical CDF (Normal)', where='post')ax[1, 0].step(ecdf_expon_x, ecdf_expon_y, color='red', label='Empirical CDF (Exponential)', where='post')ax[1, 0].set_title('Empirical Cumulative Distribution Function', fontsize=14)ax[1, 0].legend()ax[1, 0].grid(True)# 图4:K-S统计量差异点# 找到差异最大的点(即K-S统计量对应的地方)ks_diff_point = np.argmax(np.abs(cdf_norm - cdf_expon))ax[1, 1].plot(x, np.abs(cdf_norm - cdf_expon), color='purple', label='K-S Statistic Difference', linewidth=2)ax[1, 1].scatter(x[ks_diff_point], np.abs(cdf_norm[ks_diff_point] - cdf_expon[ks_diff_point]),                  color='black', zorder=5, label=f'Max Difference: {np.abs(cdf_norm[ks_diff_point] - cdf_expon[ks_diff_point]):.4f}', s=100)ax[1, 1].set_title('K-S Statistic Difference Plot', fontsize=14)ax[1, 1].legend()ax[1, 1].grid(True)# 显示结果plt.tight_layout()plt.show()# 打印K-S检验结果print(f'K-S Statistic: {ks_stat:.4f}, P-value: {p_value:.4f}')

虚拟数据生成:data_norm 是从正态分布生成的数据集,均值为 0,标准差为 1。data_expon 是从指数分布生成的数据集,参数 λ=1。

图片

图1:累积分布函数 (CDF) 显示两个分布的累积分布曲线,便于直观比较两个分布的差异。图2:概率密度函数 (PDF) 显示数据的概率分布,查看其不同取值范围内的频率分布情况。图3:经验累积分布 (Empirical CDF) 是基于实际样本计算的经验累积分布,展示数据的实际分布情况。图4:K-S 统计量差异点图,展示了累积分布函数的差异,并标出了差异最大的点,该点对应 K-S 检验中的统计量。6. Wilcoxon 符号秩检验

Wilcoxon 符号秩检验是一种非参数检验,用于比较两个相关样本的中位数差异。通常用于配对样本的比较。

原理

该检验根据两个样本之间的差异值,对差异值进行排序并赋予秩值,判断正负差异是否显著不同。

核心公式

Wilcoxon 符号秩检验的统计量  为:

公式推导

1. 差异计算:对于配对样本,计算每对样本的差异值 。

2. 秩赋值:将差异值按绝对值排序,赋予秩值。

3. 符号赋值:根据差异的符号,将正差异和负差异分别赋值。

4. 统计量计算:计算正差异的秩和 ,并通过查表判断显著性。

Python实现

假设我们有一组患者,在服用两种不同的药物治疗前后,我们记录了他们的体重变化。我们想使用 Wilcoxon 符号秩检验来比较两种药物对体重的影响是否有显著差异。

import numpy as npimport pandas as pdimport seaborn as snsimport matplotlib.pyplot as pltfrom scipy.stats import wilcoxon# 生成虚拟数据集np.random.seed(42)n = 30  # 样本数量before_treatment = np.random.normal(75, 10, n)  # 治疗前体重after_treatment = before_treatment + np.random.normal(-2, 5, n)  # 治疗后体重(假设有体重下降)# 将数据放入DataFramedf = pd.DataFrame({    'Before Treatment': before_treatment,    'After Treatment': after_treatment})# 进行Wilcoxon符号秩检验stat, p_value = wilcoxon(before_treatment, after_treatment)print(f'Wilcoxon test statistic: {stat}, p-value: {p_value}')# 画出多个图形在一个图中plt.figure(figsize=(14, 8))# 1. 箱线图(展示治疗前后体重的分布)plt.subplot(2, 2, 1)sns.boxplot(data=df, palette='Set2')plt.title('Boxplot of Before and After Treatment')plt.ylabel('Weight (kg)')plt.grid(True)# 2. 密度图(展示数据的概率密度分布)plt.subplot(2, 2, 2)sns.kdeplot(before_treatment, label='Before Treatment', color='blue', shade=True)sns.kdeplot(after_treatment, label='After Treatment', color='red', shade=True)plt.title('Density Plot of Before and After Treatment')plt.xlabel('Weight (kg)')plt.legend()plt.grid(True)# 3. 散点图(展示治疗前后配对样本的体重变化)plt.subplot(2, 2, 3)plt.scatter(np.arange(n), before_treatment, color='blue', label='Before Treatment')plt.scatter(np.arange(n), after_treatment, color='red', label='After Treatment')for i in range(n):    plt.plot([i, i], [before_treatment[i], after_treatment[i]], color='gray', linestyle='--')plt.title('Paired Scatter Plot of Before and After Treatment')plt.xlabel('Sample Index')plt.ylabel('Weight (kg)')plt.legend()plt.grid(True)# 4. 体重变化的差值分布图plt.subplot(2, 2, 4)weight_diff = after_treatment - before_treatmentsns.histplot(weight_diff, kde=True, color='purple', bins=10)plt.title('Distribution of Weight Change (After - Before)')plt.xlabel('Weight Change (kg)')plt.grid(True)# 调整布局并显示图像plt.tight_layout()plt.show()

图片

箱线图:用于比较两组体重数据的中位数和分布差异。如果箱线图有显著差异,可能说明两组数据存在系统性变化。

密度图:展示治疗前后体重的分布形态,可以直观地看出数据的集中趋势和分布情况。

散点图:每个点对应一个患者的体重变化,配对散点图连线显示了每个样本在治疗前后的体重差异,有助于可视化个体变化。

体重变化的差值分布图:展示体重变化的分布,帮助我们理解总体上是增加还是减少体重。

7. Kruskal-Wallis 检验

Kruskal-Wallis 检验是一种非参数检验方法,用于比较三个或更多独立组的中位数差异,属于非参数方差分析(ANOVA)的扩展版本。它不要求数据服从正态分布,也不需要组间方差齐性假设。

原理

Kruskal-Wallis 检验通过比较样本的秩次,将所有样本的观测值排序并赋予秩次,然后比较不同组的秩和。如果各组的秩和差异显著,则认为这些组的中位数存在显著差异。

核心公式

Kruskal-Wallis 检验的统计量  计算公式为:

 是第  组的秩和 是第  组的样本大小 是总样本数,即 公式推导

1. 秩排序:将所有样本的观测值  (即第  组的第  个观测值)按大小排序,并赋予秩次。如果有相同的观测值,则平均赋秩。

2. 计算秩和:每组数据的秩和  计算为:

3. 统计量  计算:将每组的秩和代入公式,得到统计量 。

4. 检验结果:Kruskal-Wallis 检验的统计量  近似服从卡方分布,其自由度为 ,其中  是组数。通过查卡方分布表,判断  是否显著。如果  超过临界值,则拒绝零假设,认为组间存在显著差异。

Python实现

咱们使用虚拟数据集,通过绘制以下数据分析图来说明问题~

箱线图 (Boxplot):用于显示不同组的数据分布,突出数据的中位数、四分位数和离群值。

小提琴图 (Violin Plot):展示数据的概率密度分布和数据分布的形状。

条形图 (Bar Plot):展示不同组的均值和标准误差,可以用来简单展示数据差异。

Kruskal-Wallis检验结果展示图:在图像上标出显著性检验结果。

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom scipy.stats import kruskal# 设置随机种子以确保结果可重复np.random.seed(42)# 创建虚拟数据集 (3组数据)group_1 = np.random.normal(loc=5, scale=1.5, size=100)group_2 = np.random.normal(loc=7, scale=2.0, size=100)group_3 = np.random.normal(loc=6, scale=1.2, size=100)# 将数据整合到一个DataFrame中df = pd.DataFrame({    'Value': np.concatenate([group_1, group_2, group_3]),    'Group': ['Group 1']*100 + ['Group 2']*100 + ['Group 3']*100})# 进行Kruskal-Wallis检验stat, p_value = kruskal(group_1, group_2, group_3)# 创建图形plt.figure(figsize=(15, 10))# 1. 箱线图 (Boxplot)plt.subplot(2, 2, 1)sns.boxplot(x='Group', y='Value', data=df, palette='Set2')plt.title('Boxplot of Groups')plt.ylabel('Value')plt.grid(True)# 2. 小提琴图 (Violin Plot)plt.subplot(2, 2, 2)sns.violinplot(x='Group', y='Value', data=df, palette='Set1')plt.title('Violin Plot of Groups')plt.ylabel('Value')plt.grid(True)# 3. 条形图 (Bar Plot)plt.subplot(2, 2, 3)sns.barplot(x='Group', y='Value', data=df, ci='sd', palette='Set3')plt.title('Bar Plot with Error Bars (Mean ± SD)')plt.ylabel('Mean Value')plt.grid(True)# 4. Kruskal-Wallis 检验结果展示plt.subplot(2, 2, 4)sns.boxplot(x='Group', y='Value', data=df, palette='coolwarm')plt.text(0.5, max(df['Value']) - 1, f'Kruskal-Wallis H-statistic: {stat:.2f}', fontsize=12, ha='center')plt.text(0.5, max(df['Value']) - 2, f'p-value: {p_value:.4f}', fontsize=12, ha='center')plt.title('Kruskal-Wallis Test Result')plt.ylabel('Value')plt.grid(True)# 调整图形布局plt.tight_layout()plt.show()

图片

箱线图 (Boxplot):箱线图可以直观地展示每组数据的中位数、四分位范围和离群值。用于对比不同组数据的离散性及位置差异。

小提琴图 (Violin Plot):相比箱线图,小提琴图增加了数据的密度估计,使得可以看到每组数据的分布形态,尤其是某些组可能的多峰分布。

条形图 (Bar Plot):简单展示各组的均值和标准误差,能让人更容易看出数据的集中趋势与变异情况。

Kruskal-Wallis 检验结果展示图:在数据分布图形上标注Kruskal-Wallis检验结果,说明各组之间是否存在显著差异。这种展示方式可以将统计结果和数据分布可视化地结合在一起。

8. Fisher 精确检验

Fisher 精确检验用于处理两个分类变量之间的独立性检验,特别适用于小样本数据或  的列联表。它通过计算每种可能的样本排列概率,准确判断两个变量是否独立。

原理

Fisher 精确检验基于超几何分布,计算在  列联表中,实际观察到的样本排列是否与假设的独立性一致。检验通过所有可能的排列概率之和,得出是否存在显著性差异。

核心公式

Fisher 精确检验的公式为:

 是  列联表中的频数 是样本总数,即  是组合数公式推导

1. 列联表定义:给定  的列联表:

图片

2. 超几何分布:假设行变量和列变量独立,则样本中的各元素服从超几何分布。列联表中的元素表示抽样结果,而超几何分布计算某个特定组合发生的概率。

3. 组合数计算:Fisher 精确检验通过计算所有可能的列联表配置,并基于每种配置的概率计算总体显著性。

每种可能组合的概率为:

4. p 值计算:将所有更极端的组合概率相加,得到总的 p 值。如果 p 值小于显著性水平 ,则拒绝独立性假设。

Python实现

假设我们想研究一个医院中不同年龄段(青年、中年、老年)患者是否在不同性别(男性、女性)之间的就诊频率有显著差异。

import numpy as npimport pandas as pdimport seaborn as snsimport matplotlib.pyplot as pltfrom scipy.stats import fisher_exactfrom statsmodels.graphics.mosaicplot import mosaicfrom matplotlib import colors# 设置随机种子np.random.seed(42)# 虚拟数据集data = {    'Age Group': np.random.choice(['Youth', 'Middle-aged', 'Senior'], size=100),    'Gender': np.random.choice(['Male', 'Female'], size=100)}df = pd.DataFrame(data)# 选择两个年龄组df_filtered = df[df['Age Group'].isin(['Youth', 'Middle-aged'])]# 生成交叉表contingency_table = pd.crosstab(df_filtered['Age Group'], df_filtered['Gender'])# 进行 Fisher 精确检验oddsratio, p_value = fisher_exact(contingency_table)print(f'Fisher Exact Test p-value: {p_value}')# 绘制分析图形fig, axes = plt.subplots(1, 3, figsize=(18, 6))# 图1:堆叠条形图contingency_table.plot(kind='bar', stacked=True, ax=axes[0], color=['#FF9999','#66B3FF'])axes[0].set_title('Stacked Bar Plot of Age Group vs Gender')axes[0].set_xlabel('Age Group')axes[0].set_ylabel('Count')axes[0].legend(title='Gender')# 图2:热图sns.heatmap(contingency_table, annot=True, fmt='d', cmap='YlGnBu', cbar=True, ax=axes[1])axes[1].set_title('Heatmap of Age Group vs Gender')# 图3:马赛克图props = lambda key: {'color': ['#FF9999','#66B3FF'][key[1] == 'Female']}mosaic(df_filtered, ['Age Group', 'Gender'], ax=axes[2], properties=props)axes[2].set_title('Mosaic Plot of Age Group vs Gender')# 调整布局plt.tight_layout()plt.show()

图片

堆叠条形图:通过条形的高度和颜色来比较不同性别在各个年龄段的分布,观察是否存在显著的比例差异。

热图:交叉表的频数通过颜色强度展示,便于直观观察哪些组合的频次较高或较低。

马赛克图:通过各矩形区域的大小展示不同年龄组和性别的组合频率,面积越大,频率越高,清晰呈现比例关系。

9. McNemar 检验

McNemar 检验用于分析配对样本的分类变量,特别是比较两种处理结果在二分类变量上的差异。它常用于评估两种诊断方法或实验前后差异。

原理

McNemar 检验基于配对样本的  列联表,通过比较两种结果的差异,判断处理前后的变化是否显著。特别关注变化的方向和不对称性。

核心公式

McNemar 检验的统计量为:

 和  是列联表中配对样本的不同响应数公式推导

1. 列联表定义:对于配对样本数据,构造  列联表:

图片

其中  和  表示处理前后响应一致的个数, 和  表示响应改变的个数。

2. 检验差异:McNemar 检验重点分析  和  的不对称性,表示样本在两个处理结果之间的不同变化。通过检验  和  的差异是否显著,判断处理是否有效。

3. 统计量计算:计算 McNemar 统计量:

4. 自由度与显著性:该统计量服从自由度为 1 的卡方分布。如果  超过临界值,则认为两个处理结果有显著差异。

Python实现

通过分析一个假设的二分类变量的变化(例如,测试前后某个治疗方法的效果),并展示数据的分布、变化情况及其统计结果。

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom statsmodels.stats.contingency_tables import mcnemar# 设置随机种子以保证结果可重现np.random.seed(42)# 生成虚拟数据# 前后状态: 0 = 未好转, 1 = 好转data = {    'Before': [0] * 14 + [1] * 36,  # 14人未好转,36人好转    'After': [0] * 10 + [1] * 26 + [0] * 14  # 10人好转,26人未好转}df = pd.DataFrame(data)# 进行 McNemar 检验# 形成 2x2 频数表table = pd.crosstab(df['Before'], df['After'])print('2x2 Contingency Table:')print(table)# McNemar 检验result = mcnemar(table, exact=False)print(f'McNemar Test Results: Statistic = {result.statistic}, p-value = {result.pvalue}')# 可视化plt.figure(figsize=(14, 8))# 堆叠条形图plt.subplot(2, 2, 1)sns.countplot(data=df, x='Before', hue='After', palette='bright')plt.title('Change in Status Before and After Treatment')plt.xticks([0, 1], ['Not Improved', 'Improved'])plt.ylabel('Count')# 混淆矩阵plt.subplot(2, 2, 2)sns.heatmap(table, annot=True, fmt='d', cmap='viridis', cbar=False, xticklabels=['Not Improved', 'Improved'], yticklabels=['Not Improved', 'Improved'])plt.title('Confusion Matrix')plt.xlabel('Post-Treatment Status')plt.ylabel('Pre-Treatment Status')# 比例饼图plt.subplot(2, 2, (3, 4))proportions = table.values.flatten()labels = ['Not Improved-Not Improved', 'Not Improved-Improved', 'Improved-Not Improved', 'Improved-Improved']plt.pie(proportions, labels=labels, autopct='%1.1f%%', startangle=90, colors=sns.color_palette('bright', len(labels)))plt.title('Proportional Change in Status')plt.tight_layout()plt.show()

数据生成:使用 NumPy 和 Pandas 创建一个包含治疗前后状态的虚拟数据集。“Before”列表示治疗前的状态,“After”列表示治疗后的状态。

McNemar 检验:使用 statsmodels 库中的 mcnemar 方法进行 McNemar 检验,输出统计量和 p 值,以判断治疗效果的显著性。

图片

堆叠条形图显示治疗前后状态的变化情况,便于直观了解各状态的人数分布。混淆矩阵用热图表示,帮助理解实际状态与预测状态之间的关系。比例饼图清晰展示状态变化的比例,增强结果的可读性。

通过 McNemar 检验,我们可以分析治疗前后状态的变化是否具有统计学显著性。图形化分析不仅可以直观呈现数据的分布情况,还可以帮助识别数据中的趋势和模式。

10. Cochran's Q 检验

Cochran's Q 检验是一种非参数检验,用于分析多个相关样本的二分类变量差异。它是 McNemar 检验的扩展,可以处理三个或更多相关样本的情况。

原理

Cochran's Q 检验基于多个相关样本的二分类数据,通过比较不同处理组的二分类结果是否一致,判断不同处理是否存在显著性差异。

核心公式

Cochran's Q 检验的统计量为:

 是处理组数 是样本数 是第  组的总响应数 是第  组第  个样本的响应(0 或 1)公式推导

1. 列联表构造:针对每个样本的多个处理结果,构造  的二分类矩阵,每个元素  代表样本  在处理  下的响应。

2. 总响应数计算:对于每个处理组,计算总响应数 。

3. 统计量  计算:通过总响应数和样本的响应差异,计算 Cochran's Q 统计量:

4. 显著性检验:Q 统计量服从自由度为  的卡方分布,通过查表判断是否显著。如果  超过临界值,则不同处理之间存在显著性差异。

Python实现

假设我们有 10 个患者,他们接受了三种不同的治疗(药物A、药物B 和药物C)。对于每个患者,我们记录了每种治疗是否成功(成功用 1 表示,失败用 0 表示)。我们想知道这三种治疗方法的成功率是否有显著差异。

import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsfrom statsmodels.stats.contingency_tables import cochrans_q# 生成虚拟数据集np.random.seed(42)data = {    'Patient': ['Patient {}'.format(i+1) for i in range(10)],    'Drug A': np.random.randint(0, 2, size=10),    'Drug B': np.random.randint(0, 2, size=10),    'Drug C': np.random.randint(0, 2, size=10)}df = pd.DataFrame(data)df.set_index('Patient', inplace=True)# Cochran's Q 检验# Reshape data for Cochran's Q testdata_for_cochrans_q = df.values.T  # Transpose the DataFrame to get treatments as rowsq_stat, p_value = cochrans_q(data_for_cochrans_q)print(f'Cochran's Q 检验统计量: {q_stat:.4f}, p值: {p_value:.4f}')# 可视化分析fig, axs = plt.subplots(2, 2, figsize=(12, 12))# 1. 条形图:展示每种治疗的成功率success_rate = df.mean().sort_values(ascending=False)axs[0, 0].bar(success_rate.index, success_rate, color=['blue', 'green', 'red'])axs[0, 0].set_title('Comparison of Success Rates for Treatments')axs[0, 0].set_ylabel('Success Rate')axs[0, 0].set_ylim(0, 1)# 2. 热力图:展示每个患者在不同治疗中的结果sns.heatmap(df, cmap='coolwarm', linewidths=1, linecolor='black', cbar=False, ax=axs[0, 1])axs[0, 1].set_title('Heatmap of Patient Treatment Outcomes')# 3. 点图:展示患者在每种治疗中的成功与失败情况for i, drug in enumerate(df.columns):    axs[1, 0].scatter(df.index, df[drug] + i * 0.1, label=drug, s=100, alpha=0.8)axs[1, 0].set_yticks([0, 1])axs[1, 0].set_yticklabels(['Failure', 'Success'])axs[1, 0].legend()axs[1, 0].set_title('Patient Treatment Outcomes Scatter Plot')# 4. 箱线图:展示不同治疗结果的分布df_melt = df.melt(var_name='Drug', value_name='Outcome')sns.boxplot(x='Drug', y='Outcome', data=df_melt, palette='Set2', ax=axs[1, 1])axs[1, 1].set_title('Distribution of Treatment Outcomes')plt.tight_layout()plt.show()

图片

条形图:展示了三种药物的成功率对比,能够快速识别哪个药物成功率较高或较低。条形图非常适合展示分类变量的频率或比例,因此我们使用它来比较药物成功率。

热力图:展示每个患者在不同药物下的成功或失败情况,颜色的变化使得成功与失败的模式更直观。热力图可以清晰地呈现每个患者的结果模式,通过颜色对比,易于观察每种治疗方法的差异。

点图(Dot Plot):每个患者的每次治疗结果用点表示,多个治疗之间有轻微位移,使得结果的层次更加明显。点图可以展示出每个个体在不同治疗中的详细结果,能够从个体层面上评估成功与失败情况。

箱线图:展示了不同治疗方法的结果分布。虽然数据是二值的,但仍然可以通过箱线图可视化各组的集中趋势和离散情况。箱线图适合展示数据的分布和离散情况,尽管我们的数据是二进制,但仍然可以用于展示治疗效果的波动。

通过这些图形和Cochran's Q检验结果,我们可以得出对三种药物的成功率差异的结论。如果p值小于显著性水平(通常是0.05),则说明三种药物的成功率有显著差异。

最后

以上就是今天所有的内容了。如果对你来说比较有用,记得点赞、收藏,慢慢学习~下期会有更多干货等着你!~ 本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报。