Nauč se Python > Kurzy > Datový kurz PyLadies > EDA — více proměnných a vztahy > EDA - Analýza více proměnných a vztahů

EDA - Analýza více proměnných a vztahů

V minulé lekci jsme se společně podívali na základy explorační datové analýzy a podrobněji jsme analyzovali proměnné každou zvlášť.

Následující lekce pokryje další část EDA - analýzu více proměnných současně a hledání vztahů mezi nimi.

Data k analýze jsou připravena v souboru salary.csv.

In [1]:
import pandas as pd
import seaborn as sns

%matplotlib inline

V dnešní lekci poprvé použijeme knihovnu seaborn. Seaborn je nadstavbou matplotlibu a přináší nám možnost vykreslit jeden velmi užitečný graf - tzv. heatmapu.

Načtení a kontrola dat

Nejprve si samozřejmě načteme data, která budeme dnes zpracovávat. Jedná se o informace o zaměstnancích, jejich věku, životním stylu, zkušenostech v oboru a platu. Našim cílem je zjistit, zda je mezi jednotlivými vlastnostmi zaměstnanců nějaký vztah.

Data, která dnes budeme analyzovat, jsou náhodně generovaná tak, aby alespoň některé ukázkové příklady hezky vycházely. Generování takových dat je samo o sobě náročný úkol.

In [2]:
data = pd.read_csv("static/salary.csv")

Načtení se zřejmě povedlo, ale jistotu získáme, až když si data prohlédneme.

Pro začátek uděláme klasickou sadu exploračních úkonů, abychom se s daty seznámili.

In [3]:
data
Out[3]:
id age healthy_eating active_lifestyle salary months_of_exp sex
0 0 36 5 5 2297 281.0 female
1 1 55 3 5 1134 15.0 female
2 2 61 8 1 4969 359.0 female
3 3 29 3 6 902 30.0 female
4 4 34 6 2 3574 225.0 female
... ... ... ... ... ... ... ...
995 995 33 7 7 2996 240.0 female
996 996 21 1 2 667 69.0 male
997 997 49 9 7 4158 298.0 female
998 998 56 6 7 2414 268.0 female
999 999 64 4 9 788 94.0 male

1000 rows × 7 columns

In [4]:
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 7 columns):
id                  1000 non-null int64
age                 1000 non-null int64
healthy_eating      1000 non-null int64
active_lifestyle    1000 non-null int64
salary              1000 non-null int64
months_of_exp       1000 non-null float64
sex                 1000 non-null object
dtypes: float64(1), int64(5), object(1)
memory usage: 54.8+ KB
In [5]:
data.isnull().sum()
Out[5]:
id                  0
age                 0
healthy_eating      0
active_lifestyle    0
salary              0
months_of_exp       0
sex                 0
dtype: int64
In [6]:
data.describe()
Out[6]:
id age healthy_eating active_lifestyle salary months_of_exp
count 1000.000000 1000.000000 1000.000000 1000.000000 1000.00000 1000.000000
mean 499.500000 41.155000 4.944000 5.683000 2227.46100 175.388000
std 288.819436 13.462995 2.013186 2.048587 1080.20976 96.778311
min 0.000000 18.000000 0.000000 0.000000 553.00000 3.000000
25% 249.750000 30.000000 4.000000 4.000000 1360.00000 101.000000
50% 499.500000 41.000000 5.000000 6.000000 2174.00000 173.000000
75% 749.250000 53.000000 6.000000 7.000000 2993.75000 248.000000
max 999.000000 64.000000 10.000000 10.000000 5550.00000 360.000000
In [7]:
data.hist(figsize=(20, 20));

Data se zdají být na první pohled v pořádku, neobsahují nulové hodnoty ani příliš mnoho odlehlých měření.

V datech máme následující informace:

  • identifikační číslo zaměstnance ve sloupci id
  • věk zaměstnance ve sloupci age (proměnná numerická, spojitá)
  • míra aktivního životního stylu a zdravého stravování ve sloupcích active_lifestyle a healthy_eating - oboje označeno číslem od 0 do 10 (ordinální proměnné)
  • počet měsíců v oboru ve sloupci months_of_exp (proměnná numerická, spojitá)
  • měsíční mzda ve sloupci salary (proměnná numerická, spojitá)

