Pandas & NumPy Academy · Lektion

T-tests til sammenligning af middelværdier

Udfør en en-stikprøve-, en uafhængig to-stikprøve- og en parret t-test med scipy.stats, og fortolk konfidensintervaller.

Lektion 2 af 413 trin

T-tests til sammenligning af middelværdier er en gratis Pandas & NumPy Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Pandas & NumPy Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Pandas & NumPy Academy-kurset indeholder 4 lektioner i alt.

Hvad er en t-test?

En t-test er en hypotesetest, der afgør, om en forskel mellem gruppers middelværdier er statistisk signifikant eller sandsynligvis skyldes tilfældigheder. Den sammenligner den observerede forskel med variationen i dataene og frembringer en t-statistik og en p-værdi. Hvis p ≤ 0.05 (den almindelige grænse), afviser vi nulhypotesen om, at middelværdierne er ens. Der findes tre almindelige typer: one-sample, independent two-sample og paired t-test, som hver bruges til forskellige forsøgsdesign.

One-sample t-test

One-sample t-testen tester, om middelværdien for et udsnit afviger signifikant fra en kendt eller hypotetisk populationsmiddelværdi. Eksempel: »Er vores gennemsnitlige leveringstid signifikant forskellig fra branchestandarden på 3 dage?« Brug scipy.stats.ttest_1samp(data, popmean). Nulhypotesen er H₀: mean = popmean. En lille p-værdi får dig til at afvise H₀ og konkludere, at udsnittets middelværdi afviger fra målet.

import numpy as np
from scipy import stats

np.random.seed(42)
# Delivery times in days (true mean is ~3.5, not 3)
delivery_times = np.random.normal(loc=3.5, scale=0.8, size=50)

# Test: is our mean significantly different from 3 days?
stat, p = stats.ttest_1samp(delivery_times, popmean=3.0)
print(f'Sample mean: {delivery_times.mean():.3f}')
print(f't-statistic: {stat:.3f}')
print(f'p-value: {p:.4f}')
print('Differs from 3?', 'Yes' if p < 0.05 else 'No')

Uafhængig two-sample t-test

Den uafhængige t-test for to stikprøver sammenligner gennemsnittene for to uafhængige grupper. For eksempel: »Giver A/B-testvarianten en højere gennemsnitlig omsætning end kontrolgruppen?« Brug scipy.stats.ttest_ind(group_a, group_b). Parameteren equal_var er vigtig: indstil equal_var=False (Welchs t-test), når de to grupper kan have forskellige varianser. Det er det sikre standardvalg for de fleste virkelige datasæt.

import numpy as np
from scipy import stats

np.random.seed(0)
# A/B test revenue per session
control = np.random.normal(loc=25.0, scale=8.0, size=80)
variant = np.random.normal(loc=28.0, scale=9.0, size=80)

# Welch's t-test (does not assume equal variances)
stat, p = stats.ttest_ind(control, variant, equal_var=False)
print(f'Control mean: {control.mean():.2f}')
print(f'Variant mean: {variant.mean():.2f}')
print(f't-statistic: {stat:.3f}')
print(f'p-value: {p:.4f}')
print('Significant difference?', 'Yes' if p < 0.05 else 'No')

Ensidede og tosidede test

Som standard er t-test tosidede: De tester, om gennemsnittene er forskellige i en af retningerne (større ELLER mindre end). Hvis du har en retningsbestemt hypotese (»varianten øger omsætningen«), skal du bruge en ensidet test med parameteren alternative: 'greater' eller 'less'. En ensidet test har større styrke i den specifikke retning, men giver ingen evidens for den modsatte retning. Fastlæg retningen før du ser på dataene, så du undgår HARKing (hypotesedannelse efter kendskab til resultaterne).

import numpy as np
from scipy import stats

np.random.seed(1)
control = np.random.normal(25, 8, 100)
variant = np.random.normal(27, 8, 100)

# Two-tailed (default): does mean differ at all?
stat, p_two = stats.ttest_ind(control, variant, equal_var=False,
                              alternative='two-sided')
# One-tailed: is variant > control?
stat, p_one = stats.ttest_ind(control, variant, equal_var=False,
                              alternative='less')

print(f'Two-tailed p: {p_two:.4f}')
print(f'One-tailed p (variant greater): {p_one:.4f}')

Parret t-test

Den parrede t-test bruges, når hver observation i gruppe A har en naturlig partner i gruppe B — for eksempel målinger før og efter en behandling af de samme forsøgspersoner eller i de samme butikker i to forskellige måneder. Parringen kontrollerer for variation mellem forsøgspersoner, hvilket gør testen mere effektiv end en uafhængig t-test for de samme data. Brug scipy.stats.ttest_rel(before, after). Elementernes rækkefølge skal passe sammen: before[i] og after[i] skal stamme fra den samme forsøgsperson.

