You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Data-Science-For-Beginners/translations/fi/1-Introduction/04-stats-and-probability/notebook.ipynb

581 lines
18 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Johdanto todennäköisyyksiin ja tilastotieteeseen\n",
"Tässä muistikirjassa leikitellään joillakin aiemmin käsitellyillä käsitteillä. Monet todennäköisyyden ja tilastotieteen käsitteet ovat hyvin edustettuina suurissa Pythonin tietojenkäsittelyyn tarkoitetuissa kirjastoissa, kuten `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": [
"## Satunnaismuuttujat ja jakaumat\n",
"Aloitetaan piirtämällä otos, jossa on 30 arvoa yhtenäisestä jakaumasta välillä 09. Laskemme myös keskiarvon ja varianssin.\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": [
"Arvioidaksemme visuaalisesti, kuinka monta erilaista arvoa otoksessa on, voimme piirtää **histogrammin**:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.hist(sample)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Todellisen datan analysointi\n",
"\n",
"Keskiarvo ja varianssi ovat erittäin tärkeitä todellisen elämän datan analysoinnissa. Ladataan baseball-pelaajia koskeva data osoitteesta [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": [
"> Käytämme täällä tietojenkäsittelyyn pakettia nimeltä [**Pandas**](https://pandas.pydata.org/). Puhumme lisää Pandasista ja datan käsittelystä Pythonilla myöhemmin tässä kurssissa.\n",
"\n",
"Lasketaan keskiarvot iälle, pituudelle ja painolle:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df[['Age','Height','Weight']].mean()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Keskitytään nyt pituuteen ja lasketaan keskipoikkeama ja varianssi:\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": [
"Keskiarvon lisäksi on järkevää tarkastella mediaaniarvoa ja kvartiileja. Ne voidaan visualisoida käyttämällä **laatikko-plotkia**:\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": [
"Voimme myös tehdä laatikkokaavioita datamme osajoukoista, esimerkiksi pelaajarooleittain ryhmiteltynä.\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": [
"> **Huomautus**: Tämä kaavio antaa ymmärtää, että keskimäärin ensimmäisen pesän pelaajien pituudet ovat pidempiä kuin toisen pesän pelaajien pituudet. Myöhemmin opimme, miten voimme testata tätä hypoteesia muodollisemmin ja miten voimme osoittaa, että datamme on tilastollisesti merkittävää tämän näyttämiseksi.\n",
"\n",
"Ikä, pituus ja paino ovat kaikki jatkuvia satunnaismuuttujia. Mitä luulet niiden jakauman olevan? Hyvä tapa selvittää se on piirtää arvojen histogrammi:\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": [
"## Normaali jakauma\n",
"\n",
"Luodaan keinotekoinen painonäyte, joka noudattaa normaalia jakaumaa samalla keskiarvolla ja varianssilla kuin todelliset tietomme:\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": [
"Koska useimmat arvot todellisessa elämässä ovat normaalijakautuneita, emme pitäisi käyttää tasaista satunnaislukugeneraattoria näytedata tuottamiseen. Tässä mitä tapahtuu, jos yritämme generoida painoja tasaiseen jakaumaan perustuen (generoitu `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": [
"## Luottamusvälit\n",
"\n",
"Lasketaan nyt luottamusvälit baseball-pelaajien painoille ja pituuksille. Käytämme koodia [tästä stackoverflow-keskustelusta](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": [
"## Hypoteesin testaus\n",
"\n",
"Tutkitaan eri rooleja baseball-pelaajien tietojoukossamme:\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": [
"Testataan hypoteesia, että ykköspesänpelaajat ovat pidempiä kuin kakkospelin pelaajat. Yksinkertaisin tapa tehdä tämä on testata luottamusvälejä:\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": [
"Voimme nähdä, että jaksot eivät mene päällekkäin.\n",
"\n",
"Tilastollisesti oikein tapa todistaa hypoteesi on käyttää **Studentin 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": [
"`ttest_ind`-funktion palauttamat kaksi arvoa ovat:\n",
"* p-arvoa voidaan pitää todennäköisyytenä, että kahdella jakaumalla on sama keskiarvo. Tapauksessamme se on hyvin pieni, mikä tarkoittaa, että on vahvaa näyttöä siitä, että ykköspelaajat ovat pidempiä.\n",
"* t-arvo on normalisoidun keskiarvon erotuksen välivaihe, jota käytetään t-testissä, ja sitä verrataan tietylle luottamusarvolle asetettuun kynnysarvoon.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Normaalijakauman simulointi keskeisen raja-arvolauseen avulla\n",
"\n",
"Pythonin satunnaislukugeneraattori on suunniteltu antamaan meille tasajakauma. Jos haluamme luoda normaalijakaumalle generaattorin, voimme käyttää keskeistä raja-arvolausetta. Saadaksemme normaalisti jakautuneen arvon laskemme vain tasajakautuneesta otoksesta keskiarvon.\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": [
"## Korrelaatio ja Evil Baseball Corp\n",
"\n",
"Korrelaatio antaa meille mahdollisuuden löytää yhteyksiä datan sarjojen välillä. Leikkiesimerkissämme kuvitellaan, että on olemassa ilkeä baseball-yritys, joka maksaa pelaajilleen heidän pituutensa mukaan - mitä pidempi pelaaja on, sitä enemmän hän saa rahaa. Oletetaan, että peruspalkka on 1000 dollaria, ja lisäksi maksetaan bonus 0100 dollaria pituuden perusteella. Otamme reaaliset MLB:n pelaajat ja laskemme heidän kuvitteelliset palkkansa:\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": [
"Lasketaan nyt näiden sekvenssien kovarianssi ja korrelaatio. `np.cov` antaa meille niin sanotun **kovarianssimatriisin**, joka on laajennus kovarianssille useille muuttujille. Kovarianssimatriisin $M$ alkio $M_{ij}$ on korrelaatio syötemuuttujien $X_i$ ja $X_j$ välillä, ja diagonaaliarvot $M_{ii}$ ovat $X_{i}$ variansseja. Vastaavasti `np.corrcoef` antaa meille **korrelaatiomatriisin**.\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": [
"Korrelaatio, joka on yhtä suuri kuin 1, tarkoittaa, että kahden muuttujan välillä on vahva **lineaarinen yhteys**. Voimme havaita lineaarisen yhteyden visuaalisesti piirtämällä yhden arvon toista vastaan:\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": [
"Katsotaanpa, mitä tapahtuu, jos suhde ei ole lineaarinen. Oletetaan, että yrityksemme päätti piilottaa ilmeisen lineaarisen riippuvuuden pituuden ja palkkojen välillä ja lisäsi kaavaan jonkin ei-lineaarisuuden, kuten `sin`:in:\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": [
"Tässä tapauksessa korrelaatio on hieman pienempi, mutta se on silti melko korkea. Nyt, tehdäksemme suhteesta vielä vähemmän ilmeisen, saatamme haluta lisätä hieman ylimääräistä satunnaisuutta lisäämällä palkan arvoon satunnaisen muuttujan. Katsotaan mitä tapahtuu:\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": [
"> Arvaatko, miksi pisteet asettuvat pystysuoriksi viivoiksi näin?\n",
"\n",
"Olemme havainneet korrelaation keinotekoisesti suunnitellun käsitteen, kuten palkan, ja havaintomuutujan *pituus* välillä. Tarkastellaan myös, korreloivatko kaksi havaittua muuttujaa, kuten pituus ja paino:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].ffill(),df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Valitettavasti emme saaneet mitään tuloksia vain joitakin outoja `nan`-arvoja. Tämä johtuu siitä, että joitakin sarjan arvoja ei ole määritelty, ja ne esitetään arvolla `nan`, mikä aiheuttaa myös operaation tuloksen olevan määrittelemätön. Katsomalla matriisia voimme nähdä, että `Weight` on ongelmallinen sarake, koska korkeusarvojen itsekorrelaatio on laskettu.\n",
"\n",
"> Tämä esimerkki osoittaa **aineiston valmistelun** ja **puhdistuksen** tärkeyden. Ilman asianmukaista aineistoa emme voi laskea mitään.\n",
"\n",
"Käytetään `fillna`-metodia täyttämään puuttuvat arvot ja lasketaan korrelaatio:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].fillna(method='pad'), df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Todellakin on olemassa korrelaatio, mutta ei niin vahva kuin meidän keinotekoisessa esimerkissä. Itse asiassa, jos katsomme hajontakaaviota, jossa toinen arvo asetetaan toisen vastaan, suhde olisi paljon vähemmän ilmeinen:\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": [
"## Yhteenveto\n",
"\n",
"Tässä muistikirjassa olemme oppineet suorittamaan peruslaskutoimituksia datalla tilastollisten funktioiden laskemiseksi. Tiedämme nyt, kuinka käyttää vankkaa matemaattisten ja tilastollisten menetelmien kokonaisuutta hypoteesien todistamiseen sekä kuinka laskea luottamusvälit mielivaltaisille muuttujille annetun datan otoksen perusteella.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**Vastuuvapauslauseke**:\nTämä asiakirja on käännetty tekoälypohjaisella käännöspalvelulla [Co-op Translator](https://github.com/Azure/co-op-translator). Pyrimme tarkkuuteen, mutta ole hyvä ja huomioi, että konekäännökset saattavat sisältää virheitä tai epätarkkuuksia. Alkuperäistä asiakirjaa sen alkuperäiskielellä tulee pitää virallisena lähteenä. Tärkeitä tietoja varten suositellaan ammattimaista ihmiskäännöstä. Emme ole vastuussa tämän käännöksen käytöstä aiheutuvista väärinymmärryksistä tai virhetulkinnoista.\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\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-16T15:49:16+00:00",
"source_file": "1-Introduction/04-stats-and-probability/notebook.ipynb",
"language_code": "fi"
}
},
"nbformat": 4,
"nbformat_minor": 4
}