Pro lepší představu o datech a také pro ukázku dalších technik a metod si do tabulky přidáme nový sloupec, který bude obsahovat měsíční mzdu v českých korunách.

In [8]:
data["salary_czk"] = data.salary * 23
In [9]:
data.describe()
Out[9]:
id age healthy_eating active_lifestyle salary months_of_exp salary_czk
count 1000.000000 1000.000000 1000.000000 1000.000000 1000.00000 1000.000000 1000.00000
mean 499.500000 41.155000 4.944000 5.683000 2227.46100 175.388000 51231.60300
std 288.819436 13.462995 2.013186 2.048587 1080.20976 96.778311 24844.82448
min 0.000000 18.000000 0.000000 0.000000 553.00000 3.000000 12719.00000
25% 249.750000 30.000000 4.000000 4.000000 1360.00000 101.000000 31280.00000
50% 499.500000 41.000000 5.000000 6.000000 2174.00000 173.000000 50002.00000
75% 749.250000 53.000000 6.000000 7.000000 2993.75000 248.000000 68856.25000
max 999.000000 64.000000 10.000000 10.000000 5550.00000 360.000000 127650.00000

Korelace a korelační koeficienty

Korelace znamená vzájemný vztah mezi dvěma veličinami nebo procesy. Ve statistice se tím nejčastěji myslí lineární vztah mezi dvěma proměnnými. Míra korelace se vyjadřuje korelačním koeficientem, který nabývá hodnot od -1 po 1.

  • 1 znamená, že je mezi dvěma proměnnými přímá závislost a tedy když jedna proměnná roste, roste i druhá proměnná.
  • 0 značí nulový vztah (absenci korelace).
  • -1 znamená, že je mezi dvěma proměnnými nepřímá závislost a tedy když jedna proměnná roste, druhá proměnná klesá.

Korelační koeficient 1 nebo -1 nejčastěji znamená, že je jedna proměnná přímo vypočítaná z druhé a pro další analýzu většinou nemá žádný přínos. V praxi se korelační koeficienty těmto krajním hodnotám jen přibližují a naznačují tím, že stojí za to vztah mezi nimi prozkoumat hlouběji.

Korelace neimplikuje kauzalitu

Pozor na chybné závěry vyplývající z interpretace korelačních koeficientů. Korelace je nutnou, ale nikoli postačující podmínkou kauzality. Korelace znamená, že se dvě proměnné mění stejným způsobem, ale to nemusí znamenat, že nárůst jedné z nich zapříčiňuje nárůst druhé.

Příklad z Wikipedie:

  • Korelace: Od 50. let 20. století prudce vzrostla jak úroveň atmosférického CO2, tak také výskyt obezity.
  • Falešný závěr: Takže atmosférický CO2 způsobuje obezitu. (Nebo naopak obezita způsobuje nárůst CO2 v atmosféře.)
  • Skutečná kauzalita: obojí je důsledkem toho, že bohatší populace víc jedí a zároveň spotřebovávají více energie.

Na webu spurious correlations je pak k nalezení celá řada podezřelých korelací, u nichž si kauzalitu lze představit jen těžko. Věděli jste například, že s klesajícím počtem svateb v Kentucky klesá i počet lidí, kteří se utopili po pádu z rybářské lodě? Náhoda? :)

Druhy korelací

Korelace lze identifikovat několika různými způsoby. Základní rozdělení je závislé na typu proměnných, které zkoumáme. Možné kombinace jsou:

  • dvě numerické proměnné,
  • dvě kategoriální proměnné nebo
  • numerická a kategoriální proměnná.

První možnost je ta asi nejběžnější a proto je pro ni v pandasu vše připraveno a můžeme se rovnou podívat na všechny možné kombinace proměnných. K tomu nám poslouží scatter_matrix z modulu pandas.plotting.

Dvě numerické proměnné

In [10]:
from pandas.plotting import scatter_matrix
In [11]:
scatter_matrix(data, figsize=(20,20));