import numpy as np
from scipy import stats

np.random.seed(5)
# Blood pressure before and after medication (paired)
before = np.random.normal(130, 10, 30)
after = before - np.random.normal(5, 3, 30)  # Treatment reduces BP by ~5

stat, p = stats.ttest_rel(before, after)
print(f'Mean before: {before.mean():.2f}')
print(f'Mean after: {after.mean():.2f}')
print(f't-statistic: {stat:.3f}')
print(f'p-value: {p:.4f}')
print('Treatment effective?', 'Yes' if p < 0.05 else 'No')

Fortolkning af t-statistikken

t-statistikken måler, hvor mange standardfejl den observerede forskel ligger fra nul. En t-statistik på 2 betyder, at den observerede forskel ligger 2 standardfejl over det, der ville forventes under nulhypotesen. For en tosidet test ved α=0,05 med en stor stikprøve er den kritiske værdi cirka ±1,96 — så |t| > 1,96 giver p < 0,05. p-værdien omdanner t-statistikken til en sandsynlighed, så den bliver lettere at fortolke uden at slå op i tabeller over t-fordelingen.

import numpy as np
from scipy import stats

# Demonstrate relationship between t-statistic and p-value
for t_val in [1.0, 1.96, 2.5, 3.0, 4.0]:
    # degrees of freedom = large sample -> t ~ normal
    p = 2 * stats.t.sf(abs(t_val), df=100)  # two-tailed
    print(f't = {t_val:4.2f} -> p = {p:.4f} '
          f'({'significant' if p < 0.05 else 'not significant'})')

Konfidensintervaller for forskellen mellem gennemsnit

En p-værdi alene fortæller dig ikke noget om effektens størrelse. Beregn altid et konfidensinterval for forskellen mellem gennemsnittene. Et 95 %-KI, der indeholder nul, er foreneligt med p > 0,05 (ikke signifikant); et interval, der ikke indeholder nul, betyder, at forskellen er signifikant. KI'et fortæller også, om effektstørrelsen er praktisk betydningsfuld — en statistisk signifikant forskel på 0,01 $ i omsætning kan være irrelevant, mens en forskel på 50 $ med p=0,06 stadig kan have betydning for virksomheden.

import numpy as np
from scipy import stats

np.random.seed(0)
control = np.random.normal(25, 8, 80)
variant = np.random.normal(28, 8, 80)

diff = variant.mean() - control.mean()
se = np.sqrt(control.var()/len(control) + variant.var()/len(variant))
df = len(control) + len(variant) - 2
t_crit = stats.t.ppf(0.975, df=df)
ci_low = diff - t_crit * se
ci_high = diff + t_crit * se

print(f'Mean difference: {diff:.2f}')
print(f'95% CI: [{ci_low:.2f}, {ci_high:.2f}]')
print('CI excludes zero:', ci_low > 0 or ci_high < 0)

Effektstørrelse: Cohens d

Statistisk signifikans afhænger af stikprøvestørrelsen — med tilstrækkeligt store stikprøver bliver selv ubetydelige forskelle signifikante. Cohens d måler praktisk signifikans (effektstørrelse): forskellen mellem gennemsnittene divideret med den samlede standardafvigelse. Retningslinjer: d < 0,2 er ubetydelig, 0,2–0,5 er lille, 0,5–0,8 er middelstor, og > 0,8 er stor. Rapportér altid effektstørrelsen sammen med p-værdier — en signifikant p-værdi med d = 0,05 betyder, at forskellen er reel, men sandsynligvis ikke praktisk betydningsfuld.

import numpy as np
from scipy import stats

np.random.seed(0)
g1 = np.random.normal(25, 8, 200)
g2 = np.random.normal(28, 8, 200)

stat, p = stats.ttest_ind(g1, g2)

# Cohen's d
pooled_std = np.sqrt((g1.var() + g2.var()) / 2)
cohens_d = (g2.mean() - g1.mean()) / pooled_std

print(f'p-value: {p:.4f}')
print(f'Cohen\'s d: {cohens_d:.3f}')

if cohens_d < 0.2: print('Effect: negligible')
elif cohens_d < 0.5: print('Effect: small')
elif cohens_d < 0.8: print('Effect: medium')
else: print('Effect: large')

Forudsætninger for t-testen

Den uafhængige t-test forudsætter: (1) uafhængighed — observationerne inden for hver gruppe er uafhængige af hinanden; (2) normalitet — dataene i hver gruppe er tilnærmelsesvist normalfordelte (robust for n > 30 via CLT); (3) for Students t-test (equal_var=True), ens varianser. Welchs t-test (equal_var=False) lemper forudsætning 3 og foretrækkes derfor. Når normaliteten er alvorligt overtrådt ved små stikprøver (< 30), skal du i stedet bruge Mann-Whitneys U-test.

