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:
- Adatok felfedezése: Beolvasás, típusok ellenőrzése.
- Adatmérnökség: JSON tisztítás, hiányzó értékek kezelése.
- Feature Engineering: Outlierek eltávolítása, skálázás.
- 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.




