{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Sissejuhatus tõenäosusteooriasse ja statistika\n", "Selles märkmikus katsetame mõningate kontseptsioonidega, mida oleme varem käsitlenud. Paljud tõenäosuse ja statistika mõisted on hästi esindatud suuremates andmetöötluse teekides Pythoni jaoks, nagu `numpy` ja `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": [ "## Juhuslikud muutujad ja jaotused\n", "Alustame 30 väärtuse juhusliku valimiga ühtlasest jaotusest vahemikus 0 kuni 9. Arvutame ka keskmise ja dispersiooni.\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": [ "Visuaalseks hinnanguks, kui palju erinevaid väärtusi proovis on, saame joonistada **histogrammi**:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.hist(sample)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Tõeliste andmete analüüs\n", "\n", "Keskmine ja dispersioon on reaalse maailma andmete analüüsimisel väga olulised. Laadime alla andmed pesapallurite kohta aadressilt [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": [ "> Siin kasutame andmeanalüüsiks paketti nimega [**Pandas**](https://pandas.pydata.org/). Räägime sellest, kuidas Pandasega Pythonis andmetega töötada, hiljem selles kursuses rohkem.\n", "\n", "Arvutame keskmised väärtused vanuse, pikkuse ja kaalu jaoks:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "df[['Age','Height','Weight']].mean()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nüüd keskendume pikkusele ja arvutame standardhälbe ja variatsiooni: \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": [ "Lisaks keskmisele on mõistlik vaadata ka mediaani ja kvartileid. Neid saab visualiseerida kasutades **kastdiagrammi**:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.figure(figsize=(10,2))\n", "plt.boxplot(df['Height'].ffill(), orientation='horizontal', showmeans=True)\n", "plt.grid(color='gray', linestyle='dotted')\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Me saame teha ka kastdiagramme meie andmekogumi alamhulkadest, näiteks mängija rolli järgi rühmitatult.\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": [ "> **Märkus**: See diagramm viitab sellele, et keskmiselt on esimesi pesamängijaid kõrgemad kui teisi pesamängijaid. Hiljem õpime, kuidas seda hüpoteesi formaalsemalt testida ja kuidas tõestada, et meie andmed on statistiliselt olulised selle näitamiseks. \n", "\n", "Vanus, pikkus ja kaal on kõik pidevad juhuslikud suurused. Mida sa arvad, milline võiks olla nende jaotus? Hea viis selle väljaselgitamiseks on kuvada väärtuste histogramm: \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": [ "## Norma jaotus\n", "\n", "Loome kaalude tehisnäidise, mis järgib normaaljaotust sama keskmise ja dispersiooniga nagu meie tegelikud andmed:\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": [ "Kuna enamik väärtusi päriselus on tavaliselt jaotunud, ei tohiks me sample andmete genereerimiseks kasutada ühtlast juhuarvude generaatorit. Siin on, mis juhtub, kui proovime genereerida kaalu ühtlase jaotusega (genereeritud `np.random.rand` abil):\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": [ "## Usaldusvahemikud\n", "\n", "Arvutame nüüd usaldusvahemikud pesapallimängijate kehakaaludele ja pikkustele. Kasutame koodi [sellelt stackoverflow arutelult](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'].ffill(),p)\n", " print(f\"p={p:.2f}, mean = {m:.2f} ± {h:.2f}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Hüpoteesi testimine\n", "\n", "Uurime meie pesapalli mängijate andmestikus erinevaid rolle:\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": [ "Testime hüpoteesi, et esimesed esindajad on teistest esindajatest pikemad. Lihtsaim viis selleks on testida usaldusvahemikke:\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": [ "Saame näha, et intervallid ei kattuvad.\n", "\n", "Statistiliselt korrektsem viis hüpoteesi tõestamiseks on kasutada **Studenti t-testi**:\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": [ "Kaks `ttest_ind` funktsiooni poolt tagastatud väärtust on:\n", "* p-väärtus võib pidada tõenäosuseks, et kaks jaotust omavad sama keskmist väärtust. Meie puhul on see väga madal, mis tähendab, et on tugev tõendusmaterjal, mis toetab, et esimesed pesurite mängijad on pikemad.\n", "* t-väärtus on normaliseeritud keskmise erinevuse vahevärtus, mida kasutatakse t-testis ja seda võrreldakse teatud usaldusväärtuse jaoks määratud läviväärtusega.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Normaalse jaotuse simuleerimine keskväärtuste piiriteoreemi abil\n", "\n", "Pythonis olev pseudo-juhuslike arvude generaator on loodud nii, et ta annaks meile ühtlase jaotuse. Kui soovime luua normaljaotusega generaatori, võime kasutada keskväärtuste piiriteoreemi. Normaalselt jaotunud väärtuse saamiseks arvutame lihtsalt ühtlaselt genereeritud valimi keskmise.\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": [ "## Korrelatsioon ja kurjuse pesapalli korporatsioon\n", "\n", "Korrelatsioon võimaldab meil leida seoseid andmejärjestuste vahel. Meie mängulises näites kujutame ette, et eksisteerib kurjus pesapalli korporatsioon, mis maksab oma mängijatele vastavalt nende pikkusele - mida pikem mängija on, seda rohkem raha ta saab. Oletame, et baasipalk on 1000 dollarit ja lisaboonus ulatub 0 kuni 100 dollarini, sõltuvalt pikkusest. Võtame reaalsed MLB mängijad ja arvutame nende kujuteldavad palgad:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "heights = df['Height'].ffill()\n", "salaries = 1000+(heights-heights.min())/(heights.max()-heights.mean())*100\n", "print(list(zip(heights, salaries))[:10])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Arvutame nüüd nende järjestuste kovariantsi ja korrelatsiooni. `np.cov` annab meile nn **kovariantsusmaatriksi**, mis on kovariantsi laiendus mitmele muutujale. Kovariantsusmaatriksi $M$ element $M_{ij}$ on korrelatsioon sisendmuutujate $X_i$ ja $X_j$ vahel ning diagonaalväärtused $M_{ii}$ on $X_{i}$ dispersioon. Samamoodi annab `np.corrcoef` meile **korrelatsioonimaatriksi**.\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": [ "Korrelatsioon, mis võrdub 1-ga, tähendab, et kahe muutuja vahel on tugev **lineaarne seos**. Lineaarse seose nägemiseks visuaalselt võime ühe väärtuse teisega graafikule panna:\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": [ "Vaatame, mis juhtub, kui seos ei ole lineaarne. Oletame, et meie ettevõte otsustas peita ilmselge lineaarse sõltuvuse kõrguste ja palkade vahel ning lisas valemisse mõningase mittelineaarsuse, näiteks `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": [ "Selles olukorras on korrelatsioon veidi väiksem, kuid siiski üsna kõrge. Nüüd, et seos oleks veelgi vähem ilmne, võime paluda lisada mingit juhuslikkust, lisades palgale mõne juhusliku muutuja. Vaatame, mis juhtub:\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": [ "> Kas suudad arvata, miks täpid järjestuvad selliseks vertikaalseks joonteks?\n", "\n", "Oleme täheldanud seost kunstlikult loodud kontseptsiooni nagu palk ja vaadeldava tunnuse *pikkus* vahel. Vaatame nüüd, kas ka kaks vaadeldavat tunnust, näiteks pikkus ja kaal, on seotud:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.corrcoef(df['Height'].ffill(),df['Weight'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Kahjuks ei saanud me mingeid tulemusi – ainult mõned kummalised `nan` väärtused. See tuleneb sellest, et mõned meie seeria väärtused on määratlemata, mida esindab `nan`, mis põhjustab ka operatsiooni tulemuse määratlematuks jäämise. Kui vaadata maatriksit, näeme, et probleemne veerg on `Weight`, sest on arvutatud isekorrelatsioon `Height` väärtuste vahel.\n", "\n", "> See näide näitab andmete **ettevalmistamise** ja **puhastamise** tähtsust. Ilma korralike andmeteta ei saa me midagi arvutada.\n", "\n", "Kasutame `fillna` meetodit puuduvate väärtuste täitmiseks ja arvutame korrelatsiooni: \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "np.corrcoef(df['Height'].ffill(), df['Weight'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Tegelikult on olemas korrelatsioon, kuid mitte nii tugev kui meie kunstlikus näites. Tõepoolest, kui vaatame ühe väärtuse hajuvusdiagrammi teise vastu, oleks seos palju vähem ilmne:\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": [ "## Kokkuvõte\n", "\n", "Selles märkmikus õppisime, kuidas andmetel põhitoiminguid teha, et arvutada välja statistilisi funktsioone. Nüüd teame, kuidas kasutada korralikku matemaatika ja statistika aparatuuri, et tõestada mõningaid hüpoteese, ning kuidas arvutada usaldusvahemikke suvalistele muutujatele, lähtudes andmete proovist. \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n\n\n**Lahtiütlus**:\nSee dokument on tõlgitud kasutades AI tõlketeenust [Co-op Translator](https://github.com/Azure/co-op-translator). Kuigi me püüdleme täpsuse poole, palun pange tähele, et automatiseeritud tõlgetes võib esineda vigu või ebatäpsusi. Originaaldokument selle emakeeles tuleks pidada autoriteetseks allikaks. Olulise teabe puhul soovitatakse kasutada professionaalset inimtõlget. Me ei vastuta selle tõlkega seotud eksimustest või valesti mõistmistest.\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" } }, "nbformat": 4, "nbformat_minor": 4 }