ANOVA und Post-hoc-Tests
Vergleichen Sie Mittelwerte von drei oder mehr Gruppen mit einer einfaktoriellen ANOVA und führen Sie den Tukey-HSD-Test durch, um unterschiedliche Paare zu identifizieren.
ANOVA und Post-hoc-Tests ist eine kostenlose Pandas & NumPy Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Pandas & NumPy Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Pandas & NumPy Academy-Kurs umfasst insgesamt 4 Lektionen.
Warum nicht mehrere t-Tests?
Beim Vergleich von Mittelwerten über drei oder mehr Gruppen hinweg erhöht die Durchführung mehrerer t-Tests die Fehlerquote 1. Art (Falsch-Positiv-Rate). Wenn Sie die Gruppen A vs. B, A vs. C und B vs. C jeweils mit α=0,05 testen, liegt die Wahrscheinlichkeit eines Falsch-Positiv-Ergebnisses insgesamt bei etwa 14 % und nicht bei 5 %. Die Varianzanalyse (ANOVA) löst dieses Problem, indem sie alle Gruppen gleichzeitig in einem einzigen Test prüft und die Falsch-Positiv-Rate exakt bei α hält. Eine ANOVA ersetzt für die Omnibus-Frage „Unterscheiden sich einige Gruppen?“ alle paarweisen t-Tests.
Einfaktorielle ANOVA: Der große Überblick
Die einfaktorielle ANOVA prüft, ob sich die Mittelwerte von drei oder mehr Gruppen signifikant unterscheiden. Sie zerlegt die Gesamtvarianz in die Varianz zwischen den Gruppen (erklärt durch die Gruppenzugehörigkeit) und die Varianz innerhalb der Gruppen (zufälliges Rauschen). Die F-Statistik ist ihr Verhältnis: F = (Varianz zwischen den Gruppen) / (Varianz innerhalb der Gruppen). Ein großer F-Wert bedeutet, dass die Gruppenunterschiede im Verhältnis zum Rauschen groß sind, was zu einem kleinen p-Wert führt. Die Nullhypothese lautet H₀: Alle Gruppenmittelwerte sind gleich.
import numpy as np
from scipy import stats
np.random.seed(0)
# Three product variants with different conversion rates
group_a = np.random.normal(10.0, 2.0, 50) # baseline
group_b = np.random.normal(11.5, 2.0, 50) # slightly better
group_c = np.random.normal(13.0, 2.0, 50) # clearly better
f_stat, p = stats.f_oneway(group_a, group_b, group_c)
print(f'F-statistic: {f_stat:.3f}')
print(f'p-value: {p:.6f}')
print('At least one group differs?', 'Yes' if p < 0.05 else 'No')ANOVA mit Pandas DataFrames
In der Praxis liegen Ihre Daten in einem DataFrame im Long-Format vor: Eine Spalte enthält die Gruppenbezeichnung, eine weitere die Messwerte. Extrahieren Sie jede Gruppe als Series und übergeben Sie sie an stats.f_oneway(). Alternativ können Sie bei einem DataFrame im Wide-Format (eine Spalte pro Gruppe) jede Spalte direkt übergeben. Die Funktion akzeptiert beliebig viele Positionsargumente, sodass sie problemlos auf 4, 5 oder mehr Gruppen erweitert werden kann.
import pandas as pd
import numpy as np
from scipy import stats
np.random.seed(1)
df = pd.DataFrame({
'group': ['A']*40 + ['B']*40 + ['C']*40 + ['D']*40,
'score': np.concatenate([
np.random.normal(70, 10, 40),
np.random.normal(75, 10, 40),
np.random.normal(80, 10, 40),
np.random.normal(72, 10, 40)
])
})
groups = [group['score'].values
for _, group in df.groupby('group')]
f, p = stats.f_oneway(*groups)
print(f'F={f:.3f}, p={p:.4f}')
print(df.groupby('group')['score'].mean().round(2))ANOVA-Annahmen
Die einfaktorielle ANOVA setzt Folgendes voraus: (1) Unabhängigkeit — die Beobachtungen sind voneinander unabhängig; (2) Normalverteilung — die Residuen sind innerhalb jeder Gruppe annähernd normalverteilt (bei großen Stichproben dank des zentralen Grenzwertsatzes robust); (3) Homoskedastizität — die Varianzen sind in allen Gruppen gleich. Testen Sie die Varianzannahme mit dem Levene-Test (stats.levene(*groups)). Bei ungleichen Varianzen verwenden Sie stattdessen die Welch-ANOVA, die in der Bibliothek pingouin verfügbar ist oder mit statsmodels berechnet werden kann.
import numpy as np
from scipy import stats
np.random.seed(0)
g1 = np.random.normal(10, 2, 40)
g2 = np.random.normal(12, 2, 40)
g3 = np.random.normal(11, 8, 40) # Much higher variance
# Test equal variances
stat_l, p_l = stats.levene(g1, g2, g3)
print(f'Levene\'s test: stat={stat_l:.3f}, p={p_l:.4f}')
if p_l < 0.05:
print('Warning: Unequal variances! Standard ANOVA may be unreliable.')
print('Consider Welch\'s ANOVA or Kruskal-Wallis.')Kruskal-Wallis: Nichtparametrische ANOVA
Wenn die ANOVA-Annahmen verletzt sind (nicht normalverteilte Daten, kleine Stichproben, ungleiche Varianzen), ist der Kruskal-Wallis-Test die nichtparametrische Alternative. Er prüft, ob sich die Verteilungen der Gruppen unterscheiden, indem er die Daten in Rangwerte umwandelt und die Rangsummen vergleicht. Verwenden Sie scipy.stats.kruskal(*groups). Die Nullhypothese lautet, dass alle Gruppen dieselbe Verteilung haben (entspricht dem Test auf gleiche Mediane, wenn die Verteilungen dieselbe Form haben). Der Test ist immer gültig, aber bei erfüllten Annahmen weniger aussagekräftig als die ANOVA.
import numpy as np
from scipy import stats
np.random.seed(0)
# Non-normal data: customer satisfaction scores (1-10 scale)
g1 = np.random.choice(range(1, 11), 50, p=[0.05]*10)
g2 = np.random.choice(range(1, 11), 50, p=[0.02, 0.03, 0.05, 0.08, 0.12, 0.15, 0.20, 0.15, 0.12, 0.08])
g3 = np.random.choice(range(1, 11), 50, p=[0.15, 0.15, 0.15, 0.15, 0.10, 0.10, 0.08, 0.05, 0.04, 0.03])
stat, p = stats.kruskal(g1, g2, g3)
print(f'Kruskal-Wallis: H={stat:.3f}, p={p:.4f}')
print('Groups differ?', 'Yes' if p < 0.05 else 'No')Post-hoc-Tests: Warum Sie sie benötigen
Eine signifikante ANOVA zeigt Ihnen, dass sich mindestens ein Gruppenmittelwert unterscheidet, aber nicht, welche Paare sich unterscheiden. Post-hoc-Tests führen alle paarweisen Vergleiche durch und korrigieren dabei für multiples Testen. Am weitesten verbreitet ist die Tukey-HSD (Tukeys ehrlich signifikanter Unterschied), die die familienbezogene Fehlerquote exakt bei α hält. Sie ist in statsmodels.stats.multicomp.pairwise_tukeyhsd() verfügbar. Führen Sie Post-hoc-Tests erst nach einer signifikanten ANOVA durch — nicht als willkürliche Suche nach Ergebnissen bei nicht signifikanten Resultaten.
import numpy as np
import pandas as pd
from scipy import stats
from statsmodels.stats.multicomp import pairwise_tukeyhsd
np.random.seed(0)
data = np.concatenate([
np.random.normal(70, 10, 40),
np.random.normal(80, 10, 40),
np.random.normal(75, 10, 40)
])
groups = ['A']*40 + ['B']*40 + ['C']*40
# First confirm ANOVA is significant
f, p = stats.f_oneway(*[data[i*40:(i+1)*40] for i in range(3)])
print(f'ANOVA p={p:.4f}')
if p < 0.05:
print('Post-hoc Tukey HSD:')
print(pairwise_tukeyhsd(data, groups, alpha=0.05))Tukey-HSD-Ausgabe lesen
Die Tukey-HSD-Tabelle enthält eine Zeile für jedes Gruppenpaar. Auf folgende Spalten sollten Sie besonders achten: meandiff (Mittelwertdifferenz des Paars), lower und upper (95-%-Konfidenzintervall für die Differenz) sowie reject (True, wenn sich das Paar bei α signifikant unterscheidet). Ein Konfidenzintervall, das null nicht enthält, bedeutet, dass sich das Paar signifikant unterscheidet. Gruppen, deren Konfidenzintervalle sich überschneiden, unterscheiden sich nicht signifikant voneinander.
import numpy as np
from statsmodels.stats.multicomp import pairwise_tukeyhsd
np.random.seed(42)
data = np.concatenate([
np.random.normal(10, 2, 60), # Group A
np.random.normal(13, 2, 60), # Group B (clearly higher)
np.random.normal(10.5, 2, 60) # Group C (barely different from A)
])
groups = ['A']*60 + ['B']*60 + ['C']*60
result = pairwise_tukeyhsd(data, groups, alpha=0.05)
print(result)
# A-B: reject=True (B is higher)
# A-C: reject=False (barely different)
# B-C: reject=True (B is higher)Bonferroni- und Benjamini-Hochberg-Korrekturen
Als Alternative zur Tukey-HSD können Sie eine Bonferroni-Korrektur auf paarweise t-Tests anwenden: Führen Sie alle t-Tests durch und passen Sie anschließend den Schwellenwert auf α/k an, wobei k die Anzahl der Vergleiche ist. Dieses Verfahren ist konservativ — es kann echte Unterschiede übersehen. Die Benjamini-Hochberg-Korrektur der False Discovery Rate (FDR) ist weniger konservativ: Sie kontrolliert den erwarteten Anteil falscher Entdeckungen und ermöglicht dadurch mehr echte positive Ergebnisse, allerdings um den Preis etwas mehr falsch positiver Ergebnisse. Verwenden Sie statsmodels.stats.multitest.multipletests(p_values, method='fdr_bh').
import numpy as np
from scipy import stats
from statsmodels.stats.multitest import multipletests
np.random.seed(0)
groups = [np.random.normal(10 + i*1.5, 2, 40) for i in range(4)]
names = ['A', 'B', 'C', 'D']
# All pairwise t-tests
p_values = []
pairs = []
for i in range(len(groups)):
for j in range(i+1, len(groups)):
_, p = stats.ttest_ind(groups[i], groups[j])
p_values.append(p)
pairs.append(f'{names[i]}-{names[j]}')
# Benjamini-Hochberg correction
reject, adj_p, _, _ = multipletests(p_values, method='fdr_bh')
for pair, p, ap, r in zip(pairs, p_values, adj_p, reject):
print(f'{pair}: raw_p={p:.4f}, adj_p={ap:.4f}, significant={r}')Effektgröße bei ANOVA: Eta-Quadrat
Bei der ANOVA ist Eta-Quadrat (η²) das entsprechende Maß zu Cohens d: der Anteil der Gesamtvarianz, der durch die Gruppenzugehörigkeit erklärt wird. η² = SS_between / SS_total. Richtwerte: < 0,01 ist klein, 0,06 ist mittel und > 0,14 ist groß. Das partielle Eta-Quadrat (η²_p) ist in veröffentlichten Studien verbreiteter: Es teilt nur durch die Gruppenvarianz plus die Fehlervarianz und nicht durch die Gesamtvarianz. Berechnen Sie η² stets zusammen mit dem p-Wert der ANOVA, um zu zeigen, ob der Effekt praktisch bedeutsam und nicht nur statistisch nachweisbar ist.
import numpy as np
from scipy import stats
np.random.seed(0)
groups = [
np.random.normal(10, 2, 50),
np.random.normal(12, 2, 50),
np.random.normal(14, 2, 50)
]
all_data = np.concatenate(groups)
grand_mean = all_data.mean()
ss_between = sum(len(g) * (g.mean() - grand_mean)**2 for g in groups)
ss_total = sum((x - grand_mean)**2 for g in groups for x in g)
eta_sq = ss_between / ss_total
f, p = stats.f_oneway(*groups)
print(f'F={f:.3f}, p={p:.4f}')
print(f'Eta-squared: {eta_sq:.4f} ({eta_sq:.1%} of variance explained)')Überblick über die zweifaktorielle ANOVA
Die zweifaktorielle ANOVA erweitert die einfaktorielle ANOVA um zwei kategoriale Faktoren, die gleichzeitig untersucht werden. Sie können beispielsweise prüfen, ob sich Prüfungsergebnisse sowohl nach der Unterrichtsmethode als auch nach dem Erfahrungsniveau der Studierenden unterscheiden. Außerdem wird der Interaktionseffekt getestet: Hängt der Effekt der Unterrichtsmethode vom Erfahrungsniveau ab? Die zweifaktorielle ANOVA wird in statsmodels mit ols('score ~ C(method) + C(level) + C(method):C(level)', data=df).fit() und anova_lm(model) implementiert. Sie bildet eine Grundlage für fortgeschrittenere Versuchspläne.
import pandas as pd
import numpy as np
from statsmodels.formula.api import ols
from statsmodels.stats.anova import anova_lm
np.random.seed(0)
df = pd.DataFrame({
'method': ['trad']*60 + ['active']*60,
'level': ['beginner']*30 + ['advanced']*30 + ['beginner']*30 + ['advanced']*30,
'score': (np.random.normal(70, 8, 30).tolist() +
np.random.normal(80, 8, 30).tolist() +
np.random.normal(75, 8, 30).tolist() +
np.random.normal(88, 8, 30).tolist())
})
model = ols('score ~ C(method) + C(level) + C(method):C(level)', data=df).fit()
print(anova_lm(model, typ=2)[['F', 'PR(>F)']].round(4))ANOVA mit Messwiederholungen
Eine ANOVA mit Messwiederholungen wird verwendet, wenn dieselben Versuchspersonen mehrmals gemessen werden — beispielsweise zur Untersuchung der Reaktionszeit zu den Zeitpunkten 0, 30 und 60 Minuten nach einer Behandlung. Sie ist die Verallgemeinerung des gepaarten t-Tests auf mehrere Gruppen. Da individuelle Unterschiede berücksichtigt werden, besitzt sie eine höhere Teststärke als die einfaktorielle ANOVA. Verwenden Sie in Python pingouin.rm_anova() oder pg.pairwise_tests() für die Post-hoc-Analyse. Bei verletzter Sphärizität (getestet mit dem Mauchly-Test) verwenden Sie p-Werte mit Greenhouse-Geisser-Korrektur.
import pandas as pd
import numpy as np
# Example structure for repeated measures (pingouin library)
np.random.seed(0)
subjects = list(range(20)) * 3 # 20 subjects, 3 time points
timepoints = ['T0']*20 + ['T1']*20 + ['T2']*20
scores = np.concatenate([
np.random.normal(50, 10, 20), # baseline
np.random.normal(55, 10, 20), # improved
np.random.normal(60, 10, 20) # further improved
])
df_rm = pd.DataFrame({'subject': subjects, 'time': timepoints, 'score': scores})
print(df_rm.groupby('time')['score'].mean().round(2))
# Use pingouin.rm_anova(data=df_rm, dv='score', within='time', subject='subject')Kurzer Wissenstest
Testen Sie Ihr Verständnis der Konzepte zur Datenanalyse aus dieser Lektion.
Zusammenfassung der Lektion
In dieser Lektion haben Sie gelernt: scipy.stats.f_oneway() prüft, ob sich beliebige Gruppen in ihrem Mittelwert unterscheiden, und kontrolliert dabei die Gesamtfehlerquote 1. Art; Post-hoc-Tests (Tukey-HSD) ermitteln nach einer signifikanten ANOVA, welche konkreten Paare sich unterscheiden; und der Kruskal-Wallis-Test ist die nichtparametrische Alternative, wenn die Annahmen der Normalverteilung oder gleicher Varianzen verletzt sind. Als Nächstes beginnen wir das Abschlussprojekt, in dem alle Fähigkeiten zu einer durchgängigen Datenpipeline zusammengeführt werden.
Lerne Python mit einem KI-Tutor — kostenlos
Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.
- Kurse
- 30
- Lektionen
- 120
Häufig gestellte Fragen
Ist die Lektion „ANOVA und Post-hoc-Tests“ kostenlos?
Ja — der vollständige Text von „ANOVA und Post-hoc-Tests“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Pandas & NumPy Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Pandas & NumPy Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „ANOVA und Post-hoc-Tests“?
Vergleichen Sie Mittelwerte von drei oder mehr Gruppen mit einer einfaktoriellen ANOVA und führen Sie den Tukey-HSD-Test durch, um unterschiedliche Paare zu identifizieren. Du übst Pandas & NumPy Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Pandas & NumPy Academy zu starten?
Keine Vorkenntnisse erforderlich. Pandas & NumPy Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „ANOVA und Post-hoc-Tests“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Pandas & NumPy Academy-Lektion Code schreiben und ausführen?
Ja. Jede Pandas & NumPy Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Deskriptive Statistik und Normalitätstests
- T-Tests zum Vergleich von Mittelwerten
- Chi-Quadrat-Test auf Unabhängigkeit
- ANOVA und Post-hoc-Tests