Pandas 3.0 útmutató: Újdonságok, törő változások és migráció

Fedezd fel a pandas 3.0 összes újdonságát: dedikált string típus, Copy-on-Write véglegesítése, pd.col() kifejezés-szintaxis, datetime felbontás változások, anti join támogatás és részletes migrációs útmutató a pandas 2.x-ről.

A pandas 3.0.0, amely 2026. január 21-én jelent meg, egyszerűen hatalmas lépés a Python adatelemző ökoszisztémában. Őszintén szólva, régóta vártam erre a verzióra — és nem ok nélkül. Ez a főverziós frissítés alapjaiban változtatja meg a DataFrame-ek kezelését: új alapértelmezett string típus, a Copy-on-Write viselkedés véglegesítése, egy vadonatúj kifejezés-szintaxis, és rengeteg teljesítményjavítás.

Szóval, vágjunk bele! Ebben az útmutatóban végigmegyünk az összes fontos újításon, a törő változásokon, és persze a migrációs stratégiákon is, hogy simán át tudj állni az új verzióra.

1. Dedikált string adattípus alapértelmezettként

A pandas 3.0 talán legszembetűnőbb változása, hogy a szöveges oszlopok mostantól automatikusan az új str típust kapják az eddigi object helyett. Ez a PDEP-14 javaslat megvalósítása, és alapvetően befolyásolja, hogyan dolgozol szöveges adatokkal.

Mi változott?

Korábban a pandas minden szöveges adatot object típusként tárolt, ami gyakorlatilag bármilyen Python objektumot tartalmazhatott. Ez nemcsak lassú volt, de típusbiztossági fejfájásokat is okozott. Az új str típus kizárólag szöveges értékeket és hiányzó értékeket (NaN) tartalmazhat — semmi mást.

# Pandas 2.x viselkedés
import pandas as pd
import numpy as np

# Régi viselkedés: object típus
ser_regi = pd.Series(["alma", "körte", "barack"])
print(ser_regi.dtype)  # object

# Pandas 3.0 viselkedés: str típus
ser_uj = pd.Series(["alma", "körte", "barack"])
print(ser_uj.dtype)  # str

PyArrow háttér

Ha a PyArrow telepítve van a gépeden, az új str típus automatikusan annak háttérrendszerét használja. Ez komoly teljesítményjavulást jelent, különösen nagy adathalmazok esetén. Ha nincs telepítve, a rendszer a NumPy object-dtype háttérre esik vissza — de a felhasználói API változatlan marad, szóval a kódod szempontjából ez teljesen átlátszó.

# A PyArrow háttér ellenőrzése
ser = pd.Series(["Budapest", "Debrecen", "Szeged"])
print(ser.dtype)  # str

# A háttérrendszer vizsgálata
print(type(ser.array))
# PyArrow telepítése esetén: pandas.core.arrays.string_arrow.ArrowStringArray
# PyArrow nélkül: pandas.core.arrays.string_.StringArray

Hatás a meglévő kódra

Ha a kódodban az object típusra ellenőrzöl szöveges oszlopoknál, azt mindenképp frissítened kell:

# Régi ellenőrzés (pandas 2.x) - már NEM működik megbízhatóan
if df["nev"].dtype == object:
    print("Szöveges oszlop")

# Új ellenőrzés (pandas 3.0)
if pd.api.types.is_string_dtype(df["nev"]):
    print("Szöveges oszlop")

# Vagy közvetlenül:
if df["nev"].dtype == "str":
    print("Szöveges oszlop")

Az I/O műveletek — read_csv(), read_excel(), read_json() — szintén automatikusan az új str típust használják szöveges oszlopokhoz. A hiányzó értékek kezelése is egységes lett: mindig NaN (np.nan) jelöli a hiányzó szöveges értékeket.

2. Copy-on-Write (CoW) viselkedés

A Copy-on-Write (másolás íráskor) mostantól a pandas 3.0 egyetlen és alapértelmezett működési módja. Ha valaha is láttad a rettegett SettingWithCopyWarning figyelmeztetést, most végre fellélegezhetsz — a PDEP-7 javaslat végleges megvalósítása ennek a hosszú ideje fennálló problémának vet véget.

Az alapelv

A pandas 3.0-ban minden indexelési művelet és minden olyan metódus, amely új DataFrame-et vagy Series-t ad vissza, úgy viselkedik, mintha másolatot készítene. A háttérben persze a rendszer nézet-alapú (view) megközelítést használ a teljesítmény érdekében, és csak akkor készít tényleges másolatot, amikor tényleg módosítani szeretnéd az adatot.

import pandas as pd

df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6]})