Scatter graf má na každé z os jednu proměnnou z datasetu a body označují jednotlivá individua odpovídající dané kombinaci hodnot. Jednotlivé body v grafu mohou mít také různou barvu či velikost, což umožňuje v jednom jednoduchém a dobře čitelném grafu zobrazit až 4 proměnné najednou a dělá to z něj velmi mocný nástroj.

Z jednotlivých grafů je tedy možné vyčíst, zda mezi proměnnými existuje korelace či nikoli. Někdy to v grafu však není tak úplně patrné a tak se určitě hodí i výpočet korelačního koeficientu.

Pokud nás nějaká kombinace proměnných v souhrnném grafu zaujme, můžeme si je snadno vykreslit jako samostatný graf pro danou kombinaci.

Kupříkladu závislost mezi mzdou a mzdou v korunách je naprosto jasně viditelná a také logická, protože jeden sloupec je vypočtený z druhého. Tady lze očekávat korelační koeficient na hodnotě 1. Vztah mezi mzdou a počtem měsíců v oboru je také dost dobře vidět, ale korelační koeficient z grafu tak snadno odhadnout nepůjde.

In [12]:
data.plot.scatter(x="salary", y="salary_czk");
In [13]:
data.plot.scatter(x="salary", y="months_of_exp");

Tabulku korelačních koeficientů získáme pomocí metody corr:

In [14]:
data.corr()
Out[14]:
id age healthy_eating active_lifestyle salary months_of_exp salary_czk
id 1.000000 -0.033595 -0.004993 0.028897 -0.012048 0.000071 -0.012048
age -0.033595 1.000000 -0.014969 0.148267 -0.072231 -0.058026 -0.072231
healthy_eating -0.004993 -0.014969 1.000000 0.031613 0.858405 0.700612 0.858405
active_lifestyle 0.028897 0.148267 0.031613 1.000000 -0.323575 -0.225714 -0.323575
salary -0.012048 -0.072231 0.858405 -0.323575 1.000000 0.799953 1.000000
months_of_exp 0.000071 -0.058026 0.700612 -0.225714 0.799953 1.000000 0.799953
salary_czk -0.012048 -0.072231 0.858405 -0.323575 1.000000 0.799953 1.000000

Tabulka korelačních koeficientů obsahuje na diagonále jedničky, protože každá proměnná je sama se sebou v dokonalé korelaci. Ve zbytku tabulky má smysl hledat hlavně hodnoty blízké krajním hodnotám korelačních koeficientů, k čemuž nám může dopomoci jednoduchá filtrace hodnot.

In [15]:
corr = data.corr()
corr[corr > 0.7]
Out[15]:
id age healthy_eating active_lifestyle salary months_of_exp salary_czk
id 1.0 NaN NaN NaN NaN NaN NaN
age NaN 1.0 NaN NaN NaN NaN NaN
healthy_eating NaN NaN 1.000000 NaN 0.858405 0.700612 0.858405
active_lifestyle NaN NaN NaN 1.0 NaN NaN NaN
salary NaN NaN 0.858405 NaN 1.000000 0.799953 1.000000
months_of_exp NaN NaN 0.700612 NaN 0.799953 1.000000 0.799953
salary_czk NaN NaN 0.858405 NaN 1.000000 0.799953 1.000000

Korelačním koeficientům proměnné healthy_eating se budeme věnovat později, protože se jedná o kategoriální proměnnou, která se nám v grafu a tabulce objevuje proto, že jsou její kategorie označeny číslem.

Dále je v tabulce jasně vidět vztah mezi mzdou a délkou zkušeností v oboru - obě proměnné rostou s korelačním koeficientem 0,799, což je vcelku vysoká hodnota.

Pearson vs Spearman

Pro výpočet korelace existuje více vzorců a tedy i více různých korelačních koeficientů. V tabulce výše máme Pearsonův korelační koeficient, který se hodí pro detekci lineárních vztahů, jak bylo vidět u přepočtené mzdy. Druhým častým koeficientem je Spearmanův, který se zase více hodí pro detekci monotónních vztahů.

Monotónní vztah si lze představit jako graf funkce, která v celém intervalu buď klesá nebo stoupá. Příklady jsou k dispozici na wikipedii.

Rozdíl si ukážeme na příkladu:

