Pandas fillna i dropna: Vodič za rukovanje nedostajućim podacima u Pythonu (2026)

Praktični vodič za rukovanje NaN vrijednostima u pandasu 2.2: fillna, dropna, ffill, bfill i interpolate, s primjerima iz stvarnih projekata i smjernicama kada koja metoda ima smisla.

Pandas fillna i dropna: Vodič (2026)

Ažurirano: 26. lipnja 2026.

Funkcija fillna() u pandasu zamjenjuje nedostajuće (NaN) vrijednosti u DataFrame-u ili Series-u zadanom vrijednošću, a dropna() u potpunosti uklanja retke ili stupce koji sadrže NaN. Kombinacija ove dvije metode, zajedno s isna() za detekciju i interpolate() za pametno popunjavanje, čini standardni alat za čišćenje stvarnih skupova podataka. U ovom vodiču pokazujem kako ih koristim u pandasu 2.2, s pravim brojkama, edge case-ovima i smjernicama kada koja metoda ima smisla.

  • isna() i notna() vraćaju Boolean masku. Koristite .sum() za prebrojavanje NaN-ova po stupcu.
  • fillna(value) popunjava skalarom. fillna(method='ffill') je deprecirano u pandas 2.2, pa koristite ffill() i bfill() izravno.
  • dropna(how='any') uklanja redak ako bilo koji stupac ima NaN; how='all' samo ako su svi NaN; thresh=N zadržava retke s barem N ne-NaN vrijednosti.
  • Za numeričke serije vremena, interpolate(method='linear') daje bolje rezultate od konstantnog popunjavanja.
  • Od pandas 2.2 ne preporučuje se inplace=True u lančanim pozivima. Koristite df = df.fillna(...) za predvidljivo ponašanje (vidi pandas 2.2 release notes).
  • NaN se ne uspoređuje sam sa sobom: np.nan == np.nan vraća False, zato uvijek koristite isna().

Što je NaN u pandasu i odakle dolazi?

U pandasu, NaN (Not a Number) je specijalna float vrijednost iz NumPy-a koju knjižnica koristi kao univerzalni marker za nedostajuće podatke. Pojavljuje se kada CSV ima prazne ćelije, kada se baze podataka vraćaju s NULL vrijednostima, ili kada operacije poput merge, reindex i pivot proizvedu nepostojeće kombinacije ključeva.

Za datume pandas koristi NaT (Not a Time), a za nullable cjelobrojne i boolean tipove novi pd.NA (uveden u pandas 1.0, dorađen u 2.2). Svi se ponašaju slično pri filtriranju, ali se razlikuju u dtype-u rezultirajućeg stupca. To je važno kada DataFrame šaljete u bazu ili Parquet datoteku.

Pogledajmo kratak primjer kako NaN nastaje prirodno:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "kupac": ["Ana", "Marko", "Petra", "Ivan"],
    "grad": ["Zagreb", None, "Split", "Rijeka"],
    "potrosnja": [1200.0, np.nan, 850.5, np.nan],
    "datum": pd.to_datetime(["2026-01-15", "2026-02-03", None, "2026-04-20"]),
})

print(df)
print("\nTipovi:")
print(df.dtypes)

U izlazu ćete vidjeti NaN za brojeve, None (koji pandas tretira kao NaN) za stringove, i NaT za datum koji nedostaje. Dtype stupca potrosnja ostaje float64 jer NumPy NaN postoji samo unutar float reprezentacije.

Kako otkriti nedostajuće vrijednosti u DataFrame-u

Najčešća pogreška kod nedostajućih podataka? Usporedba s == np.nan. Ne radi. NaN nije jednak ni sam sebi prema IEEE 754 standardu. Umjesto toga koristite isna() ili njen alias isnull():

# Boolean maska istih dimenzija kao DataFrame
maska = df.isna()

# Broj NaN-ova po stupcu, najkorisniji prikaz na početku analize
print(df.isna().sum())

# Postotak nedostajućih vrijednosti
print((df.isna().mean() * 100).round(2))

# Redovi koji imaju barem jedan NaN
df[df.isna().any(axis=1)]

# Redovi bez ijednog NaN-a
df[df.notna().all(axis=1)]

Za brzu vizualnu inspekciju u Jupyter bilježnici, paket missingno daje toplotnu kartu nedostajućih vrijednosti, što je dosta korisno kad istražujete obrasce u stupcima. Ako tek čistite skup podataka od nule, preporučujem prvo proći kroz naš kompletni vodič za čišćenje podataka s pandasom jer postavlja kontekst za sve što slijedi.

fillna: popunjavanje nedostajućih vrijednosti

Najjednostavniji oblik je fillna(value) gdje je value skalar koji zamjenjuje sve NaN-ove:

# Sve NaN-ove zamijeni nulom
df_popunjen = df.fillna(0)

# Različita vrijednost po stupcu
df_popunjen = df.fillna({
    "grad": "Nepoznato",
    "potrosnja": df["potrosnja"].mean(),
    "datum": pd.Timestamp("2026-01-01"),
})

# Popunjavanje samo na razini odabranog stupca
df["potrosnja"] = df["potrosnja"].fillna(df["potrosnja"].median())

