Compare commits

..

4 Commits
V1 ... main

Author SHA1 Message Date
DBras cf39afa769 fikset t-udregning; label på hyppighedsmål; ppv og npv-udregning 2026-05-21 12:46:20 +02:00
DBras 0687f47226 patches to improve code output 2026-05-20 17:11:53 +02:00
DBras e12a7c96ae Added hyppigheds- og associationsmål 2026-05-19 21:28:54 +00:00
DBras 0c957990b0 2x2-tabel 2026-05-19 14:56:10 +02:00
8 changed files with 1215 additions and 126 deletions

294
2x2-tabel.ipynb Normal file
View File

@ -0,0 +1,294 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"id": "bac57c6e-48a0-4414-bf65-ed4ff751aa87",
"metadata": {},
"outputs": [],
"source": [
"# Imports\n",
"\n",
"from IPython.display import display, Markdown\n",
"from scipy.stats import chi2_contingency\n",
"from scipy.stats import t as t_test\n",
"import numpy as np\n",
"t_value = t_test.isf\n",
"\n",
"def _display_table(data_array, row_names=None, col_names=None):\n",
" _row_num = len(data_array)\n",
" _col_num = len(data_array[0])\n",
" _rows = []\n",
" for i in range(_row_num):\n",
" row = f'| {row_names[i]} |'\n",
" for j in range(_col_num):\n",
" row += f' {data_array[i][j]:.1f} |'\n",
" row += f' {sum(data_array[i]):.0f} |'\n",
" _rows.append(row)\n",
" _total_row = '| **Total** |'\n",
" _col_tots = 0\n",
" for i in range(_col_num):\n",
" col_tot = 0\n",
" for j in range(_row_num):\n",
" col_tot += data_array[j][i]\n",
" _col_tots += col_tot\n",
" _total_row += f' **{col_tot:.0f}** |'\n",
" _total_row += f' **{_col_tots:.0f}** |'\n",
" display(Markdown(\n",
" rf\"\"\"\n",
"| | {' | '.join(col_names + ['Total'])} |\n",
"{'|-'*(len(row_names) + 2)} |\n",
"{'\\n'.join(_rows)}\n",
"{_total_row}\n",
"\"\"\"\n",
"))\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "1616dacd-4132-46dd-a1a0-df813b634b12",
"metadata": {},
"source": [
"# Sensitivitet, specificitet og positiv/negativ prædiktiv værdi"
]
},
{
"cell_type": "markdown",
"id": "ad5c44e5-dc99-4665-a1c2-1b9b1586a175",
"metadata": {},
"source": [
"$$\n",
"Sensitivitet = P(Positiv\\ test | syg) = \\frac{antal\\ sandt\\ positive}{antal\\ sandt\\ positive + antal\\ falsk\\ negative}\n",
"$$\n",
"\n",
"$$\n",
"Specificitet = P(Negativ\\ test|rask) = \\frac{antal\\ sandt\\ negative}{antal\\ sandt\\ negative + antal\\ falsk\\ positive}\n",
"$$\n",
"\n",
"$$\n",
"PPV = P(Syg|positiv\\ test) = \\frac{antal\\ sande\\ positive}{antal\\ sande\\ positive + antal\\ falske\\ positive}\n",
"$$\n",
"\n",
"$$\n",
"NPV = P(Rask|negativ\\ test) = \\frac{antal\\ sande\\ negative}{antal\\ sande\\ negative + antal\\ falske\\ negative}\n",
"$$"
]
},
{
"cell_type": "markdown",
"id": "c220e249-002a-4536-8e87-424acb2e8190",
"metadata": {},
"source": [
"## Tabel ud fra positive og negative\n",
"\n",
"| | Syg | Ikke syg | I alt |\n",
"| :----------- | :--------------: | :--------------: | --------------------------------: |\n",
"| Test positiv | _sandt positive_ | _falsk positive_ | Total positive |\n",
"| Test negativ | _falsk negative_ | _sandt negative_ | Total negative |\n",
"| I alt | Total syge | Total raske | **n** |"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "af36924c-e2e7-46cf-9bde-5a94b9d427e3",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"### 2x2-tabel\n",
"\n",
"| | Syg | Ikke syg | I alt |\n",
"| :----------- | :--------------: | :--------------: | --------------------------------: |\n",
"| Test positiv | 117 | 796 | 913 |\n",
"| Test negativ | 20 | 3142 | 3162 |\n",
"| I alt | 137 | 3938 | **4075** |\n",
"\n",
"<span style='color:red'>Sensitivitet =</span> $\\frac{sandt\\ positive}{sandt\\ positive + falsk\\ negative} = \\frac{117}{117 + 20} \\approx$ 85.40%\n",
"\n",
"<span style='color:blue'>Specificitet =</span> $\\frac{sandt\\ negative}{sandt\\ negative + falsk\\ positive} = \\frac{3142}{3142 + 796} \\approx$ 79.79%\n",
"\n",
"For personer, der er syge, vil testen altså 85.40% af tiden vise positiv.\n",
"\n",
"Ligeledes vil testen for personer, der ikke er syge, vise negativ 79.79% af tiden.\n",
"\n",
"### PPV og NPV\n",
"\n",
"<span style='color:red'>PPV =</span> $\\frac{sandt\\ positive}{sandt\\ positive + falsk\\ positive} = \\frac{117}{117 + 796} \\approx$ 12.81%\n",
"\n",
"<span style='color:blue'>NPV =</span> $\\frac{sandt\\ negative}{sandt\\ negative + falsk\\ negative} = \\frac{3142}{3142 + 20} \\approx$ 99.37%\n",
"\n",
"For en person, der tester positiv, vil der være en 12.81% sandsynlighed for, at de reelt er syge.\n",
"\n",
"For en person, der tester negativ, vil der være en 99.37% sandsynlighed for, at de reelt er raske.\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"sandt_positive = 117\n",
"sandt_negative = 3142\n",
"\n",
"falsk_positive = 796\n",
"falsk_negative = 20\n",
"\n",
"\n",
"############################################\n",
"sensitivitet = sandt_positive / (sandt_positive + falsk_negative)\n",
"specificitet = sandt_negative / (sandt_negative + falsk_positive)\n",
"ppv = sandt_positive / (sandt_positive + falsk_positive)\n",
"npv = sandt_negative / (sandt_negative + falsk_negative)\n",
"\n",
"sum_syge = sandt_positive + falsk_negative\n",
"sum_ikke_syge = falsk_positive + sandt_negative\n",
"sum_positive = sandt_positive + falsk_positive\n",
"sum_negative = sandt_negative + falsk_negative\n",
"\n",
"display(Markdown(\n",
" rf\"\"\"\n",
"### 2x2-tabel\n",
" \n",
"| | Syg | Ikke syg | I alt |\n",
"| :----------- | :--------------: | :--------------: | --------------------------------: |\n",
"| Test positiv | {sandt_positive} | {falsk_positive} | {sum_positive} |\n",
"| Test negativ | {falsk_negative} | {sandt_negative} | {sum_negative} |\n",
"| I alt | {sum_syge} | {sum_ikke_syge} | **{sum_positive + sum_negative}** |\n",
"\n",
"<span style='color:red'>Sensitivitet =</span> $\\frac{{sandt\\ positive}}{{sandt\\ positive + falsk\\ negative}} = \\frac{{{sandt_positive}}}{{{sandt_positive} + {falsk_negative}}} \\approx$ {sensitivitet:.2%}\n",
"\n",
"<span style='color:blue'>Specificitet =</span> $\\frac{{sandt\\ negative}}{{sandt\\ negative + falsk\\ positive}} = \\frac{{{sandt_negative}}}{{{sandt_negative} + {falsk_positive}}} \\approx$ {specificitet:.2%}\n",
"\n",
"For personer, der er syge, vil testen altså {sensitivitet:.2%} af tiden vise positiv.\n",
"\n",
"Ligeledes vil testen for personer, der ikke er syge, vise negativ {specificitet:.2%} af tiden.\n",
"\n",
"### PPV og NPV\n",
"\n",
"<span style='color:red'>PPV =</span> $\\frac{{sandt\\ positive}}{{sandt\\ positive + falsk\\ positive}} = \\frac{{{sandt_positive}}}{{{sandt_positive} + {falsk_positive}}} \\approx$ {ppv:.2%}\n",
"\n",
"<span style='color:blue'>NPV =</span> $\\frac{{sandt\\ negative}}{{sandt\\ negative + falsk\\ negative}} = \\frac{{{sandt_negative}}}{{{sandt_negative} + {falsk_negative}}} \\approx$ {npv:.2%}\n",
"\n",
"For en person, der tester positiv, vil der være en {ppv:.2%} sandsynlighed for, at de reelt er syge.\n",
"\n",
"For en person, der tester negativ, vil der være en {npv:.2%} sandsynlighed for, at de reelt er raske.\n",
"\"\"\"\n",
"))"
]
},
{
"cell_type": "markdown",
"id": "d72087c9-96b0-4584-bae2-854068fb9de5",
"metadata": {},
"source": [
"## PPV ud fra sensitivitet, specificitet og prævalens"
]
},
{
"cell_type": "markdown",
"id": "833a7a8d-f012-4a0f-b39d-fc1ae3d8a1b1",
"metadata": {},
"source": [
"$$\n",
"PPV = \\frac{sensitivitet \\cdot prævalens}{sensitivitet \\cdot prævalens + (1-specificitet) \\cdot (1-prævalens)}\n",
"$$"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "0b81b6b9-268a-4338-bff9-d5a7c1636a67",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"$\n",
"PPV = \\frac{sensitivitet \\cdot prævalens}{sensitivitet \\cdot prævalens + (1-specificitet) \\cdot (1-prævalens)}\n",
"$\n",
"\n",
"$\n",
"= \\frac{0.854 \\cdot 0.05}{0.854 \\cdot 0.05 + (1-0.798) \\cdot (1-0.05)}\n",
"$\n",
"\n",
"$\n",
"= 18.20%\n",
"\\%\n",
"$\n",
"\n",
"Altså vil der være en sandsynlighed på 18.20% for, at en person faktisk er syg, hvis testen er positiv.\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"sensitivitet = 0.854\n",
"specificitet = 0.798\n",
"prævalens = 0.05\n",
"\n",
"ppv = sensitivitet * prævalens / (sensitivitet * prævalens + (1-specificitet) * (1-prævalens))\n",
"\n",
"display(Markdown(\n",
" rf\"\"\"\n",
"$\n",
"PPV = \\frac{{sensitivitet \\cdot prævalens}}{{sensitivitet \\cdot prævalens + (1-specificitet) \\cdot (1-prævalens)}}\n",
"$\n",
"\n",
"$\n",
"= \\frac{{{sensitivitet} \\cdot {prævalens}}}{{{sensitivitet} \\cdot {prævalens} + (1-{specificitet}) \\cdot (1-{prævalens})}}\n",
"$\n",
"\n",
"$\n",
"= {ppv:.2%}\n",
"\\%\n",
"$\n",
"\n",
"Altså vil der være en sandsynlighed på {ppv:.2%} for, at en person faktisk er syg, hvis testen er positiv.\n",
"\"\"\"\n",
"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b6fab8ba-02cc-478d-b3f0-32d55c6400c8",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "base",
"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.13.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

224
Case-Kontrol.ipynb Normal file
View File

@ -0,0 +1,224 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"id": "4ae75850",
"metadata": {},
"outputs": [],
"source": [
"# Imports\n",
"\n",
"from IPython.display import display, Markdown\n",
"from scipy.stats import chi2_contingency\n",
"from scipy.stats import t as t_test\n",
"import numpy as np\n",
"t_value = t_test.isf\n",
"\n",
"def _display_table(data_array, row_names=None, col_names=None):\n",
" _row_num = len(data_array)\n",
" _col_num = len(data_array[0])\n",
" _rows = []\n",
" for i in range(_row_num):\n",
" row = f'| {row_names[i]} |'\n",
" for j in range(_col_num):\n",
" row += f' {data_array[i][j]:.1f} |'\n",
" row += f' {sum(data_array[i]):.0f} |'\n",
" _rows.append(row)\n",
" _total_row = '| **Total** |'\n",
" _col_tots = 0\n",
" for i in range(_col_num):\n",
" col_tot = 0\n",
" for j in range(_row_num):\n",
" col_tot += data_array[j][i]\n",
" _col_tots += col_tot\n",
" _total_row += f' **{col_tot:.0f}** |'\n",
" _total_row += f' **{_col_tots:.0f}** |'\n",
" display(Markdown(\n",
" rf\"\"\"\n",
"| | {' | '.join(col_names + ['Total'])} |\n",
"{'|-'*(len(row_names) + 2)} |\n",
"{'\\n'.join(_rows)}\n",
"{_total_row}\n",
"\"\"\"\n",
"))\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "4f6c9952",
"metadata": {},
"source": [
"# Case-kontrol\n",
"\n",
"Dette er et case-kontrol studie, da:\n",
"\n",
"- Deltagerne udvælges på baggrund af udfaldet (sygdommen/lidelsen)\n",
"- Perspektivet er retrospektivt, dvs. man ser tilbage på eksponeringen\n",
"- Både casene (de syge) og kontrollerne (de raske) har været udsat for eksponering og ikke-eksponering (indenfor den hver gruppe, ikke det enkelte individ)\n",
"\n",
"Fordel og ulemper:\n",
"\n",
"- Hurtige og billige\n",
"- Mindre sårbare end tværsnitstudier, men mere sårbare end kohorte studier\n",
"- Ofte selektions- og re-call bias\n",
"- En sygdom kan skyldes mange eksponeringer. Man kan tage højde for diverse eksponeringer, men kan kun undersøge én eksponering pr. studie\n",
"- God til sjældne sygdomme, da studiet tager udgangspunkt i udfaldet og man derfor ikke behøver at rekruttere kæmpe stikprøver"
]
},
{
"cell_type": "markdown",
"id": "5a1c374c",
"metadata": {},
"source": [
"# Hyppigheds- og associationsmål\n",
"\n",
"Odds:\n",
"\n",
"$$\n",
"Odds = \\frac{proportion}{1-proportion} = \\frac{eksponerede}{ikke\\ eksponerede}\n",
"$$\n",
"\n",
"hvor proportion er en andel ($0 \\le proportion \\le 1$). Odds fortæller hvor mange eksponerede, der er for hver _ikke_ eksponeret.\n",
"\n",
"Oddsratio (OR):\n",
"\n",
"$$\n",
"OR = \\frac{Odds_{cases}}{Odds_{kontroller}}\n",
"$$\n",
"\n",
"Oddsratio giver hvor mange gange større risiko der er for sygdom, hvis man er eksponeret.\n",
"\n",
"- Hvis $OR \\gt 1$: forøget risiko for sygdom, hvis du er eksponeret\n",
"- Hvis $OR \\lt 1$: reduceret risiko for sygdom, hvis du er eksponeret\n",
"\n",
"Nulhypotese: $OR=1$"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9ef67735",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"### 2x2-tabel\n",
"\n",
"| | blodprop | Ikke blodprop | I alt |\n",
"| :-------------- | :----------------------------------: | :-----------------------------------: | ----------------------------------------: |\n",
"| Eksponeret | 26 | 10 | 36 |\n",
"| Ikke eksponeret | 32 | 106 | 138 |\n",
"| I alt | 58 | 116 | **174** |\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/markdown": [
"\n",
"### Hyppigheds- og associationsmål\n",
"\n",
"$odds_{blodprop} = \\frac{26}{32} = 0.8125$\n",
"\n",
"$odds_{kontroller} = \\frac{10}{106} = 0.0943$\n",
"\n",
"$OR = \\frac{odds_{blodprop}}{odds_{kontroller}} = \\frac{0.8125}{0.0943} \\approx 8.6125$\n",
"\n",
"Der er 7.61 gange større risiko for blodprop, hvis man er eksponeret, i forhold til hvis man ikke er eksponeret.\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"udfald = 'blodprop' # Fx blodprop # BEMÆRK: mellemrum forsvinder\n",
"kontrol_label = 'kontrol' # hvis mellemrum skal forblive, skal der være backslash (\\) foran, fx: kontrol_label = 'ikke\\ blodprop'\n",
"\n",
"antal_syge_eksponerede = 26\n",
"antal_syge_ikke_eksponerede = 32\n",
"\n",
"antal_raske_eksponerede = 10\n",
"antal_raske_ikke_eksponerede = 106\n",
"\n",
"\n",
"#####################################\n",
"odds_syge = antal_syge_eksponerede / antal_syge_ikke_eksponerede\n",
"odds_kontrol = antal_raske_eksponerede / antal_raske_ikke_eksponerede\n",
"oddsratio = odds_syge / odds_kontrol\n",
"\n",
"sum_udfald = antal_syge_eksponerede + antal_syge_ikke_eksponerede\n",
"sum_ikke_udfald = antal_raske_eksponerede + antal_raske_ikke_eksponerede\n",
"sum_eksponerede = antal_syge_eksponerede + antal_raske_eksponerede\n",
"sum_ikke_eksponerede = antal_syge_ikke_eksponerede + antal_raske_ikke_eksponerede\n",
"\n",
"display(Markdown(\n",
" rf\"\"\"\n",
"### 2x2-tabel\n",
" \n",
"| | {udfald} | Ikke {udfald} | I alt |\n",
"| :-------------- | :----------------------------------: | :-----------------------------------: | ----------------------------------------: |\n",
"| Eksponeret | {antal_syge_eksponerede} | {antal_raske_eksponerede} | {sum_eksponerede} |\n",
"| Ikke eksponeret | {antal_syge_ikke_eksponerede} | {antal_raske_ikke_eksponerede} | {sum_ikke_eksponerede} |\n",
"| I alt | {sum_udfald} | {sum_ikke_udfald} | **{sum_udfald + sum_ikke_udfald}** |\n",
"\"\"\"\n",
"))\n",
"\n",
"display(Markdown(\n",
" rf\"\"\"\n",
"### Hyppigheds- og associationsmål\n",
"\n",
"$odds_{{{udfald}}} = \\frac{{{antal_syge_eksponerede}}}{{{antal_syge_ikke_eksponerede}}} = {odds_syge:.4f}$\n",
"\n",
"$odds_{{{kontrol_label}}} = \\frac{{{antal_raske_eksponerede}}}{{{antal_raske_ikke_eksponerede}}} = {odds_kontrol:.4f}$\n",
"\n",
"$OR = \\frac{{odds_{{{udfald}}}}}{{odds_{{{kontrol_label}}}}} = \\frac{{{odds_syge:.4f}}}{{{odds_kontrol:.4f}}} \\approx {oddsratio:.4f}$\n",
"\n",
"Der er {oddsratio-1:.2f} gange større risiko for {udfald}, hvis man er eksponeret, i forhold til hvis man ikke er eksponeret.\n",
"\"\"\"\n",
"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e2898b72",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "base",
"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.13.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 2,
"id": "f0d18716", "id": "f0d18716",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -129,7 +129,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 23, "execution_count": 4,
"id": "1e61db8b", "id": "1e61db8b",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -186,7 +186,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 37, "execution_count": 5,
"id": "e7d81100", "id": "e7d81100",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -194,7 +194,7 @@
"data": { "data": {
"text/markdown": [ "text/markdown": [
"\n", "\n",
"95%-CI\n", "95%-CI med eksakt formel:\n",
"\n", "\n",
"$=\\left[\\bar{x} \\pm t' \\cdot se\\right]$\n", "$=\\left[\\bar{x} \\pm t' \\cdot se\\right]$\n",
"\n", "\n",
@ -220,7 +220,7 @@
"t_se = t_value(0.025, n-1) * standard_error\n", "t_se = t_value(0.025, n-1) * standard_error\n",
"display(Markdown(\n", "display(Markdown(\n",
" rf\"\"\"\n", " rf\"\"\"\n",
"95%-CI\n", "95%-CI med eksakt formel:\n",
"\n", "\n",
"$=\\left[\\bar{{x}} \\pm t' \\cdot se\\right]$\n", "$=\\left[\\bar{{x}} \\pm t' \\cdot se\\right]$\n",
"\n", "\n",

View File

@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 3,
"id": "b9802fc2", "id": "b9802fc2",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -143,7 +143,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 6,
"id": "1774cb7c", "id": "1774cb7c",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -151,7 +151,7 @@
"data": { "data": {
"text/markdown": [ "text/markdown": [
"\n", "\n",
"### Data\n", "### 2x2-tabel\n",
"\n", "\n",
"| | Syg | Ikke syg | I alt |\n", "| | Syg | Ikke syg | I alt |\n",
"| :----------- | :--------------: | :--------------: | --------------------------------: |\n", "| :----------- | :--------------: | :--------------: | --------------------------------: |\n",
@ -159,15 +159,11 @@
"| Test negativ | 20 | 3142 | 3162 |\n", "| Test negativ | 20 | 3142 | 3162 |\n",
"| I alt | 137 | 3938 | **4075** |\n", "| I alt | 137 | 3938 | **4075** |\n",
"\n", "\n",
"Sensitivitet $= 85.40%$\\%\n",
"\n", "\n",
"### Nøgleværdier\n", "Specificitet $= 79.79%$\\%\n",
"\n", "\n",
"| | |\n", "\n"
"| ---------------- | ------------------ |\n",
"| **Sensitivitet** | 85.4% |\n",
"| **Specificitet** | 79.8% |\n",
"| **PPV** | 12.8% |\n",
"| **NPV** | 99.4% |\n"
], ],
"text/plain": [ "text/plain": [
"<IPython.core.display.Markdown object>" "<IPython.core.display.Markdown object>"
@ -184,6 +180,8 @@
"falsk_positive = 796\n", "falsk_positive = 796\n",
"falsk_negative = 20\n", "falsk_negative = 20\n",
"\n", "\n",
"\n",
"############################################\n",
"sensitivitet = sandt_positive / (sandt_positive + falsk_negative)\n", "sensitivitet = sandt_positive / (sandt_positive + falsk_negative)\n",
"specificitet = sandt_negative / (sandt_negative + falsk_positive)\n", "specificitet = sandt_negative / (sandt_negative + falsk_positive)\n",
"ppv = sandt_positive / (sandt_positive + falsk_positive)\n", "ppv = sandt_positive / (sandt_positive + falsk_positive)\n",
@ -196,7 +194,7 @@
"\n", "\n",
"display(Markdown(\n", "display(Markdown(\n",
" rf\"\"\"\n", " rf\"\"\"\n",
"### Data\n", "### 2x2-tabel\n",
" \n", " \n",
"| | Syg | Ikke syg | I alt |\n", "| | Syg | Ikke syg | I alt |\n",
"| :----------- | :--------------: | :--------------: | --------------------------------: |\n", "| :----------- | :--------------: | :--------------: | --------------------------------: |\n",
@ -204,15 +202,11 @@
"| Test negativ | {falsk_negative} | {sandt_negative} | {sum_negative} |\n", "| Test negativ | {falsk_negative} | {sandt_negative} | {sum_negative} |\n",
"| I alt | {sum_syge} | {sum_ikke_syge} | **{sum_positive + sum_negative}** |\n", "| I alt | {sum_syge} | {sum_ikke_syge} | **{sum_positive + sum_negative}** |\n",
"\n", "\n",
"Sensitivitet $= {sensitivitet:.2%}$\\%\n",
"\n",
"Specificitet $= {specificitet:.2%}$\\%\n",
"\n", "\n",
"### Nøgleværdier\n",
"\n", "\n",
"| | |\n",
"| ---------------- | ------------------ |\n",
"| **Sensitivitet** | {sensitivitet:.1%} |\n",
"| **Specificitet** | {specificitet:.1%} |\n",
"| **PPV** | {ppv:.1%} |\n",
"| **NPV** | {npv:.1%} |\n",
"\"\"\"\n", "\"\"\"\n",
"))" "))"
] ]
@ -727,7 +721,7 @@
], ],
"metadata": { "metadata": {
"kernelspec": { "kernelspec": {
"display_name": "base", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
@ -741,7 +735,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.13.9" "version": "3.14.5"
} }
}, },
"nbformat": 4, "nbformat": 4,

397
Kohorte-RCT.ipynb Normal file
View File

@ -0,0 +1,397 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "f3c832c5",
"metadata": {},
"outputs": [],
"source": [
"# Imports\n",
"\n",
"from IPython.display import display, Markdown\n",
"from scipy.stats import chi2_contingency\n",
"from scipy.stats import t as t_test\n",
"import numpy as np\n",
"t_value = t_test.isf\n",
"\n",
"def _display_table(data_array, row_names=None, col_names=None):\n",
" _row_num = len(data_array)\n",
" _col_num = len(data_array[0])\n",
" _rows = []\n",
" for i in range(_row_num):\n",
" row = f'| {row_names[i]} |'\n",
" for j in range(_col_num):\n",
" row += f' {data_array[i][j]:.1f} |'\n",
" row += f' {sum(data_array[i]):.0f} |'\n",
" _rows.append(row)\n",
" _total_row = '| **Total** |'\n",
" _col_tots = 0\n",
" for i in range(_col_num):\n",
" col_tot = 0\n",
" for j in range(_row_num):\n",
" col_tot += data_array[j][i]\n",
" _col_tots += col_tot\n",
" _total_row += f' **{col_tot:.0f}** |'\n",
" _total_row += f' **{_col_tots:.0f}** |'\n",
" display(Markdown(\n",
" rf\"\"\"\n",
"| | {' | '.join(col_names + ['Total'])} |\n",
"{'|-'*(len(row_names) + 2)} |\n",
"{'\\n'.join(_rows)}\n",
"{_total_row}\n",
"\"\"\"\n",
"))\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "4392857e",
"metadata": {},
"source": [
"# Kohorte / RCT\n",
"\n",
"Dette er et kohortestudie, da:\n",
"\n",
"- det tager udgangspunkt i eksponering\n",
"- kohorten følges over tid, hvorefter man kigger på udfald\n",
"- det finder en årsagssammenhæng\n",
"- det undersøger flere udfald samtidig\n",
"- det er prospektivt - analytisk\n",
"\n",
"Forskel på RCT og kohorte:\n",
"\n",
"- I RCT bestemmer man hvilken eksponering grupperne skal udsættes for, og der kan derfor være blindet\n",
"- randomiseret\n",
"\n",
"Fordele og ulemper ved kohorte:\n",
"\n",
"- langsomt\n",
"- dyrt\n",
"- det mindst sårbare studie\n",
"- loss to follow-up (bias)\n",
"- mange sygdomme (udfald i forhold til eksponering)"
]
},
{
"cell_type": "markdown",
"id": "ffac3d14",
"metadata": {},
"source": [
"# Hyppigheds- og associationsmål (3 sæt)"
]
},
{
"cell_type": "markdown",
"id": "9bf576a5",
"metadata": {},
"source": [
"## Incidensrate (IR), incidensrate ratio (IRR), incidensrate differens (IRD)"
]
},
{
"cell_type": "markdown",
"id": "cd18552f",
"metadata": {},
"source": [
"$$\n",
"IR = \\frac{antal\\ nye\\ tilfælde}{samlet\\ persontid\\ i\\ risiko(risikotid)}\n",
"$$\n",
"\n",
"$$\n",
"IRR = \\frac{IR_{eksponerede}}{IR_{ikke\\ eksponerede}}\n",
"$$\n",
"\n",
"$$\n",
"IRD = IR_{eksponerede} - IR_{ikke\\ eksponerede}\n",
"$$\n",
"\n",
"$H_0$: $IRR=1 \\Leftrightarrow IRD=0$"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "8f9ea711",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"$IR = \\frac{antal\\ nye\\ tilfælde}{observationstid\\ i\\ personår}$\n",
"\n",
"$IR_{eksponeret} = \\frac{130}{6834} \\approx 0.01902 \\approx 1.90%$\\% sv.t. 19 pr. 1000 personår\n",
"\n",
"$IR_{ikke\\ eksponeret} = \\frac{40}{9228} \\approx 0.00433 \\approx 0.43%$\\% sv.t. 4 pr. 1000 personår\n",
"\n",
"$IRR = \\frac{IR_{eksponeret}}{IR_{ikke\\ eksponeret}} = \\frac{0.01902}{0.00433} \\approx 4.388$\n",
"\n",
"$IRD = IR_{eksponeret} - IR_{ikke\\ eksponeret} = 0.01902 - 0.00433 \\approx 0.01469$ sv.t. 15 pr. 1000\n",
"\n",
"Incidensraten blandt eksponerede er 3.388 gange højere end blandt ikke-eksponerede.\n",
"\n",
"For hver 1000 personår, kan 15 ekstra incidenser tilskrives eksponering.\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"eksponeret_label = 'eksponeret' # BEMÆRK: mellemrum forsvinder\n",
"ikke_eksponeret_label = 'ikke\\ eksponeret' # hvis mellemrum skal forblive, skal der være backslash (\\) foran, fx: ikke_eksponeret_label = 'ikke\\ eksponeret'\n",
"\n",
"antal_nye_tilfælde_eksponerede = 130\n",
"observationstid_eksponerede = 6834 # Observationstid målt i personår\n",
"\n",
"antal_nye_tilfælde_ikke_eksponerede = 40\n",
"observationstid_ikke_eksponerede = 9228\n",
"\n",
"\n",
"#####################################\n",
"ir_eksponerede = antal_nye_tilfælde_eksponerede / observationstid_eksponerede\n",
"ir_ikke_eksponerede = antal_nye_tilfælde_ikke_eksponerede / observationstid_ikke_eksponerede\n",
"irr = ir_eksponerede / ir_ikke_eksponerede\n",
"ird = ir_eksponerede - ir_ikke_eksponerede\n",
"\n",
"display(Markdown(\n",
" rf\"\"\"\n",
"$IR = \\frac{{antal\\ nye\\ tilfælde}}{{observationstid\\ i\\ personår}}$\n",
"\n",
"$IR_{{{eksponeret_label}}} = \\frac{{{antal_nye_tilfælde_eksponerede}}}{{{observationstid_eksponerede}}} \\approx {ir_eksponerede:.5f} \\approx {ir_eksponerede:.2%}$\\% sv.t. {ir_eksponerede*1000:.0f} pr. 1000 personår\n",
"\n",
"$IR_{{{ikke_eksponeret_label}}} = \\frac{{{antal_nye_tilfælde_ikke_eksponerede}}}{{{observationstid_ikke_eksponerede}}} \\approx {ir_ikke_eksponerede:.5f} \\approx {ir_ikke_eksponerede:.2%}$\\% sv.t. {ir_ikke_eksponerede*1000:.0f} pr. 1000 personår\n",
"\n",
"$IRR = \\frac{{IR_{{{eksponeret_label}}}}}{{IR_{{{ikke_eksponeret_label}}}}} = \\frac{{{ir_eksponerede:.5f}}}{{{ir_ikke_eksponerede:.5f}}} \\approx {irr:.3f}$\n",
"\n",
"$IRD = IR_{{{eksponeret_label}}} - IR_{{{ikke_eksponeret_label}}} = {ir_eksponerede:.5f} - {ir_ikke_eksponerede:.5f} \\approx {ird:.5f}$ sv.t. {ird*1000:.0f} pr. 1000\n",
"\n",
"Incidensraten blandt eksponerede er {irr-1:.3f} gange højere end blandt ikke-eksponerede.\n",
"\n",
"For hver 1000 personår, kan {ird*1000:.0f} ekstra incidenser tilskrives eksponering.\n",
"\"\"\"\n",
"))"
]
},
{
"cell_type": "markdown",
"id": "a8686b0b",
"metadata": {},
"source": [
"## Risiko (KIP), relativ risiko (RR), risiko differens (RD)"
]
},
{
"cell_type": "markdown",
"id": "393753d8",
"metadata": {},
"source": [
"$$\n",
"KIP = \\frac{antal\\ nye\\ tilfælde\\ i\\ en\\ given\\ periode}{antal\\ personer\\ i\\ risiko\\ ved\\ observationsperiodens\\ start}\n",
"$$\n",
"\n",
"$$\n",
"RR = \\frac{KIP_{eksponerede}}{KIP_{ikke\\ eksponerede}}\n",
"$$\n",
"\n",
"$$\n",
"RD = KIP_{eksponerede} - KIP_{ikke\\ eksponerede}\n",
"$$\n",
"\n",
"$H_0$: $RR=1 \\Leftrightarrow RD=0$"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "96e8cc3a",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"$KIP = \\frac{antal\\ nye\\ tilfælde}{antal\\ personer}$\n",
"\n",
"$KIP_{eksponeret} = \\frac{130}{656} \\approx 0.19817 \\approx 19.82%$\\%\n",
"\n",
"$KIP_{ikke\\ eksponeret} = \\frac{40}{787} \\approx 0.05083 \\approx 5.08%$\\%\n",
"\n",
"$RR = \\frac{KIP_{eksponeret}}{KIP_{ikke\\ eksponeret}} = \\frac{0.19817}{0.05083} \\approx 3.899$\n",
"\n",
"$RD = KIP_{eksponeret} - KIP_{ikke\\ eksponeret} = 0.19817 - 0.05083 \\approx 0.14734$ sv.t. 147 pr. 1000\n",
"\n",
"Dette vil altså betyde 147 ekstra tilfælde pr. 1000\n",
"\n",
"Risikoen blandt eksponerede er 2.899 gange højere end blandt ikke-eksponerede.\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"eksponeret_label = 'eksponeret' # BEMÆRK: mellemrum forsvinder\n",
"ikke_eksponeret_label = 'ikke\\ eksponeret' # hvis mellemrum skal forblive, skal der være backslash (\\) foran, fx: ikke_eksponeret_label = 'ikke\\ eksponeret'\n",
"\n",
"antal_nye_tilfælde_eksponerede = 130\n",
"antal_eksponerede = 656\n",
"\n",
"antal_nye_tilfælde_ikke_eksponerede = 40\n",
"antal_ikke_eksponerede = 787\n",
"\n",
"\n",
"#####################################\n",
"kip_eksponerede = antal_nye_tilfælde_eksponerede / antal_eksponerede\n",
"kip_ikke_eksponerede = antal_nye_tilfælde_ikke_eksponerede / antal_ikke_eksponerede\n",
"rr = kip_eksponerede / kip_ikke_eksponerede\n",
"rd = kip_eksponerede - kip_ikke_eksponerede\n",
"\n",
"display(Markdown(\n",
" rf\"\"\"\n",
"$KIP = \\frac{{antal\\ nye\\ tilfælde}}{{antal\\ personer}}$\n",
"\n",
"$KIP_{{{eksponeret_label}}} = \\frac{{{antal_nye_tilfælde_eksponerede}}}{{{antal_eksponerede}}} \\approx {kip_eksponerede:.5f} \\approx {kip_eksponerede:.2%}$\\%\n",
"\n",
"$KIP_{{{ikke_eksponeret_label}}} = \\frac{{{antal_nye_tilfælde_ikke_eksponerede}}}{{{antal_ikke_eksponerede}}} \\approx {kip_ikke_eksponerede:.5f} \\approx {kip_ikke_eksponerede:.2%}$\\%\n",
"\n",
"$RR = \\frac{{KIP_{{{eksponeret_label}}}}}{{KIP_{{{ikke_eksponeret_label}}}}} = \\frac{{{kip_eksponerede:.5f}}}{{{kip_ikke_eksponerede:.5f}}} \\approx {rr:.3f}$\n",
"\n",
"$RD = KIP_{{{eksponeret_label}}} - KIP_{{{ikke_eksponeret_label}}} = {kip_eksponerede:.5f} - {kip_ikke_eksponerede:.5f} \\approx {rd:.5f}$ sv.t. {rd*1000:.0f} pr. 1000\n",
"\n",
"Dette vil altså betyde {rd*1000:.0f} ekstra tilfælde pr. 1000\n",
"\n",
"Risikoen blandt eksponerede er {rr-1:.3f} gange højere end blandt ikke-eksponerede.\n",
"\"\"\"\n",
"))"
]
},
{
"cell_type": "markdown",
"id": "2f69d5ff",
"metadata": {},
"source": [
"## Odds, oddsratio (OR)"
]
},
{
"cell_type": "markdown",
"id": "21428554",
"metadata": {},
"source": [
"Odds:\n",
"\n",
"$$\n",
"Odds = \\frac{proportion}{1-proportion} = \\frac{eksponerede}{ikke\\ eksponerede}\n",
"$$\n",
"\n",
"hvor proportion er en andel ($0 \\le proportion \\le 1$). Odds fortæller hvor mange eksponerede, der er for hver _ikke_ eksponeret.\n",
"\n",
"Oddsratio (OR):\n",
"\n",
"$$\n",
"OR = \\frac{Odds_{cases}}{Odds_{kontroller}}\n",
"$$\n",
"\n",
"Oddsratio giver hvor mange gange større risiko der er for sygdom, hvis man er eksponeret.\n",
"\n",
"- Hvis $OR \\gt 1$: forøget risiko for sygdom, hvis du er eksponeret\n",
"- Hvis $OR \\lt 1$: reduceret risiko for sygdom, hvis du er eksponeret\n",
"\n",
"$H_0$: $OR=1$"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "cdda6f48",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"$odds_{blodprop} = \\frac{26}{32} = 0.8125$\n",
"\n",
"$odds_{kontrol} = \\frac{10}{106} = 0.0943$\n",
"\n",
"$OR = \\frac{odds_{blodprop}}{odds_{kontrol}} = \\frac{0.8125}{0.0943} \\approx 8.6125$\n",
"\n",
"Der er 7.61 gange større risiko for blodprop, hvis man er eksponeret, i forhold til hvis man ikke er eksponeret.\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"udfald = 'blodprop' # Fx blodprop # BEMÆRK: mellemrum forsvinder\n",
"kontrol_label = 'kontrol' # hvis mellemrum skal forblive, skal der være backslash (\\) foran, fx: kontrol_label = 'ikke\\ blodprop'\n",
"\n",
"antal_syge_eksponerede = 26\n",
"antal_syge_ikke_eksponerede = 32\n",
"\n",
"antal_raske_eksponerede = 10\n",
"antal_raske_ikke_eksponerede = 106\n",
"\n",
"\n",
"#####################################\n",
"odds_syge = antal_syge_eksponerede / antal_syge_ikke_eksponerede\n",
"odds_kontrol = antal_raske_eksponerede / antal_raske_ikke_eksponerede\n",
"oddsratio = odds_syge / odds_kontrol\n",
"\n",
"display(Markdown(\n",
" rf\"\"\"\n",
"$odds_{{{udfald}}} = \\frac{{{antal_syge_eksponerede}}}{{{antal_syge_ikke_eksponerede}}} = {odds_syge:.4f}$\n",
"\n",
"$odds_{{{kontrol_label}}} = \\frac{{{antal_raske_eksponerede}}}{{{antal_raske_ikke_eksponerede}}} = {odds_kontrol:.4f}$\n",
"\n",
"$OR = \\frac{{odds_{{{udfald}}}}}{{odds_{{{kontrol_label}}}}} = \\frac{{{odds_syge:.4f}}}{{{odds_kontrol:.4f}}} \\approx {oddsratio:.4f}$\n",
"\n",
"Der er {oddsratio-1:.2f} gange større risiko for {udfald}, hvis man er eksponeret, i forhold til hvis man ikke er eksponeret.\n",
"\"\"\"\n",
"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9d077dff",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "base",
"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.13.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 1,
"id": "42259d82", "id": "42259d82",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -47,39 +47,27 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "82a22acc", "id": "3ef266dc",
"metadata": {}, "metadata": {},
"source": [ "source": [
"# Hyppigheds- og associationsmål" "# $\\Chi^2$-test\n",
"\n",
"| | Kolonne 1| Kolonne 2 |\n",
"|-|---------|---------|\n",
"|Række 1| R1 K1| R1 K2|\n",
"|Række 2| R2 K1| R2 K2|"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"id": "9920c0f3", "id": "7c426592",
"metadata": {},
"outputs": [],
"source": [
"# Odds risiko\n",
"# Relativ risiko\n",
"# Risiko differens"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "d8e8f8ea",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/markdown": [ "text/markdown": [
"\n", "$H_0$: $\\pi_1 = \\pi_0$, altså ingen sammenhæng mellem rækker og søjler, hvilket vil sige ingen sammenhæng mellem eksponering og udfald."
"Prævalens (Høj skærmtid) $= \\frac{210}{460} = 0.4565 \\approx 45.65%$ \\%\n",
"\n",
"Prævalens (Lav skærmtid) $= \\frac{90}{360} = 0.2500 \\approx 25.00%$ \\%\n",
"\n",
"PPR $= \\frac{0.4565}{0.2500} = 1.8261$\n"
], ],
"text/plain": [ "text/plain": [
"<IPython.core.display.Markdown object>" "<IPython.core.display.Markdown object>"
@ -87,44 +75,7 @@
}, },
"metadata": {}, "metadata": {},
"output_type": "display_data" "output_type": "display_data"
}
],
"source": [
"kategorier = ['Høj skærmtid', 'Lav skærmtid']\n",
"data = [[210, 460],\n",
" [90, 360]]\n",
"\n",
"\n",
"\n",
"####################################\n",
"prævalens1 = data[0][0] / data[0][1]\n",
"prævalens2 = data[1][0] / data[1][1]\n",
"\n",
"display(Markdown(\n",
" rf\"\"\"\n",
"Prævalens ({kategorier[0]}) $= \\frac{{{data[0][0]}}}{{{data[0][1]}}} = {prævalens1:.4f} \\approx {prævalens1:.2%}$ \\%\n",
"\n",
"Prævalens ({kategorier[1]}) $= \\frac{{{data[1][0]}}}{{{data[1][1]}}} = {prævalens2:.4f} \\approx {prævalens2:.2%}$ \\%\n",
"\n",
"PPR $= \\frac{{{prævalens1:.4f}}}{{{prævalens2:.4f}}} = {prævalens1 / prævalens2:.4f}$\n",
"\"\"\"\n",
"))"
]
}, },
{
"cell_type": "markdown",
"id": "3ef266dc",
"metadata": {},
"source": [
"# $\\Chi^2$-test"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "7c426592",
"metadata": {},
"outputs": [
{ {
"data": { "data": {
"text/markdown": [ "text/markdown": [
@ -187,11 +138,26 @@
"data": { "data": {
"text/markdown": [ "text/markdown": [
"\n", "\n",
"$\\Chi^2$-værdi: 36.24\n", "Frihedsgrader: 1\n",
"\n", "\n",
"$p$-værdi: 1.7e-09\n", "Udregnet ved brug af Python-biblioteket `scipy.stats.chi2_contingency`:\n",
"\n", "\n",
"Frihedsgrader: 1\n" "$\\Chi^2$-værdi/teststørrelse: 36.24\n",
"\n",
"$p$-værdi: 1.7e-09 $\\ll 0.05$\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/markdown": [
"\n",
"Da $p$ $\\ll 0.05$, kan nulhypotesen $\\pi_1 = \\pi_0$ forkastes. Der er altså signifikant sammenhæng mellem udfald og eksponering.\n"
], ],
"text/plain": [ "text/plain": [
"<IPython.core.display.Markdown object>" "<IPython.core.display.Markdown object>"
@ -202,16 +168,26 @@
} }
], ],
"source": [ "source": [
"rækker = ['Høj skærmtid', 'Lav skærmtid']\n",
"kolonner = ['Hovedpine', 'Ingen hovedpine']\n", "kolonner = ['Hovedpine', 'Ingen hovedpine']\n",
"data = [[210, 250], \n", "rækker = ['Høj skærmtid',\n",
" [90, 270]]\n", " 'Lav skærmtid']\n",
"data = [[210, 250], # R1 K1 , R1 K2\n",
" [90, 270]] # R2 K1 , R2 K2\n",
"\n", "\n",
"\n", "\n",
"\n", "\n",
"############################################\n", "############################################\n",
"stat, p, dof, expected = chi2_contingency(data)\n", "stat, p, dof, expected = chi2_contingency(data)\n",
"p_threshold = 0.05\n",
"match p:\n",
" case p if p >= p_threshold:\n",
" p_text = f'$\\ge {p_threshold}$'\n",
" case p if p < p_threshold/100:\n",
" p_text = f'$\\ll {p_threshold}$'\n",
" case _:\n",
" p_text = f'$\\lt {p_threshold}$'\n",
"\n", "\n",
"display(Markdown(rf\"$H_0$: $\\pi_1 = \\pi_0$, altså ingen sammenhæng mellem rækker og søjler, hvilket vil sige ingen sammenhæng mellem eksponering og udfald.\"))\n",
"display(Markdown('### Observeret:'))\n", "display(Markdown('### Observeret:'))\n",
"_display_table(data, rækker, kolonner)\n", "_display_table(data, rækker, kolonner)\n",
"display(Markdown('### Forventet:'))\n", "display(Markdown('### Forventet:'))\n",
@ -219,13 +195,29 @@
"\n", "\n",
"display(Markdown(\n", "display(Markdown(\n",
" rf\"\"\"\n", " rf\"\"\"\n",
"$\\Chi^2$-værdi: {stat:.2f}\n",
"\n",
"$p$-værdi: {p:.2}\n",
"\n",
"Frihedsgrader: {dof}\n", "Frihedsgrader: {dof}\n",
"\n",
"Udregnet ved brug af Python-biblioteket `scipy.stats.chi2_contingency`:\n",
"\n",
"$\\Chi^2$-værdi (teststørrelse): {stat:.2f}\n",
"\n",
"$p$-værdi: {p:.2} {p_text}\n",
"\"\"\"\n", "\"\"\"\n",
"))\n" "))\n",
"\n",
"if p < p_threshold:\n",
" display(Markdown(\n",
" rf\"\"\"\n",
"Da $p$ {p_text}, kan nulhypotesen $\\pi_1 = \\pi_0$ forkastes. Der er altså signifikant sammenhæng mellem udfald og eksponering.\n",
"\"\"\"\n",
" ))\n",
"\n",
"else:\n",
" display(Markdown(\n",
" rf\"\"\"\n",
"Da $p$ {p_text}, kan nulhypotesen $\\pi_1 = \\pi_0$ ikke forkastes. Altså kan uafhængighed mellem udfald og eksponering ikke afvises.\n",
"\"\"\"\n",
" ))"
] ]
}, },
{ {

View File

@ -2,7 +2,7 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 2,
"id": "0ba6d314", "id": "0ba6d314",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -72,25 +72,27 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 61, "execution_count": 28,
"id": "7e734740", "id": "7e734740",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/markdown": [ "text/markdown": [
"\n",
"Middeldifference: $\\bar{x} = \\bar{x}_1 - \\bar{x}_2 = 1.44 - 1.26 = 0.180$\n",
"\n", "\n",
"$H_0: \\mu_1 = \\mu_2 \\Rightarrow \\mu_1 - \\mu_2 = 0$\n", "$H_0: \\mu_1 = \\mu_2 \\Rightarrow \\mu_1 - \\mu_2 = 0$\n",
"\n", "\n",
"Test: uparret t-test med $df = 150 + 300 - 2 = 448$ frihedsgrader\n", "Test: uparret t-test med $df = 36 + 36 - 2 = $**70 frihedsgrader**\n",
"\n", "\n",
"$SD_{fælles} = \\sqrt{ \\frac{ (n_1 - 1)\\cdot SD_1^2 + (n_2-1) \\cdot SD_2^2 }{ n_1 + n_2 - 2 } } = \\sqrt{ \\frac{ (150 - 1)\\cdot 1.7^2 + (300-1) \\cdot 1.8^2 }{ 150 + 300 - 2 } } = 1.7674$\n", "$SD_{fælles} = \\sqrt{ \\frac{ (n_1 - 1)\\cdot SD_1^2 + (n_2-1) \\cdot SD_2^2 }{ n_1 + n_2 - 2 } } = \\sqrt{ \\frac{ (36 - 1)\\cdot 0.25^2 + (36-1) \\cdot 0.32^2 }{ 36 + 36 - 2 } } = 0.2871$\n",
"\n", "\n",
"$se(\\bar{x_1} - \\bar{x_2}) = \\sqrt{\\frac{1}{n_1} + \\frac{1}{n_2}} \\cdot SD_{fælles} = \\sqrt{\\frac{1}{150} + \\frac{1}{300}} \\cdot 1.7674 = 0.1767$\n", "$se(\\bar{x_1} - \\bar{x_2}) = \\sqrt{\\frac{1}{n_1} + \\frac{1}{n_2}} \\cdot SD_{fælles} = \\sqrt{\\frac{1}{36} + \\frac{1}{36}} \\cdot 0.2871 = 0.0677$\n",
"\n", "\n",
"$t(x) = \\frac{\\bar{x_1} - \\bar{x_2}}{se(\\bar{x_1} - \\bar{x_2})} = \\frac{21.9 - 21.6}{0.1767} = 1.6974$\n", "$t(x) = \\frac{\\bar{x_1} - \\bar{x_2}}{se(\\bar{x_1} - \\bar{x_2})} = \\frac{1.44 - 1.26}{0.0677} =$ **2.6596**\n",
"\n", "\n",
"For en t-test med 448 frihedsgrader og et signifikansniveau på $\\alpha = 0.05$ er den kritiske værdi for $t(x) = 1.9653$.\n" "p-værdi for $|t(x)|$ ved 70 frihedsgrader: **0.0097** $\\lt 0.05$ (fundet ved brug af Python-biblioteket `scipy.stats.t`)\n"
], ],
"text/plain": [ "text/plain": [
"<IPython.core.display.Markdown object>" "<IPython.core.display.Markdown object>"
@ -103,7 +105,7 @@
"data": { "data": {
"text/markdown": [ "text/markdown": [
"\n", "\n",
"Da teststørrelsen $t(x)$ er mindre end den kritiske værdi, kan nulhypotesen $H_0: \\mu_1 - \\mu_2 = 0$ ikke forkastes.\n" "Da $p$ $\\lt 0.05$, kan nulhypotesen $H_0: \\mu_1 - \\mu_2 = 0$ forkastes. Der er altså statistisk signifikant forskel mellem middelværdierne.\n"
], ],
"text/plain": [ "text/plain": [
"<IPython.core.display.Markdown object>" "<IPython.core.display.Markdown object>"
@ -114,13 +116,13 @@
} }
], ],
"source": [ "source": [
"middel1 = 21.9\n", "middel1 = 1.44\n",
"n1 = 150\n", "n1 = 36\n",
"sd1 = 1.7\n", "sd1 = 0.25\n",
"\n", "\n",
"middel2 = 21.6\n", "middel2 = 1.26\n",
"n2 = 300\n", "n2 = 36\n",
"sd2 = 1.8\n", "sd2 = 0.32\n",
"\n", "\n",
"\n", "\n",
"\n", "\n",
@ -128,35 +130,45 @@
"dof = n1 + n2 - 2\n", "dof = n1 + n2 - 2\n",
"sd_fælles = math.sqrt(((n1-1)*sd1**2 + (n2-1)*sd2**2) / (n1 + n2 - 2))\n", "sd_fælles = math.sqrt(((n1-1)*sd1**2 + (n2-1)*sd2**2) / (n1 + n2 - 2))\n",
"se_fælles = math.sqrt(1/n1 + 1/n2) * sd_fælles\n", "se_fælles = math.sqrt(1/n1 + 1/n2) * sd_fælles\n",
"t_x = (middel1 - middel2)/(se_fælles)\n", "t_x = (np.abs(middel1 - middel2))/(se_fælles)\n",
"crit_t = t_test.ppf(1-0.05/2, dof)\n", "p_threshold = 0.05\n",
"p_værdi = (1 - t_test.cdf(t_x, dof))*2\n",
"match p_værdi:\n",
" case p_værdi if p_værdi >= p_threshold:\n",
" p_text = f'$\\ge {p_threshold}$'\n",
" case p_værdi if p_værdi < p_threshold/100:\n",
" p_text = f'$\\ll {p_threshold}$'\n",
" case _:\n",
" p_text = f'$\\lt {p_threshold}$'\n",
"\n", "\n",
"display(Markdown(\n", "display(Markdown(\n",
" rf\"\"\"\n", " rf\"\"\"\n",
"Middeldifference: $\\bar{{x}} = \\bar{{x}}_1 - \\bar{{x}}_2 = {middel1} - {middel2} = {middel1 - middel2:.3f}$\n",
"\n",
"$H_0: \\mu_1 = \\mu_2 \\Rightarrow \\mu_1 - \\mu_2 = 0$\n", "$H_0: \\mu_1 = \\mu_2 \\Rightarrow \\mu_1 - \\mu_2 = 0$\n",
"\n", "\n",
"Test: uparret t-test med $df = {n1} + {n2} - 2 = {dof}$ frihedsgrader\n", "Test: uparret t-test med $df = {n1} + {n2} - 2 = $**{dof} frihedsgrader**\n",
"\n", "\n",
"$SD_{{fælles}} = \\sqrt{{ \\frac{{ (n_1 - 1)\\cdot SD_1^2 + (n_2-1) \\cdot SD_2^2 }}{{ n_1 + n_2 - 2 }} }} = \\sqrt{{ \\frac{{ ({n1} - 1)\\cdot {sd1}^2 + ({n2}-1) \\cdot {sd2}^2 }}{{ {n1} + {n2} - 2 }} }} = {sd_fælles:.4f}$\n", "$SD_{{fælles}} = \\sqrt{{ \\frac{{ (n_1 - 1)\\cdot SD_1^2 + (n_2-1) \\cdot SD_2^2 }}{{ n_1 + n_2 - 2 }} }} = \\sqrt{{ \\frac{{ ({n1} - 1)\\cdot {sd1}^2 + ({n2}-1) \\cdot {sd2}^2 }}{{ {n1} + {n2} - 2 }} }} = {sd_fælles:.4f}$\n",
"\n", "\n",
"$se(\\bar{{x_1}} - \\bar{{x_2}}) = \\sqrt{{\\frac{{1}}{{n_1}} + \\frac{{1}}{{n_2}}}} \\cdot SD_{{fælles}} = \\sqrt{{\\frac{{1}}{{{n1}}} + \\frac{{1}}{{{n2}}}}} \\cdot {sd_fælles:.4f} = {se_fælles:.4f}$\n", "$se(\\bar{{x_1}} - \\bar{{x_2}}) = \\sqrt{{\\frac{{1}}{{n_1}} + \\frac{{1}}{{n_2}}}} \\cdot SD_{{fælles}} = \\sqrt{{\\frac{{1}}{{{n1}}} + \\frac{{1}}{{{n2}}}}} \\cdot {sd_fælles:.4f} = {se_fælles:.4f}$\n",
"\n", "\n",
"$t(x) = \\frac{{\\bar{{x_1}} - \\bar{{x_2}}}}{{se(\\bar{{x_1}} - \\bar{{x_2}})}} = \\frac{{{middel1} - {middel2}}}{{{se_fælles:.4f}}} = {t_x:.4f}$\n", "$t(x) = \\frac{{\\bar{{x_1}} - \\bar{{x_2}}}}{{se(\\bar{{x_1}} - \\bar{{x_2}})}} = \\frac{{{middel1} - {middel2}}}{{{se_fælles:.4f}}} =$ **{t_x:.4f}**\n",
"\n", "\n",
"For en t-test med {dof} frihedsgrader og et signifikansniveau på $\\alpha = 0.05$ er den kritiske værdi for $t(x) = {crit_t:.4f}$.\n", "p-værdi for $|t(x)|$ ved {dof} frihedsgrader: **{p_værdi:.4f}** {p_text} (fundet ved brug af Python-biblioteket `scipy.stats.t`)\n",
"\"\"\"\n", "\"\"\"\n",
"))\n", "))\n",
"\n", "\n",
"if t_x > crit_t:\n", "if p_værdi < p_threshold:\n",
" display(Markdown(\n", " display(Markdown(\n",
" rf\"\"\"\n", " rf\"\"\"\n",
"Da teststørrelsen $t(x)$ er større end den kritiske værdi, kan nulhypotesen $H_0: \\mu_1 - \\mu_2 = 0$ forkastes.\n", "Da $p$ {p_text}, kan nulhypotesen $H_0: \\mu_1 - \\mu_2 = 0$ forkastes. Der er altså statistisk signifikant forskel mellem middelværdierne.\n",
"\"\"\"\n", "\"\"\"\n",
" ))\n", " ))\n",
"else:\n", "else:\n",
" display(Markdown(\n", " display(Markdown(\n",
" rf\"\"\"\n", " rf\"\"\"\n",
"Da teststørrelsen $t(x)$ er mindre end den kritiske værdi, kan nulhypotesen $H_0: \\mu_1 - \\mu_2 = 0$ ikke forkastes.\n", "Da $p$ {p_text}, kan nulhypotesen $H_0: \\mu_1 - \\mu_2 = 0$ ikke forkastes. Der kan altså ikke siges at være statistisk signifikant forskel mellem middelværdierne.\n",
"\"\"\"\n", "\"\"\"\n",
" ))" " ))"
] ]
@ -195,7 +207,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 75, "execution_count": 20,
"id": "bdc8cd82", "id": "bdc8cd82",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -203,19 +215,21 @@
"data": { "data": {
"text/markdown": [ "text/markdown": [
"\n", "\n",
"$\\bar{x}_1 = 21.9$\n", "$\\bar{x}_1 = 1.44$\n",
"\n", "\n",
"$\\bar{x}_2 = 21.6$\n", "$\\bar{x}_2 = 1.26$\n",
"\n", "\n",
"$SD_{fælles} = \\sqrt{ \\frac{ (n_1 - 1)\\cdot SD_1^2 + (n_2-1) \\cdot SD_2^2 }{ n_1 + n_2 - 2 } } = \\sqrt{ \\frac{ (150 - 1)\\cdot 1.7^2 + (300-1) \\cdot 1.8^2 }{ 150 + 300 - 2 } } = 1.7674$\n", "Eksakt formel:\n",
"\n", "\n",
"$se(\\bar{x_1} - \\bar{x_2}) = \\sqrt{\\frac{1}{n_1} + \\frac{1}{n_2}} \\cdot SD_{fælles} = \\sqrt{\\frac{1}{150} + \\frac{1}{300}} \\cdot 1.7674 = 0.1767$\n", "$SD_{fælles} = \\sqrt{ \\frac{ (n_1 - 1)\\cdot SD_1^2 + (n_2-1) \\cdot SD_2^2 }{ n_1 + n_2 - 2 } } = \\sqrt{ \\frac{ (36 - 1)\\cdot 0.25^2 + (36-1) \\cdot 0.32^2 }{ 36 + 36 - 2 } } = 0.2871$\n",
"\n",
"$se(\\bar{x_1} - \\bar{x_2}) = \\sqrt{\\frac{1}{n_1} + \\frac{1}{n_2}} \\cdot SD_{fælles} = \\sqrt{\\frac{1}{36} + \\frac{1}{36}} \\cdot 0.2871 = 0.0677$\n",
"\n", "\n",
"$95\\% CI(\\mu_1 - \\mu_2) = \\bar{x}_1 - \\bar{x}_2 \\pm t' \\cdot se(\\bar{x}_1 - \\bar{x}_2)$\n", "$95\\% CI(\\mu_1 - \\mu_2) = \\bar{x}_1 - \\bar{x}_2 \\pm t' \\cdot se(\\bar{x}_1 - \\bar{x}_2)$\n",
"\n", "\n",
"$= 21.9 - 21.6 \\pm 1.965 \\cdot 0.177$\n", "$= 1.44 - 1.26 \\pm 1.994 \\cdot 0.068$\n",
"\n", "\n",
"$= 0.300 \\pm 0.347 = \\left[-0.047\\ ;\\ 0.647\\right]$\n" "$= 0.180 \\pm 0.135 = \\left[0.045\\ ;\\ 0.315\\right]$\n"
], ],
"text/plain": [ "text/plain": [
"<IPython.core.display.Markdown object>" "<IPython.core.display.Markdown object>"
@ -228,7 +242,7 @@
"data": { "data": {
"text/markdown": [ "text/markdown": [
"\n", "\n",
"Da $0$ er inkluderet i $95\\%CI$, kan der ikke siges at være signifikant forskel på middelværdierne.\n" "Da $0$ ikke er inkluderet i $95\\%CI$, kan der siges at være signifikant forskel på middelværdierne.\n"
], ],
"text/plain": [ "text/plain": [
"<IPython.core.display.Markdown object>" "<IPython.core.display.Markdown object>"
@ -252,6 +266,8 @@
"\n", "\n",
"$\\bar{{x}}_2 = {middel2}$\n", "$\\bar{{x}}_2 = {middel2}$\n",
"\n", "\n",
"Eksakt formel:\n",
"\n",
"$SD_{{fælles}} = \\sqrt{{ \\frac{{ (n_1 - 1)\\cdot SD_1^2 + (n_2-1) \\cdot SD_2^2 }}{{ n_1 + n_2 - 2 }} }} = \\sqrt{{ \\frac{{ ({n1} - 1)\\cdot {sd1}^2 + ({n2}-1) \\cdot {sd2}^2 }}{{ {n1} + {n2} - 2 }} }} = {sd_fælles:.4f}$\n", "$SD_{{fælles}} = \\sqrt{{ \\frac{{ (n_1 - 1)\\cdot SD_1^2 + (n_2-1) \\cdot SD_2^2 }}{{ n_1 + n_2 - 2 }} }} = \\sqrt{{ \\frac{{ ({n1} - 1)\\cdot {sd1}^2 + ({n2}-1) \\cdot {sd2}^2 }}{{ {n1} + {n2} - 2 }} }} = {sd_fælles:.4f}$\n",
"\n", "\n",
"$se(\\bar{{x_1}} - \\bar{{x_2}}) = \\sqrt{{\\frac{{1}}{{n_1}} + \\frac{{1}}{{n_2}}}} \\cdot SD_{{fælles}} = \\sqrt{{\\frac{{1}}{{{n1}}} + \\frac{{1}}{{{n2}}}}} \\cdot {sd_fælles:.4f} = {se_fælles:.4f}$\n", "$se(\\bar{{x_1}} - \\bar{{x_2}}) = \\sqrt{{\\frac{{1}}{{n_1}} + \\frac{{1}}{{n_2}}}} \\cdot SD_{{fælles}} = \\sqrt{{\\frac{{1}}{{{n1}}} + \\frac{{1}}{{{n2}}}}} \\cdot {sd_fælles:.4f} = {se_fælles:.4f}$\n",

172
Tværsnit.ipynb Normal file
View File

@ -0,0 +1,172 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "eb67f7a5",
"metadata": {},
"outputs": [],
"source": [
"# Imports\n",
"\n",
"from IPython.display import display, Markdown\n",
"from scipy.stats import chi2_contingency\n",
"from scipy.stats import t as t_test\n",
"import numpy as np\n",
"t_value = t_test.isf\n",
"\n",
"def _display_table(data_array, row_names=None, col_names=None):\n",
" _row_num = len(data_array)\n",
" _col_num = len(data_array[0])\n",
" _rows = []\n",
" for i in range(_row_num):\n",
" row = f'| {row_names[i]} |'\n",
" for j in range(_col_num):\n",
" row += f' {data_array[i][j]:.1f} |'\n",
" row += f' {sum(data_array[i]):.0f} |'\n",
" _rows.append(row)\n",
" _total_row = '| **Total** |'\n",
" _col_tots = 0\n",
" for i in range(_col_num):\n",
" col_tot = 0\n",
" for j in range(_row_num):\n",
" col_tot += data_array[j][i]\n",
" _col_tots += col_tot\n",
" _total_row += f' **{col_tot:.0f}** |'\n",
" _total_row += f' **{_col_tots:.0f}** |'\n",
" display(Markdown(\n",
" rf\"\"\"\n",
"| | {' | '.join(col_names + ['Total'])} |\n",
"{'|-'*(len(row_names) + 2)} |\n",
"{'\\n'.join(_rows)}\n",
"{_total_row}\n",
"\"\"\"\n",
"))\n",
"\n"
]
},
{
"cell_type": "markdown",
"id": "c0bee775",
"metadata": {},
"source": [
"# Tværsnit\n",
"\n",
"Dette er et tværsnitstudie, da:\n",
"\n",
"- det giver et øjebliksbilledet (man ser på nuværende eksponering)\n",
"- eksponering og udfald indhentes samtidig, dvs man kan ikke finde årsagssammenhæng\n",
"- bruges til at beskrive bestanden af en given tilstand/ sygdom til et givent tidspunkt\n",
"\n",
"Fordele og ulemper:\n",
"\n",
"- hurtigt og billigt\n",
"- meget sårbart, da man ikke kender årsagssammenhæng\n",
"- hypotesegenererende\n",
"- deskriptivt (ikke analytisk)"
]
},
{
"cell_type": "markdown",
"id": "5a7b9dca",
"metadata": {},
"source": [
"## Hyppigheds- og associationsmål\n",
"\n",
"Prævalens / Prævalensproportion (PP)\n",
"\n",
"$$\n",
"PP = \\frac{antal\\ syge\\ på\\ et\\ givet\\ tidspunkt}{antal\\ personer\\ i\\ studiepopulationen\\ på\\ samme\\ tidspunkt}\n",
"$$\n",
"\n",
"$$\n",
"PPR = \\frac{PP_{eksponerede}}{PP_{ikke\\ eksponerede}}\n",
"$$"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bdd4eb49",
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"\n",
"$PP_{eksponerede} = \\frac{33}{101} \\approx 32.67%$\\%\n",
"\n",
"$PP_{ikke\\ eksponeret} = \\frac{19}{90} \\approx 21.11%$\\%\n",
"\n",
"$PPR = \\frac{PP_{eksponerede}}{PP_{ikke\\ eksponeret}} = \\frac{0.3267}{0.2111} \\approx 154.77%$\\%\n",
"\n",
"Prævalensen er 54.77% højere blandt eksponerede i forhold til ikke-eksponerede.\n"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"eksponeret_label = 'eksponerede' # BEMÆRK: mellemrum forsvinder\n",
"ikke_eksponeret_label = 'ikke\\ eksponeret' # hvis mellemrum skal forblive, skal der være backslash (\\) foran, fx: ikke_eksponeret_label = 'ikke\\ eksponeret'\n",
"\n",
"syge_eksponerede = 33\n",
"eksponerede_i_alt = 101\n",
"\n",
"syge_ikke_eksponerede = 19\n",
"ikke_eksponerede_i_alt = 90\n",
"\n",
"\n",
"################################\n",
"pp_eksponerede = syge_eksponerede / eksponerede_i_alt\n",
"pp_ikke_eksponerede = syge_ikke_eksponerede / ikke_eksponerede_i_alt\n",
"ppr = pp_eksponerede / pp_ikke_eksponerede\n",
"\n",
"display(Markdown(\n",
" rf\"\"\"\n",
"$PP_{{{eksponeret_label}}} = \\frac{{{syge_eksponerede}}}{{{eksponerede_i_alt}}} \\approx {pp_eksponerede:.2%}$\\%\n",
"\n",
"$PP_{{{ikke_eksponeret_label}}} = \\frac{{{syge_ikke_eksponerede}}}{{{ikke_eksponerede_i_alt}}} \\approx {pp_ikke_eksponerede:.2%}$\\%\n",
"\n",
"$PPR = \\frac{{PP_{{{eksponeret_label}}}}}{{PP_{{{ikke_eksponeret_label}}}}} = \\frac{{{pp_eksponerede:.4f}}}{{{pp_ikke_eksponerede:.4f}}} \\approx {ppr:.2%}$\\%\n",
"\n",
"Prævalensen er {ppr-1:.2%} højere blandt eksponerede i forhold til ikke-eksponerede.\n",
"\"\"\"\n",
"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5f8b2150",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "base",
"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.13.9"
}
},
"nbformat": 4,
"nbformat_minor": 5
}