Beschrijvende statistiek en normaliteitstoetsen
Bereken scheefheid en kurtosis met scipy.stats, voer een Shapiro-Wilk-toets op normaliteit uit en interpreteer de p-waarde.
Beschrijvende statistiek en normaliteitstoetsen is een gratis Pandas & NumPy Academy-les op CoddyKit. Dit is les 1 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Pandas & NumPy Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Pandas & NumPy Academy bevat in totaal 4 lessen.
Beschrijvende versus inferentiële statistiek
Beschrijvende statistiek vat samen wat er in je gegevens staat: gemiddelde, mediaan, standaardafwijking en scheefheid. Inferentiële statistiek doet uitspraken over een populatie op basis van een steekproef: hypothesetoetsen, betrouwbaarheidsintervallen en p-waarden. De module scipy.stats van SciPy vormt de brug tussen deze werelden — de module biedt zowel beschrijvende maten die verder gaan dan Pandas' describe() als de volledige verzameling klassieke hypothesetoetsen. Pandas combineren met SciPy voor statistische toetsen is de standaardworkflow voor data science in Python.
Uitgebreide beschrijvende statistiek
Pandas' describe() geeft het aantal waarden, gemiddelde, standaardafwijking, minimum/maximum en kwartielen. scipy.stats voegt scheefheid (asymmetrie van de verdeling) en kurtosis (zwaarte van de staarten) toe. Een scheefheid van 0 betekent symmetrie; positieve scheefheid betekent een langere rechterstaart (veel kleine waarden, enkele zeer grote). Een kurtosis van 3 (of 0 in de vorm van excess-kurtosis) is normaal; hogere waarden wijzen op zwaardere staarten met meer extreme uitschieters dan een normale verdeling zou opleveren.
import pandas as pd
from scipy import stats
import numpy as np
np.random.seed(0)
data = np.concatenate([
np.random.exponential(scale=2, size=500), # right-skewed
np.random.normal(loc=5, scale=1, size=500)
])
print('Mean:', round(data.mean(), 3))
print('Std:', round(data.std(), 3))
print('Skewness:', round(stats.skew(data), 3))
print('Kurtosis (excess):', round(stats.kurtosis(data), 3))Scheefheid begrijpen
Scheefheid is belangrijk bij het kiezen van statistische toetsen en transformaties. Een rechts-scheve (positief scheve) verdeling heeft een gemiddelde dat groter is dan de mediaan, wat typisch is voor inkomensgegevens, reactietijden en verkoopbedragen. Een links-scheve (negatief scheve) verdeling heeft een gemiddelde dat kleiner is dan de mediaan. Vuistregel: |scheefheid| < 0,5 is ongeveer symmetrisch; 0,5–1,0 is matig scheef; > 1,0 is sterk scheef en kan baat hebben bij een logaritmische of vierkantsworteltransformatie voordat je toetsen toepast die normaliteit veronderstellen.
import numpy as np
from scipy import stats
# Right-skewed: income-like data
right_skewed = np.random.lognormal(mean=1, sigma=1, size=1000)
print('Right skew:', round(stats.skew(right_skewed), 3))
# After log transform
print('After log transform:', round(stats.skew(np.log(right_skewed)), 3))
# Symmetric normal
normal_data = np.random.normal(0, 1, 1000)
print('Normal skew:', round(stats.skew(normal_data), 3))Waarom normaliteitstoetsen belangrijk zijn
Veel statistische toetsen — t-toetsen, ANOVA en Pearson-correlatie — veronderstellen dat de gegevens (of de residuen) een normale (Gaussische) verdeling volgen. Als deze aanname bij kleine steekproeven niet opgaat, kunnen de p-waarden van de toets onnauwkeurig zijn. Met een normaliteitstoets controleer je of de aanname klopt. Bij grote steekproeven (n > 100) worden normaliteitstoetsen zeer gevoelig en zullen ze normaliteit bijna altijd verwerpen vanwege triviale afwijkingen — vertrouw in dat geval op de centrale limietstelling (steekproefgemiddelden zijn bij benadering normaal) in plaats van de onbewerkte gegevens te toetsen.
De Shapiro-Wilk-toets
De Shapiro-Wilk-toets (scipy.stats.shapiro(data)) is de krachtigste normaliteitstoets voor steekproefgroottes tot ongeveer 5.000. De toets retourneert een W-statistiek en een p-waarde. Als p > 0.05, verwerp je de normaliteit niet — de gegevens zijn verenigbaar met een normale verdeling. Als p ≤ 0.05, verwerp je de normaliteit. Let op: het niet verwerpen van normaliteit bewijst niet dat de gegevens normaal zijn; het betekent alleen dat je niet genoeg bewijs hebt om te zeggen dat ze niet normaal zijn.
import numpy as np
from scipy import stats
np.random.seed(42)
# Normal data
normal = np.random.normal(0, 1, 100)
stat, p = stats.shapiro(normal)
print(f'Normal data: W={stat:.4f}, p={p:.4f}')
print('Conclusion:', 'Looks normal' if p > 0.05 else 'Not normal')
# Skewed data
skewed = np.random.exponential(1, 100)
stat2, p2 = stats.shapiro(skewed)
print(f'Skewed data: W={stat2:.4f}, p={p2:.4f}')
print('Conclusion:', 'Looks normal' if p2 > 0.05 else 'Not normal')De Kolmogorov-Smirnov-toets
De Kolmogorov-Smirnov-toets (K-S-toets) (scipy.stats.kstest(data, 'norm', args)) toetst of een steekproef een opgegeven verdeling volgt. In tegenstelling tot de Shapiro-Wilk-toets werkt deze voor elke verdeling, niet alleen de normale, en voor grote steekproeven. De toets berekent het maximale verschil tussen de empirische CDF van je gegevens en de theoretische CDF. Een variant, de K-S-toets voor twee steekproeven (stats.ks_2samp(a, b)), toetst of twee steekproeven uit dezelfde verdeling komen — nuttig om verdelingen voor en na een wijziging te vergelijken.
import numpy as np
from scipy import stats
np.random.seed(0)
data = np.random.normal(loc=5, scale=2, size=200)
# One-sample K-S test against N(5, 2) distribution
stat, p = stats.kstest(data, 'norm', args=(5, 2))
print(f'K-S test: stat={stat:.4f}, p={p:.4f}')
print('Follows N(5,2)?', 'Yes' if p > 0.05 else 'No')
# Two-sample K-S test
data2 = np.random.normal(loc=5.5, scale=2, size=200)
stat2, p2 = stats.ks_2samp(data, data2)
print(f'Two-sample K-S: stat={stat2:.4f}, p={p2:.4f}')Visuele normaliteitscontrole: QQ-plot
De Q-Q-plot (kwantiel-kwantielplot) is een visuele normaliteitscontrole: de kwantielen van je gegevens worden uitgezet tegen de kwantielen van een normale verdeling. Als de gegevens normaal zijn, liggen de punten op een rechte diagonale lijn. Afwijkingen van de lijn wijzen op een afwijking van normaliteit — S-curves wijzen op kurtosis en bochten op scheefheid. Statistische toetsen vertellen je of afwijkingen significant zijn; Q-Q-plots laten de aard en locatie van de afwijkingen zien. Gebruik scipy.stats.probplot() om gegevens voor een Q-Q-plot te genereren.
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
np.random.seed(1)
data = np.random.exponential(2, 200)
# Q-Q plot
(osm, osr), (slope, intercept, r) = stats.probplot(data, dist='norm')
print(f'R-squared of Q-Q fit: {r**2:.4f}') # Close to 1 = normal
# Visual inspection: if plotting, points on the line = normal
# plt.figure()
# stats.probplot(data, dist='norm', plot=plt)
# plt.show()De centrale limietstelling in de praktijk
De centrale limietstelling (CLT) stelt dat de verdeling van steekproefgemiddelden normaliteit benadert naarmate de steekproefomvang toeneemt, ongeacht de onderliggende verdeling. Bij n ≥ 30 is het steekproefgemiddelde bij benadering normaal, zelfs als afzonderlijke waarnemingen scheef verdeeld zijn. Daarom zijn t-toetsen robuust bij grote steekproeven: je toetst of het gemiddelde verschilt, en het gemiddelde is bij benadering normaal, zelfs wanneer de onbewerkte gegevens dat niet zijn. Gebruik bij kleine steekproeven uit niet-normale populaties niet-parametrische toetsen.
import numpy as np
from scipy import stats
np.random.seed(0)
# Population: heavily right-skewed (exponential)
population = np.random.exponential(scale=1, size=10000)
print('Population skewness:', round(stats.skew(population), 3))
# Sample means are approximately normal (CLT)
sample_means = [np.random.choice(population, 50).mean()
for _ in range(1000)]
print('Sample means skewness:', round(stats.skew(sample_means), 3))
_, p = stats.shapiro(sample_means)
print('Shapiro p-value for means:', round(p, 4))Normaliteit per groep
Bij toetsen voor groepsvergelijkingen (t-toets, ANOVA) is normaliteit vereist binnen elke groep, niet in de gegevens als geheel. Wanneer je toetst of verkoopcijfers per regio verschillen, toets je de normaliteit van de verkoopcijfers binnen elke regio afzonderlijk. Een verdeling die als geheel niet normaal is, kan binnen subgroepen toch aan de normaliteitsaanname voldoen. Pas stats.shapiro() op elke groep toe met Pandas groupby() en loop door de groepen om de aanname systematisch te controleren.
import pandas as pd
import numpy as np
from scipy import stats
np.random.seed(0)
df = pd.DataFrame({
'region': ['N']*50 + ['S']*50 + ['E']*50,
'sales': np.concatenate([
np.random.normal(100, 20, 50),
np.random.normal(110, 25, 50),
np.random.normal(95, 15, 50)
])
})
for region, group in df.groupby('region'):
stat, p = stats.shapiro(group['sales'])
print(f'Region {region}: W={stat:.4f}, p={p:.4f} -> '
f'{"Normal" if p>0.05 else "Not normal"}')Niet-parametrische alternatieven
Wanneer normaliteit niet opgaat, gebruik je niet-parametrische toetsen die geen aannames over de verdeling doen. De Mann-Whitney U-toets (stats.mannwhitneyu) vervangt de onafhankelijke t-toets; de Wilcoxon-toets met rangtekens (stats.wilcoxon) vervangt de gepaarde t-toets; de Kruskal-Wallis-toets (stats.kruskal) vervangt eenweg-ANOVA. Deze toetsen gebruiken rangen in plaats van onbewerkte waarden en zijn robuust tegen uitschieters, maar hebben minder statistische power dan hun parametrische tegenhangers wanneer normaliteit daadwerkelijk geldt.
import numpy as np
from scipy import stats
np.random.seed(0)
# Non-normal data
group_a = np.random.exponential(2, 40)
group_b = np.random.exponential(2.5, 40)
# Parametric would be wrong here; use non-parametric
stat, p = stats.mannwhitneyu(group_a, group_b, alternative='two-sided')
print(f'Mann-Whitney U test: U={stat:.1f}, p={p:.4f}')
print('Groups differ?' , 'Yes' if p < 0.05 else 'No')Statistieken voor meerdere kolommen samenvatten
Bij verkennende data-analyse moet je vaak voor alle numerieke kolommen tegelijk de normaliteit en scheefheid controleren. Combineer Pandas select_dtypes met een lus over de kolommen waarin je stats.shapiro() en stats.skew() aanroept. Maak een samenvattend DataFrame met kolommen voor scheefheid, kurtosis en de Shapiro-p-waarde om in één oogopslag te zien welke kolommen niet-normaal zijn en vóór het modelleren een transformatie nodig hebben. Dit maakt deel uit van een systematische controlelijst voor datakwaliteit.
import pandas as pd
import numpy as np
from scipy import stats
np.random.seed(0)
df = pd.DataFrame({
'age': np.random.normal(35, 10, 200),
'income': np.random.lognormal(10, 1, 200),
'score': np.random.uniform(0, 100, 200)
})
rows = []
for col in df.select_dtypes(include='number').columns:
s = stats.skew(df[col])
_, p = stats.shapiro(df[col][:200])
rows.append({'column': col, 'skewness': round(s, 3),
'shapiro_p': round(p, 4), 'normal': p > 0.05})
print(pd.DataFrame(rows).to_string(index=False))Snelle controle
Test je begrip van de concepten voor data-analyse uit deze les.
Samenvatting van de les
In deze les heb je geleerd dat scipy.stats.skew() en kurtosis() de vorm van een verdeling beschrijven naast wat describe() biedt, dat scipy.stats.shapiro() normaliteit toetst waarbij p > 0,05 betekent dat er geen bewijs tegen normaliteit is, en dat de centrale limietstelling t-toetsen robuust maakt voor grote steekproeven, zelfs met niet-normale gegevens. Hierna passen we hypothesetoetsing met t-toetsen toe om groepsgemiddelden te vergelijken.
Leer Python met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 30
- Lessen
- 120
Veelgestelde vragen
Is de les “Beschrijvende statistiek en normaliteitstoetsen” gratis?
Ja — de volledige tekst van “Beschrijvende statistiek en normaliteitstoetsen” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Pandas & NumPy Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Pandas & NumPy Academy bevat in totaal 4 lessen.
Wat leer ik in “Beschrijvende statistiek en normaliteitstoetsen”?
Bereken scheefheid en kurtosis met scipy.stats, voer een Shapiro-Wilk-toets op normaliteit uit en interpreteer de p-waarde. Je oefent met Pandas & NumPy Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Pandas & NumPy Academy te beginnen?
Ervaring vooraf is niet nodig. Pandas & NumPy Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 1 van 4.
Hoe lang duurt de les “Beschrijvende statistiek en normaliteitstoetsen”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Pandas & NumPy Academy?
Ja. Elke les over Pandas & NumPy Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Beschrijvende statistiek en normaliteitstoetsen
- T-toetsen voor het vergelijken van gemiddelden
- Chi-kwadraattoets voor onafhankelijkheid
- ANOVA en post-hoc-toetsen