Deskriptiv statistik och normalitetstest
Beräkna skevhet och kurtosis med scipy.stats, genomför ett Shapiro–Wilk-test för normalitet och tolka p-värdet.
Deskriptiv statistik och normalitetstest är en gratis lektion i Pandas & NumPy Academy på CoddyKit. Detta är lektion 1 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Pandas & NumPy Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Pandas & NumPy Academy innehåller totalt 4 lektioner.
Deskriptiv och inferentiell statistik
Deskriptiv statistik sammanfattar vad som finns i Era data: medelvärde, median, standardavvikelse och skevhet. Inferentiell statistik drar slutsatser om en population utifrån ett urval: hypotesprövningar, konfidensintervall och p-värden. SciPys modul scipy.stats förenar dessa områden — den tillhandahåller både deskriptiva mått som går längre än Pandas describe() och hela uppsättningen klassiska hypotesprövningar. Att kombinera Pandas för datamanipulering och SciPy för statistisk testning är det standardmässiga arbetsflödet inom Python-baserad datavetenskap.
Utökad deskriptiv statistik
Pandas describe() ger antal, medelvärde, standardavvikelse, min/max och kvartiler. scipy.stats lägger till skevhet (fördelningens asymmetri) och kurtosis (svansarnas tyngd). Skevhet på 0 innebär symmetri; positiv skevhet innebär en längre högersvans (många små värden och några få mycket stora). Kurtosis på 3 (eller 0 i överskottsform) är normalt; högre värden visar på tyngre svansar med fler extrema avvikare än vad en normalfördelning skulle ge.
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))Förstå skevhet
Skevhet är viktig när Ni väljer statistiska test och transformationer. En högerskev (positivt skev) fördelning har ett medelvärde som är större än medianen, vilket är typiskt för inkomstdata, reaktionstider och försäljningsbelopp. En vänsterskev (negativt skev) fördelning har ett medelvärde som är mindre än medianen. Tumregel: |skewness| < 0.5 är ungefär symmetrisk; 0.5–1.0 är måttligt skev; > 1.0 är kraftigt skev och kan ha nytta av en logaritmisk transformation eller en kvadratrotstransformation innan Ni tillämpar test som förutsätter normalitet.
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))Varför normalitetstest är viktiga
Många statistiska test — t-test, ANOVA och Pearson-korrelation — förutsätter att data (eller residualerna) följer en normalfördelning (Gaussfördelning). Om detta antagande inte håller för små urval kan testens p-värden vara felaktiga. Normalitetstest kontrollerar om antagandet håller. För stora urval (n > 100) blir normalitetstest mycket känsliga och förkastar nästan alltid normalitet vid obetydliga avvikelser — i så fall bör Ni förlita Er på centrala gränsvärdessatsen (att stickprovsmedelvärden är ungefär normalfördelade) i stället för att testa rådata.
Shapiro-Wilks test
Shapiro-Wilks test (scipy.stats.shapiro(data)) är det mest kraftfulla normalitetstestet för urvalsstorlekar upp till ungefär 5 000. Det returnerar en W-statistik och ett p-värde. Om p > 0.05 underlåter Ni att förkasta normalitet — data är förenliga med en normalfördelning. Om p ≤ 0.05 förkastar Ni normalitet. Kom ihåg att ett uteblivet förkastande av normalitet inte bevisar att data är normalfördelade; det betyder bara att Ni inte har tillräckliga belägg för att säga att de inte är det.
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')Kolmogorov-Smirnov-testet
Kolmogorov-Smirnov-testet (K-S-testet) (scipy.stats.kstest(data, 'norm', args)) testar om ett urval följer en angiven fördelning. Till skillnad från Shapiro-Wilks test fungerar det för alla fördelningar (inte bara normalfördelningen) och för stora urval. Det beräknar den största skillnaden mellan den empiriska fördelningsfunktionen för Era data och den teoretiska fördelningsfunktionen. En variant, tvåurvals-K-S-testet (stats.ks_2samp(a, b)), testar om två urval kommer från samma fördelning — användbart för att jämföra fördelningar före och efter.
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}')Visuell normalitetskontroll: Q-Q-diagram
Q-Q-diagrammet (kvantil-kvantil-diagrammet) är en visuell normalitetskontroll: det plottar kvantilerna i Era data mot kvantilerna i en normalfördelning. Om data är normalfördelad hamnar punkterna på en rak diagonal linje. Avvikelser från linjen visar avsteg från normalitet — S-kurvor visar kurtosis och böjningar visar skevhet. Statistiska test talar om huruvida avvikelserna är signifikanta; Q-Q-diagram visar avvikelsernas karaktär och var de förekommer. Använd scipy.stats.probplot() för att generera data till ett Q-Q-diagram.
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()Centrala gränsvärdessatsen i praktiken
Centrala gränsvärdessatsen (CLT) säger att fördelningen av stickprovsmedelvärden närmar sig normalitet när urvalsstorleken ökar, oavsett den underliggande fördelningen. För n ≥ 30 är stickprovsmedelvärdet ungefär normalfördelat även om de enskilda observationerna är skeva. Det är därför t-test är robusta för stora urval: Ni testar om medelvärdet skiljer sig, och medelvärdet är ungefär normalfördelat även när rådata inte är det. För små urval från icke-normalfördelade populationer bör Ni i stället använda icke-parametriska test.
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))Normalitet per grupp
Vid test av gruppskillnader (t-test, ANOVA) krävs normalitet inom varje grupp, inte i hela datamängden. När Ni testar om försäljningen skiljer sig mellan regioner bör Ni testa normaliteten för försäljningen separat inom varje region. En fördelning som inte är normal totalt kan ändå uppfylla normalitetskravet inom undergrupperna. Tillämpa stats.shapiro() på varje grupp med Pandas groupby() och iterera över grupperna för att systematiskt kontrollera antagandet.
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"}')Icke-parametriska alternativ
När normalitetsantagandet inte håller bör Ni använda icke-parametriska test som inte gör några fördelningsantaganden. Mann-Whitneys U-test (stats.mannwhitneyu) ersätter det oberoende t-testet; Wilcoxons rangsummetest (stats.wilcoxon) ersätter det parade t-testet; Kruskal-Wallis-testet (stats.kruskal) ersätter envägs-ANOVA. Dessa test använder rangordningar i stället för råvärden och är robusta mot avvikare, men har lägre statistisk styrka än sina parametriska motsvarigheter när normalitetsantagandet faktiskt håller.
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')Sammanfatta statistik för flera kolumner
Vid EDA behöver Ni ofta kontrollera normalitet och skevhet för alla numeriska kolumner samtidigt. Kombinera Pandas select_dtypes med en loop över kolumnerna som anropar stats.shapiro() och stats.skew(). Skapa en sammanfattande DataFrame med kolumner för skevhet, kurtosis och Shapiro-p-värde för att få en överblick över vilka kolumner som inte är normalfördelade och behöver transformeras före modellering. Detta ingår i en systematisk checklista för datakvalitet.
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))Snabb kontroll
Testa Er förståelse av dataanalysens begrepp från denna lektion.
Lektionssammanfattning
I denna lektion har Ni lärt Er att scipy.stats.skew() och kurtosis() beskriver en fördelnings form utöver vad describe() tillhandahåller, att scipy.stats.shapiro() testar normalitet där p > 0.05 innebär att det saknas belägg mot normalitet, samt att centrala gränsvärdessatsen gör t-test robusta för stora urval även med icke-normalfördelade data. Nästa steg är att tillämpa hypotesprövning med t-test för att jämföra gruppmedelvärden.
Lär dig Python med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 30
- Lektioner
- 120
Vanliga frågor
Är lektionen ”Deskriptiv statistik och normalitetstest” gratis?
Ja – hela texten till ”Deskriptiv statistik och normalitetstest” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Pandas & NumPy Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i Pandas & NumPy Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”Deskriptiv statistik och normalitetstest”?
Beräkna skevhet och kurtosis med scipy.stats, genomför ett Shapiro–Wilk-test för normalitet och tolka p-värdet. Ni övar på Pandas & NumPy Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Pandas & NumPy Academy?
Du behöver inga förkunskaper. Utbildningen i Pandas & NumPy Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 1 av 4.
Hur lång tid tar lektionen ”Deskriptiv statistik och normalitetstest”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Pandas & NumPy Academy-lektionen?
Ja. Varje Pandas & NumPy Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Deskriptiv statistik och normalitetstest
- T-test för jämförelse av medelvärden
- Chi-två-test för oberoende
- ANOVA och post-hoc-test