| name | statistical-testing |
| description | Select and run the correct hypothesis test based on data properties. Covers parametric/non-parametric tests, effect sizes, and multiple comparison correction.
|
| tags | ["statistics","hypothesis-testing","scipy","effect-size","multiple-comparisons","power-analysis"] |
| version | 1.0.0 |
| authors | [{"name":"awesome-rosetta-skills contributors","github":"@awesome-rosetta-skills"}] |
| license | MIT |
| platforms | ["claude-code","codex","gemini-cli","cursor"] |
| dependencies | {"python":["scipy>=1.10.0","numpy>=1.24.0","pandas>=2.0.0","statsmodels>=0.14.0","pingouin>=0.5.3"]} |
| last_updated | 2026-03-17 |
Statistical Testing
Choose and execute the right statistical test for your data. This skill covers
normality checks, parametric and non-parametric tests, effect size computation,
and multiple comparison correction.
Decision Tree
| Scenario | Groups | Normal? | Recommended Test |
|---|
| Compare means | 2 independent | Yes | Independent t-test |
| Compare means | 2 independent | No | Mann-Whitney U |
| Compare means | 2 paired | Yes | Paired t-test |
| Compare means | 2 paired | No | Wilcoxon signed-rank |
| Compare means | ≥3 independent | Yes | One-way ANOVA |
| Compare means | ≥3 independent | No | Kruskal-Wallis |
| Compare means | ≥3 repeated | Yes | Repeated-measures ANOVA |
| Compare means | ≥3 repeated | No | Friedman test |
| Association | 2 categorical | Expected ≥5 | Chi-square |
| Association | 2 categorical | Expected <5 | Fisher exact |
| Correlation | 2 continuous | Both normal | Pearson r |
| Correlation | 2 continuous | Non-normal | Spearman ρ |
Setup
pip install scipy numpy pandas statsmodels pingouin
Core Implementation
"""
statistical_testing.py
Complete statistical testing toolkit with automatic test selection.
"""
import warnings
import numpy as np
import pandas as pd
from scipy import stats
from statsmodels.stats import multitest
statsmodels.stats.power TTestIndPower, FTestAnovaPower
typing , , , , ,
() -> [, ]:
data = np.asarray(data, dtype=)
data = data[~np.isnan(data)]
n = (data)
results: [, ] = {}
n < :
stat_sw, p_sw = stats.shapiro(data)
results[] = {: stat_sw, : p_sw, : p_sw > alpha}
:
results[] = {: , : , : ,
: }
mu, sigma = np.mean(data), np.std(data, ddof=)
stat_ks, p_ks = stats.kstest(data, , args=(mu, sigma))
results[] = {: stat_ks, : p_ks, : p_ks > alpha}
n >= :
stat_da, p_da = stats.normaltest(data)
results[] = {: stat_da, : p_da, : p_da > alpha}
:
results[] = {: , : , : ,
: }
votes = [v[] v results.values() (v, ) v[] ]
results[] = (votes) >= ((votes) / )
results[] = n
verbose:
()
test_name, res results.items():
(res, ) res res[] :
verdict = res[]
()
()
results
() -> :
g1, g2 = np.asarray(group1), np.asarray(group2)
n1, n2 = (g1), (g2)
pooled_sd = np.sqrt(((n1 - ) * np.var(g1, ddof=) + (n2 - ) * np.var(g2, ddof=)) / (n1 + n2 - ))
(np.mean(g1) - np.mean(g2)) / pooled_sd
() -> :
ss_between = f_statistic * df_between
ss_total = ss_between + df_within
ss_between / ss_total
() -> :
chi2 = stats.chi2_contingency(contingency_table, correction=)[]
n = contingency_table.()
min_dim = (contingency_table.shape) -
np.sqrt(chi2 / (n * min_dim))
() -> :
thresholds = {
: [(, ), (, ), (, )],
: [(, ), (, ), (, )],
: [(, ), (, ), (, )],
}
d = (d)
threshold, label thresholds.get(measure, []):
d < threshold:
label
() -> [, ]:
groups = [np.asarray(g, dtype=) g groups]
k = (groups)
k < :
ValueError()
all_normal = (test_normality(g, alpha=alpha, verbose=)[] g groups)
result: [, ] = {}
k == :
g1, g2 = groups[], groups[]
paired:
all_normal:
stat, p = stats.ttest_rel(g1, g2)
result[] =
d = np.mean(g1 - g2) / np.std(g1 - g2, ddof=)
result[] = {: (d, )}
:
stat, p = stats.wilcoxon(g1, g2)
result[] =
result[] = {: ( - ( * stat) / ((g1) * ((g1) + )), )}
:
_, p_levene = stats.levene(g1, g2)
equal_var = p_levene > alpha
all_normal:
stat, p = stats.ttest_ind(g1, g2, equal_var=equal_var)
result[] =
d = cohens_d(g1, g2)
result[] = {: (d, ),
: interpret_effect_size(d)}
:
stat, p = stats.mannwhitneyu(g1, g2, alternative=)
result[] =
n1, n2 = (g1), (g2)
rb = - ( * stat) / (n1 * n2)
result[] = {: (rb, )}
:
paired:
all_normal:
:
pingouin pg
df_long = pd.DataFrame({
: np.concatenate(groups),
: np.repeat(np.arange(k), [(g) g groups]),
: np.tile(np.arange((groups[])), k),
})
aov = pg.rm_anova(data=df_long, dv=, within=, subject=)
stat = aov[].iloc[]
p = aov[].iloc[]
result[] =
result[] = {: (aov[].iloc[], )}
ImportError:
warnings.warn()
stat, p = stats.friedmanchisquare(*groups)
result[] =
result[] = {}
:
stat, p = stats.friedmanchisquare(*groups)
result[] =
result[] = {}
:
all_normal:
stat, p = stats.f_oneway(*groups)
result[] =
total_n = ((g) g groups)
df_between = k -
df_within = total_n - k
es = eta_squared(stat, df_between, df_within)
result[] = {: (es, ),
: interpret_effect_size(es, )}
:
stat, p = stats.kruskal(*groups)
result[] =
result[] = {}
result[] = ((stat), )
result[] = ((p), )
result[] = p < alpha
result[] = alpha
verbose:
()
()
()
result.get():
()
()
result
() -> pd.DataFrame:
reject, p_corrected, _, _ = multitest.multipletests(p_values, alpha=alpha, method=method)
pd.DataFrame({
: p_values,
: p_corrected,
: reject,
: method,
})
() -> [, ]:
analysis = TTestIndPower()
n_per_group :
n = analysis.solve_power(effect_size=effect_size, alpha=alpha, power=power, ratio=)
{: np.ceil(n), : effect_size,
: alpha, : power}
:
achieved_power = analysis.solve_power(effect_size=effect_size, alpha=alpha,
nobs1=n_per_group, ratio=)
{: n_per_group, : effect_size,
: alpha, : (achieved_power, )}
() -> [, ]:
chi2, p, dof, expected = stats.chi2_contingency(contingency)
v = cramers_v(contingency)
result = {
: expected.() >= ,
: (chi2, ),
: (p, ),
: dof,
: (v, ),
: p < alpha,
}
expected.() < :
contingency.shape == (, ):
_, p_fisher = stats.fisher_exact(contingency)
result[] = (p_fisher, )
result