# Egy szelet lekérése - mindig másolatként viselkedik
szelet = df["A"]

# A szelet módosítása NEM változtatja meg az eredeti DataFrame-et
szelet.iloc[0] = 999
print(df["A"].iloc[0])  # 1 - az eredeti változatlan!

A láncolt hozzárendelés vége

A legfontosabb törő változás: a láncolt hozzárendelés (chained assignment) többé nem működik. Ez korábban rengeteg fejtörést okozott (és volt a SettingWithCopyWarning forrása is), de most teljesen eltűnt a problémával együtt.

# FIGYELEM: Ez a minta TÖBBÉ NEM MŰKÖDIK pandas 3.0-ban!
df["A"]["B"] = ertek  # Nem módosítja a df-et!

# Ehelyett használd a .loc[] indexelést:
df.loc["B", "A"] = ertek  # Ez a helyes megoldás

# Feltételes módosítás helyes módja:
df.loc[df["kor"] > 30, "kategoria"] = "felnőtt"

A védekező .copy() hívások feleslegessé váltak

A pandas 2.x-ben szinte reflexből írtuk a .copy() hívást a figyelmeztetés elkerülésére. Ez mostantól felesleges (bár nem okoz hibát, ha benne hagyod):

# Pandas 2.x - védekező másolás
szures = df[df["ar"] > 1000].copy()
szures["kedvezmeny"] = szures["ar"] * 0.1

# Pandas 3.0 - a .copy() felesleges, de nem árt
szures = df[df["ar"] > 1000]
szures["kedvezmeny"] = szures["ar"] * 0.1  # Biztonságos!

A mode.copy_on_write konfigurációs opció elavultnak lett nyilvánítva — nincs rá többé szükség, hiszen a CoW az egyetlen működési mód.

3. A pd.col() kifejezés-szintaxis

Na, ez az egyik kedvencem! A pandas 3.0 bevezeti a pd.col() függvényt, amivel DataFrame oszlopokra hivatkozhatsz és kifejezéseket építhetsz. Ha használtál már PySpark-ot vagy Polars-t, rögtön ismerős lesz a koncepció.

Alapszintaxis

import pandas as pd

df = pd.DataFrame({
    "nev": ["Anna", "Béla", "Cecil"],
    "kor": [25, 32, 28],
    "fizetes": [450000, 620000, 530000]
})

# Régi mód: lambda függvénnyel
df_regi = df.assign(eves_fizetes=lambda df: df["fizetes"] * 12)

# Új mód: pd.col() szintaxissal
df_uj = df.assign(eves_fizetes=pd.col("fizetes") * 12)
print(df_uj)

Összetett kifejezések

A pd.col() támogatja az összes aritmetikai műveletet, sőt a Series metódusokat is:

# Több oszlopos kifejezés
df = pd.DataFrame({
    "alap_ar": [1000, 2000, 3000],
    "mennyiseg": [5, 3, 8],
    "kedvezmeny_szazalek": [10, 15, 5]
})

# Végösszeg kiszámítása kedvezménnyel
df = df.assign(
    vegosszeg=pd.col("alap_ar") * pd.col("mennyiseg") * (1 - pd.col("kedvezmeny_szazalek") / 100)
)
print(df)

String metódusok és szűrés

# String metódusok használata pd.col()-lal
df = pd.DataFrame({
    "nev": ["kovács anna", "nagy béla", "kis cecil"],
    "sebesseg": [100, 110, 95]
})

# Név nagybetűsítése
df = df.assign(nev_formalt=pd.col("nev").str.title())

# Szűrés a .loc[] segítségével
gyors = df.loc[pd.col("sebesseg") > 100]
print(gyors)

A pd.col() előnyei a lambdával szemben

  • Olvashatóbb kód: A kifejezések világosabban mutatják, mit akarsz elérni.
  • Nincs változó-elfogási probléma: A lambda függvényekkel ellentétben a pd.col() nem rögzít hivatkozásokat a külső hatókörből — így elkerülheted a scope-bugokat.
  • Metódusláncolás támogatása: A szögletes zárójelekkel szemben a pd.col() tökéletesen illeszkedik a láncolási mintákhoz.

Fontos korlátozás: jelenleg a pd.col() még nem használható a groupby() aggregációkban. Ez a funkció a jövőbeli verziókban várhatóan bővülni fog.

4. Datetime és Timedelta felbontás változásai

Ez egy olyan változás, ami első ránézésre talán nem tűnik nagynak, de éles környezetben komoly fejfájást okozhat, ha nem készülsz fel rá. A pandas 3.0 alapvetően megváltoztatja az időadatok felbontásának kezelését.

