Štatistické testovanie hypotéz v Pythone: SciPy 1.15 sprievodca pre rok 2026
Praktický sprievodca štatistickým testovaním hypotéz v SciPy 1.15. T-testy, ANOVA, Wilcoxon, chi-square, veľkosť efektu, korekcia pre viacnásobné porovnania a moderné bootstrap a permutačné metódy.
Štatistické testovanie hypotéz v Pythone znamená pomocou modulu scipy.stats zistiť, či rozdiel medzi pozorovanými dátami a očakávaným modelom (nulovou hypotézou) je štatisticky významný, alebo len šumom náhody. V SciPy 1.15 stačia dve-tri riadky kódu: scipy.stats.ttest_ind, mannwhitneyu alebo f_oneway vrátia p-hodnotu a testovú štatistiku. V tomto sprievodcovi si prejdeme, ako správne vybrať test, overiť predpoklady, interpretovať p-hodnotu spolu s veľkosťou efektu a korigovať výsledky pri viacnásobných porovnaniach.
SciPy 1.15 poskytuje viac ako 90 štatistických testov v module scipy.stats, od klasického Studentovho t-testu až po permutačné testy a bootstrap intervaly spoľahlivosti.
Výber testu závisí od typu dát (spojité vs. kategoriálne), počtu skupín a splnenia predpokladov (normalita, rovnaké rozptyly, nezávislosť pozorovaní).
Parametrické testy (t-test, ANOVA) majú vyššiu silu, ak sú splnené predpoklady; neparametrické (Wilcoxon, Mann-Whitney U, Kruskal-Wallis) sú odolnejšie voči odľahlým hodnotám.
P-hodnota < 0.05 nie je dôkaz vedeckej relevancie. Vždy uvádzajte aj veľkosť efektu (Cohen's d, η²) a interval spoľahlivosti.
Pri viacnásobných porovnaniach použite scipy.stats.false_discovery_control (Benjamini–Hochberg) alebo Bonferroni-Holmovu korekciu, inak dramaticky rastie miera falošných pozitív.
Moderné alternatívy (bootstrap cez scipy.stats.bootstrap, permutačné testy s permutation_test a bayesovský prístup v PyMC 5.x) obchádzajú väčšinu predpokladov klasického frekventistického rámca.
Základné pojmy: nulová hypotéza, p-hodnota a chyby I. a II. druhu
Skôr než napíšeme prvý riadok kódu, potrebujeme spoločný slovník. Nulová hypotéza (H₀) je tvrdenie o rovnosti alebo absencii efektu, napríklad „priemerná doba odozvy je rovnaká pre variantu A aj B". Alternatívna hypotéza (H₁) je jej opak. Test nemôže dokázať, že H₀ platí; môže ju iba zamietnuť, alebo nezamietnuť.
P-hodnota je pravdepodobnosť, že by sme za predpokladu platnosti H₀ pozorovali dáta rovnako alebo extrémnejšie, ako sme pozorovali. Nie je to pravdepodobnosť, že H₀ platí. Ide o bežnú dezinterpretáciu, ktorú Americká štatistická asociácia formálne odmietla v stanovisku ASA z roku 2016 o p-hodnotách. Ak p < α (typicky 0.05), zamietame H₀. Prah 0.05 je konvenčný, nie posvätný; genetika používa 5×10⁻⁸, fyzika 5σ (~3×10⁻⁷).
Rozlišujeme dva druhy chýb. Chyba I. druhu (α) zamietne H₀, keď skutočne platí (falošne pozitívny výsledok). Chyba II. druhu (β) nezamietne H₀, keď v skutočnosti neplatí (falošne negatívny). Sila testu = 1 − β. Vo väčšine biomedicínskych štúdií cielime na silu aspoň 0.80 pri α = 0.05. SciPy nemá vstavaný analytický kalkulátor sily, ale balík statsmodels ho poskytuje cez statsmodels.stats.power.
Ako vybrať správny štatistický test pre vaše dáta
Výber testu je najčastejšia otázka na Stack Overflow aj v mojich konzultáciách. Úprimne, kolegov to spomaľuje viac než samotné písanie kódu. Pomôže systematický rozhodovací strom postavený na štyroch otázkach: (1) čo porovnávam, teda jednu vzorku s hodnotou, dve skupiny, alebo viac skupín? (2) sú dáta spojité, ordinálne alebo kategoriálne? (3) sú pozorovania nezávislé, alebo párované? (4) sú splnené parametrické predpoklady (normalita, homoskedasticita)?
Nižšie uvedená tabuľka mapuje typické scenáre na funkcie SciPy 1.15. Odporúčam ju vytlačiť a nalepiť pri monitore.
Scenár
Parametrický test
Neparametrická alternatíva
Funkcia SciPy
Jedna vzorka vs. referenčná hodnota
Jednosample t-test
Wilcoxonov znamienkový test
ttest_1samp / wilcoxon
Dve nezávislé skupiny, spojité dáta
Studentov / Welchov t-test
Mann-Whitney U
ttest_ind / mannwhitneyu
Dve párované merania
Párový t-test
Wilcoxonov test súčtov poradí
ttest_rel / wilcoxon
3+ nezávislé skupiny
Jednofaktorová ANOVA
Kruskal-Wallis
f_oneway / kruskal
3+ párované merania
Opakovanoodberová ANOVA
Friedmanov test
friedmanchisquare
Dve kategoriálne premenné
Chi-square nezávislosti
Fisherov exaktný test (2×2)
chi2_contingency / fisher_exact
Korelácia spojitých premenných
Pearsonov r
Spearmanov ρ / Kendallovo τ
pearsonr / spearmanr
V praxi ju kombinujem s predbežnou vizualizáciou. Ak potrebujete rýchlo pripraviť histogramy, QQ-ploty alebo boxploty, pozrite si nášho sprievodcu vizualizáciou dát v Matplotlib 3.10 a Seaborn. Obsahuje šablóny presne pre diagnostické grafy pred testovaním hypotéz.
Kontrola predpokladov: testy normality a rovnakých rozptylov
Parametrické testy predpokladajú, že dáta pochádzajú z normálneho rozdelenia a (pri porovnaní skupín) že skupiny majú porovnateľné rozptyly. SciPy ponúka niekoľko diagnostík. Shapiro-Wilkov test (scipy.stats.shapiro) je štandard pre vzorky do ~5000 pozorovaní. D'Agostino-Pearsonov test (normaltest) je vhodnejší pre väčšie vzorky a citlivý na šikmosť aj špicatosť. Kolmogorov-Smirnovov test (kstest) sa hodí, keď porovnávame s ľubovoľným teoretickým rozdelením, nie len normálnym.
import numpy as np
from scipy import stats
rng = np.random.default_rng(seed=2026)
sample = rng.normal(loc=100, scale=15, size=200)
# Shapiro-Wilk - nulová hypotéza: dáta sú z normálneho rozdelenia
stat, p = stats.shapiro(sample)
print(f"Shapiro-Wilk W = {stat:.4f}, p = {p:.4f}")
# D'Agostino-Pearson
stat, p = stats.normaltest(sample)
print(f"K^2 = {stat:.4f}, p = {p:.4f}")
# Q-Q plot pre vizuálnu kontrolu (spolu s matplotlib)
import matplotlib.pyplot as plt
stats.probplot(sample, dist="norm", plot=plt)
plt.title("Q-Q plot voci normalnemu rozdeleniu")
plt.tight_layout()
plt.savefig("qq_plot.png", dpi=150)
Pre rovnosť rozptylov (homoskedasticita) použite scipy.stats.levene alebo odolnejší bartlett. Ak Levene zamietne rovnosť, prepnite z klasického Studentovho t-testu na Welchov (parameter equal_var=False), ktorý je od SciPy 1.6 predvolený.
T-testy v SciPy: jedno-, dvojvýberové, párové a Welchov test
T-test je najčastejšie používaný parametrický test. V SciPy máme tri varianty: ttest_1samp pre porovnanie jednej vzorky s referenčnou hodnotou, ttest_ind pre dve nezávislé skupiny a ttest_rel pre párované dáta (napr. „pred a po" merania na tých istých jedincoch). Od SciPy 1.10 majú všetky t-testy jednotný parameter alternative pre jednostranné vs. dvojstranné hypotézy a od 1.14 vracajú pomenované atribúty vrátane confidence_interval().
import numpy as np
from scipy import stats
rng = np.random.default_rng(2026)
# Dvojvyberovy Welchov t-test (equal_var=False je predvolene spravanie
# pri odporucani od SciPy 1.6+, ked rozptyly nemozu byt predpokladom)
kontrola = rng.normal(72, 8, size=45) # priemerne skore kontrolnej skupiny
experiment = rng.normal(76, 10, size=48) # experimentalna skupina
result = stats.ttest_ind(experiment, kontrola, equal_var=False,
alternative="greater")
print(f"t = {result.statistic:.3f}")
print(f"p = {result.pvalue:.4f}")
print(f"95% CI: {result.confidence_interval(confidence_level=0.95)}")
# Parovy t-test - napr. trening modelu pred a po ladeni hyperparametrov
pred = rng.normal(0.82, 0.03, size=30)
po = pred + rng.normal(0.01, 0.02, size=30)
result = stats.ttest_rel(po, pred, alternative="greater")
print(f"parovy t = {result.statistic:.3f}, p = {result.pvalue:.4f}")
Rozdiel medzi Studentovým a Welchovým testom je kľúčový. Studentov predpokladá rovnaké rozptyly a je citlivejší, keď sú tie skutočne rovnaké; Welchov je spoľahlivý pri nerovnakých rozptyloch aj nerovnakých veľkostiach skupín. Priznám sa, že v poslednom A/B experimente pre fintech klienta som na tomto rozdieli zbytočne stratil dva dni: Studentov test dával „významné" p, no keď som prepol na Welch, efekt sa rozplynul. Simulácie z posledných dvoch dekád (napr. Delacre et al., 2017) odporúčajú Welchov ako predvolenú voľbu. Riziko chyby I. druhu je stabilnejšie a strata sily minimálna.
Neparametrické alternatívy: Wilcoxon, Mann-Whitney U a Kruskal-Wallis
Kedy použiť parametrické vs neparametrické testy? Keď dáta výrazne porušujú normalitu, obsahujú vplyvné odľahlé hodnoty, alebo sú ordinálne (napr. Likertove škály), siahnite po neparametrických metódach. Nepracujú s pôvodnými hodnotami, ale s poradiami, a preto sú odolnejšie.
Mann-Whitneyho U test (mannwhitneyu) je neparametrická obdoba dvojvýberového t-testu. Testuje, či pozorovanie z jednej skupiny má systematicky vyšší poradie než z druhej. Wilcoxonov test (wilcoxon) rieši párované vzorky. Kruskal-Wallis (kruskal) rozširuje Mann-Whitney na tri a viac skupín. Ide o neparametrický ekvivalent jednofaktorovej ANOVA.
import numpy as np
from scipy import stats
rng = np.random.default_rng(2026)
# Silne sikme data - parametricky test by bol menej spolahlivy
group_a = rng.lognormal(mean=0, sigma=1, size=60)
group_b = rng.lognormal(mean=0.3, sigma=1, size=55)
u_res = stats.mannwhitneyu(group_a, group_b, alternative="two-sided")
print(f"Mann-Whitney U = {u_res.statistic:.1f}, p = {u_res.pvalue:.4f}")
# Kruskal-Wallis pre 4 modely klasifikatorov (napr. F1-skore napriec
# 20 opakovaniami krizovej validacie)
model_scores = [rng.beta(8, 2, 20) for _ in range(4)]
h_res = stats.kruskal(*model_scores)
print(f"H = {h_res.statistic:.3f}, p = {h_res.pvalue:.4f}")
ANOVA a chi-square: viac skupín a kategoriálne dáta
Jednofaktorová ANOVA (f_oneway) testuje, či priemery troch a viac skupín sú rovnaké. Ak F-štatistika ukáže významný rozdiel, potrebujete post-hoc test (Tukey HSD z statsmodels.stats.multicomp), pretože ANOVA sama nevie povedať, ktoré páry sa líšia. Pri porušení homoskedasticity použite Welchovu ANOVA (scipy.stats.alexandergovern od 1.7 alebo pingouin.welch_anova).
Chi-square test nezávislosti (chi2_contingency) skúma vzťah dvoch kategoriálnych premenných v kontingenčnej tabuľke. Pri malých očakávaných početnostiach (bunky < 5) prepnite na Fisherov exaktný test (fisher_exact) pre 2×2 tabuľky alebo Boschloov exaktný test (boschloo_exact, dostupný v SciPy 1.7+).
Pri budovaní klasifikačných modelov sa chi-square využíva aj na výber prediktorov. Ak trénujete pipeline v scikit-learn, kombinujte SciPy testy s SelectKBest(chi2, k=20). Kompletný workflow rozoberáme v našom sprievodcovi ML pipeline v Scikit-learn 1.8.
Veľkosť efektu a intervaly spoľahlivosti, prečo p-hodnota nestačí
P-hodnota vám povie, či efekt existuje, ale nie ako veľký je. Pri veľkých vzorkách bude štatisticky významný aj triviálny rozdiel priemerov. Preto akadémia aj priemyselný reporting (napr. odporúčania APA 7. vydanie) vyžadujú vždy uvádzať aj veľkosť efektu a interval spoľahlivosti.
Pre porovnanie dvoch skupín je štandardom Cohenov d, teda rozdiel priemerov delený spoločnou smerodajnou odchýlkou. Konvenčné hranice: 0.2 malý, 0.5 stredný, 0.8 veľký efekt. Pre ANOVA sa používa η² (eta squared) alebo odolnejšie ω² (omega squared). Chi-square má Cramérovo V. SciPy 1.15 samo poskytuje niektoré veľkosti efektu cez scipy.stats.tmean a pomocné funkcie, no komplexnejšie miery ponúka balík pingouin.
import numpy as np
from scipy import stats
def cohens_d(a, b):
"""Cohenov d s poolovanou smerodajnou odchylkou."""
n1, n2 = len(a), len(b)
s_pooled = np.sqrt(((n1-1)*np.var(a, ddof=1) +
(n2-1)*np.var(b, ddof=1)) / (n1+n2-2))
return (np.mean(a) - np.mean(b)) / s_pooled
rng = np.random.default_rng(2026)
a = rng.normal(100, 15, 500)
b = rng.normal(103, 15, 500)
t = stats.ttest_ind(a, b, equal_var=False)
d = cohens_d(a, b)
print(f"p = {t.pvalue:.4g}") # takmer isto vyznamne pri n=500 na stranu
print(f"Cohen's d = {d:.3f}") # ~0.20, maly efekt, mozno prakticky irelevantny
print(f"95% CI: {t.confidence_interval()}")
Korekcia pre viacnásobné porovnania: Bonferroni, Holm a Benjamini–Hochberg
Ako opraviť pre viacnásobné porovnania v Pythone? Pri α = 0.05 a jednom teste akceptujeme 5% šancu falošne pozitívneho výsledku. Ak však spustíte 20 nezávislých testov, pravdepodobnosť aspoň jednej falošnej pozitivity vzrastie na ~64%. To je jadro problému viacnásobného testovania, kľúčové v genomike, A/B experimentoch a klinických štúdiách.
SciPy 1.11 pridalo scipy.stats.false_discovery_control, ktorá implementuje Benjamini-Hochbergovu (BH) kontrolu falošných objavov (FDR). Bonferroniho korekciu a Holm-Bonferroniho ponúka statsmodels.stats.multitest.multipletests. BH je vhodné pre exploratívne analýzy, kde tolerujete istú mieru chýb; Bonferroni pre potvrdzujúce testy, kde je každá falošná pozitivita drahá.
import numpy as np
from scipy import stats
from statsmodels.stats.multitest import multipletests
rng = np.random.default_rng(2026)
# 40 A/B testov, z ktorych 5 ma realny efekt
pvals = []
for i in range(40):
a = rng.normal(0, 1, 200)
b = rng.normal(0.5 if i < 5 else 0, 1, 200)
pvals.append(stats.ttest_ind(a, b).pvalue)
pvals = np.array(pvals)
# Benjamini-Hochberg cez SciPy
q_bh = stats.false_discovery_control(pvals, method="bh")
# Bonferroni-Holm cez statsmodels
reject, p_adj_holm, _, _ = multipletests(pvals, alpha=0.05, method="holm")
print(f"BH signifikantnych (q < 0.05): {(q_bh < 0.05).sum()}")
print(f"Holm signifikantnych: {reject.sum()}")
Moderné alternatívy: bootstrap, permutačné testy a bayesovský prístup
Klasické t-testy a ANOVA sú optimálne, keď platia predpoklady. Keď neplatia, a v priemysle často neplatia, moderné výpočtové metódy poskytujú spoľahlivejšie intervaly a p-hodnoty priamo z dát. SciPy 1.7+ pridalo dve mimoriadne užitočné funkcie: scipy.stats.bootstrap a scipy.stats.permutation_test. Detaily nájdete v oficiálnej dokumentácii scipy.stats.
Bootstrap odhadne rozdelenie štatistiky opakovaným vzorkovaním s návratom. Funguje pre ľubovoľnú štatistiku (medián, korelácia, kvantily) bez potreby uzavretej formy. Permutačný test odhadne nulové rozdelenie pretasovaním nálepiek skupiny. Je exaktný a nezávislý od distribučných predpokladov, pokiaľ platí výmennosť (exchangeability).
import numpy as np
from scipy import stats
rng = np.random.default_rng(2026)
a = rng.gamma(2, 3, size=60) # asymetricke, tazky chvost
b = rng.gamma(2.4, 3, size=60)
# Bootstrap 95% CI pre rozdiel medianov
res = stats.bootstrap(
(a, b),
statistic=lambda x, y: np.median(x) - np.median(y),
n_resamples=10_000,
method="BCa",
random_state=rng,
)
print("95% CI pre rozdiel medianov:", res.confidence_interval)
# Permutacny test - porovnanie priemerov bez predpokladu normality
perm = stats.permutation_test(
(a, b),
statistic=lambda x, y: np.mean(x) - np.mean(y),
n_resamples=10_000,
alternative="two-sided",
random_state=rng,
)
print(f"Permutacna p-hodnota = {perm.pvalue:.4f}")
Pre komplexnejšie modely (hierarchické štruktúry, chýbajúce dáta ako parametre alebo apriórne informácie) je vhodný bayesovský rámec. Odporúčam PyMC 5.x (bývalé PyMC3) a knižnicu arviz na diagnostiku. Bayesovský ekvivalent t-testu (BEST od Kruschkeho) poskytuje distribúciu pravdepodobných rozdielov priamo, bez p-hodnôt, čo býva pre stakeholderov jednoduchšie na interpretáciu.
Pri porovnávaní verzií SciPy sledujte GitHub SciPy release notes. Verzia 1.15 (január 2025) priniesla vylepšené Axis-Aware správanie pre všetky testy a nová verzia 1.16 stabilizovala scipy.stats.MonteCarloMethod. Ak nasadzujete produkčné pipelines, pripnite verziu explicitne, pretože niekoľko starších testov (napríklad kendalltau) zmenilo predvolený režim spracovania NaN. Túto lekciu som dostal tvrdo, keď mi po `pip install --upgrade scipy` prestal fungovať CI pipeline pre klientský projekt.
Často kladené otázky
Čo je p-hodnota a ako ju správne interpretovať?
P-hodnota je pravdepodobnosť pozorovania dát aspoň takých extrémnych ako naše, za predpokladu platnosti nulovej hypotézy. Nie je to pravdepodobnosť, že H₀ je pravdivá, ani pravdepodobnosť náhody. Nízka p-hodnota (napr. < 0.05) znamená, že dáta zle zapadajú do nulovej hypotézy. Vždy ju spájajte s veľkosťou efektu a intervalom spoľahlivosti.
Aký je rozdiel medzi t-testom a z-testom?
Z-test predpokladá známy populačný rozptyl a normálne rozdelenie, čo je v praxi zriedkavý predpoklad. T-test odhaduje rozptyl zo vzorky a používa Studentovo t-rozdelenie, ktoré má ťažšie chvosty pri malých n. V SciPy použite scipy.stats.ttest_ind; z-testy poskytuje modul statsmodels.stats.weightstats, keď máte skutočne známy sigma.
Kedy použiť Welchov t-test namiesto klasického Studentovho?
Vždy, keď si nemôžete byť istý, že skupiny majú rovnaké rozptyly, alebo majú nerovnaké veľkosti. Delacre, Lakens a Leys (2017) ukazujú, že Welchov test kontroluje chybu I. druhu stabilnejšie a stráca minimum sily, keď sú rozptyly rovnaké. V SciPy nastavte equal_var=False. Od verzie 1.6 je to preferované predvolené správanie.
Ako opraviť pre viacnásobné porovnania v Pythone?
Použite scipy.stats.false_discovery_control(pvals, method="bh") pre Benjamini-Hochbergovu kontrolu falošných objavov v exploratívnych analýzach, alebo statsmodels.stats.multitest.multipletests(pvals, method="holm") pre konzervatívnu Bonferroni-Holmovu korekciu v potvrdzujúcich testoch. BH je vhodné pri stovkách testov (genomika); Holm pri desiatkach.
Ktorý test použiť pre malú vzorku (n < 30)?
Pri malých vzorkách sa testy normality môžu mýliť. Ak vizuálna Q-Q analýza podporuje normálne rozdelenie, použite klasický t-test. Je spoľahlivý pri miernych odchýlkach. Ak dáta sú zjavne šikmé alebo ordinálne, prepnite na Mann-Whitney U alebo Wilcoxonov test. Pre exaktné výsledky bez asymptotických aproximácií je bezpečnou voľbou permutačný test cez scipy.stats.permutation_test.
DuckDB 1.5 mení pravidlá hry pre Python analytiku v roku 2026. Pozrite sa, ako ho prepojiť s Pandas, čítať Parquet bez načítania do pamäte a postaviť ETL pipeline 50× rýchlejšiu ako čistý Pandas — bez servera, bez Sparku.
Praktický sprievodca vizualizáciou dát v Pythone s Matplotlib 3.10 a Seaborn 0.13. Základné aj pokročilé grafy, subplot_mosaic, Objects rozhranie, integrácia s Pandas 3.0 a vizualizácia ML výsledkov.