Statistička pravila iz prakse: za simetrične numeričke stupce koristite mean(), za asimetrične ili one s outlierima median(), a za kategorijske vrijednosti mode()[0] ili eksplicitnu oznaku poput "Nepoznato". Honestly, mean popunjavanje smanjuje varijancu (što može oštetiti modele strojnog učenja), pa za regresijske modele razmislite o bibliotekama poput scikit-learn SimpleImputer ili IterativeImputer.

ffill i bfill: propagacija vrijednosti

Kada radite s vremenskim serijama, popunjavanje srednjom vrijednošću nema smisla. Bolje je propagirati posljednju poznatu vrijednost prema naprijed (ffill) ili sljedeću poznatu prema natrag (bfill):

cijene = pd.Series(
    [100.0, np.nan, np.nan, 105.0, np.nan, 110.0],
    index=pd.date_range("2026-06-01", periods=6, freq="D"),
)

# Propagiraj posljednju poznatu cijenu prema naprijed
cijene.ffill()

# Ograniči propagaciju na najviše 1 uzastopni NaN
cijene.ffill(limit=1)

# Kombinacija: prvo ffill, ostatak bfill
cijene.ffill().bfill()

Parametar limit sprječava ekstrapolaciju preko velikih praznina. Korisno kada nedostajući podaci znače stvarni prekid (npr. zatvoreni dan trgovanja vs. dugotrajno gašenje senzora). U jednom projektu s mjernim podacima senzora sam ovo zaboravio postaviti, pa je ffill tiho popunio tjedan dana mrtvih očitanja istom posljednjom vrijednošću. Otkrili smo to tek kad se anomalija pojavila u klijentovom izvještaju. Za naprednije popunjavanje obrazaca koji se mijenjaju kroz vrijeme, kombinirajte groupby s ffill kako je opisano u našem vodiču za pandas GroupBy.

dropna: uklanjanje redaka i stupaca

Ako popunjavanje nije primjereno (npr. u eksploratornoj analizi gdje želite samo cijele zapise), dropna() uklanja redove ili stupce s nedostajućim podacima:

# Ukloni svaki red koji ima barem jedan NaN (default je how='any')
df.dropna()

# Ukloni red samo ako su SVI stupci NaN
df.dropna(how="all")

# Ukloni red ako stupci 'potrosnja' i 'datum' nemaju vrijednost
df.dropna(subset=["potrosnja", "datum"])

# Zadrži samo retke s barem 3 ne-NaN vrijednosti
df.dropna(thresh=3)

# Ukloni stupce (umjesto redaka) koji imaju ikakav NaN
df.dropna(axis=1)

Parametar thresh je iznenađujuće moćan. Koristan je za uklanjanje gotovo praznih redaka iz raštrkanih (sparse) skupova podataka bez gubitka onih koji nose koristan signal. Uvijek provjerite koliko redaka gubite prije nego se obvežete: print(len(df), "→", len(df.dropna())).

Razlika između fillna i dropna

Najčešće pitanje početnika: kada popuniti, a kada brisati? Sljedeća tablica sažima ključne razlike:

Aspektfillna()dropna()
Što radiZamjenjuje NaN konkretnom vrijednošćuUklanja redove ili stupce s NaN-om
Veličina rezultataIsta kao izvorni DataFrameManja (ili prazna)
Rizik gubitka informacijaNizak; uvodi pristranost (bias)Visok ako je puno NaN-ova
Tipičan slučajStrojno učenje, ETL produkcijski pipelineiBrza eksplorativna analiza, mali postotak NaN-a
Promjena dtype-aMože promijeniti (npr. int u float)Čuva dtype
PerformanseO(n) bez realokacijeO(n) plus realokacija indeksa

Pravilo iz prakse: ako stupac ima <5% NaN-a i redovi su skupi za izgubiti, popunite. Ako stupac ima >40% NaN-a, razmislite o uklanjanju cijelog stupca jer popunjavanje samo izmišlja podatke. Između toga, odluku donesite na temelju ciljne metrike modela, a ne intuicije.

Interpolacija za numeričke i vremenske podatke

Za uređene numeričke serije (cijene, temperature, mjerenja senzora), interpolate() ispunjava praznine korištenjem matematičkog modela između susjednih poznatih vrijednosti:

temp = pd.Series(
    [20.0, np.nan, np.nan, 23.0, 24.0, np.nan, 26.0],
    index=pd.date_range("2026-06-20", periods=7, freq="D"),
)

# Linearna interpolacija (default)
temp.interpolate(method="linear")

# Vremenska interpolacija, uzima u obzir razmake u indeksu
temp.interpolate(method="time")

# Kubni splajn, gladak rezultat, traži scipy
temp.interpolate(method="cubic")

# Ograniči koliko uzastopnih NaN-ova se popunjava
temp.interpolate(limit=2, limit_direction="forward")

Metoda time je naročito važna ako vaš vremenski indeks nije ravnomjerno raspoređen. Recimo, dnevni podaci s vikendima koji nedostaju. linear bi u tom slučaju davao iste razlike između susjednih točaka neovisno o stvarnoj razlici u datumima, dok time proporcionalno raspodjeljuje razliku. Više detalja vidite u pandas User Guide poglavlju o missing data.