Korábban az alapértelmezett felbontás mindig nanoszekundum (ns) volt, ami korlátozta az ábrázolható dátumtartományt (kb. 1678-2262). Mostantól a rendszer mikroszekundum felbontást használ alapértelmezettként, vagy a bemeneti adat felbontását veszi alapul.

Gyakorlati változások

import pandas as pd

# Pandas 2.x: mindig nanoszekundum
# Pandas 3.0: mikroszekundum (vagy a bemenet felbontása)

# Szöveges dátum feldolgozása
dt = pd.to_datetime(["2024-03-22 11:36"])
print(dt.dtype)  # datetime64[us] - mikroszekundum felbontás

# Egész szám alapú konverzió
dt_masodperc = pd.to_datetime([0], unit="s")
print(dt_masodperc.dtype)  # datetime64[s] - másodperc felbontás

# Nanoszekundum pontosság explicit megadása
dt_nano = pd.to_datetime(["2024-03-22 11:43:01.123456789"])
print(dt_nano.dtype)  # datetime64[ns] - nanoszekundum, mert a bemenet ezt igényli

Hatás a meglévő kódra

Ez a változás különösen fontos, ha az időbélyegeket egész számokká konvertálod. Figyelem: az értékek 1000-szer kisebbek lesznek, mint korábban!

# FIGYELEM: az int64 konverzió eredménye megváltozott!
ts = pd.Timestamp("2024-01-01")

# Pandas 2.x: nanoszekundum értéket adott vissza
# Pandas 3.0: mikroszekundum értéket ad vissza

# Felbontás-független kód írása:
ts_egysegben = ts.as_unit("ns").value  # Explicit nanoszekundum konverzió
print(ts_egysegben)

Érintett függvények

A felbontás változás az alábbi függvényeket érinti:

  • pd.to_datetime() — az alap felbontás us lett
  • pd.to_timedelta() — ugyanígy mikroszekundum alapú
  • read_csv() — dátum oszlopok feldolgozása
  • read_excel() — dátum cellák olvasása
  • read_parquet() — megtartja a fájl eredeti felbontását
  • pd.Timestamp() és pd.DatetimeIndex() konstruktorok

A jó hír viszont az, hogy a dátumtartomány jelentősen kiterjed — az 1678 előtti vagy 2262 utáni dátumok is ábrázolhatók lesznek, amelyek korábban túlcsordulási hibát okoztak.

5. A pd.offsets.Day naptári napként viselkedik

A pandas 3.0-ban a pd.offsets.Day mostantól valódi naptári napot jelent, nem pedig fix 24 órás időtartamot. Ez a változás elsősorban a nyári időszámítás (DST) átmeneteinél számít.

Gyakorlati példa

import pandas as pd

# Nyári időszámítás előtti időpont (USA keleti időzóna)
ts = pd.Timestamp("2025-03-08 08:00", tz="US/Eastern")

# Pandas 2.x: 24 órát ad hozzá → az óra eltolódik DST miatt
# ts + pd.offsets.Day(1)  → 2025-03-09 09:00:00-04:00 (egy órával később!)

# Pandas 3.0: naptári napot ad hozzá → megőrzi a napszakot
eredmeny = ts + pd.offsets.Day(1)
print(eredmeny)  # 2025-03-09 08:00:00-04:00 (a napszak változatlan)

Mellékhatások

Ez a változás néhány járulékos viselkedésbeli különbséget is hoz, amikre érdemes figyelni:

  • pd.offsets.Day(n) többé nem egyenlő pd.offsets.Hour(24*n)-nel.
  • A Day offset többé nem támogatja az osztást.
  • A pd.Timedelta nem fogad el Day objektumokat.
  • DST-átmeneteknél kétértelmű vagy nem létező idő keletkezhet, ami hibát dobhat.
# Összehasonlítási változás
nap = pd.offsets.Day(1)
huszonnegy_ora = pd.offsets.Hour(24)

# Pandas 2.x: True
# Pandas 3.0: False - a nap és a 24 óra többé nem egyenértékű
print(nap == huszonnegy_ora)  # False

# Ha fix 24 órás időtartamra van szükség, használd az Hour-t
ts = pd.Timestamp("2025-03-08 08:00", tz="US/Eastern")
eredmeny_24ora = ts + pd.offsets.Hour(24)
print(eredmeny_24ora)  # Pontosan 24 óra hozzáadva

6. NaN és NA kezelés egységesítése

A pandas 3.0 végre egységesíti a NaN és az NA hiányzó értékek kezelését a nullable adattípusokban. Korábban ez az inkonzisztencia rengeteg bosszúságot okozott — mostantól a NaN értéket a rendszer egyenértékűnek tekinti az NA értékkel.

