外观
t 检验
独立样本 t 检验(亦支持单样本与配对样本)。
核心代码
py
def _fit_ttest_independent(self, df: pd.DataFrame, decimals: int, title: str) -> None:
"""
执行独立样本T检验
参数:
df: 数据框
decimals: 小数位数
title: 表格标题
"""
# 获取分组变量和检验参数
group_var = self.ttest_options.get('group_var')
alpha = self.ttest_options.get('alpha', 0.05)
levene_test = self.ttest_options.get('levene_test', False)
if not group_var or group_var not in df.columns:
raise ValueError(_('未指定有效的分组变量。'))
# 检查变量
if not self.x_vars:
raise ValueError(_('未选择任何检验变量。'))
# 获取分组
groups = df[group_var].dropna().unique()
if len(groups) != 2:
raise ValueError(_('分组变量必须恰好有2个类别,当前有%(count)s个类别。') % {'count': len(groups)})
group1_name, group2_name = groups[0], groups[1]
# 构建结果表格
results = []
levene_results = []
for var in self.x_vars:
if var not in df.columns:
continue
# 获取两组数据
df_clean = df[[var, group_var]].dropna()
group1_data = df_clean[df_clean[group_var] == group1_name][var]
group2_data = df_clean[df_clean[group_var] == group2_name][var]
if len(group1_data) < 2 or len(group2_data) < 2:
continue
# 执行Levene方差齐性检验(如果勾选)
equal_var = True # 默认假设方差相等
levene_p = None
if levene_test:
from scipy.stats import levene
levene_stat, levene_p = levene(group1_data, group2_data)
# 如果Levene检验显著(p<0.05),则认为方差不相等
equal_var = levene_p >= 0.05
levene_results.append({
'Variable': var,
'Levene Statistic': f"{levene_stat:.{decimals}f}",
'P-value': f"{levene_p:.{decimals}f}",
'Equal Variance': _('是') if equal_var else _('否')
})
# 执行独立样本T检验
t_stat, p_value = ttest_ind(group1_data, group2_data, equal_var=equal_var)
# 计算各组统计量
mean1 = group1_data.mean()
mean2 = group2_data.mean()
std1 = group1_data.std()
std2 = group2_data.std()
n1 = len(group1_data)
n2 = len(group2_data)
# 计算均值差异
mean_diff = mean1 - mean2
# 计算标准误
if equal_var:
# 合并方差的标准误
pooled_var = ((n1 - 1) * std1**2 + (n2 - 1) * std2**2) / (n1 + n2 - 2)
se_diff = np.sqrt(pooled_var * (1/n1 + 1/n2))
df_t = n1 + n2 - 2
else:
# Welch's方法的标准误
se_diff = np.sqrt((std1**2 / n1) + (std2**2 / n2))
# Welch-Satterthwaite自由度
df_t = ((std1**2 / n1) + (std2**2 / n2))**2 / \
((std1**2 / n1)**2 / (n1 - 1) + (std2**2 / n2)**2 / (n2 - 1))
# 计算置信区间
from scipy.stats import t as t_dist
t_critical = t_dist.ppf(1 - alpha/2, df_t)
ci_lower = mean_diff - t_critical * se_diff
ci_upper = mean_diff + t_critical * se_diff
# 判断显著性
if p_value < 0.01:
stars = "***"
elif p_value < 0.05:
stars = "**"
elif p_value < 0.1:
stars = "*"
else:
stars = ""
results.append({
'Variable': var,
f'N ({group1_name})': int(n1),
f'Mean ({group1_name})': f"{mean1:.{decimals}f}",
f'Std ({group1_name})': f"{std1:.{decimals}f}",
f'N ({group2_name})': int(n2),
f'Mean ({group2_name})': f"{mean2:.{decimals}f}",
f'Std ({group2_name})': f"{std2:.{decimals}f}",
'Mean Diff': f"{mean_diff:.{decimals}f}",
't-statistic': f"{t_stat:.{decimals}f}{stars}",
'P-value': f"{p_value:.{decimals}f}",
f'{int((1-alpha)*100)}% CI Lower': f"{ci_lower:.{decimals}f}",
f'{int((1-alpha)*100)}% CI Upper': f"{ci_upper:.{decimals}f}"
})
if not results:
raise ValueError(_('没有可用的数据进行T检验。'))
# 生成HTML表格
results_df = pd.DataFrame(results)
title = title if title else _('独立样本T检验 (分组变量: %(group_var)s)') % {'group_var': group_var}
# 构建注释
test_method = _('Pooled t-test (等方差)') if not levene_test else _('根据Levene检验结果自动选择')
note = _('H0: mean(%(group1_name)s) = mean(%(group2_name)s); 显著性水平: α=%(alpha)s; %(test_method)s; *** p<0.01, ** p<0.05, * p<0.1') % {'group1_name': group1_name, 'group2_name': group2_name, 'alpha': alpha, 'test_method': test_method}
# 如果执行了Levene检验,生成两个表格
if levene_test and levene_results:
levene_df = pd.DataFrame(levene_results)
levene_html = self._generate_ttest_html(
levene_df,
_('Levene方差齐性检验'),
_('H0: 两组方差相等; 若p<0.05则拒绝原假设,认为方差不相等'),
decimals
)
ttest_html = self._generate_ttest_html(results_df, title, note, decimals)
self.custom_html = levene_html + ttest_html
else:
self.custom_html = self._generate_ttest_html(results_df, title, note, decimals)