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:

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.