LEGO-darabok adatkészletének elemzése
Adatok aggregálása és egyesítése a Pandas segítségével
Az alábbi pontokban számos kérdésekre keressük a válaszokat:
- Mi a valaha készült legnagyobb LEGO készlet, és hány darabból állt?
- Melyik évben adták ki az első LEGO készleteket, és hány készletet értékesített a cég az induláskor?
- Melyik LEGO témához tartozik a legtöbb készlet? Harry Potter, Ninjago, Friends, vagy valami más?
- Mikor lendült igazán fel a LEGO cég a termékkínálata alapján? Hány témát és készletet adott ki évente?
- Nőttek-e a LEGO készletek méretben és bonyolultságban az idők során? A régebbi LEGO készletek általában kevesebb vagy több darabból állnak, mint az újabbak?
A feladat során a Google Colab Notebook szoftvert fogjuk használni. Ez lényegében a Jupyter online verziója.
1. lépés: Olvassuk be a colors.csv fájlt az adat mappából.
A Pandas egy nyílt forráskódú Python könyvtár, amelyet adatkezelésre és -elemzésre használnak. Különösen hasznos a strukturált adatokat (például táblázatos adatokat) kezelő feladatokhoz. Ezt a könyvtárat fogjuk most mi is használni.
import pandas as pd
2. lépés: A struktúra megvizsgálása
Láthatjuk, hogyan néz ki az első 5 sor a head() függvény segítségével.
colors = pd.read_csv('data/colors.csv')
colors.head()
3. lépés
Öt oszlop van, amelyek tartalmazzák a színek neveit és azoknak megfelelő RGB értékeit. Hány különböző színt gyárt a LEGO cég? Az egyedi színek számának meghatározásához mindössze annyit kell tennünk, hogy ellenőrizzük, hogy minden bejegyzés a név oszlopban egyedi-e.
colors['name'].nunique()
Összesen 135 különböző szín létezik.
4. lépés
Találjuk meg az átlátszó színek számát. Két különböző módon is megtehetjük:
colors.groupby('is_trans').count()
colors.is_trans.value_counts()
28 db átlátszó szín van.
5. lépés - A sets.csv fájl feltárása
A sets.csv a LEGO készletek listáját tartalmazza. Adatokat szolgáltat nekünk arról, hogy melyik évben jelent meg a készlet és hány darab alkatrészből áll.
Mint mindig, az első lépés a .csv fájl beolvasása és annak megtekintése, hogy mi is van benne. Láthatjuk, hogy van egy azonosító (set_num) minden egyes készlethez, a készlet neve, a megjelenés éve, a theme_id (a téma nevét jelző kód) és az alkatrészek száma.
sets = pd.read_csv('data/sets.csv')
sets.head()
A tail() az utolsó 5 sort adja vissza egy Pandas DataFrame vagy Series objektumból.
sets.tail()
A sets.shape a Pandas DataFrame objektumra vonatkozó egyik attribútum, amely visszaadja a DataFrame sorainak és oszlopainak számát. A sets.shape eredménye egy tuple (kettős érték), ahol:
– Az első szám a sorok számát jelzi.
A második szám az oszlopok számát mutatja.
Például, ha a sets.shape értéke (15710, 5), az azt jelenti, hogy a DataFrame 15710 sorból és 5 oszlopból áll.
sets.shape
A sets.isna() a Pandas egy módszere, hogy megbizonyosodjunk róla, hogy NaN (Not a Number) van-e a DataFrame-ben.
True: az adott cellában NaN érték található, vagyis ez hiányzó adatot jelent.
False: az adott cellában nem NaN érték található.
Ez a módszer hasznos lehet, ha szeretnénk ellenőrizni vagy feldolgozni a hiányzó adatokat egy DataFrame-ben. Például ha azt szeretnénk megtudni, hogy mely oszlopokban és sorokban vannak hiányzó értékek, akkor használhatjuk az isna()-t.
sets.isna()
6. lépés
Melyik évben jelentek meg az első LEGO készletek, és mik voltak ezeknek nevei?
Ahhoz, hogy megtaláljuk az évet, a “year” oszlop szerint kell rendeznünk az adatokat. A .sort_values() metódus alapértelmezés szerint növekvő sorrendben rendezi az adatokat.
sets.sort_values('year').head()
7. lépés
Hány különböző terméket árult a LEGO vállalat a működésének első évében?
A fenti kumutatásból úgy tűnik, hogy a LEGO egészen 1949-ig nyúlik vissza. Az első készletek nevei nem különösebben figyelemre méltóak, de derítsük ki, hány különböző terméket árult a vállalat indulásának első évében:
sets[sets['year'] == 1949]
1949-ben a LEGO mindössze 5 különböző készletet árult. Itt a DataFrame szűrését egy feltétel alapján végezzük. Azokat a sorokat hívjuk le, ahol a year oszlop értéke 1949: sets[‘year’] == 1949.
8. lépés
Melyek azok a top 5 LEGO készletek, amelyek a legtöbb darabszámmal rendelkeznek?
Most nézzük meg, melyik LEGO készlet tartalmazza a legtöbb darabot. Ha meg akarjuk találni a legnagyobb darabszámot, akkor a num_parts oszlop szerinti rendezésnél az ascending argumentumot False-ra kell állítanunk.
sets.sort_values(by='num_parts', ascending=False).head()
A valaha készült legnagyobb LEGO készlet körülbelül 10,000 darabból áll.
9. lépés - A megjelent LEGO készletek számának időbeli vizualizálása
Most nézzük meg, hány készletet adott ki a LEGO cég évente. Ez segíthet megérteni, hogyan változott a LEGO termékkínálata az idő múlásával.
Először importáljuk a Matplotlib könyvtárat a második kódsorba, hogy vizualizálni tudjuk az eredményeinket.
import pandas as pd
import matplotlib.pyplot as plt
10. lépés
Használjuk a .groupby() és .count() metódusokat annak megjelenítésére, hány LEGO készletet adtak ki évente. Hogyan néznek ki az 1955-ben és 2019-ben kiadott készletek számai?
Most hozzunk létre egy új sorozatot, amelyet sets_by_year-nek nevezünk, és amelynek indexe az év, az értéke pedig az adott évben kiadott készletek száma. A folyamat, az adatok csoportosítása az év szerint, majd az adott évre vonatkozó bejegyzések számának megszámlálása.
sets_by_year = sets.groupby('year').count()
sets_by_year['set_num'].head()
sets_by_year = sets.groupby('year').count()
sets_by_year['set_num'].tail()
Fentebb láthatjuk, hogy a LEGO működésének első néhány évében kevesebb mint 10 különböző készletet adott ki évente. Azonban 2019-re a vállalat látványosan megnőtt, és csak abban az évben 840 készletet adott ki.
11. lépés – Adatvizualizáció Matplotlib segítségével
Észrevehetjük, hogy van egy bejegyzés 2021-re. A .csv fájl 2020 végéről származik, így úgy tűnik, hogy már tartalmaz néhány előretekintő készletet. Ezt figyelembe kell vennünk a diagramjaink elkészítésekor:
plt.plot(sets_by_year.index, sets_by_year.set_num)
12. lépés - Félrevezető diagram (javításra szorul!)
Mivel a .csv fájl 2020 végéről származik, a teljes naptári éveket ábrázolva ki kell zárnunk néhány adatot a diagramról. Használnunk kell a vágási technikákat, hogy elkerüljük az utolsó két év ábrázolását. Ugyanaz a szintaxis működik a Pandas DataFrame-eknél is. Ha nem zárjuk ki az utolsó két évet, drámai visszaesést kapunk a diagram végén.
Ez félrevezető, mert azt sugallja, hogy a LEGO nagy bajban van! Mivel a dataset nem tartalmazza 2020 teljes naptári évét, a legjobb, ha kizárjuk az utolsó két sort, hogy reálisabb képet kapjunk.
plt.plot(sets_by_year.index[:-2], sets_by_year.set_num[:-2])
Azt is láthatjuk, hogy az első körülbelül 45 évben a LEGO termékkínálata fokozatosan nőtt, de igazán az 1990-es évek közepén kezdett drámai mértékben növekedni a gyártott készletek száma.
A diagramon emellett egy rövid visszaesés is megfigyelhető a 2000-es évek elején, majd egy erőteljes fellendülés 2005 körül.
13. lépés – Adatok összesítése a Python .agg() függvénnyel
Dolgozzuk ki, hogy hány különböző témát szállítottak évente. Ez azt jelenti, hogy meg kell számolnunk az egyedi azonosítók számát naptári évenként.
A .agg() metódus egy szótárt vesz át argumentumként. Ebben a szótárban meghatározzuk, hogy melyik műveletet szeretnénk alkalmazni az egyes oszlopokra. Jelen esetben az egyedi bejegyzések számát akarjuk kiszámolni a theme_id oszlopban, az ismerős .nunique() metódus segítségével.
Adjunk a themes_by_year oszlopnak megfelelőbb nevet, és nézzük meg, mit kaptunk:
themes_by_year = sets.groupby('year').agg({'theme_id': pd.Series.nunique})
themes_by_year.rename(columns = {'theme_id' : 'nr_themes'}, inplace = True)
themes_by_year.head()
14. lépés
themes_by_year.tail()
Itt láthatjuk, hogy a LEGO az első néhány évben mindössze 2 témával rendelkezett, de az évek során, hasonlóan a készletek számához, a témák száma is sokszorosára nőtt. Ábrázoljuk azt újra egy diagramon.
15. lépés
Készítsünk vonaldiagramot az évente megjelent LEGO témák számáról. Az adathalmazban csak a teljes naptári éveket (1949-től 2019-ig) vegyük figyelembe.
plt.plot(themes_by_year.index[:-2], themes_by_year.nr_themes[:-2])
16. lépés - Vonaldiagramok egymásra helyezése külön tengelyekkel
Nem lenne nagyszerű, ha a témák számát és a készletek számát ugyanazon a diagramon ábrázolnánk? De vajon mit kapunk, ha egyszerűen úgy ábrázoljuk őket, ahogyan eddig tettük?
# Ez így borzasztóan néz ki.
plt.plot(themes_by_year.index[:-2], themes_by_year.nr_themes[:-2])
plt.plot(sets_by_year.index[:-2], sets_by_year.set_num[:-2])
17. lépés
Nos, a fenti diagram nem túl informatív! A probléma az, hogy a “témák száma” és a “készletek száma” nagyon eltérő skálán mozog. A témák száma 0 és 90 között van, míg a készletek száma 0 és 900 között változik. Szóval mit tehetünk?
Használjunk két különböző tengelyt
Be kell tudnunk állítani és ábrázolni az adatainkat két külön tengelyen ugyanazon a diagramon. Ehhez szükség van egy tengely objektumra a Matplotlib-ból.
Ezután létrehozunk egy másik tengely objektumot: ax2. A lényeg, hogy az .twinx() metódus segítségével az ax1 és ax2 ugyanazt az x-tengelyt osztja meg. Amikor az adatainkat ábrázoljuk a tengely objektumokon, ezt kapjuk:
ax1 = plt.gca() # Első tengely
ax2 = ax1.twinx() # Másik tengely, amely ugyanazt az x-tengelyt osztja meg
ax1.plot(sets_by_year.index[:-2], sets_by_year.set_num[:-2])
ax2.plot(themes_by_year.index[:-2], themes_by_year.nr_themes[:-2])
18. lépés
Ez nagyon szép! De van egy probléma: nem tudjuk megkülönböztetni a vonalakat, mert ugyanaz a színük! Vigyünk bele némi stílust. Adjunk színt a vonalaknak és a tengelyeknek, és adjunk hozzá címkéket, hogy lássuk, mi történik. Íme, amit kapunk:
ax1 = plt.gca()
ax2 = ax1.twinx()
# Add styling
ax1.plot(sets_by_year.index[:-2], sets_by_year.set_num[:-2], color='g')
ax2.plot(themes_by_year.index[:-2], themes_by_year.nr_themes[:-2], 'b')
ax1.set_xlabel('Year')
ax1.set_ylabel('Number of Sets', color='green')
ax2.set_ylabel('Number of Themes', color='blue')
19. lépés - Bonyodalmak az idő múlásával
A LEGO készletek idővel nagyobbak és bonyolultabbak lettek? Nézzük meg, hogy mi az átlagos darabszám egy LEGO készletben. Itt jöhet az, hogyan használjuk az .agg() függvényt.
Hozzunk létre egy Pandas Series-t, amit parts_per_set-nek hívunk, és amiben az év szerepel indexként, valamint az adott évben a LEGO készletek átlagos darabszáma található.
Ehhez a .groupby() és .agg() függvényeket fogjuk együtt használni. Ezúttal egy szótárat adunk át az .agg() függvénynek, hogy a num_parts oszlopra alkalmazzuk a mean() függvényt. Így az adatokat év szerint csoportosítjuk, majd kiszámítjuk az adott év készleteinek átlagos darabszámát.
parts_per_set = sets.groupby('year').agg({'num_parts': pd.Series.mean})
parts_per_set.head()
parts_per_set = sets.groupby('year').agg({'num_parts': pd.Series.mean})
parts_per_set.tail()
20. lépés
A parts_per_set adataink vizualizálásához hozzunk létre egy pontdiagramot (scatter plot). A pontdiagram egyszerűen pontokat használ az egyes adatpontok értékeinek ábrázolására.
Csak annyit kell tennünk, hogy a .plot() metódus helyett a .scatter() metódust meghívjuk a diagram létrehozásához. Az x-értékekhez a parts_per_set Series indexét (az éveket), az y-értékekhez pedig a sorozat értékeit (amelynek neve num_parts) fogjuk használni.
plt.scatter(parts_per_set.index[:-2], parts_per_set.num_parts[:-2])
21. lépés
A LEGO számos népszerű franchise-t licencelt, mint például a Harry Potter, a Marvel Superhősök és még sok más. De melyik téma rendelkezik a legnagyobb számú egyedi készlettel? Vajon a LEGO saját témái, mint a Ninjago vagy a Technic, vagy egy harmadik fél témája? Elemezzük részletesebben a LEGO termékcsaládjait!
Készletek száma LEGO témánként
Ahhoz, hogy megszámoljuk a készletek számát témánként, használhatjuk a .value_counts() metódust a theme_id oszlopon.
set_theme_count = sets["theme_id"].value_counts()
set_theme_count[:5]
Viszont van egy probléma:
Fogalmunk sincs arról, hogy valójában milyen nevek formájában szerepelnek a témák! Láthatjuk, hogy a 158-as azonosítójú téma a legnagyobb, 753 egyedi készlettel, de hogyan hívják ezt a témát? Ez nem túl hasznos. Meg kell találnunk a témák nevét a theme_id alapján a themes.csv fájlból.
22. lépés - Relációs adatbázissal való munka
Mi az adatbázis séma?
A séma az adatbázis szervezésének módja. Sok relációs adatbázis, például a LEGO adataink, különálló táblákra van bontva. Külön tábláink vannak a színekhez, a készletekhez és a témákhoz. Egy relációs adatbázisban a táblák kulcsokon keresztül kapcsolódnak egymáshoz.
A theme.csv fájl megértése
A themes.csv fájl tartalmazza a témák valódi neveit. Hogyan kapcsolódik ez a táblázat a többi táblázathoz? Nos, a sets.csv fájlban találhatóak a theme_id értékek, amelyek megegyeznek a themes.csv id oszlopának értékeivel.
Ez azt jelenti, hogy a theme_id a külső kulcs a sets.csv fájlban. Sok különböző készlet tartozhat ugyanahhoz a témához. A themes.csv fájlban azonban minden egyes theme_id (amelyet ott egyszerűen id-nek nevezünk) egyedi. Ez az egyediség teszi az id oszlopot elsődleges kulccsá a themes.csv fájlban. Hogy ezt jobban megértsük, nézzük meg a themes.csv tartalmát.
Keressük meg a “Star Wars” nevű témát. Hány id tartozik a themes.csv-ben a “Star Wars” névhez?
Használjuk az imént talált id-ket, és keressük meg a hozzájuk tartozó készleteket a sets.csv-ben (a theme_id oszlopban kell keresnünk az egyezéseket).
A themes.csv feltárása
Az első 5 sort megnézve láthatjuk az oszlopneveket.
themes = pd.read_csv('data/themes.csv')
themes.head()
23. lépés
Minden érték az id oszlopban egyedi (ez a fő kulcs a themes táblázatban). A téma nevek viszont nem egyediek. Ha a “Star Wars” névre keresünk, láthatjuk, hogy 4 különböző id tartozik ehhez a névhez.
themes[themes.name == 'Star Wars']
24. lépés
Miért lenne a Star Wars – nak ennyi különböző témája? Ellenőrizhetjük, hogy mely termékek tartoznak ezekhez a témákhoz a sets.csv fájlban:
sets[sets.theme_id == 18]
25. lépés
A Star Wars egy nagyon hosszú múltra visszatekintő franchise. A 18-as téma 2000 és 2002 között futott, és úgy tűnik, hogy a sorozat több karakterét tartalmazza. Mi a helyzet például a 209-es témával?
sets[sets.theme_id == 209]
Itt látjuk, hogy az összes Star Wars Adventi Naptár ugyanazt a theme_id-t használja. Ez teljesen érthető.
26. lépés - Hogyan lehet egyesíteni a DataFrame-eket és készíteni oszlopdiagramokat?
Nem lenne szebb, ha össze tudnánk kapcsolni a téma neveit a témákhoz tartozó készletek számával?
Használjuk a .merge() metódust, hogy két különálló DataFrame-et egyesítsünk egybe. A merge metódus azokkal az oszlopokkal működik, amelyek ugyanazzal a névvel szerepelnek mindkét DataFrame-ben.
Jelenleg a theme_id és a témákhoz tartozó készletek száma egy set_theme_count nevű Series-ben található.
set_theme_count = sets["theme_id"].value_counts()
set_theme_count[:5]
27. lépés - Adatkeretek összevonása (egyesítése) kulcs alapján
Annak érdekében, hogy biztosak legyünk benne, hogy van egy “id” nevű oszlopunk, át fogom alakítani ezt a Pandas Series-t egy Pandas DataFrame-mé.
A Pandas .merge() függvény
Ahhoz, hogy két DataFrame-t a .merge() függvénnyel egy adott oszlop mentén összekapcsoljunk, meg kell adnunk a két DataFrame-et, majd az oszlop nevét, amely mentén össze szeretnénk őket kapcsolni. Ezért állítjuk be az on=’id’ paramétert. A set_theme_count és a themes DataFrame-ünk is tartalmaz egy oszlopot ezzel a névvel.
merged_df = pd.merge(set_theme_count, themes, on='id')
merged_df[:3]
Az első három sor az összekapcsolt DataFrame-ben így néz ki:
A Star Wars valóban az a téma, amely a legtöbb LEGO szettel rendelkezik. Hozzunk létre egy diagramot a top 10 témáról.
28. lépés - Oszlopdiagram készítése
A Matplotlib szinte bármilyen diagramot képes létrehozni nagyon kevés kódsorral. A .bar() segítségével megadhatjuk a téma nevét és a készletek számát. Íme, amit kapunk:
plt.bar(merged_df.name[:10], merged_df.set_count[:10])
29. lépés
A feliratok szinte olvashatatlanok. A jó hír számunkra, hogy már tudjuk, hogyan kell testreszabni a diagramjainkat. Meg kell növelnünk a diagram méretét, hozzá kell adnunk néhány címkét, és ami a legfontosabb, elforgatjuk a kategória neveket az x-tengelyen, hogy ne fedjék egymást.
plt.figure(figsize=(14,8))
plt.xticks(fontsize=14, rotation=45)
plt.yticks(fontsize=14)
plt.ylabel('Nr of Sets', fontsize=14)
plt.xlabel('Theme Name', fontsize=14)
plt.bar(merged_df.name[:10], merged_df.set_count[:10])
A ‘Gear’ kategória önmagában hatalmas, és úgy tűnik, hogy mindent tartalmaz, a táskáktól kezdve a tolltartókig. Vajon a LEGO eltért az alaptevékenységétől, vagy sikeresen diverzifikál? Ezt nem tudjuk megválaszolni az adatainkból.