{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Úvod do pravděpodobnosti a statistiky\n", "V tomto zápisníku si budeme hrát s některými koncepty, které jsme dříve probírali. Mnoho konceptů z pravděpodobnosti a statistiky je dobře zastoupeno v hlavních knihovnách pro zpracování dat v Pythonu, jako jsou `numpy` a `pandas`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pandas as pd\n", "import random\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Náhodné proměnné a rozdělení\n", "Začněme výběrem vzorku 30 hodnot z rovnoměrného rozdělení od 0 do 9. Také vypočítáme průměr a rozptyl.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "sample = [ random.randint(0,10) for _ in range(30) ]\n", "print(f\"Sample: {sample}\")\n", "print(f\"Mean = {np.mean(sample)}\")\n", "print(f\"Variance = {np.var(sample)}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pro vizuální odhad, kolik různých hodnot se ve vzorku vyskytuje, můžeme nakreslit **histogram**:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.hist(sample)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Analýza reálných dat\n", "\n", "Průměr a rozptyl jsou velmi důležité při analýze reálných dat. Načtěme data o baseballových hráčích z [SOCR MLB Height/Weight Data](http://wiki.stat.ucla.edu/socr/index.php/SOCR_Data_MLB_HeightsWeights)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df = pd.read_csv(\"../../data/SOCR_MLB.tsv\",sep='\\t', header=None, names=['Name','Team','Role','Weight','Height','Age'])\n", "df\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> Používáme balíček zvaný [**Pandas**](https://pandas.pydata.org/) pro analýzu dat. O knihovně Pandas a práci s daty v Pythonu budeme mluvit později v tomto kurzu.\n", "\n", "Spočítejme průměrné hodnoty pro věk, výšku a váhu:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df[['Age','Height','Weight']].mean()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nyní se zaměřme na výšku a vypočítejme směrodatnou odchylku a rozptyl:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(list(df['Height'])[:20])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mean = df['Height'].mean()\n", "var = df['Height'].var()\n", "std = df['Height'].std()\n", "print(f\"Mean = {mean}\\nVariance = {var}\\nStandard Deviation = {std}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Kromě průměru dává smysl podívat se na medián a kvartily. Ty lze vizualizovat pomocí **krabicového grafu**:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.figure(figsize=(10,2))\n", "plt.boxplot(df['Height'].ffill(), vert=False, showmeans=True)\n", "plt.grid(color='gray', linestyle='dotted')\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Můžeme také vytvořit krabicové grafy podmnožin našeho datasetu, například seskupené podle role hráče.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df.boxplot(column='Height', by='Role', figsize=(10,8))\n", "plt.xticks(rotation='vertical')\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **Poznámka**: Tento diagram naznačuje, že průměrná výška prvních basemanů je vyšší než výška druhých basemanů. Později se naučíme, jak tuto hypotézu formálněji otestovat a jak ukázat, že naše data jsou statisticky významná k jejímu prokázání.\n", "\n", "Věk, výška a váha jsou všechny spojité náhodné proměnné. Jaká myslíte, že je jejich distribuce? Dobrou metodou, jak to zjistit, je vykreslit histogram hodnot:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df['Weight'].hist(bins=15, figsize=(10,6))\n", "plt.suptitle('Weight distribution of MLB Players')\n", "plt.xlabel('Weight')\n", "plt.ylabel('Count')\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Normální rozdělení\n", "\n", "Vytvořme umělý vzorek váh, který následuje normální rozdělení se stejným průměrem a rozptylem jako naše skutečná data:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "generated = np.random.normal(mean, std, 1000)\n", "generated[:20]" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.figure(figsize=(10,6))\n", "plt.hist(generated, bins=15)\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.figure(figsize=(10,6))\n", "plt.hist(np.random.normal(0,1,50000), bins=300)\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Protože většina hodnot v reálném životě má normální rozdělení, neměli bychom používat uniformní generátor náhodných čísel pro generování vzorových dat. Zde je, co se stane, pokud se pokusíme vygenerovat hmotnosti s uniformním rozdělením (vygenerované pomocí `np.random.rand`):\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "wrong_sample = np.random.rand(1000)*2*std+mean-std\n", "plt.figure(figsize=(10,6))\n", "plt.hist(wrong_sample)\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Intervaly spolehlivosti\n", "\n", "Nyní vypočítáme intervaly spolehlivosti pro váhy a výšky baseballových hráčů. Použijeme kód [z této diskuse na stackoverflow](https://stackoverflow.com/questions/15033511/compute-a-confidence-interval-from-sample-data):\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import scipy.stats\n", "\n", "def mean_confidence_interval(data, confidence=0.95):\n", " a = 1.0 * np.array(data)\n", " n = len(a)\n", " m, se = np.mean(a), scipy.stats.sem(a)\n", " h = se * scipy.stats.t.ppf((1 + confidence) / 2., n-1)\n", " return m, h\n", "\n", "for p in [0.85, 0.9, 0.95]:\n", " m, h = mean_confidence_interval(df['Weight'].fillna(method='pad'),p)\n", " print(f\"p={p:.2f}, mean = {m:.2f} ± {h:.2f}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Testování hypotéz\n", "\n", "Pojďme prozkoumat různé role v našem datasetu baseballových hráčů:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df.groupby('Role').agg({ 'Weight' : 'mean', 'Height' : 'mean', 'Age' : 'count'}).rename(columns={ 'Age' : 'Count'})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ověřme hypotézu, že první metaři jsou vyšší než druzí metaři. Nejjednodušší způsob, jak to udělat, je otestovat intervaly spolehlivosti:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for p in [0.85,0.9,0.95]:\n", " m1, h1 = mean_confidence_interval(df.loc[df['Role']=='First_Baseman',['Height']],p)\n", " m2, h2 = mean_confidence_interval(df.loc[df['Role']=='Second_Baseman',['Height']],p)\n", " print(f'Conf={p:.2f}, 1st basemen height: {m1-h1[0]:.2f}..{m1+h1[0]:.2f}, 2nd basemen height: {m2-h2[0]:.2f}..{m2+h2[0]:.2f}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vidíme, že intervaly se nepřekrývají.\n", "\n", "Statisticky správnějším způsobem, jak dokázat hypotézu, je použití **Studentova t-testu**:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from scipy.stats import ttest_ind\n", "\n", "tval, pval = ttest_ind(df.loc[df['Role']=='First_Baseman',['Height']], df.loc[df['Role']=='Second_Baseman',['Height']],equal_var=False)\n", "print(f\"T-value = {tval[0]:.2f}\\nP-value: {pval[0]}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dvě hodnoty vrácené funkcí `ttest_ind` jsou:\n", "* p-hodnota může být považována za pravděpodobnost, že dvě rozdělení mají stejný průměr. V našem případě je velmi nízká, což znamená, že existuje silný důkaz podporující, že první metaři jsou vyšší.\n", "* t-hodnota je mezihodnota normalizovaného rozdílu průměrů, která se používá v t-testu, a porovnává se s mezní hodnotou pro danou hladinu spolehlivosti.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Simulace normálního rozdělení s centrální limitní větou\n", "\n", "Generátor pseudonáhodných čísel v Pythonu je navržen tak, aby nám poskytoval rovnoměrné rozdělení. Pokud chceme vytvořit generátor pro normální rozdělení, můžeme použít centrální limitní větu. Pro získání hodnoty s normálním rozdělením jednoduše spočítáme průměr vzorku vygenerovaného rovnoměrným rozdělením.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def normal_random(sample_size=100):\n", " sample = [random.uniform(0,1) for _ in range(sample_size) ]\n", " return sum(sample)/sample_size\n", "\n", "sample = [normal_random() for _ in range(100)]\n", "plt.figure(figsize=(10,6))\n", "plt.hist(sample)\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Korelace a Evil Baseball Corp\n", "\n", "Korelace nám umožňuje nalézt vztahy mezi sekvencemi dat. V našem ukázkovém příkladu si představme, že existuje zlý baseballový korporát, který platí svým hráčům podle jejich výšky – čím vyšší hráč je, tím více peněz dostane. Předpokládejme základní plat 1000 dolarů a dodatečný bonus od 0 do 100 dolarů, v závislosti na výšce. Vezmeme skutečné hráče z MLB a vypočítáme jejich imaginární platy:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "heights = df['Height'].fillna(method='pad')\n", "salaries = 1000+(heights-heights.min())/(heights.max()-heights.mean())*100\n", "print(list(zip(heights, salaries))[:10])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nyní spočítejme kovarianci a korelaci těchto sekvencí. `np.cov` nám poskytne takzvanou **kovarianční matici**, což je rozšíření kovariance na více proměnných. Prvek $M_{ij}$ kovarianční matice $M$ je korelace mezi vstupními proměnnými $X_i$ a $X_j$, a hodnoty na diagonále $M_{ii}$ jsou rozptyly $X_{i}$. Podobně `np.corrcoef` nám poskytne **korelační matici**.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(f\"Covariance matrix:\\n{np.cov(heights, salaries)}\")\n", "print(f\"Covariance = {np.cov(heights, salaries)[0,1]}\")\n", "print(f\"Correlation = {np.corrcoef(heights, salaries)[0,1]}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Korelace rovná 1 znamená, že mezi dvěma proměnnými existuje silný **lineární vztah**. Lineární vztah můžeme vizuálně vidět tak, že zakreslíme jednu hodnotu proti druhé:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.figure(figsize=(10,6))\n", "plt.scatter(heights,salaries)\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Podívejme se, co se stane, pokud vztah není lineární. Předpokládejme, že naše společnost se rozhodla skrýt zřejmou lineární závislost mezi výškami a platy a do vzorce zavedla nějakou nelinearitu, například `sin`:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "salaries = 1000+np.sin((heights-heights.min())/(heights.max()-heights.mean()))*100\n", "print(f\"Correlation = {np.corrcoef(heights, salaries)[0,1]}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "V tomto případě je korelace o něco menší, ale stále je docela vysoká. Nyní, aby byla vazba ještě méně zřejmá, můžeme přidat nějakou dodatečnou náhodnost přidáním náhodné proměnné k platu. Podívejme se, co se stane:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "salaries = 1000+np.sin((heights-heights.min())/(heights.max()-heights.mean()))*100+np.random.random(size=len(heights))*20-10\n", "print(f\"Correlation = {np.corrcoef(heights, salaries)[0,1]}\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.figure(figsize=(10,6))\n", "plt.scatter(heights, salaries)\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> Dokážete uhodnout, proč se tečky takto srovnají do svislých linií?\n", "\n", "Pozorovali jsme korelaci mezi uměle vytvořeným konceptem, jako je plat, a pozorovanou proměnnou *výška*. Podívejme se také, zda spolu korelují dvě pozorované proměnné, jako je výška a váha:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.corrcoef(df['Height'].ffill(),df['Weight'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bohužel jsme nedostali žádné výsledky – pouze nějaké podivné hodnoty `nan`. Je to způsobeno tím, že některé hodnoty v naší sérii nejsou definované, jsou reprezentovány jako `nan`, což způsobuje, že výsledek operace je rovněž nedefinovaný. Pohledem na matici vidíme, že problematickým sloupcem je `Weight`, protože byla spočítána samokorelace mezi hodnotami `Height`.\n", "\n", "> Tento příklad ukazuje důležitost **přípravy dat** a **čištění**. Bez správných dat nemůžeme nic spočítat.\n", "\n", "Použijme metodu `fillna` pro doplnění chybějících hodnot a spočítejme korelaci: \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.corrcoef(df['Height'].fillna(method='pad'), df['Weight'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Existuje skutečně korelace, ale není tak silná jako v našem umělém příkladu. Pokud se podíváme na bodový graf jedné hodnoty vůči druhé, vztah by byl mnohem méně zřejmý:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.figure(figsize=(10,6))\n", "plt.scatter(df['Weight'],df['Height'])\n", "plt.xlabel('Weight')\n", "plt.ylabel('Height')\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Závěr\n", "\n", "V tomto sešitě jsme se naučili, jak provádět základní operace s daty pro výpočet statistických funkcí. Nyní víme, jak používat pevný aparát matematiky a statistiky k ověření některých hypotéz a jak vypočítat intervaly spolehlivosti pro libovolné proměnné na základě datového vzorku.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n\n\n**Zřeknutí se odpovědnosti**: \nTento dokument byl přeložen pomocí AI překladatelské služby [Co-op Translator](https://github.com/Azure/co-op-translator). I když usilujeme o přesnost, mějte prosím na paměti, že automatické překlady mohou obsahovat chyby nebo nepřesnosti. Originální dokument v jeho mateřském jazyce by měl být považován za autoritativní zdroj. Pro důležité informace se doporučuje profesionální lidský překlad. Nejsme odpovědní za jakákoliv nedorozumění nebo mylné výklady vyplývající z použití tohoto překladu.\n\n" ] } ], "metadata": { "interpreter": { "hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5" }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.6" }, "coopTranslator": { "original_hash": "0f899e3c5019f948e7c787b22f3b2304", "translation_date": "2026-01-16T18:34:38+00:00", "source_file": "1-Introduction/04-stats-and-probability/notebook.ipynb", "language_code": "cs" } }, "nbformat": 4, "nbformat_minor": 4 }