Skip to content

Commit 95f48ef

Browse files
pesikjZelenyMartin
andauthored
Upravy 2 (#87)
* Úpravy * Část o pivot tabulkách * Úpravy * Fix * Update python-pro-data-1/podmineny-vyber/excs/dve-kriteria.md Co-authored-by: Martin Zelený <[email protected]> * Update python-pro-data-1/pivot-tabulky/excs/dve-kriteria.md Co-authored-by: Martin Zelený <[email protected]> --------- Co-authored-by: Martin Zelený <[email protected]>
1 parent bdcaa6e commit 95f48ef

File tree

11 files changed

+9708
-4811
lines changed

11 files changed

+9708
-4811
lines changed

python-pro-data-1/entry.yml

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ lessons:
77
- spojovani
88
- agregace
99
- vizualizace
10+
- pivot-tabulky
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
## Další funkce pro tvorbu pivot tabulek
2+
3+
Pivot tabulky velmi často provádíme v kombinaci s nějakou agregací. Uvažujme například, že by nás zajímal průměrný obsah výživných látek za jednotlivé kategorie, nikoli za konkrétní potraviny.
4+
5+
```py
6+
import pandas as pd
7+
8+
food_nutrient = pd.read_csv("food_nutrient.csv")
9+
branded_food = pd.read_csv("branded_food.csv")
10+
food = pd.concat([pd.read_csv("food_sample_100.csv"), pd.read_csv("food_other.csv")], ignore_index=True)
11+
food_merged = pd.merge(food, food_nutrient, on="fdc_id")
12+
food_merged = pd.merge(food_merged, branded_food, on="fdc_id")
13+
```
14+
15+
Protože v datech máme obrovské množství různých kategorií i výživných látek, u dat provedeme filtrování. Výběr kategorií s největším počtem potravin jsme již provedli v lekci o vizualizacích. Nyní provedeme výběr výživných látek. Pro naši kontingenční tabulku si vybereme tyto výživné látky:
16+
17+
- `Protein` (bílkoviny),
18+
- `Sodium, Na` (sodík, Na),
19+
- `Total lipid (fat)` (lipidy (tuky)),
20+
- `Carbohydrate, by difference` (sacharidy, měřené rozdílově),
21+
- `Sugars, total including NLEA` (cukry, celkem včetně NLEA),
22+
- `Fatty acids, total saturated` (nasycené mastné kyseliny, celkem),
23+
- `Cholesterol` (cholesterol),
24+
- `Fiber, total dietary` (vláknina, celková stravová),
25+
- `Calcium, Ca` (vápník, Ca),
26+
- `Iron, Fe` (železo, Fe).
27+
28+
Nejprve si vyzkoušíme funkci `pivot_table()`. Pozor, jedná se o odlišnou funkci, než kterou jsme využívali v předchozí lekci. Funkci `pivot_table` určíme pět parametrů, tj. o jeden parametr víc, než který jsme zadávali funkci `pivot()`.
29+
30+
- Prvním parametrem (`data`) určujeme tabulku, se kterou bude funkce pracovat.
31+
- Druhý parametr (`value`) obsahuje název sloupce, ze kterého budou čteny hodnoty, které budou "ve vnitřní části" tabulky. V tomto případě již může být pro každou kombinaci název řádku a názvu sloupce více hodnot, protože funkce počítá s provedením agregace.
32+
- Třetí parametr (`index`) slouží jako popisek řádků. V našem případě zvolíme sloupeček `"branded_food_category"`, tj. název kategorie.
33+
- Čtvrtý parametr (`columns`) bude použit k vytvoření nových sloupečků. Sem doplníme sloupec `name`.
34+
- Jako pátý parametr (`aggfunc`) je třeba vložit funkce, která bude použita k agregaci hodnot. Protože předpokládáme, že pro každou kombinaci kategorie a výživné látky budeme znát více hodnot (protože v každé kategorii máme spousty potravin), je třeba použít nějakou funkci, která z těchto hodnot vypočte jedno číslo. Jedná se obdobu agregace, na což odkazuje i název parametru. Pokud bychom chtěli spočítat průměrnou hodnotu, můžeme například použít funkci `mean()` z modulu `numpy`. Pozor na to, že píšeme pouze název funkce **bez závorek**. Neprovádíme totiž volání funkce, to dělá funkce `pivot_table` za nás.
35+
36+
Na rozdíl od funkce `pivot()` nemusíme parametry psát jako pojmenované.
37+
38+
```py
39+
import numpy as np
40+
41+
pd.pivot_table(food_merged, "amount", "branded_food_category", "name", np.mean)
42+
```
43+
44+
Z výsledné tabulky vidíme, jak se liší průměrné množství výživných látek v jednotlivých potravinách. Kupříkladu sýry jsou poměrně bohaté na vápaník a cholesterol, naopak je v nich poměrně málo vlákniny.
45+
46+
Alternativou k funkci `pivot_table()` je funkce `crosstab()`. Ta se liší od funkce `pivot_table()` především v tom, že jí zadáváme data jako série hodnot, nikoli jako tabulku a následně názvy sloupců.
47+
48+
```py
49+
pd.crosstab(food_merged["branded_food_category"], food_merged["name"], food_merged["amount"], aggfunc=np.mean)
50+
```
51+
52+
### Standardizace a teplotní mapa
53+
54+
Kontingenční tabulka je časově náročná na čtení, především v případě, že má poměrně hodně řádků nebo sloupců. Pro rychlý přehled může být užitečnější typ vizualizace označovaný jako :term{cs="teplotní mapa" en="heat map"}. Ten převede hodnotu na barevnou škálu. V teplotní mapě můžeme rychle nalézt především výrazně nadprůměrné či podprůměrné hodnoty. U našich dat ale může být problém v tom, že máme v různých sloupcích řádově odlišné hodnoty. Je to samozřejmě ovlivněno tím, že některé výživné látky jsou zobrazné v odlišných jednotkách (množství látky v gramech a miligramech na 100 gramů potraviny). Problém bychom nevyřešili ani převodem na stejné jednotky. Vápníku nebo sodíku totiž bude v potravinách většinou řádově méně než proteinů nebo cukrů.
55+
56+
Problém ale můžeme vyřešit pomocí procesu označovaného jako {cs="normalizace" en="normalization"}. Normalizace dat v kontextu statistiky a zpracování dat znamená převedení různých rozsahů hodnot na společnou škálu, čímž se usnadňuje jejich srovnání a analýza. Tento proces pomáhá odstranit zkreslení v datech způsobená různými měřítky a umožňuje lépe identifikovat vzory a vztahy mezi proměnnými. Normalizace je klíčová pro efektivní algoritmické zpracování, například {cs="strojovém učení" en="machine learning"} a datové analýze.
57+
58+
Prakticky normalizace obsahuje dva kroky:
59+
60+
- Od hodnot odečteme průměr. Tím pádem se normalizované hodnoty budou pohybovat kolem nuly. Pokud bude nějaká normalizovaná hodnota záporná, v původních datech byla podprůměrná. Pokud bude normalizovaná hodnota kladná, v původních datech byla nadprůměrná.
61+
- Vydělíme data jejich variabilitou, konkrétně směrodatnou odchylkou. Tím data převedeme na stejné jednotky. Data se budou pohybovat ve stejných jednotkách, ať už byla původní data v desetinných čísel nebo v minionech.
62+
63+
Nejprve tedy provedeme normalizaci dat.
64+
65+
```py
66+
food_pivot_norm = (food_pivot - food_pivot.mean()) / food_pivot.std()
67+
```
68+
69+
A ve druhém kroku vytvoříme teplotní mapu.
70+
71+
```py
72+
import seaborn as sns
73+
ax = sns.heatmap(food_pivot_norm)
74+
ax.set(xlabel="Výživná látka", ylabel="Kategorie", title="Množství průměrných látek dle kategorií")
75+
```
76+
77+
Pro lepší čitelnost můžeme změnit výchozí barevnou škálu pomocí parametru `cmap`. Můžeme použít například škálu `"Blues"`, která je postavená na sytosti modré barvy.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
title: Pivot tabulky
2+
lead: Ukážeme si pivot tabulky, které umožňují analyzovat vztah mezi dvěma sloupci tabulky
3+
sections:
4+
- funkce-pivot
5+
- dalsi-funkce
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
title: Dvě kritéria
3+
demand: 3
4+
---
5+
6+
*Poznámka:* Zadání tohoto příkladu ti možná bude připadat povědomé, bylo již v lekci o podmíněném výběru. Pokud jsi ale příklad neřešil(a), nevadí. Pokud ano, uvidíš, že řešení bude díky funkci `pivot()` mnohem jednodušší.
7+
8+
Připravujeme seznam potravin pro účely lékařského výzkumu, který se bude zabývat kardiovaskulárním systémem. Chceme vybrat pottraviny, které splňují dvě kritéria:
9+
10+
- nízký obsah nasycených mastných kyselin (`"Fatty acids, total saturated"`, uvažuj méně než 1 gram),
11+
- vysoký obsah vlákniny (`"Fiber, total dietary"`, uvažuj více než 5 gramů).
12+
13+
Zatímco nasycené mastné kyseliny jsou považovány za spíše škodlivé pro kardiovaskulární systém, vláknina je považována spíše za prospěšnou. Vyber z tabulky `food_nutrient_pivot` potraviny, které vyhovují oběma podmínkám.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
## Pivot tabulky
2+
3+
Pivot tabulka (často se též používá termín kontingenční tabulka) je nástroj, který vám umožní rychle a efektivně shrnovat, analyzovat, prozkoumávat a prezentovat souhrnná data.
4+
5+
Jak bychom pivot tabulky mohli využít pro naše data? Pivot tabulky dokážou zobrazit vztah mezi dvěma sloupci tabulky (dvěma proměnnými), v našem případě můžeme například sledovat vztah mezi dvěma výživnými látkami. Mohli bychom tedy zkoumat, jestli při růstu množství jedné výživné látky roste (nebo naopak klesá) množství jiné výživné látky. Dále nám tabulka může usnadnit hledání vhodných potravin na základě více než jednoho kritéria. Pokud bychom například hledali potravinu, která má hodně vlákniny a současně málu nasycených tuků, museli bychom napsat poměrně složitou podmínku. Pivot tabulka nám situaci zjednodušší. Poslední příklad je zkoumání průměrného množství výživných látek v jednotlivých kategoriích potravin, kontingenční tabulky tedy mohou být alternativou k vizualizacím, které jsme i ukázali v minulé lekci.
6+
7+
Začneme tím, že si načteme data ze souboru `food_nutrient.csv` do tabulky `food_nutrient`.
8+
9+
```py
10+
import pandas as pd
11+
food_nutrient = pd.read_csv("food_nutrient.csv")
12+
```
13+
14+
V `pandas` existuje několik funkcí. My začneme z funkcí `pivot()`. Tato funkce slouží k "přeskládání" tabulky. Výsledná tabulka nebude mít samostatný řádek pro každou kombinaci potraviny a výživné látky. Tabulku přeskládáme tak, aby každá potravina měla pouze jeden řádek a jednotlivé výživné látky budou uloženy ve sloupcích. Namísto sloupce `name` s názvem výživné látky budeme mít názvy výživných látek přímo ve sloupcích.
15+
16+
Funkci `pivot` určíme čtyři parametry, kromě prvního parametru `data` musíme všechny psát jako pojmenované:
17+
18+
- Prvním parametrem (`data`) určujeme tabulku, se kterou bude funkce pracovat.
19+
- Parametr `index` slouží jako popisek řádků. V našem případě zvolíme sloupeček `fdc_id`, tj. unikátní číslo potraviny.
20+
- Parametr `columns` bude použit k vytvoření nových sloupečků. Každá unikátní hodnota v tomto sloupci bude znamenat nový sloupeček ve výsledné tabulce. Sem doplníme sloupec `name`.
21+
- Parametr `value` označuje sloupec, ze kterého budou členy hodnoty. V našem případě půjde o sloupec `amount`. Funkce `pivot` se pro každý řádek původní tabulky "podívá" na sloupce `fdc_id` a `name`, tj. na číslo potraviny a název výživné látky. Hodnotu, která je ve sloupci `amount`, pak doplní do nové tabulky na řádek se stejným `fdc_id` a do sloupce pro příslušnou výživnou látku.
22+
23+
U funkce `pivot()` je důležité, abychom pro každou kombinaci `fdc_id` a `name` měli pouze jeden řádek. Funkce totiž neprovádí žádnou agregaci. Pokud bychom agregaci potřebovali provést, musíme použít některou z funkcí, které si ukážeme dále.
24+
25+
Níže je použití funkce `pivot`.
26+
27+
```py
28+
food_nutrient_pivot = pd.pivot(food_nutrient, index="fdc_id", columns="name", values="amount")
29+
```
30+
31+
K tabulce `food_nutrient_pivot` můžeme připojit další informace o potravinách, se kterými jsme pracovali v předchozích lekcích. Budeme tedy vědět, kterých potravin se každý řádek týká.
32+
33+
```py
34+
branded_food = pd.read_csv("branded_food.csv")
35+
food = pd.concat([pd.read_csv("food_sample_100.csv"), pd.read_csv("food_other.csv")], ignore_index=True)
36+
food_brands = pd.merge(food, branded_food, on="fdc_id")
37+
food_nutrient_pivot = pd.merge(food_nutrient_pivot, food_brands, on="fdc_id")
38+
```
39+
40+
Po úpravě dat s využitím funkce `pivot()` můžeme snadno vytvořit další typ grafu, a to je :term{cs="bodový graf" en="scatter plot"}. Bodový graf bude mít na svislé i vodorovné ose množství některé z výživných látek. Pomocí bodového grafu uvidíme, jestli může být mezi množstvím výživných látek nějaká souvislost. Vraťme se opět k výzkumu o kardiovaskulárním systému. Pro něj mohou být škodlivé nasycené kyseliny a choresterol. Pomocí bodového grafu se můžeme podívat, jestli mají sýry s větším množstvím nasycených kyselin i větší množství chorestarolu. Graf doplníme popiskem, musíme pro něj využít mírně odlišnou syntaxi.
41+
42+
```py
43+
import seaborn as sns
44+
45+
cheese = food_nutrient_pivot[food_nutrient_pivot["branded_food_category"] == "Cheese"]
46+
g = sns.JointGrid(cheese, x="Fatty acids, total saturated", y="Cholesterol")
47+
g.plot_joint(sns.scatterplot)
48+
g.fig.suptitle("Porovnání množství výživných látek v sýrech")
49+
g.ax_joint.set_xlabel("Nasycené kyseliny")
50+
g.ax_joint.set_ylabel("Cholesterol")
51+
```
52+
53+
Výsledný graf je na obrázku níže.
54+
55+
::fig[HTML značka]{src=assets/scatterplot.png size=60}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: Dvě kritéria
3+
demand: 3
4+
---
5+
6+
Připravujeme seznam potravin pro účely lékařského výzkumu, který se bude zabývat kardiovaskulárním systémem. Chceme vybrat potraviny, které splňují dvě kritéria:
7+
8+
- nízký obsah nasycených mastných kyselin (`"Fatty acids, total saturated"`, uvažuj méně než 1 gram),
9+
- vysoký obsah vlákniny (`"Fiber, total dietary"`, uvažuj více než 5 gramů).
10+
11+
Zatímco nasycené mastné kyseliny jsou považovány za spíše škodlivé pro kardiovaskulární systém, vláknina je považována spíše za prospěšnou.
12+
13+
Nejprve je potřeba napsat dotaz, který potraviny vybere. Dotaz je poměrně složitý, ale později si v rámci kurzu ukážeme, jak takovou úlohu vyřešit jednodušeji. Je potřeba použít operátor `&` i `|` a závorky, pomocí kterých řídíme, které podmínky se vyhodnocují spolu. Níže jsou rozepsané podmínky, které budeme potřebovat:
14+
15+
- Ve sloupci `"name"` musí být hodnota `"Fatty acids, total saturated"` a současně ve sloupci `"amount"` hodnota menší než 1. Mezi tyto podmínky vložíme operátor `&`, protože musí být splněné obě.
16+
- Ve sloupci `"name"` musí být hodnota `"Fiber, total dietary"` a současně ve sloupci `"amount"` hodnota vetší než 4. Mezi tyto podmínky vložíme operátor `&`, protože musí být splněné obě.
17+
18+
Protože obě výživné látky jsou na samostatném řádku, musíme mezi obě podmínky dát operátor `|`. Pokud nějaká potraviny splňuje obě podmínky, bude tedy ve výsledné tabulce dvakrát. Pokud splňuje pouze jednou z podmínek, bude ve výsledné tabulce pouze jednou. Počet výskytů potraviny ve výsledné tabulce můžeme ověřit pomocí metodu `values_count()`.
19+
20+
U kombinace operátorů `&` a `|` je vhodné uvědomit si, v jaké prioritě by měly být používány. Ač to zní složitě, je to pojem, který už známe z úvodního kurzu z příkladu, kde jsme používali násobení a sčítání v jednom příkladu. Pro operátory `&` a `|` platí, že operátor `&` máš vyšší prioritu než `|`. To nám vyhovuje, protože my chceme nejprve vyhodnotit podmínky s operátorem `&` a poté spojit výsledky s využitím opretáro `|`.
21+
22+
Níže je tedy struktura, kterou je potřeba upravit, aby řešila popsané podmínky.
23+
24+
```py
25+
food_nutrient_filtered = food_nutrient[(ve sloupci "name" je hodnota "Fatty acids, total saturated") & (ve sloupci "amount" je hodnota menší než 1) |
26+
(ve sloupci "name" je hodnota "Fiber, total dietary") & (ve sloupci "amount" je hodnota větší než 4)]
27+
```
28+
29+
Pokud se úvaze o priotách chceš vyhnout, je možné to vyřešit přidanými závorkami. Tyto závorky nijak neovlivňují, jak Python příkaz vyhodnotí, ale můžou zlepšit čistelnost a pochopitelnost příkazu pro člověka.
30+
31+
```py
32+
food_nutrient_filtered = food_nutrient[((ve sloupci "name" je hodnota "Fatty acids, total saturated") & (ve sloupci "amount" je hodnota menší než 1)) |
33+
((ve sloupci "name" je hodnota "Fiber, total dietary") & (ve sloupci "amount" je hodnota větší než 4))]
34+
```

python-pro-data-1/podmineny-vyber/podmineny-vyber.md

+3-6
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ Pokud si vzpomeneš na hodnoty typu `bool`, víš, že můžou nabývat pouze dv
7373

7474
```py
7575
magnesium = food_nutrient[food_nutrient["name"] == "Magnesium, Mg"]
76-
magnesium.head()
7776
```
7877

7978
### Popisná statistika
@@ -88,9 +87,9 @@ magnesium["amount"].describe()
8887

8988
V datech se zobrazují tyto hodnoty:
9089

91-
- `count`: Počet hodnot,
90+
- `count`: Počet hodnot.
9291
- `mean`: Aritmetický průměr hodnot.
93-
- `std`: Směrodatná odchylka. Pomocí ní měříme různorodost (variabilitu) dat.
92+
- `std`: :term{cs="Směrodatná odchylka" en="standard deviation"}. Pomocí ní měříme :term{cs="různorodost" en="variability"} dat.
9493
- `min`: Nejmenší hodnota.
9594
- `25%`: Toto číslo rozděluje data na 25 % menších hodnot a 75 % větších hodnot.
9695
- `50%`: Medián. Jde o číslo, které by leželo přesně uprostřed seřazených hodnot, tj. rozděluje data na 50 % menších hodnot a 50 % větších hodnot.
@@ -102,7 +101,6 @@ Naším úkolem je vybrat potraviny, které mají vyšší množství hořčíku
102101

103102
```py
104103
magnesium_limit = magnesium[magnesium["amount"] > 100]
105-
magnesium_limit
106104
```
107105

108106
### Spojení více podmínek
@@ -117,7 +115,6 @@ Naším úkolem bude vybrat potraviny, které mají mezi 30 a 500 mg vápníku.
117115

118116
```py
119117
calcium_limit = calcium[(calcium["amount"] > 30) & (calcium["amount"] < 500)]
120-
calcium_limit
121118
```
122119

123120
Podmínek můžeme zkombinovat i více, například tři. Předchozí dva kroky můžeme díky tomu spojit do jednoho, tj. z původní tabulky `food_nutrient` vybereme řádky, které:
@@ -130,7 +127,6 @@ Mezi každou dvojici podmínek vložíme symbol `&`, tento symbol tedy použijem
130127

131128
```py
132129
calcium_limit = food_nutrient[(food_nutrient["name"] == "Calcium, Ca") & (food_nutrient["amount"] > 30) & (food_nutrient["amount"] < 500)]
133-
calcium_limit
134130
```
135131

136132
Pokud chceme, aby stačilo splnění jedné podmínky, použijeme symbol `|`.
@@ -144,3 +140,4 @@ Pokud chceme, aby stačilo splnění jedné podmínky, použijeme symbol `|`.
144140
## Bonusy
145141

146142
::exc[excs/ceska-jmena]
143+
::exc[excs/dve-kriteria]

0 commit comments

Comments
 (0)