外观
独立样本t检验
检验一个均值与参照值的差异,或两个均值之间的差异。
计算口径
按研究设计区分独立对象与同一对象的配对测量。小样本应关注相关分布的正态性与离群值;单侧方向应事先提出。
分组变量必须有两个有效类别。默认Welch;有充分等方差依据时可选择Student。均值差的组别顺序按结果行标识解释。
先看差值方向与置信区间,再报告t、自由度、p及效应量。p不显著不等于两者等效。原始输出保留样本和分布诊断。
同源实现
以下片段来自 core/statistical/comparisons.py 的 t_tests,由镜像脚本按语法树提取。共享辅助函数和分发逻辑包含在完整下载包中。
py
def t_tests(data, options, method):
alpha = number(options, 'alpha', .05, .0001, .25)
alternative = choice(options, 'alternative', 'two-sided', ('two-sided', 'less', 'greater'))
rows, details = [], {}
headers = [Column('variable', _('变量'), 'text')]
if method == 'stat_t_one_sample':
selected = columns(data, options.get('variables'))
numeric = numeric_frame(data, selected)
test_value = number(options, 'test_value', 0)
headers += [Column('n', 'N', 'integer'), Column('summary', _('均值±标准差'), 'mean_sd')]
for name in selected:
x = enough(numeric[name].dropna(), 2).to_numpy()
n, sd = len(x), np.std(x, ddof=1)
if sd <= 0:
raise ValueError(_('变量“%(name)s”没有有效变异', name=name))
estimate, se, df = np.mean(x)-test_value, sd/np.sqrt(n), n-1
outcome = stats.ttest_1samp(x, test_value, alternative=alternative)
rows.append({'variable': name, 'n': n, 'summary': mean_sd(x), 'difference': estimate,
't': outcome.statistic, 'df': df, 'p': outcome.pvalue,
'ci': mean_interval(estimate, se, df, alpha, alternative), 'effect': estimate/sd})
details['test_value'] = test_value
effect_label = "Cohen's d"
elif method == 'stat_t_independent':
selected = columns(data, options.get('variables'))
group = options.get('group')
equal = boolean(options, 'equal_variance', False)
headers += [Column('group_a', _('组1'), 'text'), Column('n_a', 'N', 'integer', _('组1')),
Column('a', _('均值±标准差'), 'mean_sd', _('组1')), Column('group_b', _('组2'), 'text'),
Column('n_b', 'N', 'integer', _('组2')), Column('b', _('均值±标准差'), 'mean_sd', _('组2'))]
for name in selected:
names, samples = grouped_samples(data, name, group)
if len(samples) != 2:
raise ValueError(_('独立样本t检验需要恰好两个有效组'))
a, b = [enough(x, 2) for x in samples]
na, nb = len(a), len(b)
va, vb = np.var(a, ddof=1), np.var(b, ddof=1)
pooled = ((na-1)*va+(nb-1)*vb)/(na+nb-2)
if pooled <= 0:
raise ValueError(_('两组都没有组内变异,无法进行t检验'))
if equal:
se, df = np.sqrt(pooled*(1/na+1/nb)), na+nb-2
else:
se = np.sqrt(va/na+vb/nb)
df = (va/na+vb/nb)**2/((va/na)**2/(na-1)+(vb/nb)**2/(nb-1))
estimate = np.mean(a)-np.mean(b)
outcome = stats.ttest_ind(a, b, equal_var=equal, alternative=alternative)
levene = stats.levene(a, b)
details[name] = {'levene': {'statistic': levene.statistic, 'p': levene.pvalue}, 'groups': names}
rows.append({'variable': name, 'group_a': names[0], 'group_b': names[1], 'n_a': na, 'n_b': nb,
'a': mean_sd(a), 'b': mean_sd(b), 'difference': estimate,
't': outcome.statistic, 'df': df, 'p': outcome.pvalue,
'ci': mean_interval(estimate, se, df, alpha, alternative), 'effect': estimate/np.sqrt(pooled)})
details['variance_assumption'] = 'equal' if equal else 'Welch'
effect_label = "Cohen's d"
else:
pairs = paired_columns(data, options)
headers += [Column('n', _('配对数'), 'integer'), Column('a', _('前项均值±标准差'), 'mean_sd'),
Column('b', _('后项均值±标准差'), 'mean_sd')]
for first, second in pairs:
pair = enough(numeric_frame(data, [first, second]).dropna(), 2)
a, b = pair[first].values, pair[second].values
difference = a-b
sd = np.std(difference, ddof=1)
if sd <= 0:
raise ValueError(_('配对差值没有变异,无法进行配对t检验'))
estimate, se, df = np.mean(difference), sd/np.sqrt(len(pair)), len(pair)-1
outcome = stats.ttest_rel(a, b, alternative=alternative)
rows.append({'variable': first+' − '+second, 'n': len(pair), 'a': mean_sd(a), 'b': mean_sd(b),
'difference': estimate, 't': outcome.statistic, 'df': df, 'p': outcome.pvalue,
'ci': mean_interval(estimate, se, df, alpha, alternative), 'effect': estimate/sd})
effect_label = "Cohen's dz"
headers += [Column('difference', _('均值差')), Column('t', 't'), Column('df', 'df'), Column('p', 'p', 'p'),
Column('ci', _('%(level)s%%置信区间', level='%g' % (100*(1-alpha))), 'interval'), Column('effect', effect_label)]
details.update(alternative=alternative, alpha=alpha, results=rows)
return StatisticalResult([PaperTable(_('t检验结果'), headers, rows)], details)复现本方法
在解压目录安装 requirements.txt 后执行。样例为固定种子的模拟数据,仅供验证;输出不得冒充真实研究结果。
python
import examples._bootstrap
from examples.statistics_cases import build_data, method_cases
from core.statistical.runner import analyze
method = "stat_t_independent"
options = dict(method_cases())[method]
result = analyze(build_data(), method, options)
print(result.tables[0].html())