A változás lényege

import pandas as pd
import numpy as np

# Nullable Float64 típus
ser = pd.Series([0, np.nan], dtype=pd.Float64Dtype())

# Pandas 2.x: a NaN és az NA különböző maradt
# ered = ser / 0  → [NaN, ] - inkonzisztens kezelés!

# Pandas 3.0: egységes kezelés
ered = ser / 0
print(ered)
# 0    
# 1    
# dtype: Float64
# Mindkét hiányzó érték -ként jelenik meg

A megkülönböztetés lehetősége

Ha valamilyen okból szükséged van a NaN és NA megkülönböztetésére (például tudományos számításoknál, ahol a NaN egy lebegőpontos művelet tényleges eredménye), van rá egy kísérleti opció:

# Kísérleti opció: NaN és NA megkülönböztetése
pd.options.future.distinguish_nan_and_na = True

# Ekkor a NaN egy lebegőpontos értékként viselkedik
ser = pd.Series([1.0, np.nan, pd.NA], dtype=pd.Float64Dtype())
print(ser)
# 0     1.0
# 1     NaN   ← lebegőpontos NaN
# 2       ← valódi hiányzó érték

Fontos: Ez az opció kísérleti jellegű, és a jövőben változhat. A legtöbb felhasználónak az alapértelmezett egységesített viselkedés a legjobb választás.

7. Időzóna kezelés: pytz helyett zoneinfo

A pandas 3.0 áttér a pytz könyvtárról a Python standard könyvtár zoneinfo moduljára. Ez a lépés összhangban van a Python közösség általános irányával — végül is, miért használnánk külső csomagot, ha a standard könyvtár ugyanazt tudja?

Gyakorlati változások

import pandas as pd
from zoneinfo import ZoneInfo

# Pandas 2.x: pytz objektumot adott vissza
# ts.tz → 

# Pandas 3.0: zoneinfo objektumot ad vissza
ts = pd.Timestamp(2024, 1, 15, 10, 30, tz="Europe/Budapest")
print(ts.tz)        # zoneinfo.ZoneInfo(key='Europe/Budapest')
print(type(ts.tz))  # 

# Időzóna lokalizálása
dt_index = pd.date_range("2024-01-01", periods=5, freq="D")
lokalizalt = dt_index.tz_localize("Europe/Budapest")
print(lokalizalt.dtype)  # datetime64[us, Europe/Budapest]

Kompatibilitás

A pytz továbbra is használható, ha közvetlenül átadod mint objektumot — de a pandas alapértelmezetten a zoneinfo-t fogja használni:

# A pytz továbbra is működik, ha explicit átadod
import pytz

budapest_pytz = pytz.timezone("Europe/Budapest")
ts = pd.Timestamp("2024-06-15", tz=budapest_pytz)
print(type(ts.tz))  # pytz típus marad

# De a szöveges megadás zoneinfo-t használ
ts2 = pd.Timestamp("2024-06-15", tz="Europe/Budapest")
print(type(ts2.tz))  # zoneinfo.ZoneInfo

Hibakezelés változása

A pytz-specifikus kivételek (pl. pytz.exceptions.AmbiguousTimeError) helyett mostantól a pandas szabványos ValueError-t dob. Ha a kódod pytz kivételeket kapott el, azt frissítened kell:

# Régi mód (pandas 2.x)
# try:
#     ts.tz_localize("Europe/Budapest")
# except pytz.exceptions.AmbiguousTimeError:
#     ...

# Új mód (pandas 3.0)
try:
    ts = pd.Timestamp("2024-10-27 02:30").tz_localize("Europe/Budapest")
except ValueError as e:
    print(f"Kétértelmű idő: {e}")

Ha továbbra is szükséged van a pytz-ra, telepítsd külön: pip install pandas[timezone].

8. Inplace metódusok mostantól self-et adnak vissza

Egy kisebb, de meglepő változás: azok a metódusok, amelyek inplace=True paraméterrel rendelkeznek, mostantól a módosított objektumot (self) adják vissza a korábbi None helyett. Ez elméletben lehetővé teszi a metódusláncolást inplace módban is — bár őszintén, az inplace láncolás elég ritka minta a gyakorlatban.

Érintett metódusok

  • replace()
  • fillna()
  • ffill()
  • bfill()
  • interpolate()
  • where()
  • mask()
  • clip()

Gyakorlati példa

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "nev": ["Anna", "Béla", None],
    "kor": [25, np.nan, 30],
    "fizetes": [450000, 520000, np.nan]
})