Nullable tipovi i pd.NA u pandas 2.2

Klasični NumPy int64 stupac ne može sadržavati NaN. Čim ubacite nedostajuću vrijednost, pandas tiho pretvara stupac u float64. Od pandasa 1.0 (i stabilno u 2.2), nullable dtypovi to rješavaju:

# Nullable integer (koristi pd.NA umjesto NaN)
s = pd.Series([1, 2, None, 4], dtype="Int64")
print(s.dtype)        # Int64 (s velikim I)
print(s.isna())       # [False, False, True, False]

# Nullable boolean i string tipovi
b = pd.Series([True, None, False], dtype="boolean")
t = pd.Series(["a", None, "c"], dtype="string")

# Arrow-backed string tip (brži, manje memorije, pandas 2.0+)
t_arrow = pd.Series(["a", None, "c"], dtype="string[pyarrow]")

Nullable tipovi su preporučeni put kada DataFrame šaljete u Parquet, Arrow ili Postgres, jer čuvaju semantičku razliku između "nepoznato" i "nula". Mana? Neke biblioteke trećih strana (starije verzije scikit-learn, matplotlib) ne razumiju pd.NA, pa morate konvertirati natrag prije korištenja.

Česti problemi i kako ih izbjeći

1. NaN se "vraća" nakon merge-a

Nakon pd.merge(left, right, how='left'), redovi koji se ne podudaraju u desnom DataFrame-u dobivaju NaN za sve desne stupce. To nije bug, to je očekivano. Provjerite kvalitetu spajanja s indicator=True kako biste vidjeli koliko redaka je left_only.

2. SettingWithCopyWarning kod fillna

Ako vidite to upozorenje pri df[df['x'] > 0]['y'].fillna(0), problem je u lančanom indeksiranju. Koristite .loc: df.loc[df['x'] > 0, 'y'] = df.loc[df['x'] > 0, 'y'].fillna(0). Ovu sam grešku radio mjesecima dok mi nije sjelo zašto pandas tiho ne ažurira originalni okvir.

3. inplace=True je deprecirano u lancima

Od pandasa 2.2, lančani pozivi s inplace=True generiraju upozorenje jer Copy-on-Write postaje default u pandasu 3.0. Pišite df = df.fillna(0) umjesto df.fillna(0, inplace=True) i bit ćete sigurni prema budućnosti.

4. Razlika između None i NaN

U Python objektnim stupcima, None i np.nan oba se prikazuju kao "NaN" u izlazu, ali isinstance(x, float) ih razlikuje. isna() tretira oba kao nedostajuće, što je obično ono što želite.

5. Popunjavanje prije ili poslije agregacije?

Ako popunite NaN-ove nulom prije izračuna prosjeka, prosjek će biti niži nego ako koristite mean(skipna=True) (default). Pandas funkcije po defaultu preskaču NaN, pa koristite to umjesto preventivnog popunjavanja. Za napredne transformacije koje primjenjuju vlastitu logiku popunjavanja, pogledajte naš vodič o pandas apply, map i lambda funkcijama.

Često postavljana pitanja

Koja je razlika između NaN, None i NaT u pandasu?

NaN je float marker za nedostajući broj iz NumPy-a, None je Python-ov objekt koji pandas tretira kao NaN u objektnim stupcima, a NaT (Not a Time) označava nedostajući datum ili vrijeme. Funkcija isna() ih sve tretira jednako, kao "nedostajuće".

Kako popuniti NaN vrijednosti različitim vrijednostima po stupcu?

Proslijedite rječnik u fillna: df.fillna({"dob": df["dob"].median(), "grad": "Nepoznato"}). Pandas će svakom stupcu primijeniti odgovarajuću vrijednost, a stupce koji nisu u rječniku ostaviti netaknute.

Zašto fillna ne mijenja moj DataFrame?

Većina pandas metoda vraća novi objekt umjesto da mijenja izvornik. Spremite rezultat: df = df.fillna(0). Parametar inplace=True postoji, ali je u pandasu 2.2 depreciran za lančane pozive i postat će potpuno uklonjen u pandasu 3.0.

Kako izbrisati stupce s previše nedostajućih vrijednosti?

Filtrirajte stupce po pragu postotka: df = df.loc[:, df.isna().mean() < 0.4]. Ovo zadržava samo stupce gdje je manje od 40% vrijednosti NaN. Alternativno, koristite df.dropna(axis=1, thresh=int(0.6 * len(df))).

Trebam li popuniti NaN prije treniranja modela strojnog učenja?

Da, većina scikit-learn estimatora ne podržava NaN ulaze. Koristite SimpleImputer ili IterativeImputer unutar Pipeline-a kako bi se imputacija učila na trening skupu i konzistentno primjenjivala na testni skup. Izbjegavajte popunjavanje na cijelom datasetu prije podjele jer to uzrokuje data leakage.

Editorial Team
O Autoru Editorial Team

Our team of expert writers and editors.