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/da/1-Introduction/04-stats-and-probability/notebook.ipynb

581 lines
18 KiB

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Introduktion til Sandsynlighed og Statistik\n",
"I denne notesbog vil vi lege med nogle af de begreber, vi tidligere har diskuteret. Mange begreber inden for sandsynlighed og statistik er godt repræsenteret i store biblioteker til databehandling i Python, såsom `numpy` og `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": [
"## Tilfældige variable og fordelinger\n",
"Lad os starte med at trække et stikprøve af 30 værdier fra en ensartet fordeling fra 0 til 9. Vi vil også beregne middelværdi og varians.\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": [
"For visuelt at estimere, hvor mange forskellige værdier der er i prøven, kan vi tegne **histogrammet**:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.hist(sample)\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Analyse af rigtige data\n",
"\n",
"Gennemsnit og varians er meget vigtige, når man analyserer virkelige data. Lad os indlæse dataene om baseballspillere fra [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": [
"> Vi bruger en pakke kaldet [**Pandas**](https://pandas.pydata.org/) her til dataanalyse. Vi vil tale mere om Pandas og arbejde med data i Python senere i dette kursus.\n",
"\n",
"Lad os beregne gennemsnitsværdier for alder, højde og vægt:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df[['Age','Height','Weight']].mean()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lad os nu fokusere på højde og beregne standardafvigelse og varians:\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": [
"Ud over gennemsnittet giver det mening at se på medianværdien og kvartilerne. De kan visualiseres ved hjælp af et **box plot**:\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": [
"Vi kan også lave boksplot af delmængder af vores datasæt, for eksempel grupperet efter spillerrolle.\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": [
"> **Bemærk**: Dette diagram antyder, at højderne på første basmænd i gennemsnit er højere end højderne på anden basmænd. Senere vil vi lære, hvordan vi mere formelt kan teste denne hypotese, og hvordan vi kan demonstrere, at vores data er statistisk signifikante til at vise dette. \n",
"\n",
"Alder, højde og vægt er alle kontinuerlige stokastiske variable. Hvad tror du deres fordeling er? En god måde at finde ud af det på er at tegne et histogram over værdierne: \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": [
"## Normalfordeling\n",
"\n",
"Lad os lave en kunstig prøve af vægte, der følger en normalfordeling med samme gennemsnit og varians som vores rigtige 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": [
"Da de fleste værdier i det virkelige liv er normalfordelte, bør vi ikke bruge en jævnt fordelt tilfældig talgenerator til at generere prøve-data. Her er, hvad der sker, hvis vi prøver at generere vægte med en jævn fordeling (genereret af `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": [
"## Konfidensintervaller\n",
"\n",
"Lad os nu beregne konfidensintervaller for vægtene og højderne på baseballspillere. Vi vil bruge koden [fra denne stackoverflow-diskussion](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": [
"## Hypotesetestning\n",
"\n",
"Lad os udforske forskellige roller i vores baseballspillere-datasæt:\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": [
"Lad os teste hypotesen om, at førstekædemænd er højere end andenkædemænd. Den nemmeste måde at gøre dette på er at teste konfidensintervallerne:\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": [
"Vi kan se, at intervallerne ikke overlapper.\n",
"\n",
"En statistisk mere korrekt måde at bevise hypotesen på er at bruge en **Student t-test**:\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": [
"De to værdier, der returneres af funktionen `ttest_ind`, er:\n",
"* p-værdien kan betragtes som sandsynligheden for, at to fordelinger har samme middelværdi. I vores tilfælde er den meget lav, hvilket betyder, at der er stærke beviser for, at førstekommere er højere.\n",
"* t-værdien er den mellemste værdi af den normaliserede middelværdi-forskel, der bruges i t-testen, og den sammenlignes med en tærskelværdi for en given konfidensværdi.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simulering af en normalfordeling med centralgrænseværdisætningen\n",
"\n",
"Den pseudo-tilfældige generator i Python er designet til at give os en ensartet fordeling. Hvis vi ønsker at skabe en generator for normalfordeling, kan vi bruge centralgrænseværdisætningen. For at få en normalfordelt værdi vil vi blot beregne gennemsnittet af et prøveudtagning genereret med en uniform fordeling.\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": [
"## Korrelation og Evil Baseball Corp\n",
"\n",
"Korrelation gør det muligt for os at finde relationer mellem datasekvenser. I vores legeteksempel, lad os forestille os, at der er en ond baseball-virksomhed, som betaler sine spillere efter deres højde - jo højere spilleren er, desto flere penge får han/hun. Antag, at der er en grundløn på $1000, og en ekstra bonus fra $0 til $100, afhængigt af højden. Vi vil tage de rigtige spillere fra MLB og beregne deres fiktive lønninger:\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": [
"Lad os nu beregne kovarians og korrelation af disse sekvenser. `np.cov` vil give os en såkaldt **kovariansmatrix**, som er en udvidelse af kovarians til flere variable. Elementet $M_{ij}$ i kovariansmatrixen $M$ er en korrelation mellem inputvariablerne $X_i$ og $X_j$, og de diagonale værdier $M_{ii}$ er variansen af $X_{i}$. Tilsvarende vil `np.corrcoef` give os **korrelationsmatrixen**.\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": [
"En korrelation lig med 1 betyder, at der er en stærk **lineær sammenhæng** mellem to variable. Vi kan visuelt se den lineære sammenhæng ved at plotte den ene værdi mod den anden:\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": [
"Lad os se, hvad der sker, hvis relationen ikke er lineær. Antag, at vores virksomhed besluttede at skjule den åbenlyse lineære afhængighed mellem højder og lønninger og indførte en vis ikke-linearitet i formlen, såsom `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": [
"I dette tilfælde er korrelationen en smule mindre, men den er stadig ret høj. Nu, for at gøre relationen endnu mindre åbenlys, kunne vi tilføje noget ekstra tilfældighed ved at lægge en tilfældig variabel til lønnen. Lad os se, hvad der sker:\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": [
"> Kan du gætte, hvorfor prikkerne danner lodrette linjer som dette?\n",
"\n",
"Vi har observeret korrelationen mellem et kunstigt konstrueret koncept som løn og den observerede variabel *højde*. Lad os også se, om de to observerede variable, såsom højde og vægt, også korrelerer:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].ffill(),df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Desværre fik vi ikke nogen resultater - kun nogle mærkelige `nan` værdier. Dette skyldes, at nogle af værdierne i vores serie er udefinerede, repræsenteret som `nan`, hvilket gør resultatet af operationen udefineret også. Ved at se på matricen kan vi se, at `Weight` er den problematiske kolonne, fordi selvkorrelationen mellem `Height` værdier er blevet beregnet.\n",
"\n",
"> Dette eksempel viser vigtigheden af **dataklargøring** og **rengøring**. Uden ordentlige data kan vi ikke beregne noget.\n",
"\n",
"Lad os bruge `fillna` metoden til at udfylde de manglende værdier og beregne korrelationen: \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.corrcoef(df['Height'].fillna(method='pad'), df['Weight'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Der er faktisk en korrelation, men ikke en så stærk som i vores kunstige eksempel. Hvis vi ser på scatterplottet af den ene værdi mod den anden, ville sammenhængen være meget mindre åbenlys:\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": [
"## Konklusion\n",
"\n",
"I denne notesbog har vi lært, hvordan man udfører grundlæggende operationer på data for at beregne statistiske funktioner. Vi ved nu, hvordan man bruger et solidt apparat af matematik og statistik for at bevise nogle hypoteser, og hvordan man beregner konfidensintervaller for vilkårlige variable givet en datasample.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**Ansvarsfraskrivelse**:\nDette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selvom vi bestræber os på nøjagtighed, skal du være opmærksom på, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi påtager os intet ansvar for misforståelser eller fejltolkninger, der opstår som følge af brugen af denne oversættelse.\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:46:59+00:00",
"source_file": "1-Introduction/04-stats-and-probability/notebook.ipynb",
"language_code": "da"
}
},
"nbformat": 4,
"nbformat_minor": 4
}