Š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.

Testovanie hypotéz v SciPy 1.15 (2026)

Aktualizované: 12. júla 2026

Š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árParametrický testNeparametrická alternatívaFunkcia SciPy
Jedna vzorka vs. referenčná hodnotaJednosample t-testWilcoxonov znamienkový testttest_1samp / wilcoxon
Dve nezávislé skupiny, spojité dátaStudentov / Welchov t-testMann-Whitney Uttest_ind / mannwhitneyu
Dve párované meraniaPárový t-testWilcoxonov test súčtov poradíttest_rel / wilcoxon
3+ nezávislé skupinyJednofaktorová ANOVAKruskal-Wallisf_oneway / kruskal
3+ párované meraniaOpakovanoodberová ANOVAFriedmanov testfriedmanchisquare
Dve kategoriálne premennéChi-square nezávislostiFisherov exaktný test (2×2)chi2_contingency / fisher_exact
Korelácia spojitých premennýchPearsonov rSpearmanov ρ / 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+).

import numpy as np
from scipy import stats

# ANOVA: priemerny cas ucenia troch algoritmov (sekundy)
xgb   = np.array([42, 45, 40, 44, 43, 46, 41])
lgbm  = np.array([38, 36, 39, 37, 40, 35, 39])
cat   = np.array([44, 47, 43, 46, 45, 48, 44])

f_stat, p = stats.f_oneway(xgb, lgbm, cat)
print(f"F = {f_stat:.3f}, p = {p:.5f}")

# Chi-square: konverzia (ano/nie) napriec tromi zdrojmi navstevnosti
table = np.array([[210, 190],   # organicky
                  [180, 220],   # plateny
                  [230, 170]])  # e-mail

chi2, p, dof, expected = stats.chi2_contingency(table)
print(f"chi^2 = {chi2:.3f}, dof = {dof}, p = {p:.5f}")

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.

Dr. Elena Vasquez
O Autorovi Dr. Elena Vasquez

Data scientist with a PhD in computational statistics. Translates papers into pandas one notebook at a time.