Ebben a posztban a Pandas alapvető adattisztító és adat előkészítő eszközeit mutatom be. Ha nem vagy járatos a Python programozási nyelvben, ajánlom figyelmedbe ezt a posztomat. Ha a Pandas alapok nem ismerősek számodra, akkor kukkants be ide.
Mik azok a CSV fájlok
A CSV egy betűszó, ami a Comma Separated Values elnevezéshez köthető. A CSV-k olyan egyszerű szöveges állományok (plain text), amelyekben az adatokat soronként tároljuk, és az egyes értékek vesszővel, vagy egyéb elválasztókarakterrel vannak szeparálva. Sok esetben rendelkezik egy fejléc sorral, amely az adatok elnevezéseiről ad információt. Alább látható egy tipikus CSV fájl struktúra. Az első sor a fejléc, a további sorok pedig adatok, vesszővel elválasztva. Fontos, hogy a CSV kiterjesztés nem kötelező, sokszor .txt kiterjesztés látható ezeknél az állományoknál.
CSV fájlok beolvasása
A Pandas lehetőséget nyújt CSV fájlok olvasására és feldolgozására. Gyakorlásnak ilyen állományokat például a kaggle.com oldalról szerezhetsz teljesen ingyenesen. Én ezt a dataset-et használtam a beolvasásnál:
https://www.kaggle.com/datasets/benioktopiansah/global-finance-and-sales-performance
Az első, és legfontosabb dolog mindig az adatstruktúra értelmezése.
- Date: az adott értékesítés vagy tranzakció dátuma
- Region: a földrajzi régió, ahol az értékesítés történt (például LATAM = Latin-Amerika, APAC = Ázsia és Csendes-óceáni térség)
- Product Category: az értékesített termék vagy szolgáltatás kategóriája (például Enterprise Software vagy Consulting)
- Sales Channel: az értékesítési csatorna típusa, vagyis hogyan történt az eladás (például Online vagy Direct)
- Revenue_USD: a teljes bevétel amerikai dollárban
- COGS_USD: az eladott termékek vagy szolgáltatások közvetlen költsége amerikai dollárban (Cost of Goods Sold)
- Budget_Target: az előre kitűzött bevételi vagy üzleti cél amerikai dollárban
- CSAT: ügyfélelégedettségi mutató (Customer Satisfaction), általában 1–5 közötti érték
- Discount_Percent: az alkalmazott kedvezmény százalékos mértéke
Az alábbi kóddal tudunk CSV fájlokat beolvasni Pandas segítségével:
import pandas as pd
df = pd.read_csv("global_finance_sales_dataset_1200_rows.csv")
Alapadatok kinyerése
A következőkben az alapadatok kinyerésével fogunk foglalkozni. Az alábbi kód a sorok és oszlopok számát adja vissza.
#sorok és oszlopok száma
print(df.shape) #(1200, 9)
A következő kódsorok mutatják az adattípusokat:
print(df.dtypes)
Ilyen típusok találhatók a csv fájlban:
- str: karakterlánc (string)
- int64: egész szám (64 bites integer)
- float64: tört szám (64 bites tört)
A következő kódsor automatikusan kiszámolja a legalapvetőbb statisztikai mutatókat.
print(df.describe())
- count: hány darab van
- mean: átlag
- std: szórás
- min: minimum
- 25%: első kvartilis (az adatok 25%-a ennél az értéknél kisebb)
- 50%: második kvartilis
- 75%: harmadik kvartilis
- max: maximum érték
A Pandas lehetővé teszi az egyes metódusok láncolását (chaining). Ha szimplán csak az isnull metódust hívnánk meg az adatkészletre, az minden egyes sorban és oszlopban (lényegében cellákban) egy True vagy False értéket jelenítene meg attól függően, hogy az adott sor üres-e vagy sem. A sum aggregálja ezeket az eredményeket oszloponként, tehát azt adja meg, hogy az adott oszlopokban hány null érték volt megtalálható. Én magam kézzel kitöröltem bizonyos értékeket, így keletkeztek nálam nullától eltérő értékek. Ezt te magad is megteheted.
print(df.isnull().sum())
A duplikált értékek kiszűrése lényeges lépés. Erre is létezik megoldás a Pandas-ban. Ne feledjük, hogy ez nem jelent megoldást a duplikátumokra, csupán jelzi, hogy léteznek! Én kézzel lemásoltam egy sort, hogy legyen ilyen a datasetben.
print(df.duplicated().sum())
Az adatok tisztítása
Négy alapvető hiba szokott lenni az adatokban, amelyek rossz eredményre vezethetnek.
- hiányzó adatok
- duplikált/többszörözött sorok
- kiugró értékek
- dátum oszlopok konvertálása
Hiányzó adatok
Ha hiányzik egy adat, akkor általában véve vagy az átlaggal, vagy a mediánnal töltjük fel az adott cellát, de akár törölhetjük is a teljes sort. Úgy vélem, hogy teljes sort csak akkor érdemes törölni, hogyha kevés adat hiányzik. Ebben az esetben a sor törlése nem okoz komoly problémát. Most kevés adat nincs meg, de ennek ellenére nem fogok törölni, ami mögött pedagógiai szándék rejlik.
Lényeges különbség az átlag és a medián között, hogy az átlag érzékenyebb az eloszlás szimmetriájára, vagy a kiugró értékekre, emiatt a medián általában véve jobban reprezentálja az adatokat.
Itt jönnek képbe az alakmutatók, jelen esetben az alakmutatók. Ezek csúcsosságot és aszimmetriát képesek mérni. Ha egyetlen adat aszimmetriáját szeretném kalkulálni, akkor így járhatok el:
print("aszimmetria\n", df['Revenue_USD'].skew()) #0.042
A Pandas skew metódusa alapértelmezetten a Fisher-Pearson-féle mutatót számolja ki. Negatív értékek esetében bal, pozitív értékeknél jobb oldali aszimmetria van. Tehát, ha jobbra nyúlik az eloszlás szára, akkor pozitív értéket kapunk. A -1 alatti és 1 fölötti értékek jelentős aszimmetriára utalnak. -0.5 és 0.5 között az aszimmetria nem jelentős. A 0.042-es érték meglehetősen alacsony.
Ilyen a jobb oldali aszimmetria (jobbra nyúló szár):