In [16]:
nums = range(1000)
values = [x**4 for x in range(1000)]
test = pd.DataFrame({"num": nums, "pow": values})
test
Out[16]:
num pow
0 0 0
1 1 1
2 2 16
3 3 81
4 4 256
... ... ...
995 995 980149500625
996 996 984095744256
997 997 988053892081
998 998 992023968016
999 999 996005996001

1000 rows × 2 columns

DataFrame je označení pro tabulku (lepší český ekvivalent asi neexistuje) a používá se i v jiných jazycích a statistických nástrojích. Doposud se nám DataFrame tvořil automaticky při načtení dat ze souboru, ale jak je vidět v tomto případě, je velmi snadné jej vytvořit i ručně a naplnit libovolnými daty. Když už jsme u pojmenování, jednotlivé sloupce naší tabulky jsou Serie a chovají se velmi podobně jako seznamy v Pythonu.

In [17]:
test.plot.line(x="num");
In [18]:
test.corr()
Out[18]:
num pow
num 1.000000 0.865904
pow 0.865904 1.000000
In [19]:
test.corr(method="spearman")
Out[19]:
num pow
num 1.0 1.0
pow 1.0 1.0

Pro vygenerovanou řadu čísel a jejich čtvrtou mocninu jsem nechal vypočítat oba korelační koeficienty. Oba byly vysoké, ale z rozdílu je vidět, že Pearsonův korelační koeficient zaregistroval, že vztah není lineární, zatímco Spearmanův odhalil dokonalou korelaci i v nelineárním vztahu.

V praxi se u nástrojů k tomu určených proto nejčastěji počítají oba koeficienty a ty už teď znáš rozdíl mezi nimi.

Dvě kategoriální proměnné

I když bychom v tomto případě mohli také využít scatter plot, zkusíme pro dvě kategoriální proměnné využít jiných, pro ně specifických metod, odhalování vzájemných vztahů.

Základním nástrojem je tzv. cross tabulka, která umí dle zadaných parametrů vypsat počet výskytů jednotlivých kombinací pro zkoumané kategorie. Pojďme se tedy podívat, zda existuje nějaká korelace mezi aktivním životním stylem a pohlavím zaměstnance:

In [20]:
pd.crosstab(data.sex, data.active_lifestyle)
Out[20]:
active_lifestyle 0 1 2 3 4 5 6 7 8 9 10
sex
female 6 13 20 47 44 84 109 79 52 27 10
male 1 13 14 45 60 84 104 84 62 37 5

Z tabulky je vidět, že zde nejsou žádné závratné rozdíly mezi muži a ženami v jednotlivých úrovních aktivního životního stylu. Pro grafickou reprezentaci stejné informace můžeme využít sloupcový graf, ve kterém necháme jednotlivé kategorie stát na sobě. Uvidíme tedy rozdíly mezi nimi a také rozdíl v celkovém počtu můžu a žen.

In [21]:
pd.crosstab(data.sex, data.active_lifestyle).plot.bar(stacked=True);

Když vytvoříme cross tabulku opačně (vyměníme řádky a sloupce), bude i její grafická reprezentace zobrazovat stejná data jiným způsobem.

In [22]:
pd.crosstab(data.active_lifestyle, data.sex).plot.bar(stacked=True);
In [23]:
pd.crosstab(data.active_lifestyle, data.sex).plot.bar(stacked=False);

Pojďme se podívat na kombinaci zdravého stravování a aktivního životního stylu.

In [24]:
crosstab = pd.crosstab(data.healthy_eating, data.active_lifestyle)
crosstab
Out[24]:
active_lifestyle 0 1 2 3 4 5 6 7 8 9 10
healthy_eating
0 0 0 0 1 4 3 1 3 2 0 0
1 0 0 3 1 2 5 5 3 2 3 1
2 0 1 2 7 13 12 14 8 8 5 1
3 1 3 3 14 16 27 35 17 13 7 2
4 1 9 6 16 16 28 29 35 22 9 2
5 1 4 7 17 20 28 32 33 17 17 3
6 4 2 11 11 12 30 38 34 20 12 2
7 0 3 1 18 11 15 34 16 12 3 3
8 0 3 0 5 5 13 15 9 16 6 1
9 0 1 1 2 2 6 8 5 0 1 0
10 0 0 0 0 3 1 2 0 2 1 0

