Python与统计学系列(二):多因素方差分析详解(原理与代码实践)
前言
自学笔记,分享给对统计学原理不太清楚但需要在论文中用到的小伙伴,欢迎大佬们补充或绕道。ps:本文不涉及公式讲解(文科生小白友好体质)~(部分定义等来源于知乎)
本文重点:多因素方差分析
【1.多因素方差分析简单原理】
【2.多因素方差分析步骤】
【3.多因素方差分析代码(配对/独立+事后检验)】
1.多因素方差分析简单原理
多因素方差分析,用于研究一个因变量是否受到多个自变量(也称为因素)的影响,它检验多个因素取值水平的不同组合之间,因变量的均值之间是否存在显著的差异。多因素方差分析既可以分析单个因素的作用(主效应),也可以分析因素之间的交互作用(交互效应),还可以进行协方差分析,以及各个因素变量与协变量的交互作用。
*主效应(Main Effect):
*交互效应(Interaction Effect):
也就是说,
如果只有主效应显著,说明各因素独立地影响观测指标。
如果交互效应显著,说明因素之间存在相互影响,需要进一步分析交互效应的性质和方向。
2.多因素方差分析步骤
之前学的时候写的笔记(虽然是日语)
①交互作用の検定
②交互作用OK: 単純主効果の検定→3水準以上(多重比較)
交互作用No: 主効果の検定→3水準以上(多重比較)
①首先在做多因素方差分析之前要看数据是否满足前提条件
检验方差是否满足方差齐性,以及数据的正态性(详情参考之前的t检验和单因素方差分析)
②检验交互效应(因素之间是否存在显著交互)
③(如果交互效应显著)分析单纯主效应
④(如果交互效应不显著)分析主效应:
3.多因素方差分析以及事后比较(独立样本代码)
①读取数据,进行方差齐性检验
使用的是一组教育学数据进行两因素方差分析
有实验组(Group1)和对照组(Group2)进行两种不同的方法教学,其中再把她们分成10人,20人和30人的班(Size),集中教学一段时间后进行测试(成绩为Score)
检验group(教学方法)和班级规模(size)的两因素,是否对最后的学生测试成绩有影响
import pandas as pd
from scipy.stats import levene
from statsmodels.stats.anova import AnovaRM
# 从 CSV 文件读取数据
df = pd.read_csv('/content/taionasi.csv')
balanced_df = pd.DataFrame(columns=df.columns)
# 按照 group 进行抽样,确保每个组的样本大小相同
for group in df['group'].unique():
group_data = df[df['group'] == group]
# 对每个组进行抽样,使得样本大小相同
min_size = min(group_data['size'])
sampled_data = group_data.groupby('size', group_keys=False).apply(lambda x: x.sample(min_size, random_state=42))
# 将抽样后的数据添加到平衡的 DataFrame 中
balanced_df = balanced_df.append(sampled_data, ignore_index=True)
# 检查平衡后的数据结构
print(balanced_df.head())
# 对平衡后的数据进行 Levene's Test
grouped_data_balanced = [balanced_df[balanced_df['group'] == group]['score'].values for group in balanced_df['group'].unique()]
statistic, p_value = levene(*grouped_data_balanced)
# 打印 Levene's Test 的结果
print(f"Levene's Test Statistic: {statistic}")
print(f"P-value: {p_value}")
# 根据 P-value 判断方差齐性
alpha = 0.05 # 有意水準
if p_value < alpha:
print('帰無仮説を棄却:データのグループ間に等分散性がない可能性が高いです。')
else:
print('帰無仮説は棄却されません:データのグループ間に等分散性があると考えられます。')
*注意:检验方差齐性的时候为了确保每组数据的个数一样,进行了数据抽样。如果不进行数据抽样虽然也不会报错但是数据结果截然相反。
结果:抽样数据显示满足方差齐性,可以进行多因素方差分析
group size score
0 1 10 62
1 1 10 70
2 1 10 83
3 1 10 61
4 1 10 79
Levene's Test Statistic: 1.2774939867588024
P-value: 0.26301796308207803
帰無仮説は棄却されません:データのグループ間に等分散性があると考えられます。
②用图表检查是因素之间是否存在交互效应
#交互作用プロット
from statsmodels.graphics.factorplots import interaction_plot
from matplotlib import pyplot as plt # import matplotlib.pyplot as plt グラフを描画するライブラリ
fig = interaction_plot(df['size'], #x軸のデータ
df['group'], #層別するデータ
df['score'], #y軸のデータ
colors=['red', 'blue'], #グラフの色を設定
ms=15) #グラフの点の大きさの設定
plt.show()
数据存在交点,证明存在交互效应(如果没有交互效应,两条线是平行的)
③进行多因素方差分析
#二元配置分散分析(交互作用あり)
# 統計モデルを推定するライブラリ
import statsmodels.formula.api as smf
import statsmodels.api as sm
anova_mod = smf.ols('score ~ group + size + group:size', data=df).fit()
taionasi=sm.stats.anova_lm(anova_mod, type=2)
taionasi.columns = ["自由度","平方和","平均平方和","F値","p値"] #列名を日本語に差し替え
print("交互作用ありの結果:"+"\n"+str(taionasi))
交互作用ありの結果:
自由度 平方和 平均平方和 F値 p値
group 1.0 26.450000 26.450000 0.261825 6.095178e-01
size 2.0 11238.033333 5619.016667 55.621907 2.108493e-19
group:size 2.0 4057.500000 2028.750000 20.082329 1.421430e-08
Residual 174.0 17577.766667 101.021648 NaN NaN
④事后检验
from statsmodels.stats.multicomp import pairwise_tukeyhsd
from itertools import combinations
import pandas as pd
from IPython.display import display, HTML
# df 是你的数据框
# 调整数据类型
df['group'] = df['group'].astype(str)
df['size'] = df['size'].astype(str)
# 初始化一个空的数据框,用于存储多重比较结果
combined_results = pd.DataFrame(columns=['Group', 'Comparison', 'Mean Difference', 'Lower CI', 'Upper CI', 'Reject Null'])
# 定义函数执行多重比较
def run_tukey_comparison(group_label, group_data, size_values):
group_combinations = combinations(group_data, 2)
for size1, size2 in group_combinations:
m_comp = pairwise_tukeyhsd(endog=pd.concat([size1['score'], size2['score']]),
groups=pd.concat([pd.Series([f'{group_label}_size_{size_values[size1.iloc[0]["size"]]}'] * len(size1)),
pd.Series([f'{group_label}_size_{size_values[size2.iloc[0]["size"]]}'] * len(size2))]),
alpha=0.05)
# 提取多重比较结果的重要信息
comparison_results = pd.DataFrame({
'Group': [f'{group_label}'],
'Comparison': [f"{size1.iloc[0]['size']} vs {size2.iloc[0]['size']}"],
'Mean Difference': [m_comp.meandiffs[0]],
'Lower CI': [m_comp.confint[0, 0]],
'Upper CI': [m_comp.confint[0, 1]],
'Reject Null': [m_comp.reject[0]],
})
# 将结果添加到总的数据框中
global combined_results
combined_results = pd.concat([combined_results, comparison_results], ignore_index=True)
# 运行 group1 的多重比较
run_tukey_comparison('group1', group1_sizes, {'10': 10, '20': 20, '30': 30})
# 运行 group2 的多重比较
run_tukey_comparison('group2', group2_sizes, {'10': 10, '20': 20, '30': 30})
# 调整表格显示顺序
combined_results = combined_results[['Group', 'Comparison', 'Mean Difference', 'Lower CI', 'Upper CI', 'Reject Null']]
# 打印合并结果
print("Combined Results:")
display(HTML(combined_results.to_html(index=False)))
事后检验结果:
Group Comparison Mean Difference Lower CI Upper CI Reject Null
group1 10 vs 20 -9.533333 -13.918702 -5.147965 True
group1 10 vs 30 -30.266667 -35.333353 -25.199980 True
group1 20 vs 30 -20.733333 -25.577774 -15.888892 True
group2 10 vs 20 -9.533333 -13.918702 -5.147965 True
group2 10 vs 30 -30.266667 -35.333353 -25.199980 True
group2 20 vs 30 -20.733333 -25.577774 -15.888892 True
总的来说,这些结果表明:
- 在 Group1 和 Group2 中,size 水平为 20 的组的平均值显著高于 size 水平为 10 的组。
- 在 Group1 和 Group2 中,size 水平为 30 的组的平均值显著高于 size 水平为 10 的组。
- 在 Group1 和 Group2 中,size 水平为 30 的组的平均值显著高于 size 水平为 20 的组。
这些发现表明,不同的 size 水平对因变量有显著影响,并且 size 水平越高,因变量的值越高。此外,Group1 和 Group2 表现出相同的模式,这表明 group 因素可能对 size 水平之间的差异没有显著影响。
作者:TUTO_TUTO