# Pandas 2.x: az inplace=True None-t adott vissza
# eredmeny = df.fillna(0, inplace=True)
# print(eredmeny)  # None

# Pandas 3.0: az inplace=True a módosított df-et adja vissza
eredmeny = df.fillna(0, inplace=True)
print(eredmeny is df)  # True - ugyanaz az objektum!

# Ez lehetővé teszi a láncolást (bár az inplace láncolás ritkán ajánlott)
df.fillna(0, inplace=True).clip(lower=0, upper=1000000, inplace=True)

Meglévő kód kompatibilitás

Ha a kódod explicit módon ellenőrizte, hogy az inplace művelet None-t ad vissza, azt feltétlenül frissítened kell:

# Régi minta (pandas 2.x) - problémás pandas 3.0-ban
eredmeny = df.fillna(0, inplace=True)
if eredmeny is None:
    print("Inplace módosítás történt")  # Ez többé nem igaz!

# Új minta (pandas 3.0)
eredmeny = df.fillna(0, inplace=True)
# Az eredmeny most maga a df
print(eredmeny is df)  # True

9. I/O fejlesztések

A pandas 3.0 számos izgalmas bemeneti/kimeneti fejlesztést hoz. Nézzük a legfontosabbakat!

Apache Iceberg támogatás

Az új read_iceberg() és DataFrame.to_iceberg() függvényekkel közvetlenül olvashatsz és írhatsz Apache Iceberg táblákat. Ha dolgozol adattárházakkal, ez hatalmas könnyebbség:

import pandas as pd

# Iceberg tábla olvasása
df = pd.read_iceberg("s3://adattarhaz/termekek_tabla")
print(df.head())

# DataFrame írása Iceberg táblába
df.to_iceberg("s3://adattarhaz/uj_tabla")

Anti join a merge()-ben

Végre! A merge() függvény mostantól támogatja az anti join műveleteket. Korábban ehhez nehézkes megkerülő megoldásokra volt szükség (gondolj a ~isin() vagy az indicator-os merge-re):

import pandas as pd

# Rendelések és visszáruk táblák
rendelesek = pd.DataFrame({
    "rendeles_id": [1, 2, 3, 4, 5],
    "termek": ["Laptop", "Telefon", "Tablet", "Monitor", "Billentyűzet"]
})

visszaruk = pd.DataFrame({
    "rendeles_id": [2, 4],
    "ok": ["Hibás", "Nem kért"]
})

# Left anti join: csak azok a rendelések, amelyeket NEM küldtek vissza
aktiv_rendelesek = rendelesek.merge(
    visszaruk,
    on="rendeles_id",
    how="left_anti"
)
print(aktiv_rendelesek)
#    rendeles_id        termek
# 0            1        Laptop
# 2            3        Tablet
# 4            5  Billentyűzet

# Right anti join is elérhető
eredmeny = visszaruk.merge(
    rendelesek,
    on="rendeles_id",
    how="right_anti"
)

Excel fejlesztések

A DataFrame.to_excel() is kapott néhány hasznos új funkciót:

import pandas as pd

df = pd.DataFrame({
    "Termék": ["Laptop", "Telefon", "Tablet"],
    "Ár": [350000, 180000, 120000],
    "Darabszám": [50, 200, 150]
})

# Automatikus szűrő hozzáadása minden oszlophoz
df.to_excel("termekek.xlsx", autofilter=True)

# MultiIndex oszlopfejlécek esetén csak az oszlopfejlécek összevonása
df_multi = df.set_index(["Termék"])
df_multi.to_excel("termekek_multi.xlsx", merge_cells="columns")

CSV float formázás f-string támogatással

# Új f-string formázás a float_format paraméterben
df = pd.DataFrame({"ertek": [3.14159, 2.71828, 1.41421]})

# F-string használata (új pandas 3.0-ban)
df.to_csv("szamok.csv", float_format="{:.2f}")

# A régi módszerek továbbra is működnek
df.to_csv("szamok2.csv", float_format="%.2f")

Parquet és egyéb fejlesztések

# Parquet: to_pandas_kwargs továbbítása
df = pd.read_parquet(
    "adatok.parquet",
    to_pandas_kwargs={"maps_as_pydicts": True}
)

# SQL: új if_exists="delete_rows" opció
# Ez törli az összes sort az insert előtt (a tábla szerkezete megmarad)
df.to_sql("termekek", engine, if_exists="delete_rows")

# JSON: a Decimal típus szöveggé konvertálódik float helyett
import json
from decimal import Decimal

df = pd.DataFrame({"osszeg": [Decimal("19.99"), Decimal("29.99")]})
df.to_json("osszegek.json")  # A Decimal értékek stringként jelennek meg

