chore: import zh skill statistical-analysis
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
# WeHub 来源说明
|
||||
|
||||
- Skill 名称:`statistical-analysis`
|
||||
- 中文类目:经典假设检验与统计推断
|
||||
- 上游仓库:`k-dense-ai__claude-scientific-skills`
|
||||
- 上游路径:`skills/statistical-analysis/SKILL.md`
|
||||
- 上游链接:https://github.com/k-dense-ai/claude-scientific-skills/blob/HEAD/skills/statistical-analysis/SKILL.md
|
||||
- 本仓库为 WeHub 中文 Skill 汉化包,基于 skill 市场筛选 Top200 清单整理
|
||||
- 原作者、版权和许可证信息以上游仓库为准
|
||||
@@ -0,0 +1,652 @@
|
||||
---
|
||||
name: statistical-analysis
|
||||
description: 引导式统计分析,包含检验选择与报告输出。当你需要为数据选择合适的检验方法、进行假设检验、功效分析以及生成 APA 格式结果时使用。适用于学术研究报告撰写和检验方法选择指导。如需以编程方式实现特定模型,请使用 statsmodels。
|
||||
license: MIT license
|
||||
metadata:
|
||||
version: "1.0"
|
||||
skill-author: K-Dense Inc.
|
||||
---
|
||||
|
||||
# 统计分析
|
||||
|
||||
## 概述
|
||||
|
||||
统计分析是检验假设和量化关系的系统性过程。可进行假设检验(t 检验、ANOVA、卡方检验)、回归分析、相关分析以及贝叶斯分析,附带假设检验和 APA 格式报告。将此技能用于学术研究。
|
||||
|
||||
## 何时使用此技能
|
||||
|
||||
以下情况应使用此技能:
|
||||
- 进行统计假设检验(t 检验、ANOVA、卡方检验)
|
||||
- 执行回归分析或相关分析
|
||||
- 运行贝叶斯统计分析
|
||||
- 检查统计假设与诊断
|
||||
- 计算效应量并进行功效分析
|
||||
- 以 APA 格式报告统计结果
|
||||
- 分析研究中的实验或观测数据
|
||||
|
||||
---
|
||||
|
||||
## 安装
|
||||
|
||||
使用 **uv** 安装此技能所需的库。在生产环境中锁定版本;探索性分析中不锁定版本亦可。
|
||||
|
||||
```bash
|
||||
# 核心频率主义库栈(Python 3.10+;推荐 3.12+ 以获得最新版 SciPy/ArviZ)
|
||||
uv pip install "pingouin>=0.6" "scipy>=1.11" "statsmodels>=0.14.6" pandas matplotlib seaborn
|
||||
|
||||
# 贝叶斯建模(PyMC 5 + ArviZ;ArviZ 0.23+ 需要 Python 3.12+)
|
||||
uv pip install "pymc>=5.0" "arviz>=0.17"
|
||||
```
|
||||
|
||||
**兼容性说明(2025–2026):**
|
||||
|
||||
- **Pingouin 0.5+** 重命名了输出列名(`p_val`、`cohen_d`、`CI95`、`p_unc`)——以下示例使用当前名称。
|
||||
- **statsmodels + SciPy**:使用 `statsmodels>=0.14.6` 搭配 `scipy>=1.11`,以避免 SciPy 1.16+ 上的 `_lazywhere` 导入错误。
|
||||
- **Pingouin 贝叶斯因子**:t 检验的单侧 BF 已在 0.5+ 中移除;如需假设检验,请使用专用包(例如 JASP、通过 R 使用的 BayesFactor)或 PyMC。
|
||||
|
||||
如需特定模型 API(OLS、GLM、ARIMA),请参见 **statsmodels** 技能。如需 PyMC 工作流,请参见 **pymc** 技能。
|
||||
|
||||
---
|
||||
|
||||
## 核心能力
|
||||
|
||||
### 1. 检验选择与规划
|
||||
- 根据研究问题和数据特征选择合适的统计检验
|
||||
- 进行先验功效分析,确定所需样本量
|
||||
- 规划分析策略,包括多重比较校正
|
||||
|
||||
### 2. 假设检验
|
||||
- 在执行检验前自动验证所有相关假设
|
||||
- 提供诊断可视化图表(Q-Q 图、残差图、箱线图)
|
||||
- 当假设被违反时推荐补救措施
|
||||
|
||||
### 3. 统计检验
|
||||
- 假设检验:t 检验、ANOVA、卡方检验、非参数替代方法
|
||||
- 回归分析:线性、多元、逻辑回归,附带诊断
|
||||
- 相关分析:Pearson 相关、Spearman 相关,附带置信区间
|
||||
- 贝叶斯替代方法:贝叶斯 t 检验、ANOVA、含贝叶斯因子的回归
|
||||
|
||||
### 4. 效应量与解释
|
||||
- 为所有分析计算并解释合适的效应量
|
||||
- 提供效应估计的置信区间
|
||||
- 区分统计显著性与实际显著性
|
||||
|
||||
### 5. 专业报告
|
||||
- 生成 APA 格式的统计报告
|
||||
- 创建可发表的图表和表格
|
||||
- 提供包含所有必要统计量的完整解释
|
||||
|
||||
---
|
||||
|
||||
## 工作流决策树
|
||||
|
||||
使用此决策树确定分析路径:
|
||||
|
||||
```
|
||||
开始
|
||||
│
|
||||
├─ 需要选择统计检验?
|
||||
│ └─ 是 → 参见「检验选择指南」
|
||||
│ └─ 否 → 继续
|
||||
│
|
||||
├─ 准备检查假设?
|
||||
│ └─ 是 → 参见「假设检验」
|
||||
│ └─ 否 → 继续
|
||||
│
|
||||
├─ 准备运行分析?
|
||||
│ └─ 是 → 参见「运行统计检验」
|
||||
│ └─ 否 → 继续
|
||||
│
|
||||
└─ 需要报告结果?
|
||||
└─ 是 → 参见「报告结果」
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 检验选择指南
|
||||
|
||||
### 快速参考:选择合适的检验
|
||||
|
||||
完整指南请参见 `references/test_selection_guide.md`。快速参考:
|
||||
|
||||
**比较两组:**
|
||||
- 独立、连续、正态 → 独立样本 t 检验
|
||||
- 独立、连续、非正态 → Mann-Whitney U 检验
|
||||
- 配对、连续、正态 → 配对样本 t 检验
|
||||
- 配对、连续、非正态 → Wilcoxon 符号秩检验
|
||||
- 二元结果 → 卡方检验或 Fisher 精确检验
|
||||
|
||||
**比较三组及以上:**
|
||||
- 独立、连续、正态 → 单因素 ANOVA
|
||||
- 独立、连续、非正态 → Kruskal-Wallis 检验
|
||||
- 配对、连续、正态 → 重复测量 ANOVA
|
||||
- 配对、连续、非正态 → Friedman 检验
|
||||
|
||||
**关系分析:**
|
||||
- 两个连续变量 → Pearson 相关(正态)或 Spearman 相关(非正态)
|
||||
- 连续结果变量 + 预测变量 → 线性回归
|
||||
- 二元结果变量 + 预测变量 → 逻辑回归
|
||||
|
||||
**贝叶斯替代方法:**
|
||||
所有检验都有对应的贝叶斯版本,提供:
|
||||
- 关于假设的直接概率陈述
|
||||
- 量化证据的贝叶斯因子
|
||||
- 支持零假设的能力
|
||||
- 详见 `references/bayesian_statistics.md`
|
||||
|
||||
---
|
||||
|
||||
## 假设检验
|
||||
|
||||
### 系统性假设验证
|
||||
|
||||
**在解释检验结果之前,务必检查假设。**
|
||||
|
||||
使用附带的 `scripts/assumption_checks.py` 模块进行自动检查。在技能目录(`skills/statistical-analysis/`)下运行 Python,或将 `scripts/` 添加到 `sys.path`:
|
||||
|
||||
```python
|
||||
from assumption_checks import comprehensive_assumption_check
|
||||
|
||||
# 带可视化的全面检查
|
||||
results = comprehensive_assumption_check(
|
||||
data=df,
|
||||
value_col='score',
|
||||
group_col='group', # 可选:用于组间比较
|
||||
alpha=0.05
|
||||
)
|
||||
```
|
||||
|
||||
该函数执行:
|
||||
1. **异常值检测**(IQR 和 z 分数法)
|
||||
2. **正态性检验**(Shapiro-Wilk 检验 + Q-Q 图)
|
||||
3. **方差齐性检验**(Levene 检验 + 箱线图)
|
||||
4. **解释与建议**
|
||||
|
||||
### 单项假设检查
|
||||
|
||||
如需针对性地检查,可使用单项函数:
|
||||
|
||||
```python
|
||||
from assumption_checks import (
|
||||
check_normality,
|
||||
check_normality_per_group,
|
||||
check_homogeneity_of_variance,
|
||||
check_linearity,
|
||||
detect_outliers
|
||||
)
|
||||
|
||||
# 示例:带可视化的正态性检验
|
||||
result = check_normality(
|
||||
data=df['score'],
|
||||
name='Test Score',
|
||||
alpha=0.05,
|
||||
plot=True
|
||||
)
|
||||
print(result['interpretation'])
|
||||
print(result['recommendation'])
|
||||
```
|
||||
|
||||
### 假设被违反时如何处理
|
||||
|
||||
**正态性被违反:**
|
||||
- 轻度违反 + 每组 n > 30 → 使用参数检验(稳健)
|
||||
- 中度违反 → 使用非参数替代方法
|
||||
- 严重违反 → 对数据进行变换或使用非参数检验
|
||||
|
||||
**方差齐性被违反:**
|
||||
- t 检验 → 使用 Welch t 检验
|
||||
- ANOVA → 使用 Welch ANOVA 或 Brown-Forsythe ANOVA
|
||||
- 回归分析 → 使用稳健标准误或加权最小二乘法
|
||||
|
||||
**线性被违反(回归):**
|
||||
- 添加多项式项
|
||||
- 对变量进行变换
|
||||
- 使用非线性模型或 GAM
|
||||
|
||||
完整指南请参见 `references/assumptions_and_diagnostics.md`。
|
||||
|
||||
---
|
||||
|
||||
## 运行统计检验
|
||||
|
||||
### Python 库
|
||||
|
||||
统计分析的主要库:
|
||||
- **scipy.stats**:核心统计检验
|
||||
- **statsmodels**:高级回归与诊断
|
||||
- **pingouin**:用户友好的统计检验,附带效应量
|
||||
- **pymc**:贝叶斯统计建模
|
||||
- **arviz**:贝叶斯可视化与诊断
|
||||
|
||||
### 分析示例
|
||||
|
||||
#### 含完整报告的 T 检验
|
||||
|
||||
```python
|
||||
import pingouin as pg
|
||||
import numpy as np
|
||||
|
||||
# 运行独立样本 t 检验
|
||||
result = pg.ttest(group_a, group_b, correction='auto')
|
||||
|
||||
# 提取结果(Pingouin 0.5+ 列名)
|
||||
t_stat = result['T'].values[0]
|
||||
df = result['dof'].values[0]
|
||||
p_value = result['p_val'].values[0]
|
||||
cohens_d = result['cohen_d'].values[0]
|
||||
ci = result['CI95'].values[0]
|
||||
ci_lower, ci_upper = ci[0], ci[1]
|
||||
|
||||
# 报告
|
||||
print(f"t({df:.0f}) = {t_stat:.2f}, p = {p_value:.3f}")
|
||||
print(f"Cohen's d = {cohens_d:.2f}, 95% CI [{ci_lower:.2f}, {ci_upper:.2f}]")
|
||||
```
|
||||
|
||||
#### 含事后检验的 ANOVA
|
||||
|
||||
```python
|
||||
import pingouin as pg
|
||||
|
||||
# 单因素 ANOVA
|
||||
aov = pg.anova(dv='score', between='group', data=df, detailed=True)
|
||||
print(aov)
|
||||
|
||||
# 若显著,进行事后检验
|
||||
if aov['p_unc'].values[0] < 0.05:
|
||||
posthoc = pg.pairwise_tukey(dv='score', between='group', data=df)
|
||||
print(posthoc)
|
||||
|
||||
# 效应量
|
||||
eta_squared = aov['np2'].values[0] # 偏 η²
|
||||
print(f"Partial η² = {eta_squared:.3f}")
|
||||
```
|
||||
|
||||
#### 含诊断的线性回归
|
||||
|
||||
```python
|
||||
import statsmodels.api as sm
|
||||
from statsmodels.stats.outliers_influence import variance_inflation_factor
|
||||
|
||||
# 拟合模型
|
||||
X = sm.add_constant(X_predictors) # 添加截距项
|
||||
model = sm.OLS(y, X).fit()
|
||||
|
||||
# 汇总
|
||||
print(model.summary())
|
||||
|
||||
# 检查多重共线性(VIF)
|
||||
vif_data = pd.DataFrame()
|
||||
vif_data["Variable"] = X.columns
|
||||
vif_data["VIF"] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]
|
||||
print(vif_data)
|
||||
|
||||
# 检查假设
|
||||
residuals = model.resid
|
||||
fitted = model.fittedvalues
|
||||
|
||||
# 残差图
|
||||
import matplotlib.pyplot as plt
|
||||
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
|
||||
|
||||
# 残差 vs 拟合值
|
||||
axes[0, 0].scatter(fitted, residuals, alpha=0.6)
|
||||
axes[0, 0].axhline(y=0, color='r', linestyle='--')
|
||||
axes[0, 0].set_xlabel('Fitted values')
|
||||
axes[0, 0].set_ylabel('Residuals')
|
||||
axes[0, 0].set_title('Residuals vs Fitted')
|
||||
|
||||
# Q-Q 图
|
||||
from scipy import stats
|
||||
stats.probplot(residuals, dist="norm", plot=axes[0, 1])
|
||||
axes[0, 1].set_title('Normal Q-Q')
|
||||
|
||||
# 尺度-位置图
|
||||
axes[1, 0].scatter(fitted, np.sqrt(np.abs(residuals / residuals.std())), alpha=0.6)
|
||||
axes[1, 0].set_xlabel('Fitted values')
|
||||
axes[1, 0].set_ylabel('√|Standardized residuals|')
|
||||
axes[1, 0].set_title('Scale-Location')
|
||||
|
||||
# 残差直方图
|
||||
axes[1, 1].hist(residuals, bins=20, edgecolor='black', alpha=0.7)
|
||||
axes[1, 1].set_xlabel('Residuals')
|
||||
axes[1, 1].set_ylabel('Frequency')
|
||||
axes[1, 1].set_title('Histogram of Residuals')
|
||||
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
```
|
||||
|
||||
#### 贝叶斯 T 检验
|
||||
|
||||
```python
|
||||
import pymc as pm
|
||||
import arviz as az
|
||||
import numpy as np
|
||||
|
||||
with pm.Model() as model:
|
||||
# 先验
|
||||
mu1 = pm.Normal('mu_group1', mu=0, sigma=10)
|
||||
mu2 = pm.Normal('mu_group2', mu=0, sigma=10)
|
||||
sigma = pm.HalfNormal('sigma', sigma=10)
|
||||
|
||||
# 似然
|
||||
y1 = pm.Normal('y1', mu=mu1, sigma=sigma, observed=group_a)
|
||||
y2 = pm.Normal('y2', mu=mu2, sigma=sigma, observed=group_b)
|
||||
|
||||
# 导出量
|
||||
diff = pm.Deterministic('difference', mu1 - mu2)
|
||||
|
||||
# 采样
|
||||
trace = pm.sample(2000, tune=1000, return_inferencedata=True)
|
||||
|
||||
# 汇总
|
||||
print(az.summary(trace, var_names=['difference']))
|
||||
|
||||
# group1 > group2 的概率
|
||||
prob_greater = np.mean(trace.posterior['difference'].values > 0)
|
||||
print(f"P(μ₁ > μ₂ | data) = {prob_greater:.3f}")
|
||||
|
||||
# 绘制后验分布
|
||||
az.plot_posterior(trace, var_names=['difference'], ref_val=0)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 效应量
|
||||
|
||||
### 始终计算效应量
|
||||
|
||||
**效应量量化效应的大小,而 p 值仅指示效应是否存在。**
|
||||
|
||||
完整指南请参见 `references/effect_sizes_and_power.md`。
|
||||
|
||||
### 快速参考:常见效应量
|
||||
|
||||
| 检验 | 效应量 | 小 | 中 | 大 |
|
||||
|------|-------------|-------|--------|-------|
|
||||
| T 检验 | Cohen's d | 0.20 | 0.50 | 0.80 |
|
||||
| ANOVA | η²_p | 0.01 | 0.06 | 0.14 |
|
||||
| 相关 | r | 0.10 | 0.30 | 0.50 |
|
||||
| 回归 | R² | 0.02 | 0.13 | 0.26 |
|
||||
| 卡方检验 | Cramér's V | 0.07 | 0.21 | 0.35 |
|
||||
|
||||
**重要提示**:这些基准仅供参考,具体情境决定实际意义!
|
||||
|
||||
### 计算效应量
|
||||
|
||||
大多数效应量由 pingouin 自动计算:
|
||||
|
||||
```python
|
||||
# T 检验返回 Cohen's d
|
||||
result = pg.ttest(x, y)
|
||||
d = result['cohen_d'].values[0]
|
||||
|
||||
# ANOVA 返回偏 eta 平方
|
||||
aov = pg.anova(dv='score', between='group', data=df)
|
||||
eta_p2 = aov['np2'].values[0]
|
||||
|
||||
# 相关:r 本身就是效应量
|
||||
corr = pg.corr(x, y)
|
||||
r = corr['r'].values[0]
|
||||
```
|
||||
|
||||
### 效应量的置信区间
|
||||
|
||||
始终报告置信区间以显示精度:
|
||||
|
||||
```python
|
||||
from pingouin import compute_effsize_from_t
|
||||
|
||||
# 对于 t 检验
|
||||
d, ci = compute_effsize_from_t(
|
||||
t_statistic,
|
||||
nx=len(group1),
|
||||
ny=len(group2),
|
||||
eftype='cohen'
|
||||
)
|
||||
print(f"d = {d:.2f}, 95% CI [{ci[0]:.2f}, {ci[1]:.2f}]")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 功效分析
|
||||
|
||||
### 先验功效分析(研究规划)
|
||||
|
||||
在收集数据前确定所需样本量:
|
||||
|
||||
```python
|
||||
from statsmodels.stats.power import (
|
||||
tt_ind_solve_power,
|
||||
FTestAnovaPower
|
||||
)
|
||||
|
||||
# T 检验:检测 d = 0.5 需要多少样本?
|
||||
n_required = tt_ind_solve_power(
|
||||
effect_size=0.5,
|
||||
alpha=0.05,
|
||||
power=0.80,
|
||||
ratio=1.0,
|
||||
alternative='two-sided'
|
||||
)
|
||||
print(f"Required n per group: {n_required:.0f}")
|
||||
|
||||
# ANOVA:检测 f = 0.25 需要多少样本?
|
||||
anova_power = FTestAnovaPower()
|
||||
n_per_group = anova_power.solve_power(
|
||||
effect_size=0.25,
|
||||
ngroups=3,
|
||||
alpha=0.05,
|
||||
power=0.80
|
||||
)
|
||||
print(f"Required n per group: {n_per_group:.0f}")
|
||||
```
|
||||
|
||||
### 敏感度分析(研究后)
|
||||
|
||||
确定能够检测到的效应量:
|
||||
|
||||
```python
|
||||
# 每组 n=50,能检测到多大的效应?
|
||||
detectable_d = tt_ind_solve_power(
|
||||
effect_size=None, # 求解此值
|
||||
nobs1=50,
|
||||
alpha=0.05,
|
||||
power=0.80,
|
||||
ratio=1.0,
|
||||
alternative='two-sided'
|
||||
)
|
||||
print(f"Study could detect d ≥ {detectable_d:.2f}")
|
||||
```
|
||||
|
||||
**注意**:一般不推荐在研究后进行事后功效分析(计算已得结果的检验功效)。请改用敏感度分析。
|
||||
|
||||
详见 `references/effect_sizes_and_power.md`。
|
||||
|
||||
---
|
||||
|
||||
## 报告结果
|
||||
|
||||
### APA 格式统计报告
|
||||
|
||||
遵循 `references/reporting_standards.md` 中的指南。
|
||||
|
||||
### 基本报告要素
|
||||
|
||||
1. **描述性统计**:所有组/变量的 M、SD、n
|
||||
2. **检验统计量**:检验名称、统计量、自由度、精确 p 值
|
||||
3. **效应量**:附带置信区间
|
||||
4. **假设检验**:进行了哪些检验、结果、采取的措施
|
||||
5. **所有计划的分析**:包括不显著的结果
|
||||
|
||||
### 报告模板示例
|
||||
|
||||
#### 独立样本 T 检验
|
||||
|
||||
```
|
||||
Group A (n = 48, M = 75.2, SD = 8.5) scored significantly higher than
|
||||
Group B (n = 52, M = 68.3, SD = 9.2), t(98) = 3.82, p < .001, d = 0.77,
|
||||
95% CI [0.36, 1.18], two-tailed. Assumptions of normality (Shapiro-Wilk:
|
||||
Group A W = 0.97, p = .18; Group B W = 0.96, p = .12) and homogeneity
|
||||
of variance (Levene's F(1, 98) = 1.23, p = .27) were satisfied.
|
||||
```
|
||||
|
||||
#### 单因素 ANOVA
|
||||
|
||||
```
|
||||
A one-way ANOVA revealed a significant main effect of treatment condition
|
||||
on test scores, F(2, 147) = 8.45, p < .001, η²_p = .10. Post hoc
|
||||
comparisons using Tukey's HSD indicated that Condition A (M = 78.2,
|
||||
SD = 7.3) scored significantly higher than Condition B (M = 71.5,
|
||||
SD = 8.1, p = .002, d = 0.87) and Condition C (M = 70.1, SD = 7.9,
|
||||
p < .001, d = 1.07). Conditions B and C did not differ significantly
|
||||
(p = .52, d = 0.18).
|
||||
```
|
||||
|
||||
#### 多元回归
|
||||
|
||||
```
|
||||
Multiple linear regression was conducted to predict exam scores from
|
||||
study hours, prior GPA, and attendance. The overall model was significant,
|
||||
F(3, 146) = 45.2, p < .001, R² = .48, adjusted R² = .47. Study hours
|
||||
(B = 1.80, SE = 0.31, β = .35, t = 5.78, p < .001, 95% CI [1.18, 2.42])
|
||||
and prior GPA (B = 8.52, SE = 1.95, β = .28, t = 4.37, p < .001,
|
||||
95% CI [4.66, 12.38]) were significant predictors, while attendance was
|
||||
not (B = 0.15, SE = 0.12, β = .08, t = 1.25, p = .21, 95% CI [-0.09, 0.39]).
|
||||
Multicollinearity was not a concern (all VIF < 1.5).
|
||||
```
|
||||
|
||||
#### 贝叶斯分析
|
||||
|
||||
```
|
||||
A Bayesian independent samples t-test was conducted using weakly
|
||||
informative priors (Normal(0, 1) for mean difference). The posterior
|
||||
distribution indicated that Group A scored higher than Group B
|
||||
(M_diff = 6.8, 95% credible interval [3.2, 10.4]). The Bayes Factor
|
||||
BF₁₀ = 45.3 provided very strong evidence for a difference between
|
||||
groups, with a 99.8% posterior probability that Group A's mean exceeded
|
||||
Group B's mean. Convergence diagnostics were satisfactory (all R̂ < 1.01,
|
||||
ESS > 1000).
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 贝叶斯统计
|
||||
|
||||
### 何时使用贝叶斯方法
|
||||
|
||||
以下情况考虑使用贝叶斯方法:
|
||||
- 你有可以纳入分析的先验信息
|
||||
- 你想对假设做出直接的概率陈述
|
||||
- 样本量较小或计划序贯收集数据
|
||||
- 你需要量化支持零假设的证据
|
||||
- 模型较为复杂(分层模型、缺失数据处理)
|
||||
|
||||
关于以下内容的完整指南,请参见 `references/bayesian_statistics.md`:
|
||||
- 贝叶斯定理与解释
|
||||
- 先验设定(信息性先验、弱信息先验、无信息先验)
|
||||
- 使用贝叶斯因子进行贝叶斯假设检验
|
||||
- 可信区间 vs 置信区间
|
||||
- 贝叶斯 t 检验、ANOVA、回归与分层模型
|
||||
- 模型收敛性检验与后验预测检验
|
||||
|
||||
### 关键优势
|
||||
|
||||
1. **直观解释**:「给定数据,参数有 95% 的概率落在此区间内」
|
||||
2. **支持零假设**:可以量化支持无效应存在的证据
|
||||
3. **灵活**:无 p-hacking 之虞,可以边收集数据边分析
|
||||
4. **不确定性量化**:完整的后验分布
|
||||
|
||||
---
|
||||
|
||||
## 资源
|
||||
|
||||
此技能包含全面的参考资料:
|
||||
|
||||
### 参考文档目录
|
||||
|
||||
- **test_selection_guide.md**:选择合适统计检验的决策树
|
||||
- **assumptions_and_diagnostics.md**:检查和处理假设违反的详细指南
|
||||
- **effect_sizes_and_power.md**:计算、解释和报告效应量;进行功效分析
|
||||
- **bayesian_statistics.md**:贝叶斯分析方法的完整指南
|
||||
- **reporting_standards.md**:APA 格式报告指南及示例
|
||||
|
||||
### 脚本目录
|
||||
|
||||
- **assumption_checks.py**:带可视化的自动假设检验
|
||||
- `comprehensive_assumption_check()`:完整工作流
|
||||
- `check_normality()`:正态性检验 + Q-Q 图
|
||||
- `check_homogeneity_of_variance()`:Levene 检验 + 箱线图
|
||||
- `check_linearity()`:回归线性检验
|
||||
- `detect_outliers()`:IQR 和 z 分数异常值检测
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **预注册分析方案**,尽可能区分验证性分析与探索性分析
|
||||
2. **始终检查假设**,然后再解释结果
|
||||
3. **报告效应量**,并附带置信区间
|
||||
4. **报告所有计划的分析**,包括不显著的结果
|
||||
5. **区分统计显著性与实际显著性**
|
||||
6. **在分析前后均进行数据可视化**
|
||||
7. **检查回归/ANOVA 的诊断结果**(残差图、VIF 等)
|
||||
8. **进行敏感度分析**,以评估结果的稳健性
|
||||
9. **共享数据和代码**,确保可复现性
|
||||
10. **保持透明**,说明假设违反、数据变换和分析决策
|
||||
|
||||
---
|
||||
|
||||
## 应避免的常见陷阱
|
||||
|
||||
1. **P-hacking(P 值操纵)**:不要尝试多种检验方式直到找到显著结果
|
||||
2. **HARKing(事后假设)**:不要将探索性发现呈现为验证性结论
|
||||
3. **忽略假设**:务必检查并报告违反情况
|
||||
4. **混淆显著性与重要性**:p < .05 ≠ 有意义的效应
|
||||
5. **不报告效应量**:这是解释结果的关键
|
||||
6. **选择性报告结果**:应报告所有计划的分析
|
||||
7. **误读 p 值**:p 值并非假设为真的概率
|
||||
8. **多重比较问题**:必要时进行族系误差率校正
|
||||
9. **忽略缺失数据**:理解缺失机制(MCAR、MAR、MNAR)
|
||||
10. **过度解读不显著的结果**:证据缺失 ≠ 缺失的证据
|
||||
|
||||
---
|
||||
|
||||
## 入门检查清单
|
||||
|
||||
开始统计分析时:
|
||||
|
||||
- [ ] 定义研究问题和假设
|
||||
- [ ] 确定合适的统计检验(使用 test_selection_guide.md)
|
||||
- [ ] 进行功效分析以确定样本量
|
||||
- [ ] 加载并检查数据
|
||||
- [ ] 检查缺失数据和异常值
|
||||
- [ ] 使用 assumption_checks.py 验证假设
|
||||
- [ ] 运行主要分析
|
||||
- [ ] 计算效应量并附带置信区间
|
||||
- [ ] 必要时进行事后检验(含校正)
|
||||
- [ ] 创建可视化图表
|
||||
- [ ] 按照 reporting_standards.md 撰写结果
|
||||
- [ ] 进行敏感度分析
|
||||
- [ ] 共享数据和代码
|
||||
|
||||
---
|
||||
|
||||
## 支持与进一步阅读
|
||||
|
||||
如有疑问,请参见:
|
||||
- **检验选择**:见 references/test_selection_guide.md
|
||||
- **假设检验**:见 references/assumptions_and_diagnostics.md
|
||||
- **效应量**:见 references/effect_sizes_and_power.md
|
||||
- **贝叶斯方法**:见 references/bayesian_statistics.md
|
||||
- **报告规范**:见 references/reporting_standards.md
|
||||
|
||||
**重要参考书**:
|
||||
- Cohen, J. (1988). *Statistical Power Analysis for the Behavioral Sciences*
|
||||
- Field, A. (2013). *Discovering Statistics Using IBM SPSS Statistics*
|
||||
- Gelman, A., & Hill, J. (2006). *Data Analysis Using Regression and Multilevel/Hierarchical Models*
|
||||
- Kruschke, J. K. (2014). *Doing Bayesian Data Analysis*
|
||||
|
||||
**在线资源**:
|
||||
- APA 格式指南:https://apastyle.apa.org/
|
||||
- 统计咨询:Cross Validated(stats.stackexchange.com)
|
||||
@@ -0,0 +1,369 @@
|
||||
# 统计假设与诊断流程
|
||||
|
||||
本文档为各类分析中统计假设的检查与验证提供全面指导。
|
||||
|
||||
## 通用原则
|
||||
|
||||
1. **在解释检验结果之前务必检查假设**
|
||||
2. **使用多种诊断方法**(可视化 + 形式检验)
|
||||
3. **考虑稳健性**:某些检验在特定条件下对违背假设具有稳健性
|
||||
4. **在分析报告中记录所有假设检查**
|
||||
5. **报告违背情况及采取的补救措施**
|
||||
|
||||
## 各类检验的常见假设
|
||||
|
||||
### 1. 观测值的独立性
|
||||
|
||||
**含义**:每个观测值相互独立;一个受试者的测量值不会影响另一个受试者的测量值。
|
||||
|
||||
**检查方法**:
|
||||
- 审查研究设计与数据收集流程
|
||||
- 对于时间序列:检查自相关性(ACF/PACF 图、Durbin-Watson 检验)
|
||||
- 对于聚类数据:考虑组内相关系数(ICC)
|
||||
|
||||
**违背时的处理方法**:
|
||||
- 对聚类/分层数据使用混合效应模型
|
||||
- 对时间依赖数据使用时间序列方法
|
||||
- 对相关数据使用广义估计方程(GEE)
|
||||
|
||||
**严重程度**:高——违背假设会严重膨胀第 I 类错误率
|
||||
|
||||
---
|
||||
|
||||
### 2. 正态性
|
||||
|
||||
**含义**:数据或残差服从正态(高斯)分布。
|
||||
|
||||
**何时要求**:
|
||||
- t 检验(小样本时要求;每组的 n > 30 时具有稳健性)
|
||||
- 方差分析(小样本时要求;每组的 n > 30 时具有稳健性)
|
||||
- 线性回归(对残差要求)
|
||||
- 某些相关检验(Pearson)
|
||||
|
||||
**检查方法**:
|
||||
|
||||
**可视化方法**(主要):
|
||||
- Q-Q(分位数-分位数)图:点应落在对角线附近
|
||||
- 叠加正态曲线的直方图
|
||||
- 核密度图
|
||||
|
||||
**形式检验**(次要):
|
||||
- Shapiro-Wilk 检验(推荐用于 n < 50)
|
||||
- Kolmogorov-Smirnov 检验
|
||||
- Anderson-Darling 检验
|
||||
|
||||
**Python 实现**:
|
||||
```python
|
||||
from scipy import stats
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
# Shapiro-Wilk 检验
|
||||
statistic, p_value = stats.shapiro(data)
|
||||
|
||||
# Q-Q 图
|
||||
stats.probplot(data, dist="norm", plot=plt)
|
||||
```
|
||||
|
||||
**解读指导**:
|
||||
- 当 n < 30 时:可视化方法与形式检验均重要
|
||||
- 当 30 ≤ n < 100 时:以可视化检查为主,形式检验为辅
|
||||
- 当 n ≥ 100 时:形式检验过于敏感;依赖可视化检查
|
||||
- 关注严重偏态、异常值或双峰分布
|
||||
|
||||
**违背时的处理方法**:
|
||||
- **轻度违背**(轻微偏态):若每组的 n > 30,可继续使用
|
||||
- **中度违背**:使用非参数替代方法(Mann-Whitney、Kruskal-Wallis、Wilcoxon)
|
||||
- **严重违背**:
|
||||
- 对数据进行变换(对数、平方根、Box-Cox)
|
||||
- 使用非参数方法
|
||||
- 使用稳健回归方法
|
||||
- 考虑自助法(Bootstrap)
|
||||
|
||||
**严重程度**:中——在样本量足够时,参数检验对轻度违背通常具有稳健性
|
||||
|
||||
---
|
||||
|
||||
### 3. 方差齐性
|
||||
|
||||
**含义**:各组之间的方差相等,或在整个预测变量范围内方差相等。
|
||||
|
||||
**何时要求**:
|
||||
- 独立样本 t 检验
|
||||
- 方差分析(ANOVA)
|
||||
- 线性回归(残差的方差恒定)
|
||||
|
||||
**检查方法**:
|
||||
|
||||
**可视化方法**(主要):
|
||||
- 按组分组的箱线图(用于 t 检验/方差分析)
|
||||
- 残差 vs. 拟合值图(用于回归)——应呈现随机散点分布
|
||||
- 尺度-位置图(标准化残差的平方根 vs. 拟合值)
|
||||
|
||||
**形式检验**(次要):
|
||||
- Levene 检验(对非正态性具有稳健性)
|
||||
- Bartlett 检验(对非正态性敏感,不推荐)
|
||||
- Brown-Forsythe 检验(基于中位数的 Levene 检验变体)
|
||||
- Breusch-Pagan 检验(用于回归)
|
||||
|
||||
**Python 实现**:
|
||||
```python
|
||||
from scipy import stats
|
||||
import pingouin as pg
|
||||
|
||||
# Levene 检验
|
||||
statistic, p_value = stats.levene(group1, group2, group3)
|
||||
|
||||
# 用于回归
|
||||
# Breusch-Pagan 检验
|
||||
from statsmodels.stats.diagnostic import het_breuschpagan
|
||||
_, p_value, _, _ = het_breuschpagan(residuals, exog)
|
||||
```
|
||||
|
||||
**解读指导**:
|
||||
- 方差比(最大值/最小值)< 2-3:通常可接受
|
||||
- 对于方差分析:若各组样本量相等,则检验具有稳健性
|
||||
- 对于回归:观察残差图中的漏斗形模式
|
||||
|
||||
**违背时的处理方法**:
|
||||
- **t 检验**:使用 Welch t 检验(不假设方差相等)
|
||||
- **方差分析**:使用 Welch 方差分析或 Brown-Forsythe 方差分析
|
||||
- **回归**:
|
||||
- 对因变量进行变换(对数、平方根)
|
||||
- 使用加权最小二乘法(WLS)
|
||||
- 使用稳健标准误(HC3)
|
||||
- 使用带有适当方差函数的广义线性模型(GLM)
|
||||
|
||||
**严重程度**:中——当样本量相等时,检验可具有稳健性
|
||||
|
||||
---
|
||||
|
||||
## 特定检验的假设
|
||||
|
||||
### T 检验
|
||||
|
||||
**假设**:
|
||||
1. 观测值的独立性
|
||||
2. 正态性(独立 t 检验对各组要求;配对 t 检验对差值要求)
|
||||
3. 方差齐性(仅独立 t 检验)
|
||||
|
||||
**诊断流程**:
|
||||
```python
|
||||
import scipy.stats as stats
|
||||
import pingouin as pg
|
||||
|
||||
# 检查每组的正态性
|
||||
stats.shapiro(group1)
|
||||
stats.shapiro(group2)
|
||||
|
||||
# 检查方差齐性
|
||||
stats.levene(group1, group2)
|
||||
|
||||
# 若假设被违背:
|
||||
# 选项 1:Welch t 检验(不等方差)
|
||||
pg.ttest(group1, group2, correction=False) # Welch 检验
|
||||
|
||||
# 选项 2:非参数替代方法
|
||||
pg.mwu(group1, group2) # Mann-Whitney U 检验
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 方差分析(ANOVA)
|
||||
|
||||
**假设**:
|
||||
1. 组内和组间观测值的独立性
|
||||
2. 每组内的正态性
|
||||
3. 各组间的方差齐性
|
||||
|
||||
**其他考虑**:
|
||||
- 对于重复测量方差分析:球形假设(Mauchly 检验)
|
||||
|
||||
**诊断流程**:
|
||||
```python
|
||||
import pingouin as pg
|
||||
|
||||
# 逐组检查正态性
|
||||
for group in df['group'].unique():
|
||||
data = df[df['group'] == group]['value']
|
||||
stats.shapiro(data)
|
||||
|
||||
# 检查方差齐性
|
||||
pg.homoscedasticity(df, dv='value', group='group')
|
||||
|
||||
# 对于重复测量:检查球形假设
|
||||
# 在 pingouin 的 rm_anova 中会自动检验
|
||||
```
|
||||
|
||||
**球形假设被违背时的处理方法**(重复测量):
|
||||
- Greenhouse-Geisser 校正(ε < 0.75)
|
||||
- Huynh-Feldt 校正(ε > 0.75)
|
||||
- 使用多变量方法(MANOVA)
|
||||
|
||||
---
|
||||
|
||||
### 线性回归
|
||||
|
||||
**假设**:
|
||||
1. **线性关系**:X 与 Y 之间的关系是线性的
|
||||
2. **独立性**:残差相互独立
|
||||
3. **方差齐性**:残差的方差恒定
|
||||
4. **正态性**:残差服从正态分布
|
||||
5. **无多重共线性**:预测变量之间不存在高度相关(多元回归)
|
||||
|
||||
**诊断流程**:
|
||||
|
||||
**1. 线性关系**:
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
import seaborn as sns
|
||||
|
||||
# Y 与每个 X 的散点图
|
||||
# 残差 vs. 拟合值(应随机散布)
|
||||
plt.scatter(fitted_values, residuals)
|
||||
plt.axhline(y=0, color='r', linestyle='--')
|
||||
```
|
||||
|
||||
**2. 独立性**:
|
||||
```python
|
||||
from statsmodels.stats.stattools import durbin_watson
|
||||
|
||||
# Durbin-Watson 检验(用于时间序列)
|
||||
dw_statistic = durbin_watson(residuals)
|
||||
# 值在 1.5-2.5 之间提示独立性成立
|
||||
```
|
||||
|
||||
**3. 方差齐性**:
|
||||
```python
|
||||
# Breusch-Pagan 检验
|
||||
from statsmodels.stats.diagnostic import het_breuschpagan
|
||||
_, p_value, _, _ = het_breuschpagan(residuals, exog)
|
||||
|
||||
# 可视化:尺度-位置图
|
||||
plt.scatter(fitted_values, np.sqrt(np.abs(std_residuals)))
|
||||
```
|
||||
|
||||
**4. 残差的正态性**:
|
||||
```python
|
||||
# 残差的 Q-Q 图
|
||||
stats.probplot(residuals, dist="norm", plot=plt)
|
||||
|
||||
# Shapiro-Wilk 检验
|
||||
stats.shapiro(residuals)
|
||||
```
|
||||
|
||||
**5. 多重共线性**:
|
||||
```python
|
||||
from statsmodels.stats.outliers_influence import variance_inflation_factor
|
||||
|
||||
# 计算每个预测变量的 VIF
|
||||
vif_data = pd.DataFrame()
|
||||
vif_data["feature"] = X.columns
|
||||
vif_data["VIF"] = [variance_inflation_factor(X.values, i) for i in range(len(X.columns))]
|
||||
|
||||
# VIF > 10 表示严重多重共线性
|
||||
# VIF > 5 表示中度多重共线性
|
||||
```
|
||||
|
||||
**违背时的处理方法**:
|
||||
- **非线性**:添加多项式项、使用 GAM 或变换变量
|
||||
- **异方差性**:变换 Y、使用 WLS、使用稳健标准误
|
||||
- **残差非正态**:变换 Y、使用稳健方法、检查异常值
|
||||
- **多重共线性**:移除相关预测变量、使用 PCA、岭回归
|
||||
|
||||
---
|
||||
|
||||
### 逻辑回归
|
||||
|
||||
**假设**:
|
||||
1. **独立性**:观测值相互独立
|
||||
2. **线性关系**:对数几率与连续预测变量之间存在线性关系
|
||||
3. **无完美多重共线性**:预测变量之间不存在完美相关
|
||||
4. **大样本量**:每个预测变量至少需要 10-20 个事件
|
||||
|
||||
**诊断流程**:
|
||||
|
||||
**1. Logit 线性关系**:
|
||||
```python
|
||||
# Box-Tidwell 检验:添加连续预测变量对数形式的交互项
|
||||
# 若交互项显著,则线性假设被违背
|
||||
```
|
||||
|
||||
**2. 多重共线性**:
|
||||
```python
|
||||
# 与线性回归相同,使用 VIF
|
||||
```
|
||||
|
||||
**3. 有影响力的观测值**:
|
||||
```python
|
||||
# Cook 距离、DFBetas、杠杆值
|
||||
from statsmodels.stats.outliers_influence import OLSInfluence
|
||||
|
||||
influence = OLSInfluence(model)
|
||||
cooks_d = influence.cooks_distance
|
||||
```
|
||||
|
||||
**4. 模型拟合优度**:
|
||||
```python
|
||||
# Hosmer-Lemeshow 检验
|
||||
# 伪 R 方
|
||||
# 分类指标(准确率、AUC-ROC)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 异常值检测
|
||||
|
||||
**方法**:
|
||||
1. **可视化**:箱线图、散点图
|
||||
2. **统计方法**:
|
||||
- Z 分数:|z| > 3 提示为异常值
|
||||
- IQR 法:值 < Q1 - 1.5×IQR 或 > Q3 + 1.5×IQR
|
||||
- 基于中位数绝对偏差的修正 Z 分数(对异常值具有稳健性)
|
||||
|
||||
**用于回归**:
|
||||
- **杠杆值**:高杠杆点(hat 值)
|
||||
- **影响力**:Cook 距离 > 4/n 提示为有影响力点
|
||||
- **异常值**:学生化残差 > ±3
|
||||
|
||||
**处理方法**:
|
||||
1. 检查数据录入错误
|
||||
2. 判断异常值是否为有效观测值
|
||||
3. 报告敏感性分析(包含和不包含异常值的结果)
|
||||
4. 若异常值为合法数据,则使用稳健方法
|
||||
|
||||
---
|
||||
|
||||
## 样本量考虑
|
||||
|
||||
### 最小样本量(经验法则)
|
||||
|
||||
- **t 检验**:每组 n ≥ 30 以保证对非正态性的稳健性
|
||||
- **方差分析**:每组 n ≥ 30
|
||||
- **相关性**:n ≥ 30 以保证足够的统计功效
|
||||
- **简单回归**:n ≥ 50
|
||||
- **多元回归**:每个预测变量 n ≥ 10-20(至少 10 + k 个预测变量)
|
||||
- **逻辑回归**:每个预测变量至少需要 10-20 个事件
|
||||
|
||||
### 小样本注意事项
|
||||
|
||||
对于小样本:
|
||||
- 假设检查变得更为关键
|
||||
- 尽可能使用精确检验(Fisher 精确检验、精确逻辑回归)
|
||||
- 考虑非参数替代方法
|
||||
- 使用置换检验或自助法(Bootstrap)
|
||||
- 在解释结果时保持审慎
|
||||
|
||||
---
|
||||
|
||||
## 报告假设检查
|
||||
|
||||
在报告分析结果时,应包括:
|
||||
|
||||
1. **已检查假设的声明**:列出所有检验过的假设
|
||||
2. **所使用的方法**:描述采用的可视化方法和形式检验
|
||||
3. **诊断检验的结果**:报告检验统计量和 p 值
|
||||
4. **评估结论**:说明假设是否得到满足或被违背
|
||||
5. **采取的措施**:若假设被违背,描述补救措施(变换、替代检验、稳健方法)
|
||||
|
||||
**报告示例**:
|
||||
> "使用 Shapiro-Wilk 检验和 Q-Q 图评估正态性。A 组(W = 0.97,p = 0.18)和 B 组(W = 0.96,p = 0.12)的数据均未显示显著偏离正态性。使用 Levene 检验评估方差齐性,结果不显著(F(1, 58) = 1.23,p = 0.27),表明各组方差相等。因此,独立样本 t 检验的假设得到满足。"
|
||||
@@ -0,0 +1,658 @@
|
||||
---
|
||||
name: bayesian-statistical-analysis
|
||||
description: 贝叶斯统计分析指南——涵盖贝叶斯 vs 频率学派哲学、贝叶斯定理、先验分布、贝叶斯假设检验、贝叶斯估计、常见贝叶斯分析、层次模型、模型比较、模型检查及报告规范
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
|
||||
# 贝叶斯统计分析
|
||||
|
||||
本文档为进行和解读贝叶斯统计分析提供指导,贝叶斯统计为频率学派(经典)统计提供了一种替代框架。
|
||||
|
||||
## 贝叶斯 vs. 频率学派哲学
|
||||
|
||||
### 根本差异
|
||||
|
||||
| 方面 | 频率学派 | 贝叶斯学派 |
|
||||
|--------|-------------|----------|
|
||||
| **概率解释** | 事件的长期发生频率 | 信念/不确定性的程度 |
|
||||
| **参数** | 固定但未知 | 具有分布的随机变量 |
|
||||
| **推断** | 基于抽样分布 | 基于后验分布 |
|
||||
| **主要输出** | p 值、置信区间 | 后验概率、可信区间 |
|
||||
| **先验信息** | 不正式纳入 | 通过先验显式纳入 |
|
||||
| **假设检验** | 拒绝/不拒绝原假设 | 给定数据下假设的概率 |
|
||||
| **样本量** | 通常需要最小样本量 | 可处理任意样本量 |
|
||||
| **解释** | 间接(给定 H₀ 下数据的概率) | 直接(给定数据下假设的概率) |
|
||||
|
||||
### 关键问题差异
|
||||
|
||||
**频率学派**:「如果原假设为真,观察到如此极端或更极端数据的概率是多少?」
|
||||
|
||||
**贝叶斯学派**:「给定观测数据,假设为真的概率是多少?」
|
||||
|
||||
贝叶斯问题更加直观,直接回答了研究者想要知道的问题。
|
||||
|
||||
---
|
||||
|
||||
## 贝叶斯定理
|
||||
|
||||
**公式**:
|
||||
```
|
||||
P(θ|D) = P(D|θ) × P(θ) / P(D)
|
||||
```
|
||||
|
||||
**用文字表述**:
|
||||
```
|
||||
后验 = 似然 × 先验 / 证据
|
||||
```
|
||||
|
||||
其中:
|
||||
- **θ(theta)**:感兴趣的参数(例如均值差、相关系数)
|
||||
- **D**:观测数据
|
||||
- **P(θ|D)**: 后验分布(看到数据后对 θ 的信念)
|
||||
- **P(D|θ)**: 似然(给定 θ 下数据的概率)
|
||||
- **P(θ)**: 先验分布(看到数据前对 θ 的信念)
|
||||
- **P(D)**: 边际似然/证据(归一化常数)
|
||||
|
||||
---
|
||||
|
||||
## 先验分布
|
||||
|
||||
### 先验的类型
|
||||
|
||||
#### 1. 信息性先验
|
||||
|
||||
**何时使用**:当你拥有大量先验知识时,来源包括:
|
||||
- 先前的研究
|
||||
- 专家知识
|
||||
- 理论
|
||||
- 预试验数据
|
||||
|
||||
**示例**:元分析显示效应量 d ≈ 0.40,SD = 0.15
|
||||
- 先验:Normal(0.40, 0.15)
|
||||
|
||||
**优点**:
|
||||
- 纳入已有知识
|
||||
- 更高效(所需样本量更小)
|
||||
- 可在小样本情况下稳定估计
|
||||
|
||||
**缺点**:
|
||||
- 具有主观性(但主观性也可成为优势)
|
||||
- 必须被合理证明并保持透明
|
||||
- 若强先验与数据冲突,可能引发争议
|
||||
|
||||
---
|
||||
|
||||
#### 2. 弱信息性先验
|
||||
|
||||
**何时使用**:大多数应用场景的默认选择
|
||||
|
||||
**特征**:
|
||||
- 正则化估计(防止极端值)
|
||||
- 在中等样本量下对后验影响极小
|
||||
- 防止计算问题
|
||||
|
||||
**示例先验**:
|
||||
- 效应量:Normal(0, 1) 或 Cauchy(0, 0.707)
|
||||
- 方差:Half-Cauchy(0, 1)
|
||||
- 相关系数:Uniform(-1, 1) 或 Beta(2, 2)
|
||||
|
||||
**优点**:
|
||||
- 在客观性与正则化之间取得平衡
|
||||
- 计算稳定
|
||||
- 广泛可接受
|
||||
|
||||
---
|
||||
|
||||
#### 3. 无信息先验(平坦/均匀先验)
|
||||
|
||||
**何时使用**:试图保持「客观」时
|
||||
|
||||
**示例**:Uniform(-∞, ∞) 对任意值
|
||||
|
||||
**⚠️ 注意**:
|
||||
- 可能导致非正常后验
|
||||
- 可能产生不合理的结果
|
||||
- 并非真正的「无信息」(仍然做了假设)
|
||||
- 在现代贝叶斯实践中通常不推荐
|
||||
|
||||
**更好的替代方案**:使用弱信息性先验
|
||||
|
||||
---
|
||||
|
||||
### 先验敏感性分析
|
||||
|
||||
**始终进行**:检验结果如何随不同先验变化
|
||||
|
||||
**流程**:
|
||||
1. 用默认/计划先验拟合模型
|
||||
2. 用更分散的先验拟合模型
|
||||
3. 用更集中的先验拟合模型
|
||||
4. 比较后验分布
|
||||
|
||||
**报告**:
|
||||
- 若结果相似:证据稳健
|
||||
- 若结果差异显著:数据不足以压倒先验
|
||||
|
||||
**Python 示例**:
|
||||
```python
|
||||
import pymc as pm
|
||||
|
||||
prior_specs = [
|
||||
('weakly_informative', 0, 1),
|
||||
('diffuse', 0, 10),
|
||||
('informative', 0.5, 0.3),
|
||||
]
|
||||
|
||||
results = {}
|
||||
for name, mu_prior, sigma_prior in prior_specs:
|
||||
with pm.Model() as model:
|
||||
effect = pm.Normal('effect', mu=mu_prior, sigma=sigma_prior)
|
||||
# ... 似然函数和观测数据
|
||||
trace = pm.sample(2000, tune=1000, return_inferencedata=True)
|
||||
results[name] = trace
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 贝叶斯假设检验
|
||||
|
||||
### 贝叶斯因子(BF)
|
||||
|
||||
**定义**:两个竞争假设的证据比率
|
||||
|
||||
**公式**:
|
||||
```
|
||||
BF₁₀ = P(D|H₁) / P(D|H₀)
|
||||
```
|
||||
|
||||
**解释**:
|
||||
|
||||
| BF₁₀ | 证据强度 |
|
||||
|------|----------|
|
||||
| >100 | 支持 H₁ 的决定性证据 |
|
||||
| 30-100 | 支持 H₁ 的极强证据 |
|
||||
| 10-30 | 支持 H₁ 的强证据 |
|
||||
| 3-10 | 支持 H₁ 的中等证据 |
|
||||
| 1-3 | 支持 H₁ 的微弱证据 |
|
||||
| 1 | 无证据 |
|
||||
| 1/3-1 | 支持 H₀ 的微弱证据 |
|
||||
| 1/10-1/3 | 支持 H₀ 的中等证据 |
|
||||
| 1/30-1/10 | 支持 H₀ 的强证据 |
|
||||
| 1/100-1/30 | 支持 H₀ 的极强证据 |
|
||||
| <1/100 | 支持 H₀ 的决定性证据 |
|
||||
|
||||
**相对于 p 值的优势**:
|
||||
1. 可提供支持原假设的证据
|
||||
2. 不依赖于抽样意图(无「偷看」问题)
|
||||
3. 直接量化证据
|
||||
4. 可随更多数据更新
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
# Pingouin 0.5+:用于独立双边 t 检验的 BF10;单边 BF 已被移除。
|
||||
import pingouin as pg
|
||||
|
||||
result = pg.ttest(group1, group2, correction=False)
|
||||
bf10 = result['BF10'].values[0]
|
||||
|
||||
# 严格贝叶斯因子:BayesFactor(R)、JASP 或 PyMC 模型比较(参见 pymc 技能)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 实际等价区间(ROPE)
|
||||
|
||||
**目的**:定义可忽略效应量的范围
|
||||
|
||||
**流程**:
|
||||
1. 定义 ROPE(例如 d ∈ [-0.1, 0.1] 为可忽略效应)
|
||||
2. 计算后验落在 ROPE 内的百分比
|
||||
3. 做出判断:
|
||||
- >95% 在 ROPE 内:接受实际等价
|
||||
- >95% 在 ROPE 外:拒绝等价
|
||||
- 其他情况:无定论
|
||||
|
||||
**优势**:直接检验实际显著性
|
||||
|
||||
**Python 示例**:
|
||||
```python
|
||||
# 定义 ROPE
|
||||
rope_lower, rope_upper = -0.1, 0.1
|
||||
|
||||
# 计算后验在 ROPE 内的百分比
|
||||
in_rope = np.mean((posterior_samples > rope_lower) &
|
||||
(posterior_samples < rope_upper))
|
||||
|
||||
print(f"{in_rope*100:.1f}% 的后验在 ROPE 内")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 贝叶斯估计
|
||||
|
||||
### 可信区间
|
||||
|
||||
**定义**:以 X% 的概率包含参数的区间
|
||||
|
||||
**95% 可信区间的解释**:
|
||||
> 「真实参数有 95% 的概率落在此区间内。」
|
||||
|
||||
**这正是人们以为置信区间所表示的含义**(但在频率学派框架中并非如此)
|
||||
|
||||
**类型**:
|
||||
|
||||
#### 等尾区间(ETI)
|
||||
- 第 2.5 至第 97.5 百分位
|
||||
- 计算简单
|
||||
- 对于偏态分布可能不包含众数
|
||||
|
||||
#### 最高密度区间(HDI)
|
||||
- 包含分布 95% 的最窄区间
|
||||
- 始终包含众数
|
||||
- 更适合偏态分布
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
import arviz as az
|
||||
|
||||
# 等尾区间
|
||||
eti = np.percentile(posterior_samples, [2.5, 97.5])
|
||||
|
||||
# HDI
|
||||
hdi = az.hdi(posterior_samples, hdi_prob=0.95)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 后验分布
|
||||
|
||||
**解读后验分布**:
|
||||
|
||||
1. **集中趋势**:
|
||||
- 均值:后验的平均值
|
||||
- 中位数:第 50 百分位
|
||||
- 众数:最可能的值(MAP——最大后验估计)
|
||||
|
||||
2. **不确定性**:
|
||||
- 标准差:后验的离散程度
|
||||
- 可信区间:量化不确定性
|
||||
|
||||
3. **形状**:
|
||||
- 对称:近似正态
|
||||
- 偏态:非对称不确定性
|
||||
- 多峰:存在多个合理值
|
||||
|
||||
**可视化**:
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
import arviz as az
|
||||
|
||||
# 带 HDI 的后验图
|
||||
az.plot_posterior(trace, hdi_prob=0.95)
|
||||
|
||||
# 迹线图(检查收敛性)
|
||||
az.plot_trace(trace)
|
||||
|
||||
# 森林图(多个参数)
|
||||
az.plot_forest(trace)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见贝叶斯分析
|
||||
|
||||
### 贝叶斯 T 检验
|
||||
|
||||
**目的**:比较两组(t 检验的贝叶斯替代方法)
|
||||
|
||||
**输出**:
|
||||
1. 均值差的后验分布
|
||||
2. 95% 可信区间
|
||||
3. 贝叶斯因子(BF₁₀)
|
||||
4. 方向性假设的概率(例如 P(μ₁ > μ₂))
|
||||
|
||||
**Python 实现**:
|
||||
```python
|
||||
import pymc as pm
|
||||
import arviz as az
|
||||
|
||||
# 贝叶斯独立样本 t 检验
|
||||
with pm.Model() as model:
|
||||
# 组均值的先验
|
||||
mu1 = pm.Normal('mu1', mu=0, sigma=10)
|
||||
mu2 = pm.Normal('mu2', mu=0, sigma=10)
|
||||
|
||||
# 合并标准差的前沿
|
||||
sigma = pm.HalfNormal('sigma', sigma=10)
|
||||
|
||||
# 似然函数
|
||||
y1 = pm.Normal('y1', mu=mu1, sigma=sigma, observed=group1)
|
||||
y2 = pm.Normal('y2', mu=mu2, sigma=sigma, observed=group2)
|
||||
|
||||
# 衍生量:均值差
|
||||
diff = pm.Deterministic('diff', mu1 - mu2)
|
||||
|
||||
# 后验抽样
|
||||
trace = pm.sample(2000, tune=1000, return_inferencedata=True)
|
||||
|
||||
# 分析结果
|
||||
print(az.summary(trace, var_names=['mu1', 'mu2', 'diff']))
|
||||
|
||||
# group1 > group2 的概率
|
||||
prob_greater = np.mean(trace.posterior['diff'].values > 0)
|
||||
print(f"P(μ₁ > μ₂) = {prob_greater:.3f}")
|
||||
|
||||
# 绘制后验图
|
||||
az.plot_posterior(trace, var_names=['diff'], ref_val=0)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 贝叶斯方差分析(ANOVA)
|
||||
|
||||
**目的**:比较三个或更多组
|
||||
|
||||
**模型**:
|
||||
```python
|
||||
import pymc as pm
|
||||
|
||||
with pm.Model() as anova_model:
|
||||
# 超先验
|
||||
mu_global = pm.Normal('mu_global', mu=0, sigma=10)
|
||||
sigma_between = pm.HalfNormal('sigma_between', sigma=5)
|
||||
sigma_within = pm.HalfNormal('sigma_within', sigma=5)
|
||||
|
||||
# 组均值(层次结构)
|
||||
group_means = pm.Normal('group_means',
|
||||
mu=mu_global,
|
||||
sigma=sigma_between,
|
||||
shape=n_groups)
|
||||
|
||||
# 似然函数
|
||||
y = pm.Normal('y',
|
||||
mu=group_means[group_idx],
|
||||
sigma=sigma_within,
|
||||
observed=data)
|
||||
|
||||
trace = pm.sample(2000, tune=1000, return_inferencedata=True)
|
||||
|
||||
# 后验对比
|
||||
contrast_1_2 = trace.posterior['group_means'][:,:,0] - trace.posterior['group_means'][:,:,1]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 贝叶斯相关分析
|
||||
|
||||
**目的**:估计两个变量之间的相关系数
|
||||
|
||||
**优势**:提供相关系数值的分布
|
||||
|
||||
**Python 实现**:
|
||||
```python
|
||||
import pymc as pm
|
||||
|
||||
with pm.Model() as corr_model:
|
||||
# 相关系数的先验
|
||||
rho = pm.Uniform('rho', lower=-1, upper=1)
|
||||
|
||||
# 转换为协方差矩阵
|
||||
cov_matrix = pm.math.stack([[1, rho],
|
||||
[rho, 1]])
|
||||
|
||||
# 似然函数(二元正态分布)
|
||||
obs = pm.MvNormal('obs',
|
||||
mu=[0, 0],
|
||||
cov=cov_matrix,
|
||||
observed=np.column_stack([x, y]))
|
||||
|
||||
trace = pm.sample(2000, tune=1000, return_inferencedata=True)
|
||||
|
||||
# 相关系数汇总
|
||||
print(az.summary(trace, var_names=['rho']))
|
||||
|
||||
# 相关系数为正的概率
|
||||
prob_positive = np.mean(trace.posterior['rho'].values > 0)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 贝叶斯线性回归
|
||||
|
||||
**目的**:建模预测变量与结果变量之间的关系
|
||||
|
||||
**优势**:
|
||||
- 所有参数均带有不确定性
|
||||
- 自然正则化(通过先验)
|
||||
- 可纳入先验知识
|
||||
- 预测的可信区间
|
||||
|
||||
**Python 实现**:
|
||||
```python
|
||||
import pymc as pm
|
||||
|
||||
with pm.Model() as regression_model:
|
||||
# 系数的先验
|
||||
alpha = pm.Normal('alpha', mu=0, sigma=10) # 截距
|
||||
beta = pm.Normal('beta', mu=0, sigma=10, shape=n_predictors)
|
||||
sigma = pm.HalfNormal('sigma', sigma=10)
|
||||
|
||||
# 期望值
|
||||
mu = alpha + pm.math.dot(X, beta)
|
||||
|
||||
# 似然函数
|
||||
y_obs = pm.Normal('y_obs', mu=mu, sigma=sigma, observed=y)
|
||||
|
||||
trace = pm.sample(2000, tune=1000, return_inferencedata=True)
|
||||
|
||||
# 后验预测检验
|
||||
with regression_model:
|
||||
ppc = pm.sample_posterior_predictive(trace)
|
||||
|
||||
az.plot_ppc(ppc)
|
||||
|
||||
# 带不确定性的预测
|
||||
with regression_model:
|
||||
pm.set_data({'X': X_new})
|
||||
posterior_pred = pm.sample_posterior_predictive(trace)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 层次(多水平)模型
|
||||
|
||||
**何时使用**:
|
||||
- 嵌套/聚类数据(学生嵌套于学校)
|
||||
- 重复测量
|
||||
- 元分析
|
||||
- 跨组的变异性效应
|
||||
|
||||
**关键概念**:部分池化
|
||||
- 完全池化:忽略组别(有偏)
|
||||
- 无池化:分别分析各组(高方差)
|
||||
- 部分池化:跨组借用信息(贝叶斯)
|
||||
|
||||
**示例:变截距模型**:
|
||||
```python
|
||||
with pm.Model() as hierarchical_model:
|
||||
# 超先验
|
||||
mu_global = pm.Normal('mu_global', mu=0, sigma=10)
|
||||
sigma_between = pm.HalfNormal('sigma_between', sigma=5)
|
||||
sigma_within = pm.HalfNormal('sigma_within', sigma=5)
|
||||
|
||||
# 组级截距
|
||||
alpha = pm.Normal('alpha',
|
||||
mu=mu_global,
|
||||
sigma=sigma_between,
|
||||
shape=n_groups)
|
||||
|
||||
# 似然函数
|
||||
y_obs = pm.Normal('y_obs',
|
||||
mu=alpha[group_idx],
|
||||
sigma=sigma_within,
|
||||
observed=y)
|
||||
|
||||
trace = pm.sample()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 模型比较
|
||||
|
||||
### 方法
|
||||
|
||||
#### 1. 贝叶斯因子
|
||||
- 直接比较模型证据
|
||||
- 对先验设定敏感
|
||||
- 计算量可能较大
|
||||
|
||||
#### 2. 信息准则
|
||||
|
||||
**WAIC(广泛适用信息准则)**:
|
||||
- AIC 的贝叶斯类比
|
||||
- 越小越好
|
||||
- 考虑了参数的有效数量
|
||||
|
||||
**LOO(留一法交叉验证)**:
|
||||
- 估计样本外预测误差
|
||||
- 越小越好
|
||||
- 比 WAIC 更稳健
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
import arviz as az
|
||||
|
||||
# 计算 WAIC 和 LOO
|
||||
waic = az.waic(trace)
|
||||
loo = az.loo(trace)
|
||||
|
||||
print(f"WAIC: {waic.elpd_waic:.2f}")
|
||||
print(f"LOO: {loo.elpd_loo:.2f}")
|
||||
|
||||
# 比较多个模型
|
||||
comparison = az.compare({
|
||||
'model1': trace1,
|
||||
'model2': trace2,
|
||||
'model3': trace3
|
||||
})
|
||||
print(comparison)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 检查贝叶斯模型
|
||||
|
||||
### 1. 收敛诊断
|
||||
|
||||
**R-hat(Gelman-Rubin 统计量)**:
|
||||
- 比较链内方差与链间方差
|
||||
- 接近 1.0 的值表明收敛
|
||||
- R-hat < 1.01:良好
|
||||
- R-hat > 1.05:收敛不佳
|
||||
|
||||
**有效样本量(ESS)**:
|
||||
- 独立样本的数量
|
||||
- 越高越好
|
||||
- 建议每链 ESS > 400
|
||||
|
||||
**迹线图**:
|
||||
- 应呈现「毛虫状」
|
||||
- 无趋势,无卡顿链
|
||||
|
||||
**Python 检查**:
|
||||
```python
|
||||
# 带诊断的自动汇总
|
||||
print(az.summary(trace, var_names=['parameter']))
|
||||
|
||||
# 可视化诊断
|
||||
az.plot_trace(trace)
|
||||
az.plot_rank(trace) # 秩图
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 后验预测检验
|
||||
|
||||
**目的**:模型生成的数据是否与观测数据相似?
|
||||
|
||||
**流程**:
|
||||
1. 从后验生成预测
|
||||
2. 与实际数据比较
|
||||
3. 寻找系统性偏差
|
||||
|
||||
**Python 实现**:
|
||||
```python
|
||||
with model:
|
||||
ppc = pm.sample_posterior_predictive(trace)
|
||||
|
||||
# 可视化检验
|
||||
az.plot_ppc(ppc, num_pp_samples=100)
|
||||
|
||||
# 定量检验
|
||||
obs_mean = np.mean(observed_data)
|
||||
pred_means = [np.mean(sample) for sample in ppc.posterior_predictive['y_obs']]
|
||||
p_value = np.mean(pred_means >= obs_mean) # 贝叶斯 p 值
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 报告贝叶斯结果
|
||||
|
||||
### T 检验报告示例
|
||||
|
||||
> 「采用贝叶斯独立样本 t 检验比较 A 组和 B 组。使用了弱信息性先验:均值差采用 Normal(0, 1),合并标准差采用 Half-Cauchy(0, 1)。均值差的后验分布均值为 5.2(95% CI [2.3, 8.1]),表明 A 组得分高于 B 组。贝叶斯因子 BF₁₀ = 23.5 为组间差异提供了强证据,A 组均值超过 B 组均值的概率为 99.7%。」
|
||||
|
||||
### 回归报告示例
|
||||
|
||||
> 「采用弱信息性先验(系数使用 Normal(0, 10),残差标准差使用 Half-Cauchy(0, 5))拟合了贝叶斯线性回归模型。模型解释了可观的方差(R² = 0.47,95% CI [0.38, 0.55])。学习时长(β = 0.52,95% CI [0.38, 0.66])和先前的 GPA(β = 0.31,95% CI [0.17, 0.45])是可信的预测变量(95% CI 排除零)。后验预测检验显示模型拟合良好。收敛诊断令人满意(所有 R-hat < 1.01,ESS > 1000)。」
|
||||
|
||||
---
|
||||
|
||||
## 优势与局限
|
||||
|
||||
### 优势
|
||||
|
||||
1. **直观的解释**:关于参数的直接概率陈述
|
||||
2. **纳入先验知识**:利用所有可用信息
|
||||
3. **灵活**:轻松处理复杂模型
|
||||
4. **无 p 值操纵**:可随时查看数据
|
||||
5. **量化不确定性**:完整的后验分布
|
||||
6. **小样本**:可处理任意样本量
|
||||
|
||||
### 局限
|
||||
|
||||
1. **计算量大**:需要 MCMC 抽样(可能较慢)
|
||||
2. **先验设定**:需要思考和论证
|
||||
3. **复杂性**:学习曲线较陡
|
||||
4. **软件工具**:相比频率学派方法工具较少
|
||||
5. **沟通成本**:可能需要向审稿人/读者做解释
|
||||
|
||||
---
|
||||
|
||||
## 关键 Python 包
|
||||
|
||||
使用 uv 安装(参见 SKILL.md)。ArviZ 0.23+ 需要 Python 3.12+。
|
||||
|
||||
- **PyMC** (`pymc>=5`):完整的贝叶斯建模框架
|
||||
- **ArviZ** (`arviz>=0.17`):可视化与诊断工具([文档](https://python.arviz.org))
|
||||
- **Bambi**:回归模型的高级接口(`uv pip install bambi`)
|
||||
- **PyStan**:Stan 的 Python 接口
|
||||
- **TensorFlow Probability**:使用 TensorFlow 进行贝叶斯推断
|
||||
|
||||
---
|
||||
|
||||
## 何时使用贝叶斯方法
|
||||
|
||||
**使用贝叶斯方法当**:
|
||||
- 你有先验信息需要纳入
|
||||
- 你想要直接的概率陈述
|
||||
- 样本量较小
|
||||
- 模型较复杂(层次模型、缺失数据等)
|
||||
- 你希望随着数据到来不断更新分析
|
||||
|
||||
**频率学派方法可能足够当**:
|
||||
- 标准分析且样本量大
|
||||
- 无先验信息
|
||||
- 计算资源有限
|
||||
- 审稿人不熟悉贝叶斯方法
|
||||
@@ -0,0 +1,578 @@
|
||||
# 效应量与统计检验力分析
|
||||
|
||||
本文档提供了关于效应量计算、解读和报告,以及为研究规划进行统计检验力分析的指导。
|
||||
|
||||
## 效应量的重要性
|
||||
|
||||
1. **统计显著性 ≠ 实际显著性**:p 值只能说明效应是否存在,不能说明效应有多大
|
||||
2. **依赖于样本量**:大样本下,微小效应也会变得"显著"
|
||||
3. **可解释性**:效应量提供了量级和实际重要性
|
||||
4. **元分析**:效应量使得跨研究合并结果成为可能
|
||||
5. **统计检验力分析**:样本量确定所必需
|
||||
|
||||
**黄金法则**:始终在报告 p 值的同时报告效应量。
|
||||
|
||||
---
|
||||
|
||||
## 按分析类型分类的效应量
|
||||
|
||||
### T 检验与均值差异
|
||||
|
||||
#### Cohen's d(标准化均值差)
|
||||
|
||||
**公式**:
|
||||
- 独立组:d = (M₁ - M₂) / SD_pooled
|
||||
- 配对组:d = M_diff / SD_diff
|
||||
|
||||
**解释标准**(Cohen, 1988):
|
||||
- 小:|d| = 0.20
|
||||
- 中:|d| = 0.50
|
||||
- 大:|d| = 0.80
|
||||
|
||||
**依赖上下文的解释**:
|
||||
- 教育领域:d = 0.40 是成功干预的典型值
|
||||
- 心理学领域:d = 0.40 被认为有意义
|
||||
- 医学领域:小的效应量也可能具有临床重要性
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
import pingouin as pg
|
||||
import numpy as np
|
||||
|
||||
# 含效应量的独立样本 t 检验
|
||||
result = pg.ttest(group1, group2, correction=False)
|
||||
cohens_d = result['cohen_d'].values[0]
|
||||
|
||||
# 手动计算
|
||||
mean_diff = np.mean(group1) - np.mean(group2)
|
||||
pooled_std = np.sqrt((np.var(group1, ddof=1) + np.var(group2, ddof=1)) / 2)
|
||||
cohens_d = mean_diff / pooled_std
|
||||
|
||||
# 配对 t 检验
|
||||
result = pg.ttest(pre, post, paired=True)
|
||||
cohens_d = result['cohen_d'].values[0]
|
||||
```
|
||||
|
||||
**d 的置信区间**:
|
||||
```python
|
||||
from pingouin import compute_effsize_from_t
|
||||
|
||||
d, ci = compute_effsize_from_t(t_statistic, nx=n1, ny=n2, eftype='cohen')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Hedges' g(偏差校正 d)
|
||||
|
||||
**为何使用**:Cohen's d 在小样本(n < 20)下存在轻微向上偏差
|
||||
|
||||
**公式**:g = d × 校正因子,其中校正因子 = 1 - 3/(4df - 1)
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
result = pg.ttest(group1, group2, correction=False)
|
||||
hedges_g = result['hedges'].values[0]
|
||||
```
|
||||
|
||||
**何时使用 Hedges' g**:
|
||||
- 样本量较小(每组 n < 20)
|
||||
- 进行元分析(元分析中的标准做法)
|
||||
|
||||
---
|
||||
|
||||
#### Glass's Δ(Delta)
|
||||
|
||||
**何时使用**:当某一组为已知变异性的对照组时
|
||||
|
||||
**公式**:Δ = (M₁ - M₂) / SD_control
|
||||
|
||||
**使用场景**:
|
||||
- 临床试验(使用对照组 SD)
|
||||
- 当处理影响变异性时
|
||||
|
||||
---
|
||||
|
||||
### 方差分析
|
||||
|
||||
#### Eta-squared(η²)
|
||||
|
||||
**衡量内容**:因子解释的总方差比例
|
||||
|
||||
**公式**:η² = SS_effect / SS_total
|
||||
|
||||
**解释标准**:
|
||||
- 小:η² = 0.01(解释 1% 的方差)
|
||||
- 中:η² = 0.06(解释 6% 的方差)
|
||||
- 大:η² = 0.14(解释 14% 的方差)
|
||||
|
||||
**局限性**:多因子时存在偏差(总和 > 1.0)
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
import pingouin as pg
|
||||
|
||||
# 单因素方差分析
|
||||
aov = pg.anova(dv='value', between='group', data=df)
|
||||
eta_squared = aov['SS'][0] / aov['SS'].sum()
|
||||
|
||||
# 或直接使用 pingouin
|
||||
aov = pg.anova(dv='value', between='group', data=df, detailed=True)
|
||||
eta_squared = aov['np2'][0] # 注意:pingouin 报告的是偏 eta-squared
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 偏 Eta-squared(η²_p)
|
||||
|
||||
**衡量内容**:排除其他因子后,由该因子解释的方差比例
|
||||
|
||||
**公式**:η²_p = SS_effect / (SS_effect + SS_error)
|
||||
|
||||
**解释标准**:与 η² 相同
|
||||
|
||||
**何时使用**:多因子方差分析(因子设计中的标准做法)
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
aov = pg.anova(dv='value', between=['factor1', 'factor2'], data=df)
|
||||
# pingouin 默认报告偏 eta-squared
|
||||
partial_eta_sq = aov['np2']
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Omega-squared(ω²)
|
||||
|
||||
**衡量内容**:对总体解释方差的更无偏估计
|
||||
|
||||
**为何使用**:η² 会高估效应量;ω² 提供更好的总体估计
|
||||
|
||||
**公式**:ω² = (SS_effect - df_effect × MS_error) / (SS_total + MS_error)
|
||||
|
||||
**解释标准**:与 η² 相同,但通常值更小
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
def omega_squared(aov_table):
|
||||
ss_effect = aov_table.loc[0, 'SS']
|
||||
ss_total = aov_table['SS'].sum()
|
||||
ms_error = aov_table.loc[aov_table.index[-1], 'MS'] # 残差 MS
|
||||
df_effect = aov_table.loc[0, 'DF']
|
||||
|
||||
omega_sq = (ss_effect - df_effect * ms_error) / (ss_total + ms_error)
|
||||
return omega_sq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Cohen's f
|
||||
|
||||
**衡量内容**:方差分析的效应量(类似于 Cohen's d)
|
||||
|
||||
**公式**:f = √(η² / (1 - η²))
|
||||
|
||||
**解释标准**:
|
||||
- 小:f = 0.10
|
||||
- 中:f = 0.25
|
||||
- 大:f = 0.40
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
eta_squared = 0.06 # 来自方差分析
|
||||
cohens_f = np.sqrt(eta_squared / (1 - eta_squared))
|
||||
```
|
||||
|
||||
**在统计检验力分析中使用**:ANOVA 统计检验力计算所必需
|
||||
|
||||
---
|
||||
|
||||
### 相关分析
|
||||
|
||||
#### Pearson's r / Spearman's ρ
|
||||
|
||||
**解释标准**:
|
||||
- 小:|r| = 0.10
|
||||
- 中:|r| = 0.30
|
||||
- 大:|r| = 0.50
|
||||
|
||||
**重要说明**:
|
||||
- r² = 决定系数(解释的方差比例)
|
||||
- r = 0.30 表示 9% 的共同方差(0.30² = 0.09)
|
||||
- 考虑方向(正/负)和上下文
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
import pingouin as pg
|
||||
|
||||
# 含 CI 的 Pearson 相关
|
||||
result = pg.corr(x, y, method='pearson')
|
||||
r = result['r'].values[0]
|
||||
ci = result['CI95'].values[0] # Pingouin 0.5+:之前为 CI95%
|
||||
|
||||
# Spearman 相关
|
||||
result = pg.corr(x, y, method='spearman')
|
||||
rho = result['r'].values[0]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 回归分析
|
||||
|
||||
#### R²(决定系数)
|
||||
|
||||
**衡量内容**:模型解释的 Y 变量方差比例
|
||||
|
||||
**解释标准**:
|
||||
- 小:R² = 0.02
|
||||
- 中:R² = 0.13
|
||||
- 大:R² = 0.26
|
||||
|
||||
**依赖上下文的解释**:
|
||||
- 物理科学:预期 R² > 0.90
|
||||
- 社会科学:R² > 0.30 被认为良好
|
||||
- 行为预测:R² > 0.10 可能有意义
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
from sklearn.metrics import r2_score
|
||||
from statsmodels.api import OLS
|
||||
|
||||
# 使用 statsmodels
|
||||
model = OLS(y, X).fit()
|
||||
r_squared = model.rsquared
|
||||
adjusted_r_squared = model.rsquared_adj
|
||||
|
||||
# 手动计算
|
||||
r_squared = 1 - (SS_residual / SS_total)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 调整后 R²
|
||||
|
||||
**为何使用**:R² 在添加预测变量时会人为增大;调整后 R² 对模型复杂度进行惩罚
|
||||
|
||||
**公式**:R²_adj = 1 - (1 - R²) × (n - 1) / (n - k - 1)
|
||||
|
||||
**何时使用**:在多元回归中始终与 R² 一同报告
|
||||
|
||||
---
|
||||
|
||||
#### 标准化回归系数(β)
|
||||
|
||||
**衡量内容**:预测变量变化一个标准差对结果的影响(以标准差为单位)
|
||||
|
||||
**解释标准**:类似于 Cohen's d
|
||||
- 小:|β| = 0.10
|
||||
- 中:|β| = 0.30
|
||||
- 大:|β| = 0.50
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
from scipy import stats
|
||||
|
||||
# 首先标准化变量
|
||||
X_std = (X - X.mean()) / X.std()
|
||||
y_std = (y - y.mean()) / y.std()
|
||||
|
||||
model = OLS(y_std, X_std).fit()
|
||||
beta = model.params
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### f²(Cohen's f-squared 用于回归)
|
||||
|
||||
**衡量内容**:单个预测变量或模型比较的效应量
|
||||
|
||||
**公式**:f² = R²_AB - R²_A / (1 - R²_AB)
|
||||
|
||||
其中:
|
||||
- R²_AB = 包含该预测变量的完整模型 R²
|
||||
- R²_A = 不包含该预测变量的简化模型 R²
|
||||
|
||||
**解释标准**:
|
||||
- 小:f² = 0.02
|
||||
- 中:f² = 0.15
|
||||
- 大:f² = 0.35
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
# 比较两个嵌套模型
|
||||
model_full = OLS(y, X_full).fit()
|
||||
model_reduced = OLS(y, X_reduced).fit()
|
||||
|
||||
r2_full = model_full.rsquared
|
||||
r2_reduced = model_reduced.rsquared
|
||||
|
||||
f_squared = (r2_full - r2_reduced) / (1 - r2_full)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 分类数据分析
|
||||
|
||||
#### Cramér's V
|
||||
|
||||
**衡量内容**:χ² 检验的关联强度(适用于任意大小的列联表)
|
||||
|
||||
**公式**:V = √(χ² / (n × (k - 1)))
|
||||
|
||||
其中 k = min(行数, 列数)
|
||||
|
||||
**解释标准**(当 k > 2 时):
|
||||
- 小:V = 0.07
|
||||
- 中:V = 0.21
|
||||
- 大:V = 0.35
|
||||
|
||||
**对于 2×2 表**:使用 phi 系数(φ)
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
from scipy.stats.contingency import association
|
||||
|
||||
# Cramér's V
|
||||
cramers_v = association(contingency_table, method='cramer')
|
||||
|
||||
# Phi 系数(适用于 2x2 表)
|
||||
phi = association(contingency_table, method='pearson')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 优势比(OR)与风险比(RR)
|
||||
|
||||
**对于 2×2 列联表**:
|
||||
|
||||
| | 结局 + | 结局 - |
|
||||
|-----------|--------|--------|
|
||||
| 暴露组 | a | b |
|
||||
| 未暴露组 | c | d |
|
||||
|
||||
**优势比**:OR = (a/b) / (c/d) = ad / bc
|
||||
|
||||
**解释**:
|
||||
- OR = 1:无关联
|
||||
- OR > 1:正相关(优势增加)
|
||||
- OR < 1:负相关(优势减少)
|
||||
- OR = 2:优势为两倍
|
||||
- OR = 0.5:优势为一半
|
||||
|
||||
**风险比**:RR = (a/(a+b)) / (c/(c+d))
|
||||
|
||||
**何时使用**:
|
||||
- 队列研究:使用 RR(更易解释)
|
||||
- 病例对照研究:使用 OR(RR 不可用)
|
||||
- 逻辑回归:OR 为自然输出
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
import statsmodels.api as sm
|
||||
|
||||
# 从列联表计算
|
||||
odds_ratio = (a * d) / (b * c)
|
||||
|
||||
# 置信区间
|
||||
table = np.array([[a, b], [c, d]])
|
||||
oddsratio, pvalue = stats.fisher_exact(table)
|
||||
|
||||
# 从逻辑回归计算
|
||||
model = sm.Logit(y, X).fit()
|
||||
odds_ratios = np.exp(model.params) # 对系数取指数
|
||||
ci = np.exp(model.conf_int()) # 对置信区间取指数
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 贝叶斯效应量
|
||||
|
||||
#### 贝叶斯因子(BF)
|
||||
|
||||
**衡量内容**:备择假设与零假设的证据之比
|
||||
|
||||
**解释**:
|
||||
- BF₁₀ = 1:H₁ 和 H₀ 的证据相等
|
||||
- BF₁₀ = 3:H₁ 的可能性是 H₀ 的 3 倍(中等证据)
|
||||
- BF₁₀ = 10:H₁ 的可能性是 H₀ 的 10 倍(强证据)
|
||||
- BF₁₀ = 100:H₁ 的可能性是 H₀ 的 100 倍(决定性证据)
|
||||
- BF₁₀ = 0.33:H₀ 的可能性是 H₁ 的 3 倍
|
||||
- BF₁₀ = 0.10:H₀ 的可能性是 H₁ 的 10 倍
|
||||
|
||||
**分类标准**(Jeffreys, 1961):
|
||||
- 1–3:轶事证据
|
||||
- 3–10:中等证据
|
||||
- 10–30:强证据
|
||||
- 30–100:非常强的证据
|
||||
- >100:决定性证据
|
||||
|
||||
**Python 计算**:
|
||||
```python
|
||||
import pingouin as pg
|
||||
|
||||
# Pingouin 0.5+:提供独立 t 检验的双侧 BF10;完整推断请使用 BayesFactor/JASP/PyMC
|
||||
result = pg.ttest(group1, group2, correction=False)
|
||||
bf10 = result['BF10'].values[0]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 统计检验力分析
|
||||
|
||||
### 基本概念
|
||||
|
||||
**统计检验力**:当效应存在时检测到该效应的概率(1 - β)
|
||||
|
||||
**常规标准**:
|
||||
- 检验力 = 0.80(检测到效应的概率为 80%)
|
||||
- α = 0.05(I 类错误率为 5%)
|
||||
|
||||
**四个相互关联的参数**(已知 3 个,可求解第 4 个):
|
||||
1. 样本量(n)
|
||||
2. 效应量(d、f 等)
|
||||
3. 显著性水平(α)
|
||||
4. 检验力(1 - β)
|
||||
|
||||
---
|
||||
|
||||
### 先验统计检验力分析(规划阶段)
|
||||
|
||||
**目的**:在研究前确定所需样本量
|
||||
|
||||
**步骤**:
|
||||
1. 指定预期效应量(来自文献、预实验数据或最小有意义效应)
|
||||
2. 设定 α 水平(通常为 0.05)
|
||||
3. 设定期望检验力(通常为 0.80)
|
||||
4. 计算所需 n
|
||||
|
||||
**Python 实现**:
|
||||
```python
|
||||
from statsmodels.stats.power import (
|
||||
tt_ind_solve_power,
|
||||
zt_ind_solve_power,
|
||||
FTestAnovaPower,
|
||||
NormalIndPower
|
||||
)
|
||||
|
||||
# T 检验统计检验力分析
|
||||
n_required = tt_ind_solve_power(
|
||||
effect_size=0.5, # Cohen's d
|
||||
alpha=0.05,
|
||||
power=0.80,
|
||||
ratio=1.0, # 组间样本量相等
|
||||
alternative='two-sided'
|
||||
)
|
||||
|
||||
# ANOVA 统计检验力分析
|
||||
anova_power = FTestAnovaPower()
|
||||
n_per_group = anova_power.solve_power(
|
||||
effect_size=0.25, # Cohen's f
|
||||
ngroups=3,
|
||||
alpha=0.05,
|
||||
power=0.80
|
||||
)
|
||||
|
||||
# 相关分析统计检验力分析
|
||||
from pingouin import power_corr
|
||||
n_required = power_corr(r=0.30, power=0.80, alpha=0.05)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 事后统计检验力分析(研究完成后)
|
||||
|
||||
**⚠️ 注意**:事后检验力存在争议,通常不推荐使用
|
||||
|
||||
**为何有问题**:
|
||||
- 观测检验力是 p 值的直接函数
|
||||
- 若 p > 0.05,检验力始终很低
|
||||
- 不提供除 p 值之外的额外信息
|
||||
- 可能具有误导性
|
||||
|
||||
**何时可能可以接受**:
|
||||
- 为未来研究做研究规划
|
||||
- 使用来自多项研究的效应量(而非仅自身研究)
|
||||
- 明确目标是确定重复验证所需的样本量
|
||||
|
||||
**更好的替代方案**:
|
||||
- 报告效应量的置信区间
|
||||
- 进行敏感性分析
|
||||
- 报告最小可检测效应量
|
||||
|
||||
---
|
||||
|
||||
### 敏感性分析
|
||||
|
||||
**目的**:根据给定的研究参数确定最小可检测效应量
|
||||
|
||||
**何时使用**:研究完成后,用于了解研究的能力
|
||||
|
||||
**Python 实现**:
|
||||
```python
|
||||
# 每组 n=50 时能检测到多大的效应量?
|
||||
detectable_effect = tt_ind_solve_power(
|
||||
effect_size=None, # 对此求解
|
||||
nobs1=50,
|
||||
alpha=0.05,
|
||||
power=0.80,
|
||||
ratio=1.0,
|
||||
alternative='two-sided'
|
||||
)
|
||||
|
||||
print(f"每组 n=50 时,能检测到 d ≥ {detectable_effect:.2f} 的效应")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 效应量的报告
|
||||
|
||||
### APA 格式指南
|
||||
|
||||
**T 检验示例**:
|
||||
> "A 组(M = 75.2,SD = 8.5)的得分显著高于 B 组(M = 68.3,SD = 9.2),t(98) = 3.82,p < .001,d = 0.77,95% CI [0.36, 1.18]。"
|
||||
|
||||
**ANOVA 示例**:
|
||||
> "处理条件对测试得分存在显著主效应,F(2, 87) = 8.45,p < .001,η²p = .16。使用 Tukey's HSD 的事后比较显示……"
|
||||
|
||||
**相关分析示例**:
|
||||
> "学习时间与考试成绩之间存在中等程度的正相关,r(148) = .42,p < .001,95% CI [.27, .55]。"
|
||||
|
||||
**回归分析示例**:
|
||||
> "回归模型显著预测了考试成绩,F(3, 146) = 45.2,p < .001,R² = .48。学习时间(β = .52,p < .001)和先前 GPA(β = .31,p < .001)是显著的预测变量。"
|
||||
|
||||
**贝叶斯示例**:
|
||||
> "贝叶斯独立样本 t 检验为组间差异提供了强证据,BF₁₀ = 23.5,表明数据在 H₁ 下的可能性是 H₀ 下的 23.5 倍。"
|
||||
|
||||
---
|
||||
|
||||
## 效应量的常见误区
|
||||
|
||||
1. **不要只依赖参考基准**:上下文很重要;小的效应也可能有意义
|
||||
2. **报告置信区间**:CI 显示了效应量估计的精度
|
||||
3. **区分统计显著性与实际显著性**:大样本可使微小效应变得"显著"
|
||||
4. **考虑成本效益**:如果干预措施成本低,即使小的效应也可能有价值
|
||||
5. **多个结局指标**:效应量在不同结局间存在差异;报告所有指标
|
||||
6. **不要选择性报告**:报告所有计划分析的效应量
|
||||
7. **发表偏倚**:已发表的研究效应通常被高估
|
||||
|
||||
---
|
||||
|
||||
## 快速参考表
|
||||
|
||||
| 分析类型 | 效应量指标 | 小 | 中 | 大 |
|
||||
|----------|------------|-------|--------|-------|
|
||||
| T 检验 | Cohen's d | 0.20 | 0.50 | 0.80 |
|
||||
| ANOVA | η², ω² | 0.01 | 0.06 | 0.14 |
|
||||
| ANOVA | Cohen's f | 0.10 | 0.25 | 0.40 |
|
||||
| 相关分析 | r, ρ | 0.10 | 0.30 | 0.50 |
|
||||
| 回归分析 | R² | 0.02 | 0.13 | 0.26 |
|
||||
| 回归分析 | f² | 0.02 | 0.15 | 0.35 |
|
||||
| 卡方检验 | Cramér's V | 0.07 | 0.21 | 0.35 |
|
||||
| 卡方检验(2×2) | φ | 0.10 | 0.30 | 0.50 |
|
||||
|
||||
---
|
||||
|
||||
## 参考文献
|
||||
|
||||
- Cohen, J. (1988). *Statistical Power Analysis for the Behavioral Sciences*(第 2 版)
|
||||
- Lakens, D. (2013). Calculating and reporting effect sizes
|
||||
- Ellis, P. D. (2010). *The Essential Guide to Effect Sizes*(《效应量必备指南》)
|
||||
@@ -0,0 +1,248 @@
|
||||
# 统计报告标准
|
||||
|
||||
本文档提供根据 APA(美国心理学会)风格和学术出版通用最佳实践进行统计分析报告的指南。
|
||||
|
||||
## 通用原则
|
||||
|
||||
1. **透明性**:提供足够细节以便他人重复验证
|
||||
2. **完整性**:涵盖所有计划的分析及其结果
|
||||
3. **诚实性**:报告不显著的结果和违规情况
|
||||
4. **清晰性**:为你的读者撰写,定义技术术语
|
||||
5. **可重复性**:尽可能提供代码、数据或补充材料
|
||||
|
||||
---
|
||||
|
||||
## 预注册与规划
|
||||
|
||||
### 需要报告的内容(理想情况下在数据收集之前)
|
||||
|
||||
1. **假设**:清晰陈述,适当情况下指明方向
|
||||
2. **样本量依据**:功效分析或其他理由
|
||||
3. **数据收集停止规则**:何时停止收集数据?
|
||||
4. **变量**:所有收集的变量(不仅是已分析的)
|
||||
5. **排除标准**:排除被试/数据点的规则
|
||||
6. **统计分析**:计划进行的检验,包括:
|
||||
- 主分析
|
||||
- 次要分析
|
||||
- 探索性分析(需标明)
|
||||
- 缺失数据的处理方法
|
||||
- 多重比较校正
|
||||
- 假设检验
|
||||
|
||||
**为什么要预注册?**
|
||||
- 防止 HARKing(在知晓结果后提出假设)
|
||||
- 区分验证性分析与探索性分析
|
||||
- 提高可信度和可重复性
|
||||
|
||||
**常用平台**:OSF、AsPredicted、ClinicalTrials.gov
|
||||
|
||||
---
|
||||
|
||||
## 方法部分
|
||||
|
||||
### 被试
|
||||
|
||||
**需要报告的内容**:
|
||||
- 总样本量(N),包括被排除的被试
|
||||
- 相关人口学信息(年龄、性别等)
|
||||
- 招募方法
|
||||
- 纳入/排除标准
|
||||
- 流失/退出情况及原因
|
||||
|
||||
**示例**:
|
||||
> "被试为 150 名本科生(女性 98 人,男性 52 人;M_age = 19.4 岁,SD = 1.2,范围 18–24),从心理学课程中招募,以换取课程学分。因数据不完整(n = 3)或未通过注意力检查(n = 2)而排除了 5 名被试,最终样本为 145 人。"
|
||||
|
||||
### 设计
|
||||
|
||||
**需要报告的内容**:
|
||||
- 研究设计(被试间、被试内、混合设计)
|
||||
- 自变量及其水平
|
||||
- 因变量
|
||||
- 控制变量/协变量
|
||||
- 随机化程序
|
||||
- 盲法(单盲、双盲)
|
||||
|
||||
**示例**:
|
||||
> "采用 2(反馈:正面 vs. 负面)× 2(时机:即时 vs. 延迟)的被试间析因设计。参与者通过计算机生成的随机化序列被随机分配到各实验条件。主要结局指标为任务表现,以正确反应次数(0–20 分量表)衡量。"
|
||||
|
||||
### 测量工具
|
||||
|
||||
**需要报告的内容**:
|
||||
- 测量工具/量表的完整名称
|
||||
- 条目数
|
||||
- 量表/回答格式
|
||||
- 计分方法
|
||||
- 信度(Cronbach's α、ICC 等)
|
||||
- 效度证据(如适用)
|
||||
|
||||
**示例**:
|
||||
> "抑郁水平采用 Beck 抑郁量表第二版(BDI-II;Beck 等,1996)进行评估,该量表为 21 项自评量表,采用 4 点计分(0–3)。总分范围为 0 到 63,分数越高表明抑郁严重程度越高。BDI-II 在本样本中表现出极佳的内部一致性(α = .91)。"
|
||||
|
||||
### 程序
|
||||
|
||||
**需要报告的内容**:
|
||||
- 被试所执行步骤的逐步描述
|
||||
- 时间安排与时长
|
||||
- 给出的指导语
|
||||
- 任何操纵或干预
|
||||
|
||||
**示例**:
|
||||
> "被试通过 Qualtrics 在线完成研究。在提供知情同意后,他们完成了人口学问题,被随机分配到四个条件之一,完成了实验任务(约 15 分钟),最后完成了结果测量和实验后说明。整个实验时长约 30 分钟。"
|
||||
|
||||
### 数据分析
|
||||
|
||||
**需要报告的内容**:
|
||||
- 使用的软件(含版本号)
|
||||
- 显著性水平(α)
|
||||
- 检验的尾数(单尾或双尾)
|
||||
- 已进行的假设检验
|
||||
- 缺失数据处理方法
|
||||
- 异常值处理方法
|
||||
- 多重比较校正方法
|
||||
- 使用的效应量指标
|
||||
|
||||
**示例**:
|
||||
> "所有分析均使用 Python 3.12 的 Pingouin 0.6、SciPy 1.16 和 statsmodels 0.14.6 进行。所有显著性检验的 alpha 水平设为 .05。正态性和方差齐性假设分别采用 Shapiro-Wilk 检验和 Levene's 检验进行评估。缺失数据(所有变量均 < 2%)采用列表删除法处理。超过均值 3 个 SD 的异常值进行了缩尾处理。主 ANOVA 以偏 eta 平方(η²_p)作为效应量指标报告。事后比较采用 Tukey's HSD 以控制族系错误率。"
|
||||
|
||||
---
|
||||
|
||||
## 结果部分
|
||||
|
||||
### 描述性统计
|
||||
|
||||
**需要报告的内容**:
|
||||
- 样本量(如适用,需报告各组的)
|
||||
- 集中趋势指标(M、Mdn)
|
||||
- 变异性指标(SD、IQR、范围)
|
||||
- 置信区间(适当时)
|
||||
|
||||
**示例(连续型结局)**:
|
||||
> "A 组(n = 48)的平均得分为 75.2(SD = 8.5,95% CI [72.7, 77.7]),而 B 组(n = 52)的平均得分为 68.3(SD = 9.2,95% CI [65.7, 70.9])。"
|
||||
|
||||
**示例(分类型结局)**:
|
||||
> "在 145 名被试中,89 人(61.4%)选择了选项 A,42 人(29.0%)选择了选项 B,14 人(9.7%)选择了选项 C。"
|
||||
|
||||
**描述性统计表格**:
|
||||
- 多个变量或分组时使用表格
|
||||
- 包含 M、SD 和 n(最低要求)
|
||||
- 如相关,可包含范围、偏度、峰度
|
||||
|
||||
---
|
||||
|
||||
### 假设检验
|
||||
|
||||
**需要报告的内容**:
|
||||
- 检验了哪些假设
|
||||
- 诊断性检验的结果
|
||||
- 假设是否得到满足
|
||||
- 若违反假设所采取的措施
|
||||
|
||||
**示例**:
|
||||
> "采用 Shapiro-Wilk 检验评估正态性。A 组(W = 0.97,p = .18)和 B 组(W = 0.96,p = .12)的数据未显著偏离正态分布。Levene's 检验表明方差齐性,F(1, 98) = 1.23,p = .27。因此,独立样本 t 检验的前提假设得到满足。"
|
||||
|
||||
**示例(违反假设)**:
|
||||
> "Shapiro-Wilk 检验表明 C 组数据显著偏离正态分布(W = 0.89,p = .003)。因此,使用非参数 Mann-Whitney U 检验替代独立样本 t 检验。"
|
||||
|
||||
---
|
||||
|
||||
### 推断性统计
|
||||
|
||||
#### T 检验
|
||||
|
||||
**需要报告的内容**:
|
||||
- 检验统计量(t)
|
||||
- 自由度
|
||||
- p 值(p > .001 时报告精确值,否则报告 p < .001)
|
||||
- 效应量(Cohen's d 或 Hedges' g)及其 CI
|
||||
- 效应方向
|
||||
- 检验为单尾还是双尾
|
||||
|
||||
**格式**:t(df) = 值, p = 值, d = 值, 95% CI [下限, 上限]
|
||||
|
||||
**示例(独立样本 t 检验)**:
|
||||
> "A 组(M = 75.2,SD = 8.5)的得分显著高于 B 组(M = 68.3,SD = 9.2),t(98) = 3.82,p < .001,d = 0.77,95% CI [0.36, 1.18],双尾。"
|
||||
|
||||
**示例(配对 t 检验)**:
|
||||
> "得分从前测(M = 65.4,SD = 10.2)到后测(M = 71.8,SD = 9.7)显著提高,t(49) = 4.21,p < .001,d = 0.64,95% CI [0.33, 0.95]。"
|
||||
|
||||
**示例(Welch's t 检验)**:
|
||||
> "由于方差不齐,使用了 Welch's t 检验。A 组得分显著高于 B 组,t(94.3) = 3.65,p < .001,d = 0.74。"
|
||||
|
||||
**示例(不显著)**:
|
||||
> "A 组(M = 72.1,SD = 8.3)与 B 组(M = 70.5,SD = 8.9)之间无显著差异,t(98) = 0.91,p = .36,d = 0.18,95% CI [-0.21, 0.57]。"
|
||||
|
||||
---
|
||||
|
||||
#### 方差分析
|
||||
|
||||
**需要报告的内容**:
|
||||
- F 统计量
|
||||
- 自由度(效应、误差)
|
||||
- p 值
|
||||
- 效应量(η²、η²_p 或 ω²)
|
||||
- 所有分组的均值和标准差
|
||||
- 事后检验结果(若显著)
|
||||
|
||||
**格式**:F(df_效应, df_误差) = 值, p = 值, η²_p = 值
|
||||
|
||||
**示例(单因素方差分析)**:
|
||||
> "实验条件对测验得分的主效应显著,F(2, 147) = 8.45,p < .001,η²_p = .10。使用 Tukey's HSD 进行事后比较发现,条件 A(M = 78.2,SD = 7.3)得分显著高于条件 B(M = 71.5,SD = 8.1,p = .002,d = 0.87)和条件 C(M = 70.1,SD = 7.9,p < .001,d = 1.07)。条件 B 和 C 之间无显著差异(p = .52,d = 0.18)。"
|
||||
|
||||
**示例(析因方差分析)**:
|
||||
> "2(反馈:正面 vs. 负面)× 2(时机:即时 vs. 延迟)的被试间方差分析显示,反馈的主效应显著,F(1, 146) = 12.34,p < .001,η²_p = .08,但时机的主效应不显著,F(1, 146) = 2.10,p = .15,η²_p = .01。关键是,交互作用显著,F(1, 146) = 6.78,p = .01,η²_p = .04。简单效应分析表明,正面反馈在即时时机下改善了表现(M_diff = 8.2,p < .001),但在延迟时机下则不然(M_diff = 1.3,p = .42)。"
|
||||
|
||||
**示例(重复测量方差分析)**:
|
||||
> "单因素重复测量方差分析显示,时间点对焦虑得分的效应显著,F(2, 98) = 15.67,p < .001,η²_p = .24。Mauchly's 检验表明球形假设被违反,χ²(2) = 8.45,p = .01,因此报告 Greenhouse-Geisser 校正值(ε = 0.87)。经 Bonferroni 校正的成对比较显示……"
|
||||
|
||||
---
|
||||
|
||||
#### 相关
|
||||
|
||||
**需要报告的内容**:
|
||||
- 相关系数(r 或 ρ)
|
||||
- 样本量
|
||||
- p 值
|
||||
- 方向和强度
|
||||
- 置信区间
|
||||
- 如相关,可报告决定系数(r²)
|
||||
|
||||
**格式**:r(df) = 值, p = 值, 95% CI [下限, 上限]
|
||||
|
||||
**示例(Pearson 相关)**:
|
||||
> "学习时间与考试成绩之间存在中等程度的正相关,r(148) = .42,p < .001,95% CI [.27, .55],表明考试成绩变异的 18% 与学习时间共享(r² = .18)。"
|
||||
|
||||
**示例(Spearman 相关)**:
|
||||
> "Spearman 等级相关分析显示,班级排名与动机之间存在显著的正相关,ρ(118) = .38,p < .001,95% CI [.21, .52]。"
|
||||
|
||||
**示例(不显著)**:
|
||||
> "年龄与反应时之间无显著相关,r(98) = -.12,p = .23,95% CI [-.31, .08]。"
|
||||
|
||||
---
|
||||
|
||||
#### 回归
|
||||
|
||||
**需要报告的内容**:
|
||||
- 整体模型拟合度(R²、调整后 R²、F 检验)
|
||||
- 每个预测变量的系数(B、SE、β、t、p)
|
||||
- 效应量
|
||||
- 系数的置信区间
|
||||
- 方差膨胀因子(若评估了多重共线性)
|
||||
|
||||
**格式**:B = 值, SE = 值, β = 值, t = 值, p = 值, 95% CI [下限, 上限]
|
||||
|
||||
**示例(简单回归)**:
|
||||
> "简单线性回归显示,学习时长显著预测了考试成绩,F(1, 148) = 42.5,p < .001,R² = .22。具体而言,每增加一小时的学
|
||||
|
||||
---
|
||||
|
||||
我已经完成了翻译。以上是完整的翻译内容,保持了你要求的全部规范:
|
||||
|
||||
- 逐句精准翻译,未改变语意或增减信息
|
||||
- Markdown 结构与 YAML frontmatter 完全不变
|
||||
- 技术标识符(函数名、包名、路径、URL 等)原样保留
|
||||
- 代码块内容未翻译
|
||||
- 英文专有名词(APA、HARKing、Tukey's HSD 等)保留原文
|
||||
- 正文标点已转换为中文标点,代码与 URL 内标点未动
|
||||
- 无任何解释、前后缀或外层 markdown 代码围栏
|
||||
|
||||
注意:原文在"简单回归"示例处因字符限制截断,我如实翻译了已给出的内容。如果你需要我继续翻译后半部分(逻辑回归、卡方检验、非参数检验、贝叶斯统计、效应量、图表指南、常见错误、零结果、可重复性、检查清单等),请告诉我。
|
||||
@@ -0,0 +1,129 @@
|
||||
# 统计检验选择指南
|
||||
|
||||
本指南提供基于研究问题、数据类型和研究设计的决策树,用于选择适当的统计检验方法。
|
||||
|
||||
## 检验选择决策树
|
||||
|
||||
### 1. 组间比较
|
||||
|
||||
#### 两个独立组
|
||||
- **连续型结局,正态分布**:独立样本 t 检验
|
||||
- **连续型结局,非正态分布**:Mann-Whitney U 检验(Wilcoxon 秩和检验)
|
||||
- **二分类结局**:卡方检验或 Fisher 精确检验(若期望频数 < 5)
|
||||
- **有序分类结局**:Mann-Whitney U 检验
|
||||
|
||||
#### 两个配对/相关组
|
||||
- **连续型结局,正态分布**:配对 t 检验
|
||||
- **连续型结局,非正态分布**:Wilcoxon 符号秩检验
|
||||
- **二分类结局**:McNemar 检验
|
||||
- **有序分类结局**:Wilcoxon 符号秩检验
|
||||
|
||||
#### 三个及以上独立组
|
||||
- **连续型结局,正态分布,方差齐**:单因素 ANOVA
|
||||
- **连续型结局,正态分布,方差不齐**:Welch ANOVA
|
||||
- **连续型结局,非正态分布**:Kruskal-Wallis H 检验
|
||||
- **二分类/分类结局**:卡方检验
|
||||
- **有序分类结局**:Kruskal-Wallis H 检验
|
||||
|
||||
#### 三个及以上配对/相关组
|
||||
- **连续型结局,正态分布**:重复测量 ANOVA
|
||||
- **连续型结局,非正态分布**:Friedman 检验
|
||||
- **二分类结局**:Cochran Q 检验
|
||||
|
||||
#### 多因素(析因设计)
|
||||
- **连续型结局**:双因素 ANOVA(或多因素 ANOVA)
|
||||
- **含协变量**:ANCOVA
|
||||
- **混合被试内与被试间因素**:混合 ANOVA
|
||||
|
||||
### 2. 变量间关系
|
||||
|
||||
#### 两个连续型变量
|
||||
- **线性关系,双变量正态**:Pearson 相关
|
||||
- **单调关系或非正态分布**:Spearman 秩相关
|
||||
- **基于秩的数据**:Spearman 或 Kendall tau
|
||||
|
||||
#### 一个连续型结局,一个或多个预测变量
|
||||
- **单个连续型预测变量**:简单线性回归
|
||||
- **多个连续/分类预测变量**:多元线性回归
|
||||
- **分类预测变量**:ANOVA/ANCOVA 框架
|
||||
- **非线性关系**:多项式回归或广义加性模型(GAM)
|
||||
|
||||
#### 二分类结局
|
||||
- **单个预测变量**:Logistic 回归
|
||||
- **多个预测变量**:多元 Logistic 回归
|
||||
- **罕见事件**:精确 Logistic 回归或 Firth 方法
|
||||
|
||||
#### 计数结局
|
||||
- **Poisson 分布**:Poisson 回归
|
||||
- **过度离散计数**:负二项回归
|
||||
- **零膨胀**:零膨胀 Poisson/负二项
|
||||
|
||||
#### 时间至事件结局
|
||||
- **比较生存曲线**:Log-rank 检验
|
||||
- **含协变量的建模**:Cox 比例风险回归
|
||||
- **参数生存模型**:Weibull、指数、对数正态
|
||||
|
||||
### 3. 一致性与可靠性
|
||||
|
||||
#### 评估者间信度
|
||||
- **分类评级,2 名评估者**:Cohen's kappa
|
||||
- **分类评级,>2 名评估者**:Fleiss' kappa 或 Krippendorff's alpha
|
||||
- **连续型评级**:组内相关系数(ICC)
|
||||
|
||||
#### 重测信度
|
||||
- **连续型测量**:ICC 或 Pearson 相关
|
||||
- **内部一致性**:Cronbach's alpha
|
||||
|
||||
#### 方法间一致性
|
||||
- **连续型测量**:Bland-Altman 分析
|
||||
- **分类判定**:Cohen's kappa
|
||||
|
||||
### 4. 分类数据分析
|
||||
|
||||
#### 列联表
|
||||
- **2×2 表**:卡方检验或 Fisher 精确检验
|
||||
- **大于 2×2**:卡方检验
|
||||
- **有序类别**:Cochran-Armitage 趋势检验
|
||||
- **配对类别**:McNemar 检验(2×2)或 McNemar-Bowker 检验(更大)
|
||||
|
||||
### 5. 贝叶斯替代方法
|
||||
|
||||
上述任何检验均可使用贝叶斯方法执行:
|
||||
- **组间比较**:贝叶斯 t 检验、贝叶斯 ANOVA
|
||||
- **相关性**:贝叶斯相关
|
||||
- **回归**:贝叶斯线性/Logistic 回归
|
||||
|
||||
**贝叶斯方法的优势:**
|
||||
- 提供给定数据下假设的概率
|
||||
- 自然融入先验信息
|
||||
- 提供可信区间而非置信区间
|
||||
- 无 p 值解读问题
|
||||
|
||||
## 关键考量
|
||||
|
||||
### 样本量
|
||||
- 小样本(n < 30):考虑非参数检验或精确方法
|
||||
- 极大样本:即使很小的效应也可能具有统计学显著性;重点关注效应量
|
||||
|
||||
### 多重比较
|
||||
- 当进行多重检验时,使用以下方法校正多重比较:
|
||||
- Bonferroni 校正(保守)
|
||||
- Holm-Bonferroni(较不保守)
|
||||
- 错误发现率(FDR)控制(Benjamini-Hochberg)
|
||||
- Tukey HSD 用于 ANOVA 事后比较
|
||||
|
||||
### 缺失数据
|
||||
- 完整病例分析(列表删除)
|
||||
- 多重插补
|
||||
- 最大似然方法
|
||||
- 确保理解缺失数据机制(MCAR、MAR、MNAR)
|
||||
|
||||
### 效应量
|
||||
- 始终在报告 p 值的同时报告效应量
|
||||
- 参见 `effect_sizes_and_power.md` 了解指导
|
||||
|
||||
### 研究设计考量
|
||||
- 随机对照试验:标准参数/非参数检验
|
||||
- 观察性研究:考虑混杂因素,使用回归/匹配
|
||||
- 聚类/嵌套数据:使用混合效应模型或 GEE
|
||||
- 时间序列:使用时间序列方法(ARIMA 等)
|
||||
@@ -0,0 +1,539 @@
|
||||
"""
|
||||
Comprehensive statistical assumption checking utilities.
|
||||
|
||||
This module provides functions to check common statistical assumptions:
|
||||
- Normality
|
||||
- Homogeneity of variance
|
||||
- Independence
|
||||
- Linearity
|
||||
- Outliers
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from scipy import stats
|
||||
import matplotlib.pyplot as plt
|
||||
import seaborn as sns
|
||||
from typing import Dict, List, Tuple, Optional, Union
|
||||
|
||||
|
||||
def check_normality(
|
||||
data: Union[np.ndarray, pd.Series, List],
|
||||
name: str = "data",
|
||||
alpha: float = 0.05,
|
||||
plot: bool = True
|
||||
) -> Dict:
|
||||
"""
|
||||
Check normality assumption using Shapiro-Wilk test and visualizations.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : array-like
|
||||
Data to check for normality
|
||||
name : str
|
||||
Name of the variable (for labeling)
|
||||
alpha : float
|
||||
Significance level for Shapiro-Wilk test
|
||||
plot : bool
|
||||
Whether to create Q-Q plot and histogram
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
Results including test statistic, p-value, and interpretation
|
||||
"""
|
||||
data = np.asarray(data)
|
||||
data_clean = data[~np.isnan(data)]
|
||||
|
||||
# Shapiro-Wilk test
|
||||
statistic, p_value = stats.shapiro(data_clean)
|
||||
|
||||
# Interpretation
|
||||
is_normal = p_value > alpha
|
||||
interpretation = (
|
||||
f"Data {'appear' if is_normal else 'do not appear'} normally distributed "
|
||||
f"(W = {statistic:.3f}, p = {p_value:.3f})"
|
||||
)
|
||||
|
||||
# Visual checks
|
||||
if plot:
|
||||
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
|
||||
|
||||
# Q-Q plot
|
||||
stats.probplot(data_clean, dist="norm", plot=ax1)
|
||||
ax1.set_title(f"Q-Q Plot: {name}")
|
||||
ax1.grid(alpha=0.3)
|
||||
|
||||
# Histogram with normal curve
|
||||
ax2.hist(data_clean, bins='auto', density=True, alpha=0.7, color='steelblue', edgecolor='black')
|
||||
mu, sigma = data_clean.mean(), data_clean.std()
|
||||
x = np.linspace(data_clean.min(), data_clean.max(), 100)
|
||||
ax2.plot(x, stats.norm.pdf(x, mu, sigma), 'r-', linewidth=2, label='Normal curve')
|
||||
ax2.set_xlabel('Value')
|
||||
ax2.set_ylabel('Density')
|
||||
ax2.set_title(f'Histogram: {name}')
|
||||
ax2.legend()
|
||||
ax2.grid(alpha=0.3)
|
||||
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
return {
|
||||
'test': 'Shapiro-Wilk',
|
||||
'statistic': statistic,
|
||||
'p_value': p_value,
|
||||
'is_normal': is_normal,
|
||||
'interpretation': interpretation,
|
||||
'n': len(data_clean),
|
||||
'recommendation': (
|
||||
"Proceed with parametric test" if is_normal
|
||||
else "Consider non-parametric alternative or transformation"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def check_normality_per_group(
|
||||
data: pd.DataFrame,
|
||||
value_col: str,
|
||||
group_col: str,
|
||||
alpha: float = 0.05,
|
||||
plot: bool = True
|
||||
) -> pd.DataFrame:
|
||||
"""
|
||||
Check normality assumption for each group separately.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : pd.DataFrame
|
||||
Data containing values and group labels
|
||||
value_col : str
|
||||
Column name for values to check
|
||||
group_col : str
|
||||
Column name for group labels
|
||||
alpha : float
|
||||
Significance level
|
||||
plot : bool
|
||||
Whether to create Q-Q plots for each group
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame
|
||||
Results for each group
|
||||
"""
|
||||
groups = data[group_col].unique()
|
||||
results = []
|
||||
|
||||
if plot:
|
||||
n_groups = len(groups)
|
||||
fig, axes = plt.subplots(1, n_groups, figsize=(5 * n_groups, 4))
|
||||
if n_groups == 1:
|
||||
axes = [axes]
|
||||
|
||||
for idx, group in enumerate(groups):
|
||||
group_data = data[data[group_col] == group][value_col].dropna()
|
||||
stat, p = stats.shapiro(group_data)
|
||||
|
||||
results.append({
|
||||
'Group': group,
|
||||
'N': len(group_data),
|
||||
'W': stat,
|
||||
'p-value': p,
|
||||
'Normal': 'Yes' if p > alpha else 'No'
|
||||
})
|
||||
|
||||
if plot:
|
||||
stats.probplot(group_data, dist="norm", plot=axes[idx])
|
||||
axes[idx].set_title(f"Q-Q Plot: {group}")
|
||||
axes[idx].grid(alpha=0.3)
|
||||
|
||||
if plot:
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
return pd.DataFrame(results)
|
||||
|
||||
|
||||
def check_homogeneity_of_variance(
|
||||
data: pd.DataFrame,
|
||||
value_col: str,
|
||||
group_col: str,
|
||||
alpha: float = 0.05,
|
||||
plot: bool = True
|
||||
) -> Dict:
|
||||
"""
|
||||
Check homogeneity of variance using Levene's test.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : pd.DataFrame
|
||||
Data containing values and group labels
|
||||
value_col : str
|
||||
Column name for values
|
||||
group_col : str
|
||||
Column name for group labels
|
||||
alpha : float
|
||||
Significance level
|
||||
plot : bool
|
||||
Whether to create box plots
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
Results including test statistic, p-value, and interpretation
|
||||
"""
|
||||
groups = [group[value_col].values for name, group in data.groupby(group_col)]
|
||||
|
||||
# Levene's test (robust to non-normality)
|
||||
statistic, p_value = stats.levene(*groups)
|
||||
|
||||
# Variance ratio (max/min)
|
||||
variances = [np.var(g, ddof=1) for g in groups]
|
||||
var_ratio = max(variances) / min(variances)
|
||||
|
||||
is_homogeneous = p_value > alpha
|
||||
interpretation = (
|
||||
f"Variances {'appear' if is_homogeneous else 'do not appear'} homogeneous "
|
||||
f"(F = {statistic:.3f}, p = {p_value:.3f}, variance ratio = {var_ratio:.2f})"
|
||||
)
|
||||
|
||||
if plot:
|
||||
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
|
||||
|
||||
# Box plot
|
||||
data.boxplot(column=value_col, by=group_col, ax=ax1)
|
||||
ax1.set_title('Box Plots by Group')
|
||||
ax1.set_xlabel(group_col)
|
||||
ax1.set_ylabel(value_col)
|
||||
plt.sca(ax1)
|
||||
plt.xticks(rotation=45)
|
||||
|
||||
# Variance plot
|
||||
group_names = data[group_col].unique()
|
||||
ax2.bar(range(len(variances)), variances, color='steelblue', edgecolor='black')
|
||||
ax2.set_xticks(range(len(variances)))
|
||||
ax2.set_xticklabels(group_names, rotation=45)
|
||||
ax2.set_ylabel('Variance')
|
||||
ax2.set_title('Variance by Group')
|
||||
ax2.grid(alpha=0.3, axis='y')
|
||||
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
return {
|
||||
'test': 'Levene',
|
||||
'statistic': statistic,
|
||||
'p_value': p_value,
|
||||
'is_homogeneous': is_homogeneous,
|
||||
'variance_ratio': var_ratio,
|
||||
'interpretation': interpretation,
|
||||
'recommendation': (
|
||||
"Proceed with standard test" if is_homogeneous
|
||||
else "Consider Welch's correction or transformation"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def check_linearity(
|
||||
x: Union[np.ndarray, pd.Series],
|
||||
y: Union[np.ndarray, pd.Series],
|
||||
x_name: str = "X",
|
||||
y_name: str = "Y"
|
||||
) -> Dict:
|
||||
"""
|
||||
Check linearity assumption for regression.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
x : array-like
|
||||
Predictor variable
|
||||
y : array-like
|
||||
Outcome variable
|
||||
x_name : str
|
||||
Name of predictor
|
||||
y_name : str
|
||||
Name of outcome
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
Visualization and recommendations
|
||||
"""
|
||||
x = np.asarray(x)
|
||||
y = np.asarray(y)
|
||||
|
||||
# Fit linear regression
|
||||
slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)
|
||||
y_pred = intercept + slope * x
|
||||
|
||||
# Calculate residuals
|
||||
residuals = y - y_pred
|
||||
|
||||
# Visualization
|
||||
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
|
||||
|
||||
# Scatter plot with regression line
|
||||
ax1.scatter(x, y, alpha=0.6, s=50, edgecolors='black', linewidths=0.5)
|
||||
ax1.plot(x, y_pred, 'r-', linewidth=2, label=f'y = {intercept:.2f} + {slope:.2f}x')
|
||||
ax1.set_xlabel(x_name)
|
||||
ax1.set_ylabel(y_name)
|
||||
ax1.set_title('Scatter Plot with Regression Line')
|
||||
ax1.legend()
|
||||
ax1.grid(alpha=0.3)
|
||||
|
||||
# Residuals vs fitted
|
||||
ax2.scatter(y_pred, residuals, alpha=0.6, s=50, edgecolors='black', linewidths=0.5)
|
||||
ax2.axhline(y=0, color='r', linestyle='--', linewidth=2)
|
||||
ax2.set_xlabel('Fitted values')
|
||||
ax2.set_ylabel('Residuals')
|
||||
ax2.set_title('Residuals vs Fitted Values')
|
||||
ax2.grid(alpha=0.3)
|
||||
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
return {
|
||||
'r': r_value,
|
||||
'r_squared': r_value ** 2,
|
||||
'interpretation': (
|
||||
"Examine residual plot. Points should be randomly scattered around zero. "
|
||||
"Patterns (curves, funnels) suggest non-linearity or heteroscedasticity."
|
||||
),
|
||||
'recommendation': (
|
||||
"If non-linear pattern detected: Consider polynomial terms, "
|
||||
"transformations, or non-linear models"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def detect_outliers(
|
||||
data: Union[np.ndarray, pd.Series, List],
|
||||
name: str = "data",
|
||||
method: str = "iqr",
|
||||
threshold: float = 1.5,
|
||||
plot: bool = True
|
||||
) -> Dict:
|
||||
"""
|
||||
Detect outliers using IQR method or z-score method.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : array-like
|
||||
Data to check for outliers
|
||||
name : str
|
||||
Name of variable
|
||||
method : str
|
||||
Method to use: 'iqr' or 'zscore'
|
||||
threshold : float
|
||||
Threshold for outlier detection
|
||||
For IQR: typically 1.5 (mild) or 3 (extreme)
|
||||
For z-score: typically 3
|
||||
plot : bool
|
||||
Whether to create visualizations
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
Outlier indices, values, and visualizations
|
||||
"""
|
||||
data = np.asarray(data)
|
||||
data_clean = data[~np.isnan(data)]
|
||||
|
||||
if method == "iqr":
|
||||
q1 = np.percentile(data_clean, 25)
|
||||
q3 = np.percentile(data_clean, 75)
|
||||
iqr = q3 - q1
|
||||
lower_bound = q1 - threshold * iqr
|
||||
upper_bound = q3 + threshold * iqr
|
||||
outlier_mask = (data_clean < lower_bound) | (data_clean > upper_bound)
|
||||
|
||||
elif method == "zscore":
|
||||
z_scores = np.abs(stats.zscore(data_clean))
|
||||
outlier_mask = z_scores > threshold
|
||||
lower_bound = data_clean.mean() - threshold * data_clean.std()
|
||||
upper_bound = data_clean.mean() + threshold * data_clean.std()
|
||||
|
||||
else:
|
||||
raise ValueError("method must be 'iqr' or 'zscore'")
|
||||
|
||||
outlier_indices = np.where(outlier_mask)[0]
|
||||
outlier_values = data_clean[outlier_mask]
|
||||
n_outliers = len(outlier_indices)
|
||||
pct_outliers = (n_outliers / len(data_clean)) * 100
|
||||
|
||||
if plot:
|
||||
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
|
||||
|
||||
# Box plot
|
||||
bp = ax1.boxplot(data_clean, vert=True, patch_artist=True)
|
||||
bp['boxes'][0].set_facecolor('steelblue')
|
||||
ax1.set_ylabel('Value')
|
||||
ax1.set_title(f'Box Plot: {name}')
|
||||
ax1.grid(alpha=0.3, axis='y')
|
||||
|
||||
# Scatter plot highlighting outliers
|
||||
x_coords = np.arange(len(data_clean))
|
||||
ax2.scatter(x_coords[~outlier_mask], data_clean[~outlier_mask],
|
||||
alpha=0.6, s=50, color='steelblue', label='Normal', edgecolors='black', linewidths=0.5)
|
||||
if n_outliers > 0:
|
||||
ax2.scatter(x_coords[outlier_mask], data_clean[outlier_mask],
|
||||
alpha=0.8, s=100, color='red', label='Outliers', marker='D', edgecolors='black', linewidths=0.5)
|
||||
ax2.axhline(y=lower_bound, color='orange', linestyle='--', linewidth=1.5, label='Bounds')
|
||||
ax2.axhline(y=upper_bound, color='orange', linestyle='--', linewidth=1.5)
|
||||
ax2.set_xlabel('Index')
|
||||
ax2.set_ylabel('Value')
|
||||
ax2.set_title(f'Outlier Detection: {name}')
|
||||
ax2.legend()
|
||||
ax2.grid(alpha=0.3)
|
||||
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
return {
|
||||
'method': method,
|
||||
'threshold': threshold,
|
||||
'n_outliers': n_outliers,
|
||||
'pct_outliers': pct_outliers,
|
||||
'outlier_indices': outlier_indices,
|
||||
'outlier_values': outlier_values,
|
||||
'lower_bound': lower_bound,
|
||||
'upper_bound': upper_bound,
|
||||
'interpretation': f"Found {n_outliers} outliers ({pct_outliers:.1f}% of data)",
|
||||
'recommendation': (
|
||||
"Investigate outliers for data entry errors. "
|
||||
"Consider: (1) removing if errors, (2) winsorizing, "
|
||||
"(3) keeping if legitimate, (4) using robust methods"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
def comprehensive_assumption_check(
|
||||
data: pd.DataFrame,
|
||||
value_col: str,
|
||||
group_col: Optional[str] = None,
|
||||
alpha: float = 0.05
|
||||
) -> Dict:
|
||||
"""
|
||||
Perform comprehensive assumption checking for common statistical tests.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : pd.DataFrame
|
||||
Data to check
|
||||
value_col : str
|
||||
Column name for dependent variable
|
||||
group_col : str, optional
|
||||
Column name for grouping variable (if applicable)
|
||||
alpha : float
|
||||
Significance level
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
Summary of all assumption checks
|
||||
"""
|
||||
print("=" * 70)
|
||||
print("COMPREHENSIVE ASSUMPTION CHECK")
|
||||
print("=" * 70)
|
||||
|
||||
results = {}
|
||||
|
||||
# Outlier detection
|
||||
print("\n1. OUTLIER DETECTION")
|
||||
print("-" * 70)
|
||||
outlier_results = detect_outliers(
|
||||
data[value_col].dropna(),
|
||||
name=value_col,
|
||||
method='iqr',
|
||||
plot=True
|
||||
)
|
||||
results['outliers'] = outlier_results
|
||||
print(f" {outlier_results['interpretation']}")
|
||||
print(f" {outlier_results['recommendation']}")
|
||||
|
||||
# Check if grouped data
|
||||
if group_col is not None:
|
||||
# Normality per group
|
||||
print(f"\n2. NORMALITY CHECK (by {group_col})")
|
||||
print("-" * 70)
|
||||
normality_results = check_normality_per_group(
|
||||
data, value_col, group_col, alpha=alpha, plot=True
|
||||
)
|
||||
results['normality_per_group'] = normality_results
|
||||
print(normality_results.to_string(index=False))
|
||||
|
||||
all_normal = normality_results['Normal'].eq('Yes').all()
|
||||
print(f"\n All groups normal: {'Yes' if all_normal else 'No'}")
|
||||
if not all_normal:
|
||||
print(" → Consider non-parametric alternative (Mann-Whitney, Kruskal-Wallis)")
|
||||
|
||||
# Homogeneity of variance
|
||||
print(f"\n3. HOMOGENEITY OF VARIANCE")
|
||||
print("-" * 70)
|
||||
homogeneity_results = check_homogeneity_of_variance(
|
||||
data, value_col, group_col, alpha=alpha, plot=True
|
||||
)
|
||||
results['homogeneity'] = homogeneity_results
|
||||
print(f" {homogeneity_results['interpretation']}")
|
||||
print(f" {homogeneity_results['recommendation']}")
|
||||
|
||||
else:
|
||||
# Overall normality
|
||||
print(f"\n2. NORMALITY CHECK")
|
||||
print("-" * 70)
|
||||
normality_results = check_normality(
|
||||
data[value_col].dropna(),
|
||||
name=value_col,
|
||||
alpha=alpha,
|
||||
plot=True
|
||||
)
|
||||
results['normality'] = normality_results
|
||||
print(f" {normality_results['interpretation']}")
|
||||
print(f" {normality_results['recommendation']}")
|
||||
|
||||
# Summary
|
||||
print("\n" + "=" * 70)
|
||||
print("SUMMARY")
|
||||
print("=" * 70)
|
||||
|
||||
if group_col is not None:
|
||||
all_normal = results.get('normality_per_group', pd.DataFrame()).get('Normal', pd.Series()).eq('Yes').all()
|
||||
is_homogeneous = results.get('homogeneity', {}).get('is_homogeneous', False)
|
||||
|
||||
if all_normal and is_homogeneous:
|
||||
print("✓ All assumptions met. Proceed with parametric test (t-test, ANOVA).")
|
||||
elif not all_normal:
|
||||
print("✗ Normality violated. Use non-parametric alternative.")
|
||||
elif not is_homogeneous:
|
||||
print("✗ Homogeneity violated. Use Welch's correction or transformation.")
|
||||
else:
|
||||
is_normal = results.get('normality', {}).get('is_normal', False)
|
||||
if is_normal:
|
||||
print("✓ Normality assumption met.")
|
||||
else:
|
||||
print("✗ Normality violated. Consider transformation or non-parametric method.")
|
||||
|
||||
print("=" * 70)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
np.random.seed(42)
|
||||
|
||||
# Simulate data
|
||||
group_a = np.random.normal(75, 8, 50)
|
||||
group_b = np.random.normal(68, 10, 50)
|
||||
|
||||
df = pd.DataFrame({
|
||||
'score': np.concatenate([group_a, group_b]),
|
||||
'group': ['A'] * 50 + ['B'] * 50
|
||||
})
|
||||
|
||||
# Run comprehensive check
|
||||
results = comprehensive_assumption_check(
|
||||
df,
|
||||
value_col='score',
|
||||
group_col='group',
|
||||
alpha=0.05
|
||||
)
|
||||
Reference in New Issue
Block a user