Ilyen a bal oldali aszimmetria (balra nyúló szár):

A csúcsosság mérésére a "kurt" metódus való. Az eloszlás csúcsossága azt írja le, hogy az adatok milyen mértékben koncentrálódnak a középérték körül. Nagy koncentráció csúcsosabb eloszlást eredményez. A Fisher-féle csúcsossági mutató esetében a normál eloszlás értéke nulla. A nullánál kisebb számok laposabb, a nagyobbak csúcsosabb eloszlást feltételeznek.
A -1.07-es érték laposabb eloszlást jelöl. Ezt egyetlen ismérvre így tudod használni:
print("csúcsosság:\n", df[['Revenue_USD']].kurt()) #-1.07
Nade, akkor hogyan is pótoljuk a mediánnal, vagy az átlaggal az adatokat?
A "select_dtypes" metódus képes bizonyos típusú adatokat, pontosabban azok indexeit kiválasztani. Az adattípust az "include" paraméterben lehet kiválasztani. Az alábbi példában a szám (number) típusú adatokat választottuk ki. A print így néz ki:
num_cols = df.select_dtypes(include='number').columns
print(num_cols)
df[num_cols] = df[num_cols].fillna(df[num_cols].median())
Ha kézzel akarnánk megadni több mezőt, akkor ezt kéne tennünk. Itt direkt az átlagot választottam a pótlásra, hogy megmutassam azt is:
df[['Revenue_USD', 'COGS_USD']] = df[['Revenue_USD', 'COGS_USD']].fillna(df[['Revenue_USD', 'COGS_USD']].mean())
A statisztikai mutatók számításakor a Pandas automatikusan figyelmen kívül hagyja a hiányzó értékeket, így a valós eloszlást látjuk. A legtöbb esetben érdemes először megnézni az eloszlást, és utána pótolni az értékeket.
Ha kategorikus oszlopban szeretnénk kitölteni a hiányzó adatokat, akkor azt így tehetjük meg. Ha hiányzik egy régió, akkor azt feltöltjük az 'Unknown' karakterlánccal.
df['Region'] = df['Region'].fillna('Unknown')
Duplikált sorok
A duplikált sorokat a következőképpen eliminálhatjuk:
df = df.drop_duplicates()
Kiugró értékek eltávolítása
A kiugró értékek kezelésére az IQR-módszert (vagy más néven Tukey-féle korlátokat) alkalmaztam. Ez a számítás az interkvartilis tartomány 1.5tel való szorzatát használja fel arra, hogy kijelölje az alsó és felső küszöbértékeket, amelyeken kívül eső adatokat kiugrónak tekintjük.
Q1 = df['Revenue_USD'].quantile(0.25)
Q3 = df['Revenue_USD'].quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
df = df[(df['Revenue_USD'] >= lower) & (df['Revenue_USD'] <= upper)]
Próbáljuk meg értelmezni a kódot! A quantile(0.25) az alsó kvartilist adja vissza. Ennél az értéknél az adataink negyede kisebb. A felső kvartilis természetesen azt jelenti, hogy az adataink negyede nagyobb annál az értéknél, tehát háromnegyede kisebb. Az utolsó sor az úgynevezett vektoralapú szűrés, vagy más néven maszkolás. Itt annyit állítottunk be, hogy a DataFrame-ben a lower értéknél ne legyen kisebb, és az upper értéknél ne legyen nagyobb. Az & operátor a bitenkénti ÉS, jelen példánál azt jelenti, hogy a bal és jobb oldali kifejezések mindegyikének igaznak kell lennie az adott értékekre vonatkozóan.
Dátumok kezelése
A Pandas a legtöbb esetben automatikus típuskonverziót végez. A dátumoknál viszont ezt a szívességet nem teszi meg magától. Ha dátumműveleteket akarunk elvégezni, ahhoz az szükséges, hogy a string típusból date legyen.
Ezt a feladatot így abszolválhatjuk:
df['Date'] = pd.to_datetime(df['Date'], errors='coerce')
Valójában a dátumokat is be tudja olvasni helyes típusként már a beolvasás pillanatában, ha használod a parse_dates=['Date'] paramétert a read_csv() függvényben.
Az errors paraméter azt határozza meg, hogy mi történjen, amennyibe hibás értéket talál a Pandas. Három lehetőség van:
- raise: Megáll a kód, hibát dob, és leáll a kód.
- ignore: Megtartja az eredeti értéket.
- coerce: Lecseréli az értéket NaT-ra. (Not a Time.)
Ha a típuskonverziót követően megnézzük a DataFrame-ünk oszlopainak típusait, akkor ez a látvány fogad bennünket:





Top comments (0)