|
1 | 1 | ## Pokročilé úpravy
|
2 | 2 |
|
3 |
| -V předchozí lekci jsme si ukázali, jak v `pandas` vytváříme `DataFrame` a jak z něj můžeme vybírat data pomocí různých způsobů dotazování. Nyní se posuneme o kus dále a ukážeme si, jak můžeme s `DataFrame` dělat složitější operace jako je filtrování chybějících hodnot, spojování a agregace. |
4 |
| - |
5 |
| -### Maturita |
6 |
| - |
7 |
| -Abychom měli nějaký praktický příklad k procvičování, použijeme fiktivní data z výsledků maturitních zkoušek během jednoho týdne na nějakém menším gymnáziu. Maturita se odehrává ve třech místnostech: U202, U203 a U302. Máme tedy tři tabulky dat, z každé místnosti jednu. Níže si můžete prohlédnout příklad tabulky z místnosti U202. Všechny tabulky jsou ke stažení zde: [u202.csv](assets/u202.csv), [u203.csv](assets/u203.csv), [u302.csv](assets/u302.csv). |
8 |
| - |
9 |
| -Funkce `read_csv()` knihovny `pandas` umí stáhnout CSV soubor rovnou z internetu. |
10 |
| - |
11 |
| -```py |
12 |
| -import pandas |
13 |
| - |
14 |
| -u202 = pandas.read_csv("https://kodim.cz/cms/assets/analyza-dat/python-data-1/python-pro-data-1/agregace-a-spojovani/pokrocile-upravy/u202.csv") |
15 |
| -u203 = pandas.read_csv("https://kodim.cz/cms/assets/analyza-dat/python-data-1/python-pro-data-1/agregace-a-spojovani/pokrocile-upravy/u203.csv") |
16 |
| -u302 = pandas.read_csv("https://kodim.cz/cms/assets/analyza-dat/python-data-1/python-pro-data-1/agregace-a-spojovani/pokrocile-upravy/u302.csv") |
17 |
| -``` |
18 |
| - |
19 |
| -|cisloStudenta |predmet |znamka|den| |
20 |
| -|---:|:----------------|------:|:---| |
21 |
| -|1 |Chemie | |pá | |
22 |
| -|2 |Dějepis |3 |pá | |
23 |
| -|3 |Matematika |2 |út | |
24 |
| -|2 |Společenské vědy|2 |pá | |
25 |
| -|4 |Biologie |1 |pá | |
26 |
| -|5 |Dějepis |1 |po | |
27 |
| -|6 |Fyzika |2 |čt | |
28 |
| -|7 |Dějepis |4 |po | |
29 |
| -|8 |Matematika |2 |po | |
30 |
| -|9 |Dějepis | |pá | |
31 |
| -|10 |Chemie |2 |st | |
32 |
| -|3 |Chemie |5 |út | |
33 |
| -|11 |Matematika |1 |st | |
34 |
| -|12 |Biologie |4 |st | |
35 |
| -|10 |Dějepis |5 |st | |
| 3 | +V předchozí lekci jsme si ukázali, jak v `pandas` načteme data do tabulky (`DataFrame`) a jak z něj můžeme vybírat data pomocí různých způsobů dotazování. Nyní se posuneme o kus dále a ukážeme si, jak můžeme s `DataFrame` dělat složitější operace jako je filtrování chybějících hodnot, spojování a agregace. |
36 | 4 |
|
37 | 5 | ### Práce s chybějícími hodnotami
|
38 | 6 |
|
39 |
| -V praxi se poměrně často setkáme s tím, že v datovém setu některé hodnoty chybí. Můžeme si například všimnout, že v tabulce U202 dvěma studentům chybí známka. To znamená, že se studenti k maturitě nedostavili. Na takové případy je třeba být připraven. |
40 |
| - |
41 |
| -V `pandas`, ale i obecně v datové analýze, je možné se s chybějícími daty vypořádat různými způsoby: |
| 7 | +V praxi se poměrně často setkáme s tím, že v datovém setu některé hodnoty chybí. Můžeme si například všimnout, že v tabulce `food_nutrient.csv` jsou chybějící hodnoty. Ty jsou při výpisu zobrazovány jako `NaN`. |
42 | 8 |
|
43 |
| -1. Nejlepší je vždy ověření, proč údaje chybí (např. u poskytovatele dat) a pokud je to možné, zajistit jejich doplnění. |
44 |
| -1. Nahradit chybějící hodnoty jinými hodnotami. |
45 |
| -1. Odstranit všechny řádky s chybějícími daty z datového setu. |
46 |
| -1. Vyčlenit je do separátního datasetu a zpracovat je zvlášť. |
| 9 | +Při práci s daty, je možné se s chybějícími daty vypořádat různými způsoby. |
47 | 10 |
|
48 |
| -Důležité je mít na paměti, že vyřazením některých řádků může dojít ke zkreslení výsledků analýzy! |
| 11 | +Nejprve bychom si měli uvědomit, zda jsou pro nějaké sloupec chybějící hodnoty vlastně problém. Typický příklad sloupečku, kde to nevadí, je `footnote`. To, že k nějaké hodnotě není poznámka pod čarou, nevadí, zkrátka k měření žádná doplňující poznámka není. Naopak u sloupce `amount` to vadit může. U nějaké konkrétní výživné látky nevíme její obsah v nějaké konkrétní potravině. |
49 | 12 |
|
50 |
| -### Odstranění neúplných řádků |
| 13 | +Co v takovém případě udělat? Nejlepší je vždy ověření, proč údaje chybí (např. u poskytovatele dat, v metodice sběru, v programu na export dat) a pokud je to možné, zajistit jejich doplnění. Při hledání příčiny může pomoci i uložení těchto dat do samostatné tabulky, protože v ní můžeme vidět nějaké společné znaky, které tyto neúplné řádky mají. Zkusme si to na našich datech. |
51 | 14 |
|
52 |
| -Předpokládejme, že jsme si ověřili, že data chybí skutečně pouze u studentů, kteří z daného předmětu nematurovali. Protože nás budou zajímat především statistiky jednotlivých předmětů, můžeme prázdné řádky vynechat, protože označují zkoušky, které ve skutečnosti neproběhly. |
53 |
| - |
54 |
| -Pokud jsme tak ještě neučinili, načteme si naši první tabulku jako DataFrame. |
| 15 | +Pokud nemáš načtená data, použij stejný příkaz jako v minulé lekci. |
55 | 16 |
|
56 | 17 | ```py
|
57 |
| -import pandas |
58 |
| -u202 = pandas.read_csv('u202.csv') |
| 18 | +import pandas as pd |
| 19 | +food_nutrient = pd.read_csv('food_nutrient.csv') |
59 | 20 | ```
|
60 | 21 |
|
61 |
| -Pokud `pandas` narazí na prázdnou buňku, vloží místo ní do tabulky speciální hodnotu `NaN`, se kterou už jsme se setkali. |
62 |
| - |
63 |
| -Série obsahují metodu `isnull()`, která vrátí pravdivostní sérii s hodnotou `True` všude tam, kde v původní sérii chybí hodnota. Metoda `notnull()` pracuje přesně opačně. Vrátí pravdivostní sérii s hodnotami `True` všude tam, kde v původní sérii hodnota nechybí. |
| 22 | +Zkusíme si uložit řádky bez množství výživné látky do tabulky `food_nutrient_incomplete`. Použijeme metodu `isna()`, která pro každý řádek vrátí pravdivostní hodnotu (tj. hodnotu `True` pro řádek s hodnotou nebo `False` pro prázdný řádek). Poté můžeme použít dotaz, který jsme si ukázali už v minulé lekci. |
64 | 23 |
|
65 | 24 | ```py
|
66 |
| -print(u202['znamka'].isnull()) |
| 25 | +food_nutrient_incomplete = food_nutrient[food_nutrient["amount"].isna()] |
| 26 | +food_nutrient_incomplete.head() |
67 | 27 | ```
|
68 | 28 |
|
69 |
| -```shell |
70 |
| -0 True |
71 |
| -1 False |
72 |
| -2 False |
73 |
| -3 False |
74 |
| -4 False |
75 |
| -5 False |
76 |
| -6 False |
77 |
| -7 False |
78 |
| -8 False |
79 |
| -9 True |
80 |
| -10 False |
81 |
| -11 False |
82 |
| -12 False |
83 |
| -13 False |
84 |
| -14 False |
85 |
| -Name: znamka, dtype: bool |
86 |
| -``` |
87 |
| - |
88 |
| -Tyto metody můžeme využít například k tomu, abychom získali všechna data, kde chybí hodnota ve sloupečku `znamka`. |
| 29 | +Metoda `.notna()` funuje obráceně (tj. vrací hodnotu `False` pro řádek s hodnotou nebo `True` pro prázdný řádek). |
89 | 30 |
|
90 | 31 | ```py
|
91 |
| -print(u202[u202['znamka'].isnull()]) |
| 32 | +food_nutrient_complete = food_nutrient[food_nutrient["amount"].notna()] |
| 33 | +food_nutrient_complete.head() |
92 | 34 | ```
|
93 | 35 |
|
94 |
| -```shell |
95 |
| - cisloStudenta predmet znamka den |
96 |
| -0 1 Chemie NaN pá |
97 |
| -9 9 Dějepis NaN pá |
98 |
| -``` |
| 36 | +V některých případech může být vhodné nahradit chybějící hodnoty jinými hodnotami. Uvažujme třeba výkaz práce, kde je chybějící hodnota u nějakého zaměstnance a projektu. V programu, který data generuje, zjistíme, že to znamená, že daný zaměstnanec na projektu ten měsíc nepracoval. Prázdnou hodnotu tedy můžeme nahradit nulou. |
99 | 37 |
|
100 |
| -Další užitečné metody na práci s chybějícími hodnotami najdeme na DataFrame. |
| 38 | +Poslední možností je odstranit všechny řádky, které nejsou úplné. Musíme pak ale pamatovat na to, že již nepracujeme s kompletními daty. Vyřazením některých řádků může dojít ke zkreslení výsledků analýzy. |
101 | 39 |
|
102 |
| -1. `dropna()` vrátí datový set očištěn od chybějících dat. |
103 |
| -1. `dropna(axis=1)` odstraní všechny sloupce, které obsahují chybějící data. |
104 |
| -1. `fillna(x)` nahradí všechna chybějící data a hodnoty hodnotou x. |
| 40 | +V našem případě použijeme poslední možnost, tj. odstraníme všechny řádky, kde chybí množství výživné látky. K tomu je možné použít metodu `.notna()`, kterou jsme si už ukazovali. Ukážeme si ale ještě jednu metodu, a to `dropna()`. Pokud chceme, aby se metoda řídila pouze některými sloupci, použijeme parametr `subset` (podmnožina). V opačném případě metoda smaže všechny řádky, kde je chybějící hodnota alespoň v jednom sloupci. |
105 | 41 |
|
106 |
| -### Spojení dat |
107 |
| - |
108 |
| -Nyní bychom chtěli všechny tři naše tabulky spojit do jedné. Nejprve si ukážeme, jak spojit tabulky **pod sebe**. Výsledná tabulka tedy bude mít stále **tři sloupce** a **počet řádků bude odpovídat součtu počtu řádků všech tří tabulek**. V SQL používáme pro danou operaci klíčové slovo `UNION`. |
109 |
| - |
110 |
| -Začneme s tím, že každou tabulku uložíme do `DataFrame` s tím, že vyhodíme studenty, kteří na maturitu nedorazili. |
| 42 | +Jako hodnotu můžeme dát název jednoho sloupce jako řetězec nebo seznam názvů sloupců. |
111 | 43 |
|
112 | 44 | ```py
|
113 |
| -u202 = pandas.read_csv('u202.csv').dropna() |
114 |
| -u203 = pandas.read_csv('u203.csv').dropna() |
115 |
| -u302 = pandas.read_csv('u302.csv').dropna() |
| 45 | +food_nutrient = food_nutrient.dropna(subset="amount") |
116 | 46 | ```
|
117 | 47 |
|
118 |
| -Pokud chceme tyto tři DataFrame spojit do jednoho, můžeme použít funkci `concat`. |
| 48 | +### Spojení dat |
119 | 49 |
|
120 |
| -```py |
121 |
| -maturita = pandas.concat([u202, u203, u302]) |
122 |
| -``` |
| 50 | +Nyní bychom chtěli všechny tři naše tabulky spojit do jedné. Nejprve si ukážeme, jak spojit tabulky **pod sebe**. Jaké budou rozměry výsledné tabulky? |
123 | 51 |
|
124 |
| -Pozor ale na to, že v takto vzniklém DataFrame se nám **rozbije index**, protože se prostě spojí za sebe indexy jednotlivých tabulek. Pokud chceme, aby `pandas` při spojování index přepočítal, musíme nastavit hodnotu parametru `ignore_index` na `True`. |
| 52 | +- Počet **sloupců** je ve výsledné tabulce stejný jako u spojovaných tabulek. |
| 53 | +- Počet **řádků** odpovídá součtu řádků spojovaných tabulek. |
125 | 54 |
|
126 |
| -```py |
127 |
| -maturita = pandas.concat([u202, u203, u302], ignore_index=True) |
128 |
| -``` |
| 55 | +V SQL používáme pro danou operaci klíčové slovo `UNION`, `pandas` používáme funkci `concat()`. |
129 | 56 |
|
130 |
| -To už je lepší. Stále nám však zůstává jeden problém. Po spojení tabulek do jedné už nevíme, kdo maturoval v jaké místnosti. Tuto informaci si proto doplníme do původních tří tabulek jako nový sloupeček. Až poté tabulky spojíme do jedné. |
| 57 | +Začneme s tím, že každou tabulku uložíme do `DataFrame` s tím, že vyhodíme studenty, kteří na maturitu nedorazili. |
131 | 58 |
|
132 |
| -```py |
133 |
| -u202['mistnost'] = 'u202' |
134 |
| -u203['mistnost'] = 'u203' |
135 |
| -u302['mistnost'] = 'u302' |
136 |
| -maturita = pandas.concat([u202, u203, u302], ignore_index=True) |
137 |
| -``` |
| 59 | +My funkci využijeme, abychom si vytvořili větší tabulku s názvy potravin. V naší tabulce `food_sample_100.csv` máme pouze 100 vybraných potravin. My si k nim přidáme data z tabulky [food_other.csv](assets/food_other.csv). |
138 | 60 |
|
139 |
| -Takto už nám vznikla pěkná vyčištěná tabulka. Uložme si ji do CSV, ať ji nemusíme vyrábět pořád znova. Nebudeme ukládat index, protože ten si vždycky necháme vyrobit automaticky. |
| 61 | +Pozor na to, že v takto vzniklém DataFrame se nám **rozbije index**, protože se spojí za sebe indexy jednotlivých tabulek. Pokud chceme, aby `pandas` při spojování index přepočítal, musíme nastavit hodnotu parametru `ignore_index` na `True`. |
140 | 62 |
|
141 | 63 | ```py
|
142 |
| -maturita.to_csv('maturita.csv', index=False) |
| 64 | +food_other = pd.read_csv("food_other.csv", ignore_index=True) |
| 65 | +food = pd.concat([food_sample_100, food_other]) |
143 | 66 | ```
|
144 | 67 |
|
145 |
| -Výslednou tabulku si můžete stáhnout jako soubor [maturita.csv](assets/maturita.csv). |
| 68 | +K čemu je spojování vlastně dobré? Některé programy například ukládají data za každý den do samostatného souboru, takže pokud potřebujeme data za jeden týden, stačí nám stáhnout a spojit 7 souborů a ostatní stovky souborů a gigabajty dat můžeme ignorovat. |
| 69 | + |
0 commit comments