Hogyan tisztítsd meg könnyedén a hibás adathalmazokat

Mindenki töltött már órákat egy modell debugolásával, csak hogy kiderüljön: nem az algoritmus volt a hibás, hanem egy rossz nullérték a 47 832. sorban. A Kaggle versenyek(Kaggle Competition) tiszta CSV fájljai hamis illúziót keltenek. A valóságban az adatok hiányosak, hibásak és kaotikusak. Ebben a cikkben a NoBroker (egy indiai ingatlan-technológiai cég) valós toborzási feladatán keresztül mutatunk be négy gyakorlati lépést az adattisztításhoz. A célunk egy modell építése, amely megjósolja, hány interakciót kap egy ingatlan. De először rendet kell tennünk a káoszban.

1. Hiányzó adatok kezelése: Törlés vagy pótlás?

A hiányzó adat nem csak technikai hiba, hanem döntési pont. Töröljük a sort? Töltsük ki átlaggal? A válasz a hiány okától függ.

A példaprojektben a photo_urls oszlopban 28 888 sorból 11 022 hiányzott (38%). Ha ezeket törölnénk, elveszítenénk az adatbázis harmadát. A megoldás: feltételezzük, hogy ahol nincs URL, ott 0 fotó van.

Python kód a javításhoz:

import numpy as np
import json

def correction(x):
    # Ha nincs adat vagy 'NaN', akkor 0 fotó van
    if x is np.nan or x == 'NaN':
        return 0
    else:
        # JSON tisztítás és hossz számolása
        return len(json.loads(x.replace('\\', '').replace('{title','{"title')))

# Új oszlop létrehozása a fotók számával
pics['photo_count'] = pics['photo_urls'].apply(correction)

A numerikus (pl. emeletek száma) és kategória (pl. épület típusa) adatoknál a pótlást választottuk:

  • Számoknál: Átlaggal (mean) töltjük fel.
  • Kategóriáknál: A leggyakoribb értékkel (mode) pótoljuk.
# Numerikus hiányok pótlása átlaggal
for col in x_remain_withNull.columns:
    x_remain[col] = x_remain_withNull[col].fillna(x_remain_withNull[col].mean())

# Kategória hiányok pótlása módusszal
for col in x_cat_withNull.columns:
    x_cat[col] = x_cat_withNull[col].fillna(x_cat_withNull[col].mode()[0])

Tanulság: Soha ne törölj gondolkodás nélkül!

2. Kiugró értékek (Outlierek) detektálása

Egy 800 éves ház vagy egy 40 000 négyzetméteres lakás gyanús. Lehet, hogy luxusingatlan, de valószínűbb az adatrögzítési hiba. A „dobozdiagramok” (box plots) azonnal megmutatják ezeket a szélsőségeket.

A megoldás az Interkvartilis Tartomány (IQR) módszer. Minden olyan értéket kiszűrünk, ami az IQR kétszeresénél távolabb esik az átlagtól.

Függvény a szűréshez:

def remove_outlier(df_in, col_name):
    q1 = df_in[col_name].quantile(0.25)
    q3 = df_in[col_name].quantile(0.75)
    iqr = q3 - q1
    
    # Határok meghatározása (itt 2-szeres szorzót használunk)
    fence_low = q1 - 2 * iqr
    fence_high = q3 + 2 * iqr
    
    # Szűrés
    df_out = df_in.loc[(df_in[col_name] <= fence_high) & (df_in[col_name] >= fence_low)]
    return df_out

# Alkalmazás az összes numerikus oszlopra (kivéve a binárisokat)
df = dataset.copy()
for col in df_num.columns:
    if col not in ['gym', 'lift', 'swimming_pool']:
        df = remove_outlier(df, col)

print(f"Eltávolítva: {dataset.shape[0] - df.shape[0]} sor")

Ez a módszer 12,7%-kal csökkentette az adatsort, de a modell pontossága nőtt. Bizonyos esetekben a törlés helyett a „sapkázás” (capping) a jobb: például minden 10 feletti értéket egységesen 10-nek veszünk.

3. Duplikációk és inkonzisztencia

A duplikált sorokat könnyű törölni (df.drop_duplicates()). A valódi rémálom az inkonzisztens formátum.

A NoBroker adatbázisban a JSON mezők tele voltak hibákkal: hiányzó idézőjelek, felesleges backslash karakterek.

Hibás JSON javítása:

text_before = pics['photo_urls'][0]
# Eredmény: tele backslash-ekkel és rossz formázással

# Karaktercserék sorozata a valid JSON eléréséhez
text_after = text_before.replace('\\', '').replace('{title', '{"title').replace(']"', ']').replace('],"', ']","')

# Most már beolvasható
parsed_json = json.loads(text_after)

Ez nem elegáns, de működik. A lényeg a szabványosítás: minden dátum, szám és szöveg formátumának egységesnek kell lennie.

4. Adattípusok validálása és sémaellenőrzés

Már a beolvasáskor (read_csv) meg kell határozni a típusokat. Ha később derül ki, hogy a dátum szövegként van tárolva, az rengeteg fejfájást okoz.

Helyes beolvasás Pandasban:

# Rossz módszer (alapértelmezett típusok)
data = pd.read_csv('property_data_set.csv')
print(data['activation_date'].dtype) # 'object' (szöveg) lesz

# Jó módszer (típusok kényszerítése)
data = pd.read_csv('property_data_set.csv',
                   parse_dates=['activation_date'], 
                   infer_datetime_format=True, 
                   dayfirst=True)
print(data['activation_date'].dtype) # 'datetime64' lesz

Így már végezhetünk számításokat a dátumokkal, például kiszámolhatjuk a különbséget napokban:

num_req['request_day'] = (num_req['request_date'] - num_req['activation_date']) / np.timedelta64(1, 'D')

Dokumentáció, a jövőbeli éned megmentője

Három hónap múlva nem fogsz emlékezni rá, miért szűrted ki a 10 feletti értékeket. Ha nem dokumentálod a tisztítási lépéseket, a kódod egy érthetetlen varázslattá válik.

Minden transzformációt kommentelj, és használj strukturált notebookokat tartalomjegyzékkel.

Egy minta struktúra:

  1. Adatok felfedezése: Beolvasás, típusok ellenőrzése.
  2. Adatmérnökség: JSON tisztítás, hiányzó értékek kezelése.
  3. Feature Engineering: Outlierek eltávolítása, skálázás.
  4. Modellezés: Gépi tanulási algoritmusok futtatása.

A tiszta adat mítosz. A jó adattudós nem az, aki tökéletes adatot vár, hanem az, aki képes megszelídíteni a káoszt.

Kérjük, ellenőrizd a mező formátumát, és próbáld újra.
Köszönjük, hogy feliratkoztál.

vagyunk.hu hírlevél

Hozzászólás

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük