Pandas — tabeller i Python
Kunna läsa, filtrera, gruppera och sammanfoga data i DataFrames.
Förkunskaper
Intuition
En DataFrame är en tabell med namngivna kolumner — som ett kalkylblad, men i kod och utan musen.
| Det du vill göra | Pandas |
|---|---|
| Läsa in en fil | pd.read_csv("data.csv") |
| Titta | df.head(), df.info(), df.describe() |
| Välja kolumner | df[["a", "b"]] |
| Filtrera rader | df[df.alder > 15] |
| Ny kolumn | df["bmi"] = df.vikt / df.langd ** 2 |
| Gruppera | df.groupby("klass").betyg.mean() |
| Slå ihop tabeller | df.merge(annan, on="elev_id") |
| Sortera | df.sort_values("betyg", ascending=False) |
Börja alltid med df.info() och df.describe(). Den första visar radantal, kolumntyper och hur många värden som saknas; den andra visar min, max och kvartiler. Tillsammans avslöjar de de flesta problemen på fem sekunder — en ålder på 999, en kolumn som blev text i stället för tal, tusen saknade värden.
Kod
import pandas as pd
df = pd.DataFrame({
"elev": ["Ada", "Bo", "Cim", "Dag", "Eve"],
"klass": ["7A", "7A", "7B", "7B", "7B"],
"poang": [82, 95, 67, None, 74],
"timmar": [12, 20, 8, 15, 10],
})
print(df.info()) # antal rader, typer, non-null per kolumn
print(df.describe()) # min, max, medel, kvartiler för numeriska kolumner
# Filtrera — parenteser krävs runt varje villkor, och & / | i stället för and / or
print(df[(df.poang > 70) & (df.klass == "7B")])
# Ny kolumn
df["poang_per_timme"] = df.poang / df.timmar
# Gruppera och aggregera flera mått samtidigt
print(df.groupby("klass").agg(
antal=("elev", "count"),
medelpoang=("poang", "mean"),
max_timmar=("timmar", "max"),
))
# antal medelpoang max_timmar
# klass
# 7A 2 88.5 20
# 7B 3 70.5 15 ← medel räknas på 2 värden, None hoppas över
# Sammanfoga — kontrollera ALLTID radantalet efteråt
narvaro = pd.DataFrame({"elev": ["Ada", "Bo", "Cim"], "narvaro": [0.95, 0.80, 0.99]})
ihop = df.merge(narvaro, on="elev", how="left", validate="one_to_one")
print(len(df), len(ihop)) # 5 5 — samma antal, som väntat
# Vanlig fälla: en merge som råkar duplicera rader
dubbel = pd.DataFrame({"elev": ["Ada", "Ada"], "prov": [1, 2]})
print(len(df.merge(dubbel, on="elev", how="left"))) # 6 — en rad blev två!
Tre fällor som kostar mest tid:
| Fälla | Symtom | Rätt sätt |
|---|---|---|
and/or i filter | ValueError: truth value is ambiguous | & och ` |
| Kedjad tilldelning | SettingWithCopyWarning, ändringen försvinner | df.loc[villkor, "kol"] = värde |
| Merge som duplicerar | radantalet växer tyst | validate="one_to_one" eller kontrollera len() |
Den sista är den farligaste eftersom inget felmeddelande kommer. Kontrollera radantalet efter varje merge — det är en rad kod och sparar timmar.
Interaktivt
Ett arbetsflöde som fungerar varje gång du får en ny fil:
df = pd.read_csv("ny_fil.csv")
# 1. Hur ser den ut?
print(df.shape) # (rader, kolumner)
print(df.dtypes) # blev något text som borde vara tal?
print(df.isna().sum()) # saknade värden per kolumn
print(df.duplicated().sum()) # exakta dubbletter
# 2. Är värdena rimliga?
print(df.describe()) # min/max avslöjar 999, -1, 0 som «saknas»
for k in df.select_dtypes("object"):
print(k, df[k].nunique(), df[k].unique()[:5]) # stavfel, blandade format
# 3. Först därefter: analys
Steg 1 och 2 tar en minut och hittar nästan alltid något. Vanliga fynd:
- En kolumn med
dtype: objectsom borde varafloat— det finns ett"-"eller"n/a"någonstans i den. maxpå 999 ellerminpå −1 i en ålderskolumn — någon har kodat «saknas» som ett tal.- Kategorikolumner med 47 unika värden när det borde vara 5 — stavfel och blandad versalisering.
- Fler rader än väntat efter en merge.
Gör det till en vana innan du skriver en enda rad analys. Det är samma princip som att titta på datan innan man tränar en modell — och det är i särklass den mest lönsamma minuten i hela projektet.
Behärskning innebär
- Läser in och filtrerar data
- Grupperar och aggregerar
- Sammanfogar tabeller och kontrollerar resultatet
Logga in för att göra övningarna och bygga upp din behärskning.
Källor
- pandas — User Guide (BSD-3) — BSD-3-Clause
- Python-dokumentationen (PSF-licens) — PSF