10. GroupBy, Rolling és aggregációs fejlesztések

A pandas 3.0 komolyan bővíti a csoportosítási és ablakfüggvények képességeit. Nézzük, mit kapunk!

A skipna paraméter a GroupBy-ban

A csoportosított aggregációs metódusok (sum, mean, median, prod, min, max, std, var, sem) mostantól elfogadják a skipna paramétert:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "kategoria": ["A", "A", "B", "B", "B"],
    "ertek": [10, np.nan, 20, 30, np.nan]
})

# skipna=True (alapértelmezett): kihagyja a NaN értékeket
atlag_skipna = df.groupby("kategoria")["ertek"].mean(skipna=True)
print(atlag_skipna)
# kategoria
# A    10.0
# B    25.0

# skipna=False: NaN-t ad vissza, ha bármilyen NaN van a csoportban
atlag_noskip = df.groupby("kategoria")["ertek"].mean(skipna=False)
print(atlag_noskip)
# kategoria
# A     NaN
# B     NaN

NamedAgg fejlesztések

A NamedAgg mostantól támogatja a *args és **kwargs továbbítását az aggregációs függvényeknek — ami sokkal rugalmasabbá teszi az egyedi aggregációkat:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "csoport": ["X", "X", "Y", "Y"],
    "ertek": [1, 2, 3, 4],
    "suly": [0.5, 0.5, 0.3, 0.7]
})

# NamedAgg args és kwargs támogatással
def sulyozott_atlag(x, suly):
    return np.average(x, weights=suly)

eredmeny = df.groupby("csoport").agg(
    atlag_ertek=pd.NamedAgg(column="ertek", aggfunc="mean"),
    sulyozott=pd.NamedAgg(
        column="ertek",
        aggfunc=sulyozott_atlag,
        suly=df["suly"]  # kwargs továbbítása
    )
)
print(eredmeny)

Új Rolling és Expanding metódusok

Jött pár új ablakfüggvény is, amikre sokan vártak:

import pandas as pd

ser = pd.Series([3, 1, 4, 1, 5, 9, 2, 6, 5, 3])

# Rolling.first() - az ablak első értéke
print(ser.rolling(3).first())

# Rolling.last() - az ablak utolsó értéke
print(ser.rolling(3).last())

# Rolling.nunique() - egyedi értékek száma az ablakban
print(ser.rolling(4).nunique())

# Rolling.pipe() - egyedi függvény alkalmazása
def sajat_statisztika(rolling_obj):
    return rolling_obj.mean() / rolling_obj.std()

eredmeny = ser.rolling(5).pipe(sajat_statisztika)
print(eredmeny)

Rolling és Expanding NamedAgg aggregáció

import pandas as pd

df = pd.DataFrame({
    "A": [1, 2, 3, 4, 5],
    "B": [10, 20, 30, 40, 50]
})

# NamedAgg a Rolling.aggregate()-ben
eredmeny = df.rolling(3).aggregate(
    a_atlag=pd.NamedAgg(column="A", aggfunc="mean"),
    b_max=pd.NamedAgg(column="B", aggfunc="max")
)
print(eredmeny)

A GroupBy observed=False javított viselkedése

A kategorikus adatok csoportosításánál az observed=False mostantól konzisztensen kezeli a nem megfigyelt csoportokat:

import pandas as pd

df = pd.DataFrame({
    "szin": pd.Categorical(
        ["piros", "kék", "piros", "kék"],
        categories=["piros", "kék", "zöld"]  # A "zöld" nem szerepel az adatban
    ),
    "ertek": [10, 20, 30, 40]
})

# observed=False: a nem megfigyelt csoportok is megjelennek
eredmeny = df.groupby("szin", observed=False)["ertek"].sum()
print(eredmeny)
# szin
# piros    40
# kék      60
# zöld      0   ← Korábban NaN lehetett, most 0

11. További fontos változások

Arrow PyCapsule interfész

A pandas 3.0 bevezeti az Arrow C Data Interface támogatást, ami lehetővé teszi az adatok nulla másolatos (zero-copy) cseréjét különböző DataFrame könyvtárak között. Ez a háttérben zajlik, de a teljesítményre komoly hatással van:

import pandas as pd

# DataFrame importálása Arrow-kompatibilis objektumból
# df = pd.DataFrame.from_arrow(arrow_tabla)

# A pandas DataFrame exportálása Arrow formátumba
# A __arrow_c_stream__ protokoll automatikusan elérhető
# import pyarrow as pa
# arrow_tabla = pa.table(df)

Új string metódusok

import pandas as pd

ser = pd.Series(["Helló", "Világ", "2024", "Tëszt™"])