import numpy as np
from scipy import stats

np.random.seed(0)
g1 = np.random.normal(10, 2, 30)
g2 = np.random.normal(11, 5, 30)  # Very different variance!

# Levene test for equal variances
stat_l, p_l = stats.levene(g1, g2)
print(f'Levene test p: {p_l:.4f}')
if p_l < 0.05:
    print('Unequal variances -> use Welch\'s (equal_var=False)')
    stat, p = stats.ttest_ind(g1, g2, equal_var=False)
else:
    print('Equal variances OK -> Student\'s t-test')
    stat, p = stats.ttest_ind(g1, g2, equal_var=True)
print(f'Result: t={stat:.3f}, p={p:.4f}')

t-test på Pandas-serier

I praksis ligger de data, du vil teste, i en kolonne i en Pandas DataFrame. Du kan sende en Pandas-serie direkte til funktioner i scipy.stats — de fungerer problemfrit med både serier og NumPy-arrays. En almindelig arbejdsgang er at filtrere DataFrame-en for at hente hver gruppes serie, køre t-testen og gemme resultaterne i en oversigts-DataFrame. Dette mønster kan udvides til at teste mange par af kolonner eller grupper i en løkke.

import pandas as pd
import numpy as np
from scipy import stats

np.random.seed(0)
df = pd.DataFrame({
    'group': ['A']*60 + ['B']*60,
    'revenue': np.concatenate([
        np.random.normal(100, 20, 60),
        np.random.normal(110, 22, 60)
    ])
})

grp_a = df.loc[df['group'] == 'A', 'revenue']
grp_b = df.loc[df['group'] == 'B', 'revenue']

stat, p = stats.ttest_ind(grp_a, grp_b, equal_var=False)
print(f'A mean: {grp_a.mean():.2f}, B mean: {grp_b.mean():.2f}')
print(f'p-value: {p:.4f}')

Problemet med multiple sammenligninger

Hvis du kører mange t-test samtidig, øges risikoen for et falsk positivt resultat. Hvis du kører 20 t-test ved α=0,05, forventer du 1 falsk positivt resultat alene på grund af tilfældigheder. Det er problemet med multiple sammenligninger. Anvend Bonferroni-korrektionen: divider α med antallet af test (p_threshold = 0.05 / n_tests). Du får større styrke med mindre konservatisme ved at bruge Benjamini-Hochbergs korrektion for falske opdagelser (FDR), som findes i statsmodels. Korrigér altid for multiple sammenligninger i A/B-test med mange målinger.

import numpy as np
from scipy import stats

np.random.seed(0)
n_tests = 10
results = []
for i in range(n_tests):
    g1 = np.random.normal(0, 1, 50)
    g2 = np.random.normal(0.1, 1, 50)  # Tiny true effect
    _, p = stats.ttest_ind(g1, g2)
    results.append(p)

print('p-values:', [round(p, 3) for p in results])
bonferroni_thresh = 0.05 / n_tests
print(f'Bonferroni threshold: {bonferroni_thresh}')
print('Significant after Bonferroni:', sum(p < bonferroni_thresh for p in results))

Hurtigt tjek

Test din forståelse af begreberne inden for dataanalyse fra denne lektion.

Opsummering af lektionen

I denne lektion lærte du: ttest_1samp tester et stikprøvegennemsnit mod en referenceværdi, ttest_ind (Welchs med equal_var=False) sammenligner to uafhængige grupper, og ttest_rel håndterer parrede målinger. Rapportér altid Cohens d sammen med p-værdien for at skelne mellem statistisk og praktisk signifikans. Dernæst tester vi relationer mellem kategoriske variabler med chi-i-anden-testen.

Gratis at komme i gang

Lær Python med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
30
Lektioner
120

Ofte stillede spørgsmål

Er lektionen “T-tests til sammenligning af middelværdier” gratis?

Ja — hele teksten til “T-tests til sammenligning af middelværdier” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Pandas & NumPy Academy-kurset, skal du opgradere til CoddyKit PRO. Pandas & NumPy Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “T-tests til sammenligning af middelværdier”?

Udfør en en-stikprøve-, en uafhængig to-stikprøve- og en parret t-test med scipy.stats, og fortolk konfidensintervaller. Du øver dig i Pandas & NumPy Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Pandas & NumPy Academy?

Der kræves ingen tidligere erfaring. Pandas & NumPy Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.

Hvor lang tid tager lektionen “T-tests til sammenligning af middelværdier”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Pandas & NumPy Academy-lektion?

Ja. Alle Pandas & NumPy Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Deskriptiv statistik og test af normalitet
  2. T-tests til sammenligning af middelværdier
  3. Chi-i-anden-test for uafhængighed
  4. ANOVA og post-hoc-test
← Tilbage til Pandas & NumPy Academy