V takto velké tabulce už není snadné vztah mezi dvěma proměnnými najít. Pro přesné statistické ověření (ne)závislosti kategoriálních proměnných se používají různé chi-square testy, jejichž podrobné vysvětlení je ovšem mimo rámec tohoto kurzu. Jejich problém je hlavně v tom, že jednotlivé proměnné musí splnit celou řadu kritérií, aby se dal test vůbec provést a podle některých kritérií se i volí správná varianta testu.

My si v tomto a následujících případech zkusíme vystačit s grafickou reprezentací. Tabulku si pomocí seabornu převedeme na tzv. heatmapu, která nám buňky obarví podle hodnoty.

In [25]:
crosstab = pd.crosstab(data.healthy_eating, data.active_lifestyle)
sns.heatmap(crosstab, annot=True);

Pokud by se v absolutních číslech dalo hůře vyznat, můžeme si nechat počet jednotlivých kombinací normalizovat (vydělit celkovým množstvím zaměstnanců) a to už je jen jedno násobení od procentuálního vyjádření.

In [26]:
crosstab = pd.crosstab(data.healthy_eating, data.active_lifestyle, normalize="all")*100
sns.heatmap(crosstab, annot=True);

Další užitečnou funkcí crosstab je možnost nechat si vypočítat součty pro jednotlivé řádky a sloupce.

In [27]:
pd.crosstab(data.healthy_eating, data.active_lifestyle, margins=True)
Out[27]:
active_lifestyle 0 1 2 3 4 5 6 7 8 9 10 All
healthy_eating
0 0 0 0 1 4 3 1 3 2 0 0 14
1 0 0 3 1 2 5 5 3 2 3 1 25
2 0 1 2 7 13 12 14 8 8 5 1 71
3 1 3 3 14 16 27 35 17 13 7 2 138
4 1 9 6 16 16 28 29 35 22 9 2 173
5 1 4 7 17 20 28 32 33 17 17 3 179
6 4 2 11 11 12 30 38 34 20 12 2 176
7 0 3 1 18 11 15 34 16 12 3 3 116
8 0 3 0 5 5 13 15 9 16 6 1 73
9 0 1 1 2 2 6 8 5 0 1 0 26
10 0 0 0 0 3 1 2 0 2 1 0 9
All 7 26 34 92 104 168 213 163 114 64 15 1000

V tabulce je vidět, že nejvíce zaměstnanců je někde kolem průměru obou kategorií. To je dáno především distribucí dat, která je patrná z posledního řádku a sloupce.

Numerická a kategoriální proměnná

Zpět ke scatter plotu. Je-li možné kategoriální proměnnou vyjádřit číslem (healthy_eating nebo active_lifestyle), můžeme pro odhalování vztahů opět použít scatter plot.

Pojďme si ověřit něco, co bylo vidět v grafu od samotného začátku:

In [28]:
data.plot.scatter(x="salary", y="healthy_eating");

V grafu je vidět, že s rostoucím příjmem se zvyšuje i míra zdravého stravování. Vede zdravější stravování k lepším výsledkům a tedy vyšší mzdě? Nebo stojí vyšší mzda za utrácením více peněz za zdravé potraviny? To se z tohoto grafu nedozvíme, ale vztah tam očividně je a můžeme si jej i vyčíslit korelačním koeficientem (díky tomu, že kategorie jsou označeny číslem a vyšší číslo znamená lepší stravování).

In [29]:
data.corr()
Out[29]:
id age healthy_eating active_lifestyle salary months_of_exp salary_czk
id 1.000000 -0.033595 -0.004993 0.028897 -0.012048 0.000071 -0.012048
age -0.033595 1.000000 -0.014969 0.148267 -0.072231 -0.058026 -0.072231
healthy_eating -0.004993 -0.014969 1.000000 0.031613 0.858405 0.700612 0.858405
active_lifestyle 0.028897 0.148267 0.031613 1.000000 -0.323575 -0.225714 -0.323575
salary -0.012048 -0.072231 0.858405 -0.323575 1.000000 0.799953 1.000000
months_of_exp 0.000071 -0.058026 0.700612 -0.225714 0.799953 1.000000 0.799953
salary_czk -0.012048 -0.072231 0.858405 -0.323575 1.000000 0.799953 1.000000

