You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -47,13 +47,13 @@ V `pandas`, ale i obecně v datové analýze, je možné se s chybějícími dat
47
47
48
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!
49
49
50
-
####Odstranění neúplných řádků
50
+
### Odstranění neúplných řádků
51
51
52
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
53
54
54
Pokud jsme tak ještě neučinili, načteme si naši první tabulku jako DataFrame.
55
55
56
-
```pycon
56
+
```py
57
57
import pandas
58
58
u202 = pandas.read_csv('u202.csv')
59
59
```
@@ -62,9 +62,11 @@ Pokud `pandas` narazí na prázdnou buňku, vloží místo ní do tabulky speci
62
62
63
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í.
64
64
65
-
```pycon
65
+
```py
66
66
print(u202['znamka'].isnull())
67
+
```
67
68
69
+
```shell
68
70
0 True
69
71
1 False
70
72
2 False
@@ -85,9 +87,11 @@ Name: znamka, dtype: bool
85
87
86
88
Tyto metody můžeme využít například k tomu, abychom získali všechna data, kde chybí hodnota ve sloupečku `znamka`.
87
89
88
-
```pycon
90
+
```py
89
91
print(u202[u202['znamka'].isnull()])
92
+
```
90
93
94
+
```shell
91
95
cisloStudenta predmet znamka den
92
96
0 1 Chemie NaN pá
93
97
9 9 Dějepis NaN pá
@@ -105,27 +109,27 @@ Nyní bychom chtěli všechny tři naše tabulky spojit do jedné. Nejprve si uk
105
109
106
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.
107
111
108
-
```pycon
112
+
```py
109
113
u202 = pandas.read_csv('u202.csv').dropna()
110
114
u203 = pandas.read_csv('u203.csv').dropna()
111
115
u302 = pandas.read_csv('u302.csv').dropna()
112
116
```
113
117
114
118
Pokud chceme tyto tři DataFrame spojit do jednoho, můžeme použít funkci `concat`.
115
119
116
-
```pycon
120
+
```py
117
121
maturita = pandas.concat([u202, u203, u302])
118
122
```
119
123
120
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`.
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é.
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.
136
140
137
-
```pycon
141
+
```py
138
142
maturita.to_csv('maturita.csv', index=False)
139
143
```
140
144
@@ -146,10 +150,12 @@ Výslednou tabulku si můžete stáhnout jako soubor [maturita.csv](assets/matur
146
150
147
151
Naše výsledky byly anonymní. Pokud bychom ale chtěli vytisknout maturitní vysvědčení, potřebujeme k číslům studenta zjistit jejich jména. Jména najdeme v samostatné tabulce [studenti.csv](assets/studenti.csv). Načtěme si jej jako `DataFrame`.
@@ -167,10 +173,12 @@ Propojení tabulek se v `pandas` dělá pomocí funkce `merge` (dokumentaci k n
167
173
168
174
Ve výchozím nastavení funkce `merge()` ponechá pouze řádky, které mají záznamy v obou tabulkách. V SQL bychom tuto operaci označili jako `INNER JOIN`.
169
175
170
-
```pycon
176
+
```py
171
177
propojeny_df = pandas.merge(u202, studenti)
172
178
print(propojeny_df.head())
179
+
```
173
180
181
+
```shell
174
182
cisloStudenta predmet znamka den jmeno
175
183
0 1 Chemie NaN pá Jana Zbořilová
176
184
1 2 Dějepis 3.0 pá Lukáš Jurčík
@@ -181,38 +189,51 @@ print(propojeny_df.head())
181
189
182
190
Pokud by například nějaký student nebyl uvedený v tabulce se studenty, jeho maturitní výsledek by zmizel. U nového `DataFrame` bychom tedy měli zkontrolovat, zda má `spojenyDF` stejný počet řádků jako `u202`.
183
191
184
-
```pycon
185
-
u202.shape
192
+
```py
193
+
print(u202.shape)
194
+
```
195
+
196
+
```shell
186
197
(15, 4)
187
-
propojeny_df.shape
198
+
```
199
+
200
+
```py
201
+
print(propojeny_df.shape)
202
+
```
203
+
204
+
```shell
188
205
(15, 5)
189
206
```
190
207
191
208
Zde vidíme, že data jsou zřejmě v pořádku.
192
209
193
210
Dále připojíme tabulku [predsedajici.csv](assets/predsedajici.csv), kde máme vypsané předsedy maturitních komisí. Tu si opět načteme jako `DataFrame`.
Tentokrát jsme příliš neuspěli, výsledný `DataFrame` je prázdný. Proč tomu tak je? Protože v obou `DataFrame` máme sloupec `jmeno`, v jednom případě však jde o jméno studenta a ve druhém o jméno předsedy komise. To ale `pandas` samozřejmě neví. Proto mu musíme říct, že chceme data spojit pouze podle sloupce `den`.
Zatím to vypadá dobře. Pokud se ovšem podíváme na `shape`, něco nám tady nehraje.
225
246
226
-
```pycon
247
+
```py
227
248
print(novy_propojeny_df.shape)
249
+
```
228
250
251
+
```shell
229
252
(10, 8)
230
253
```
231
254
232
255
Najednou máme v tabulce pouze 12 řádků, některé tedy zmizely. To znamená, že funkce `merge()` nenašla pro všechna zkoušení odpovídajícího předsedu. Jak je to možné? Zkusme nyní říct funkci `merge()`, aby nám zachovala v prvním `DataFrame` ty řádky, pro které nenajde odpovídající záznam. Této operaci se v jazyce SQL říká LEFT OUTER JOIN. My ho provede tak, že funkci `merge()` jako parametr `how` zadáme hodnotu `left`.
Tentokrát jsme již o data nepřišli, ale kde se stala chyba? Zkusme si zobrazit ty řádky, které se nepodařilo propojit. Poznáme je tak, že mají prázdný sloupec `datum`.
cisloStudenta predmet znamka den mistnost jmeno_x datum jmeno_y
247
274
5 5.0 Dějepis 1.0 po u202 Kateřina Novotná NaN NaN
248
275
6 7.0 Dějepis 4.0 po u202 Vasil Lácha NaN NaN
@@ -253,32 +280,36 @@ Nyní jsme již na stopě problému. Z nějakého důvodu nám nefunguje propoje
253
280
254
281
Pokud nemáme možnost vstupní data opravit, můžeme použít funkci `strip()`, která z řetězce odstraní mezery (a další bílé znaky) na začátku a na konci. Tyto mezery jsou v drtivé většině případů způsobeny chybou a proto jejich odstraněním nic nezkazíme.
Poslední nepříjemností, na kterou se podíváme, je to, že sloupce `jmeno` se automaticky přejmenovaly, aby neměly v tabulce stejný název. Zde můžeme použít metodu `rename`, abychom sloupečky přejmenovali na něco smysluplného.
Z databází známe kromě UNION a JOIN také operaci GROUP BY. V `pandas` ji provedeme tak, že pomocí metody `groupby` vyrobíme z `DataFrame` speciální objekt `DataFrameGroupBy`. Dejme tomu, že chceme grupovat podle sloupečku `mistnost`.
272
301
273
-
```pycon
302
+
```py
274
303
maturita.groupby('mistnost')
275
304
```
276
305
277
306
Na tomto speciálním objektu pak můžeme používat různé agregační funkce. Nejjednodušší je funkce `count`
278
307
279
-
```pycon
280
-
maturita.groupby('mistnost').count()
308
+
```py
309
+
print(maturita.groupby('mistnost').count())
310
+
```
281
311
312
+
```shell
282
313
jméno předmět známka den datum předs
283
314
místnost
284
315
u202 13 13 13 13 13 13
@@ -302,17 +333,19 @@ Další užitečné agregační funkce jsou například:
302
333
303
334
Nemusíme samozřejmě grupovat přes všechny sloupečky. Vybereme si pouze ty, které nás zajímají. Zkusme například spočítat průměrnou známku z jednotlivých předmětů.
Pomocí agregací můžeme vyřešit i náš problém s nákupy. Pokud máme stále načtený `Data Frame``nakupy`, můžeme použít funkci `groupby` podle jména a následně spočítat sumu nákupů pomocí `.sum()`.
310
341
311
-
```pycon
342
+
```py
312
343
nakupy = pandas.read_csv('nakupy.csv')
313
344
nakupy_celkem = nakupy.groupby("Jméno")["Částka v korunách"].sum()
314
345
print(nakupy_celkem)
346
+
```
315
347
348
+
```shell
316
349
Jméno
317
350
Libor 124
318
351
Míša 160
@@ -323,74 +356,35 @@ Zuzka 80
323
356
Name: Částka v korunách, dtype: int64
324
357
```
325
358
326
-
#### Čtení na doma: Více různých agregací
327
-
328
-
Pokud chceme provést více různých agregací, použijeme metodu `agg`. Metodě `agg` vložíme jako parametr slovník, kde klíčem je název sloupce, pro který počítáme agregaci, a hodnotou je řetězec nebo seznam řetězců se jmény agregací, které chceme provést. Například u maturity chceme zjistit, jestli student prospěl, prospěl s vyznamenáním nebo neprospěl. K tomu potřebujeme funkci `max()` (pětka znamená, že student neuspěl a trojka znamená, že nemůže získat vyznamenání) a funkci `mean()` (abychom zjistili, zda je průměr známek menší než 1.5).
K určení výsledku studenta bychom ještě potřebovali nový sloupec, jehož hodnota bude určena na základě podmínky, což si ukážeme níže.
335
-
336
359
### Počítané sloupce
337
360
338
361
Občas je užitečné přidat nový sloupec, který obsahuje hodnotu vypočtenou na základě hodnot ostatních sloupců. Vraťme se například k naší tabulce s údaji o státech ve světě. Máme informaci o rozloze a počtu obyvatel, mohli bychom tedy přidal sloupec s hodnotou hustoty zalidnění (počet obyvatel na 1 km čtvereční), který získáme vydělením počtu obyvatel rozlohou země.
339
362
340
363
Pokud nemáme načtený soubor s daty, načteme si ho.
341
364
342
-
```pycon
365
+
```py
343
366
staty = pandas.read_json("staty.json")
344
367
staty = staty.set_index("name")
345
368
```
346
369
347
370
Přidání nového sloupce je poměrně jednoduché. Před znaménko `=` vložíme proměnnou s `DataFrame` a do hranatých závorek vložíme název nového sloupce. Na pravou stranu umístíme výpočet. Ve výpočtu pracujeme s jednotlivými sloupci, v našem konkrétním případě vydělíme sloupec `population` sloupcem `area`.
**Poznámka:**`pandas` nás neupozorní, pokud sloupec již existuje, musíme si tedy dát pozor, abychom nepřepsali nějaký existující sloupec.
354
377
355
-
#### Čtení na doma: Podmíněný sloupec
356
-
357
-
Občas chceme do výpočtu zapracovat i podmínku. Ve skutečnosti je podmínka to poslední, co nám chybělo k vyřešení našeho problému s finančním vypořádání spolubydlících pomocí `pandas`. Náš výpočet se skládá z pěti kroků.
358
-
359
-
1. Provedeme agregaci hodnot nákupů podle jmen. Tím zjistíme sumu, kolik každý utratil.
360
-
1. Zjistíme si průměrnou útratu za osobu. K tomu použijeme funkci `mean()`.
361
-
1. Přidáme sloupec s podmínkou. V podmínce porovnáváme, zda spolubydlící utratil více nebo méně, než je průměr. K tomu použijeme funkci `where`, která je součástí modulu `numpy`. Nejprve provedeme import modulu `numpy` a následně z modulu zavoláme funkci `where()`. Jako první parametr zadáme podmínku (porovnání hodnot), jako druhý hodnotu vloženou v případě splnění podmínky (text "má dáti") a jako poslední hodnotu vloženou v případě nesplnění podmínky (text "dostane"). Jako předposlední krok si určíme částku potřebnou k vypořádání - rozdíl mezi součtem pro danou osobu a průměrnou útratou. Poslední krok je pak jen výpisem hodnoty.
362
-
363
-
```pycon
364
-
nakupy = pandas.read_csv('nakupy.csv')
365
-
nakupy_celkem = nakupy.groupby("Jméno")[["Částka v korunách"]].sum()
366
-
prumerna_hodnota = nakupy_celkem["Částka v korunách"].mean()
367
-
import numpy
368
-
nakupy_celkem["Operace"] = numpy.where(nakupy_celkem["Částka v korunách"] > prumerna_hodnota, "má dáti", "dostane")
369
-
nakupy_celkem["Kolik"] = abs(nakupy_celkem["Částka v korunách"] - prumerna_hodnota)
370
-
print(nakupy_celkem[["Operace", "Kolik"]])
371
-
372
-
Operace Kolik
373
-
Jméno
374
-
Libor dostane 118.166667
375
-
Míša dostane 82.166667
376
-
Ondra má dáti 257.833333
377
-
Pavla dostane 192.166667
378
-
Petr má dáti 296.833333
379
-
Zuzka dostane 162.166667
380
-
```
381
-
382
-
Srovnej si toto řešení s tím, které jsme si ukazovali na úvodním workshopu. Zdá se ti jednodušší?
383
-
384
378
### Řazení
385
379
386
380
Data řadíme poměrně často. U běžeckého závodu nás zajímají ti nejrychlejší běžci, u položek v e-shopu ty nejlépe hodnocené, u projektu zase chceme vidět úkoly s nejbližším deadline. Abychom tyto hodnoty získali, musíme data seřadit. Ve světě databází pro to používáme klíčová slova `ORDER BY`, v `pandas` nám poslouží metoda `sort_values`. Jako její první parametr zadáváme sloupec (nebo seznam sloupců), podle kterého (kterých) řadíme.
387
381
388
-
```pycon
382
+
```py
389
383
staty.sort_values(by="population")
390
384
```
391
385
392
386
Metoda `sort_values` standardně řadí vzestupně. Chceme-li řadit sestupně, zadáme jí parametr `ascending` a nastavíme ho na `False`.
0 commit comments