# Új: str.isascii() - ASCII karakterek ellenőrzése
print(ser.str.isascii())
# 0    False  (Helló - ékezetes)
# 1    False  (Világ - ékezetes)
# 2     True  (2024 - csak számok)
# 3    False  (Tëszt™ - speciális karakterek)

# Új: str.replace() szótárral
ser2 = pd.Series(["alma-körte", "barack-szilva"])
eredmeny = ser2.str.replace({"-": ", ", "alma": "Alma"})
print(eredmeny)

Új dátum offsetek

import pandas as pd

# Féléves offsetek
felev_eleje = pd.offsets.HalfYearBegin()
felev_vege = pd.offsets.HalfYearEnd()

ts = pd.Timestamp("2024-03-15")
print(ts + felev_eleje)  # A következő félév elejére ugrik

# Üzleti féléves offsetek
uzleti_felev = pd.offsets.BHalfYearBegin()
print(ts + uzleti_felev)

# Húsvét offset orthodox módszerrel
husvet = pd.offsets.Easter(method="orthodox")
print(pd.Timestamp("2024-01-01") + husvet)

Hiányzó értékek kezelésének javulása

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A": [1, np.nan, 3],
    "B": [np.nan, 5, 6]
})

# fillna() mostantól elfogadja a value=None paramétert
# Ez automatikusan a megfelelő NA értéket használja a típus alapján
df_kitoltott = df.fillna(value=None)

# fillna() axis=1 támogatás szótárral
df_vizszintes = df.fillna({"A": 0, "B": -1}, axis=1)
print(df_vizszintes)

Teljesítmény és csomagolás

  • Windows ARM64 kerék (wheel) fájlok: A pandas mostantól natív Windows ARM64 binárisokat is kínál.
  • Python szabad szálkezelés (free-threading) támogatás: Windowson is elérhető a GIL-mentes Python támogatás.
  • Minimális Python verzió: Python 3.11 vagy újabb szükséges.
  • Minimális NumPy verzió: NumPy 1.26.0 vagy újabb szükséges.
  • Tömeges konfiguráció: A set_option() mostantól szótárat is elfogad.
# Tömeges konfiguráció szótárral
pd.set_option({
    "display.max_rows": 100,
    "display.max_columns": 50,
    "display.width": 120
})

API modul frissítés

A pandas 3.0 frissítette a nyilvános API __module__ attribútumát is — sokkal olvashatóbb kijelzést eredményez:

# Pandas 2.x
# 

# Pandas 3.0
# 
# Sokkal tisztább és olvashatóbb!

12. Migrációs útmutató: pandas 2.x-ről 3.0-ra

Az átállás a pandas 3.0-ra némi körültekintést igényel, de ne aggódj — az alábbi lépésenkénti útmutatóval simán végig lehet menni rajta.

1. lépés: Frissíts először pandas 2.3-ra

A pandas csapat ajánlása szerint először frissíts a pandas 2.3-ra, ami már tartalmazza a legtöbb elavultsági figyelmeztetést a 3.0-ás változásokhoz. Így nem ér meglepetés:

# Először frissíts 2.3-ra
pip install pandas==2.3.3

# Futtasd a tesztjeidet és javítsd az elavultsági figyelmeztetéseket
python -W all -m pytest tests/

# Ezután frissíts 3.0-ra
pip install pandas==3.0.0

# PyArrow telepítése az optimális teljesítményhez (opcionális, de ajánlott)
pip install pyarrow

2. lépés: String típus kezelés frissítése

# ELLENŐRIZD: dtype ellenőrzések frissítése
# Régi
if df["oszlop"].dtype == object:  # ← NEM megbízható

# Új
if pd.api.types.is_string_dtype(df["oszlop"]):  # ← Helyes

# ELLENŐRIZD: select_dtypes hívások
# Régi
df.select_dtypes(include=[object])  # Csak object típust választ

# Új
df.select_dtypes(include=["string"])  # String típus kiválasztása

3. lépés: Copy-on-Write kompatibilitás

# TÖRÖLD: felesleges .copy() hívások
# Régi (felesleges a 3.0-ban)
szurt = df[df["ar"] > 100].copy()

# Új (biztonságos copy nélkül is)
szurt = df[df["ar"] > 100]

# JAVÍTSD: láncolt hozzárendelések
# Régi (NEM működik)
df["A"][0] = 42

# Új (helyes)
df.loc[0, "A"] = 42
# vagy
df.iloc[0, df.columns.get_loc("A")] = 42

4. lépés: Datetime felbontás ellenőrzése