K získání přesnějších informací o mzdách v jednotlivých kategoriích budeme potřebovat něco, čemu se říká seskupování. Seskupování probíhá tak, že se vybere jeden či více sloupců, které obsahují kategorie, které nás v tu danou chvíli zajímají. Celou tabulku podle těchto sloupců seskupíme (všechny řádky se stejnou kategorií slijeme dohromady) a řekneme pandasu, co má udělat se zbývajícími sloupci.

Pojďmě si celý proces ilustrovat na jednoduchém příkladu. Mějme jednoduchou tabulku se zaměstnanci:

zdrojová tabulka

Po provedení operace groupby jsou řádky rozdělené do samostatných tabulek podle toho, který sloupec se pro seskupení použil. V tomto ilustračním příkladu jsme zaměstnance seskupili podle oddělení.

seskupené tabulky

Posledním krokem je použití agregační funkce, která spojí tabulky zpět dohromady tak, že každou z nich nejdříve agreguje do jednoho řádku. V našem případě se vypočte průměr, což mimo jiné znamená, že přijdeme o sloupce, ze kterých průměr vypočíst nelze.

výsledek

Zpět k našim datům. Jak asi vypadá průměrná mzda pro jednotlivé míry zdravého stravování?

In [30]:
data.groupby("healthy_eating").mean()
Out[30]:
id age active_lifestyle salary months_of_exp salary_czk
healthy_eating
0 539.285714 39.785714 5.500000 1826.000000 127.857143 41998.000000
1 489.320000 43.160000 5.840000 1351.120000 127.920000 31075.760000
2 568.380282 40.760563 5.591549 929.000000 77.338028 21367.000000
3 450.057971 40.753623 5.550725 1078.927536 83.934783 24815.333333
4 509.543353 41.583815 5.601156 1576.346821 130.387283 36255.976879
5 506.067039 41.033520 5.759777 2120.731844 168.597765 48776.832402
6 489.482955 41.767045 5.732955 2707.954545 217.267045 62282.954545
7 494.646552 42.560345 5.577586 3325.715517 253.344828 76491.456897
8 512.095890 37.575342 6.136986 3777.219178 293.808219 86876.041096
9 455.538462 42.076923 5.346154 4541.692308 325.076923 104458.923077
10 640.222222 37.444444 6.000000 4971.666667 340.333333 114348.333333

Při takovém seskupení se ze sloupce healthy_eating stal index a ze všech ostatních numerických sloupců se pro jednotlivé kategorie vypočetl průměr. Stejně jako v ilustračním příkladu.

Kromě průměru existují i agregační funkce pro sumu, počet záznamů, minimum, maximum a další deskriptivní statistiky.

Pojďme si výsledek ukázat v grafu a zjistit, zda potvrdí naši hypotézu.

In [31]:
data.groupby("healthy_eating").mean().plot.bar(y="salary");

Je to skutečně tak. S rostoucí mzdou se zvyšuje i pravděpodobnost, že zaměstnanec se bude zdravěji stravovat. V grafu ale máme průměrné mzdy, což může znamenat, že některé sloupce ovlivňují odlehlá měření. To by mohlo znamenat, že vysokou mzdu u velmi nezdravého stravování způsobuje jen několik jedinců se zálibou ve fastfoodech. Ověřit si toto tvrzení můžeme známým boxplotem, který nám prozradí, kolik odlehlých měření v jednotlivých sloupcích máme. Všimněte si, že boxplot umí seskupování udělat úplně sám a není mu tak třeba data připravovat předem.

In [32]:
data.boxplot(column="salary", by="healthy_eating");

Ukázalo se, že náš předpoklad byl mylný. Vztah mezi mzdou a mírou zdravého stravování není zcela lineární a odlehlá pozorování na to nemají vliv.

Pojďme se podívat ještě na jeden vztah, který z úvodní matice scatter plotů nebyl tak úplně zřejmý a korelační koeficient pro něj nebyl vysoký - závislost mzdy na aktivním životním stylu. Nejprve v obyčejném grafu s průměry pomoci groupby:

In [33]:
data.groupby("active_lifestyle").mean().plot.bar(y="salary");

I když průměrná mzda zaměstnance klesá, čím aktivnější jeho životní styl je, oba korelační koeficienty vyšly velmi blízko nule. Čím to? K řešení nás přivede boxplot:

In [34]:
data.boxplot(column="salary", by="active_lifestyle");

Jak je v boxplotu vidět, ve všech kategoriích aktivního životního stylu je celkem velký rozptyl možných platů a tak z klesajícího průměru není možné vyvozovat silné závěry.

Pro tuto kombinaci proměnných také existují statistické testy jako např. ANOVA, T-test, Z-test atp. Jejich výběr je ale ještě složitější než u předchozí kombinace dvou kategoriálních proměnných.

Na co si dát pozor

Korelace a křivky

Při prvním pokusu o zkoumání vztahů na začátku lekce jsme se nedívali na graf jen tak pro nic za nic. Existují totiž situace, kdy je v grafu vztah dvou proměnných zřejmý, ale korelační koeficienty o tom nevypovídají. Příkladem mohou být křivky, u kterých je vztah viditelný, ale špatně se detekuje početně.

In [35]:
from random import randrange

nums = []
values = []
for x in range(-10, 11):
    for _ in range(10):
        nums.append(x)
        values.append(randrange(x**2-10, x**2+10))

test = pd.DataFrame({"num": nums, "value": values})
test
Out[35]:
num value
0 -10 99
1 -10 107
2 -10 101
3 -10 106
4 -10 104
... ... ...
205 10 106
206 10 102
207 10 102
208 10 104
209 10 101

210 rows × 2 columns

Jako základní tvar nám posloužila kvadratická funkce a pro každé číslo na ose X jsme vygenerovali deset náhodných čísel okolo paraboly.

Z grafu je vztah mezi těmito proměnnými jasně patrný:

In [36]:
test.plot.scatter(x="num", y="value");

Ovšem korelační koeficienty jej nechají bez povšimnutí:

In [37]:
test.corr()
Out[37]:
num value
num 1.000000 0.002869
value 0.002869 1.000000
In [38]:
test.corr(method="spearman")
Out[38]:
num value
num 1.000000 -0.002439
value -0.002439 1.000000

Korelace a odlehlá pozorování

Nejen tvar grafu znázorňující vztah mezi proměnnými, ale i odlehlá měření mohou mít velmi negativní vliv na výsledky korelačních koeficientů.

In [39]:
nums = []
values = []
for x in range(20):
    for _ in range(3):
        nums.append(x)
        values.append(randrange(x*2-3, x*2+3))

test = pd.DataFrame({"num": nums, "value": values})
In [40]:
test.plot.scatter(x="num", y="value");
In [41]:
test.corr()
Out[41]:
num value
num 1.000000 0.989905
value 0.989905 1.000000

Opět máme náhodně generovaná data tentokrát s drobným rozptylem kolem přímky. A korelační koeficient je dle očekávání velmi vysoký. Pojďme se podívat, co se stane, když do našich dat přidáme pár odlehlých měření.

In [42]:
test.loc[60] = 20, 0
test.loc[61] = 21, 0
test.loc[62] = 22, 0
In [43]:
test.plot.scatter(x="num", y="value");
In [44]:
test.corr()
Out[44]:
num value
num 1.000000 0.730346
value 0.730346 1.000000

Jak je vidět, stačí jen pár odlehlých měření, která jsou navíc zcela očividně mimo očekávání, a korelační koeficient na to ihned reaguje rapidním poklesem.

V jedné z následujících lekcí se naučíme, jak odlehlá měření správně detekovat a jak se s nimi vypořádat.

Čas na hraní

Stejně jako po minulé lekci i tentokrát budeš mít fůru času zkusit si nově získané vědomosti a schopnosti aplikovat na svých datech. Po minulé lekci znáš vybraná data a jednotlivé proměnné v nich jako své boty a tak jistě nebude problém na ně aplikovat novinky z této lekce.


Toto je stránka lekce z kurzu, který probíhá nebo proběhl naživo s instruktorem.