# ELLENŐRIZD: int64 konverziók
# Régi (nanoszekundum értéket feltételez)
ns_ertek = ts.value  # Nanoszekundum volt

# Új (felbontás-független)
ns_ertek = ts.as_unit("ns").value  # Explicit nanoszekundum

# ELLENŐRIZD: dtype összehasonlítások
# Régi
if idx.dtype == "datetime64[ns]":  # Lehet, hogy nem ns többé

# Új
if pd.api.types.is_datetime64_any_dtype(idx):  # Felbontás-független

5. lépés: Időzóna kód frissítése

# CSERÉLD: pytz importokat zoneinfo-ra
# Régi
import pytz
tz = pytz.timezone("Europe/Budapest")

# Új
from zoneinfo import ZoneInfo
tz = ZoneInfo("Europe/Budapest")

# JAVÍTSD: pytz kivételkezelés
# Régi
# except pytz.exceptions.AmbiguousTimeError:

# Új
# except ValueError:

6. lépés: inplace visszatérési érték ellenőrzése

# ELLENŐRIZD: kód, ami None-ra számít inplace műveleteknél
# Régi minta
eredmeny = df.fillna(0, inplace=True)
assert eredmeny is None  # Régen igaz volt, most HAMIS

# Új minta
df.fillna(0, inplace=True)  # A df módosult, és a visszatérési érték is df
# VAGY (ajánlott) az inplace kerülése:
df = df.fillna(0)

7. lépés: Eltávolított funkciók kezelése

Számos korábban elavultnak nyilvánított funkció véglegesen eltávolításra került:

  • A date_parser paraméter a read_csv()-ben — használd helyette a date_format-ot.
  • A keep_date_col kulcsszó a read_csv()-ben — elavultnak nyilvánítva.
  • A read_excel(), read_json(), read_html() és read_xml() többé nem fogadnak el nyers szöveges adatot közvetlenül — használj fájlútvonalat vagy puffert.
# Régi (eltávolítva):
# df = pd.read_csv("adat.csv", date_parser=sajat_parser)

# Új:
df = pd.read_csv("adat.csv", date_format="%Y-%m-%d %H:%M")

# Régi (eltávolítva):
# df = pd.read_json('{"a": [1, 2]}')  # Nyers szöveg

# Új:
from io import StringIO
df = pd.read_json(StringIO('{"a": [1, 2]}'))

Összefoglaló ellenőrzőlista

  1. Frissíts pandas 2.3-ra, javítsd a figyelmeztetéseket, majd frissíts 3.0-ra.
  2. Keresd meg és javítsd az object dtype ellenőrzéseket szöveges oszlopoknál.
  3. Távolítsd el a felesleges .copy() hívásokat és javítsd a láncolt hozzárendeléseket.
  4. Ellenőrizd a datetime int64 konverziókat és a felbontás-függő kódot.
  5. Cseréld a pytz használatot zoneinfo-ra ahol lehetséges.
  6. Ellenőrizd az inplace metódusok visszatérési értékére vonatkozó feltételezéseket.
  7. Frissítsd az eltávolított és elavult funkciók használatát.
  8. Telepítsd a PyArrow-t az optimális teljesítményhez: pip install pyarrow.

Összefoglalás

A pandas 3.0.0 kétségkívül a könyvtár történetének legjelentősebb frissítése. A dedikált string típus jobb típusbiztonságot és teljesítményt nyújt, a Copy-on-Write véglegesítése megszünteti a régóta ismerős másolás-nézet kétértelműségeket, a pd.col() szintaxis pedig olvashatóbb és biztonságosabb kódot tesz lehetővé.

A datetime felbontás változása kiterjeszti az ábrázolható dátumtartományt, míg a zoneinfo átállás és az NaN/NA egységesítés a modern Python ökoszisztémával való összhangot erősíti. Az I/O fejlesztések — köztük az Apache Iceberg támogatás és az anti join — pedig új lehetőségeket nyitnak az adatfeldolgozásban.

Igen, a migrációhoz kell egy kis tervezés. De a pandas csapat kiváló átállási útmutatókat kínál, és a pandas 2.3-ról való fokozatos frissítés biztosítja, hogy minden törő változásra felkészülhess. A befektetett energia bőven megtérül: tisztább kód, jobb teljesítmény, és egy jövőbiztos adatelemzési alaprendszer vár rád.

Akár kezdő, akár tapasztalt fejlesztő vagy — érdemes minél hamarabb megismerkedned az új lehetőségekkel és elkezdened a migrációt. A pandas 3.0 egyértelműen a Python adattudományi ökoszisztémájának érettségét jelzi.

A Szerzőről Editorial Team

Our team of expert writers and editors.