Mathematik für Biologiestudierende II¶
Sommersemester 2024
02.07.2024
© 2024 Prof. Dr. Rüdiger W. Braun
In [1]:
import numpy as np
import pandas as pd
from scipy import stats
import statsmodels.formula.api as smf
import seaborn as sns
sns.set_theme()
import warnings
warnings.filterwarnings('ignore', message='The figure layout has changed')
Klausur¶
- Sie können sich jetzt zur Klausur am 06.08.2024 anmelden.
- Die Klausur dauert 120 Minuten.
Es gibt zwei verschiedene Aufgabensaätze
- Klausur mit den Themen vor dem WS 2023/24
- Klausur mit den Themen ab dem WS 2024/24
- neue Klausuraufgaben bekommt
- wer im WS 2023/24 oder im SS 2024 Übungspunkte gesammelt hat
- wer keine Übungspunkte hat und sich im Oktober 2023 oder später erstmals im LSF zur Vorlesung angemeldet hat
- alte Klausuraufgaben bekommt
- wer vor dem WS 2023/24 Übungspunkte gesammelt hat
- wer keine Übungspunkte hat und sich vor Oktober 2023 im LSF zur Vorlesung angemeldet hat
- wer sowohl vor als auch nach Oktober 2023 Übungspunkte bekommen hat und sich anmeldet, wird von mir angeschrieben
- Mit der Aufteilung auf die Hörsäle teile ich mit, welche Aufgaben jemand bekommen wird
- Dann kann man widersprechen, aber bitte zügig
Themen heute¶
- Lineare Modelle mit kategoriellen Daten
- ANOVA als lineares Modell
- Regression im exponentiellen Modell
- Halblogarithmische Darstellung
- Halbwerts- und Verdoppelungszeit
Lineare Modelle mit kategoriellen Daten¶
Wir kommen zu dem Rattenbeispiel aus Lektion 21 zurück:
- kontaminiertes Gelände: fange 10 Ratten
- unbelastetes Vergleichsgelände: fange 10 Ratten
- für jede Ratte wird ihr Alter in Monaten und der Bleigehalt im Gewebe bestimmt
In [2]:
df = pd.read_csv('ratten.csv')
In [3]:
sns.lmplot(df, x='Alter', y='Belastung', hue='Gelände');
- Der t-Test zeigte keinen Unterschied zwischen den Ratten auf kontaminierten und nicht kontaminiertem Gelände.
- Die Ratten auf dem kontaminierten Gelände sind aber im Schnitt jünger.
- Wir wollen gleichaltrige Ratten vergleichen
In [4]:
formel = 'Belastung ~ Alter + Gelände'
modell = smf.ols(formel, df)
res = modell.fit()
In [5]:
res.summary()
Out[5]:
Dep. Variable: | Belastung | R-squared: | 0.673 |
---|---|---|---|
Model: | OLS | Adj. R-squared: | 0.635 |
Method: | Least Squares | F-statistic: | 17.52 |
Date: | Sun, 14 Jul 2024 | Prob (F-statistic): | 7.42e-05 |
Time: | 17:41:16 | Log-Likelihood: | -63.935 |
No. Observations: | 20 | AIC: | 133.9 |
Df Residuals: | 17 | BIC: | 136.9 |
Df Model: | 2 | ||
Covariance Type: | nonrobust |
coef | std err | t | P>|t| | [0.025 | 0.975] | |
---|---|---|---|---|---|---|
Intercept | 39.1728 | 5.166 | 7.583 | 0.000 | 28.273 | 50.072 |
Gelände[T.unkontaminiert] | -11.0980 | 3.124 | -3.552 | 0.002 | -17.689 | -4.507 |
Alter | 3.5490 | 0.617 | 5.752 | 0.000 | 2.247 | 4.851 |
Omnibus: | 1.119 | Durbin-Watson: | 2.547 |
---|---|---|---|
Prob(Omnibus): | 0.572 | Jarque-Bera (JB): | 0.408 |
Skew: | -0.346 | Prob(JB): | 0.815 |
Kurtosis: | 3.102 | Cond. No. | 33.2 |
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
Gelände[T.unkontaminiert]
ist signifikant- Allerdings ist das der Unterschied bei Alter = 0
- Das ist Unsinn
- Wir vergleichen im Alter von 8 und 9 Monaten
In [6]:
anfrage = pd.DataFrame()
anfrage['Alter'] = [8,8,9,9]
anfrage['Gelände'] = ['kontaminiert', 'unkontaminiert', 'kontaminiert', 'unkontaminiert']
anfrage
Out[6]:
Alter | Gelände | |
---|---|---|
0 | 8 | kontaminiert |
1 | 8 | unkontaminiert |
2 | 9 | kontaminiert |
3 | 9 | unkontaminiert |
In [7]:
res.get_prediction(anfrage).summary_frame()
Out[7]:
mean | mean_se | mean_ci_lower | mean_ci_upper | obs_ci_lower | obs_ci_upper | |
---|---|---|---|---|---|---|
0 | 67.564695 | 2.037898 | 63.265107 | 71.864283 | 53.358146 | 81.771244 |
1 | 56.466728 | 2.284487 | 51.646882 | 61.286575 | 42.094168 | 70.839289 |
2 | 71.113678 | 2.182221 | 66.509596 | 75.717761 | 56.812030 | 85.415327 |
3 | 60.015712 | 2.074920 | 55.638014 | 64.393409 | 45.785328 | 74.246095 |
- Relevant sind hier die Konfidenzintervalle für die Mittelwerte
- Für beide Werte von
Alter
ist die untere Vertrauensgrenze für die Belastung im Gewebe der Ratten vom kontaminierten Gelände höher als die obere Vertrauensgrenze für die Ratten vom unkontaminierten Gelände - Zum Signifikanzniveau $\alpha = 0.95$ ist der Unterschied in der Bleibelastung signifikant
Bestimmung des p-Werts¶
- Der p-Wert wird nur für den Unterschies beim Alter 0 ausgegeben.
- Trick: Verlegung des Nullpunkts.
- Im Beispiel verlegen wird den Nullpunkt auf 8 Monate.
- Wir führen in der Tabelle also eine Spalte mit der Altersdifferenz zu 8 Monaten ein
In [8]:
df['Altersdifferenz'] = df.Alter - 8
df.head()
Out[8]:
Alter | Belastung | Gelände | Altersdifferenz | |
---|---|---|---|---|
0 | 10 | 63 | unkontaminiert | 2 |
1 | 12 | 67 | unkontaminiert | 4 |
2 | 6 | 55 | unkontaminiert | -2 |
3 | 6 | 42 | unkontaminiert | -2 |
4 | 11 | 73 | unkontaminiert | 3 |
In [9]:
formel2 = 'Belastung ~ Altersdifferenz + Gelände'
modell2 = smf.ols(formel2, df)
res2 = modell2.fit()
In [10]:
res2.summary()
Out[10]:
Dep. Variable: | Belastung | R-squared: | 0.673 |
---|---|---|---|
Model: | OLS | Adj. R-squared: | 0.635 |
Method: | Least Squares | F-statistic: | 17.52 |
Date: | Sun, 14 Jul 2024 | Prob (F-statistic): | 7.42e-05 |
Time: | 17:41:16 | Log-Likelihood: | -63.935 |
No. Observations: | 20 | AIC: | 133.9 |
Df Residuals: | 17 | BIC: | 136.9 |
Df Model: | 2 | ||
Covariance Type: | nonrobust |
coef | std err | t | P>|t| | [0.025 | 0.975] | |
---|---|---|---|---|---|---|
Intercept | 67.5647 | 2.038 | 33.154 | 0.000 | 63.265 | 71.864 |
Gelände[T.unkontaminiert] | -11.0980 | 3.124 | -3.552 | 0.002 | -17.689 | -4.507 |
Altersdifferenz | 3.5490 | 0.617 | 5.752 | 0.000 | 2.247 | 4.851 |
Omnibus: | 1.119 | Durbin-Watson: | 2.547 |
---|---|---|---|
Prob(Omnibus): | 0.572 | Jarque-Bera (JB): | 0.408 |
Skew: | -0.346 | Prob(JB): | 0.815 |
Kurtosis: | 3.102 | Cond. No. | 6.48 |
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
- Der p-Wert ist 0.002
Regression im exponentiellen Modell¶
Beispiel Covid-Erkrankungen¶
In [11]:
df = pd.read_csv('corona.csv')
df.head()
Out[11]:
Tag (im März) | Anzahl | |
---|---|---|
0 | 3 | 38 |
1 | 4 | 52 |
2 | 5 | 109 |
3 | 6 | 185 |
4 | 7 | 150 |
In [12]:
ax = sns.scatterplot(data=df, x="Tag (im März)", y="Anzahl");
- Das Wachstum war exponentiell
- Es gab aber Schankungen durch unterschiedliche Verzögerungen der Berichte der Gesundheitsämter
Halblogarithmische Darstellung¶
Bei halblogarithmischer Darstellung
- ist die $x$-Achse linear skaliert: Gleiche absolute Zuwächse pro Längeneinheit
- ist die $y$-Achse logarithmisch skaliert: Gleiche relative Zuwächse pro Längeneinheit
- Das bedeutet: Der Logarithmus der Daten wird angezeigt, und die $y$-Achse wird entsprechend unterteilt
- Exponentiell wachsende Daten liegen bei halblogarithmischer Darstellung annäherend auf einer wachsenden Geraden, exponentiell fallende auf einer fallenden Geraden
In [13]:
ax.set_yscale('log')
ax.figure
Out[13]:
Exponentielles Modell vs. Lineare Regression¶
- Lineares Modell: in gleichen Zeitabständen gleiche absolute Zuwächse
- Exponentielles Modell: in gleichen Zeitabständen gleiche relative Zuwächse
- Biologische Wachstums- oder Abklingprozesse verlaufen meistens exponentiell
- Aufgabe der Regression im exponentiellen Modell ist es, bei Wachstumsprozessen die Verdoppelungszeit und bei Abklingprozessen die Halbwertszeit zu bestimmen
- Dies geschieht, indem man die Werte logarithmiert und dann deren lineare Regression berechnet
Regression im exponentiellen Modell¶
- $x$ die Zeit, $z$ Daten, die exponentiell wachsen (bzw. abklingen)
- Modellgleichung für Wachstumsprozess: $$ z = c \cdot e^{m\cdot x} $$
- logarithmierte Modellgleichung $$ y = \ln(z) = \ln(c) + m \cdot x $$
- bestimme diese Gerade durch lineare Regression
- wenn $m < 0$, dann Abklingprozess
In [14]:
df['logAnzahl'] = np.log(df.Anzahl)
df['Tag'] = df['Tag (im März)']
In [15]:
formel = 'logAnzahl ~ Tag'
modell = smf.ols(formel, df)
res = modell.fit()
In [16]:
res.summary()
Out[16]:
Dep. Variable: | logAnzahl | R-squared: | 0.960 |
---|---|---|---|
Model: | OLS | Adj. R-squared: | 0.958 |
Method: | Least Squares | F-statistic: | 458.1 |
Date: | Sun, 14 Jul 2024 | Prob (F-statistic): | 9.25e-15 |
Time: | 17:41:16 | Log-Likelihood: | -2.9636 |
No. Observations: | 21 | AIC: | 9.927 |
Df Residuals: | 19 | BIC: | 12.02 |
Df Model: | 1 | ||
Covariance Type: | nonrobust |
coef | std err | t | P>|t| | [0.025 | 0.975] | |
---|---|---|---|---|---|---|
Intercept | 3.4410 | 0.151 | 22.728 | 0.000 | 3.124 | 3.758 |
Tag | 0.2260 | 0.011 | 21.403 | 0.000 | 0.204 | 0.248 |
Omnibus: | 0.968 | Durbin-Watson: | 1.597 |
---|---|---|---|
Prob(Omnibus): | 0.616 | Jarque-Bera (JB): | 0.816 |
Skew: | -0.438 | Prob(JB): | 0.665 |
Kurtosis: | 2.594 | Cond. No. | 34.1 |
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
- m = 0.226
- b = 3.441
Die Regressionsgerade für die logarithmierten Daten ist $$ y = 0.226 \cdot x + 3.441 $$
In [17]:
tage = np.arange(3, 24)
gerade = 0.226*tage + 3.441
In [18]:
titel = "Die logarithmierten Daten zusammen mit ihrer Regressionsgerade"
ax2 = sns.scatterplot(x=df.Tag, y=df.logAnzahl)
sns.lineplot(x=tage, y=gerade)
ax2.set_title(titel);
In [19]:
titel = "Die exponentierte Regressionskurve zusammen mit den Ausgangsdaten in halblogarithmischer Darstellung"
sns.lineplot(x=tage, y=np.exp(gerade), ax=ax)
ax.set_title(titel)
ax.figure
Out[19]:
In [20]:
titel = "Die exponentierte Regressionskurve zusammen mit den Ausgangsdaten in linearer Darstellung"
ax.set_title(titel)
ax.set_yscale('linear')
ax.figure
Out[20]:
Halbwerts- bzw. Verdoppelungszeit¶
- Modell eines Wachstumsprozesses $$ z = c \cdot e^{m\cdot x} $$
- Verdoppelungszeit $t$ bestimmt durch $$ e^{m\cdot t} = 2 $$
- Also $$ t = \frac{\ln 2}m $$
- Bei Abklingprozessen ist $m < 0$, dann ist $$ t = -\frac{\ln 2}m $$ die Halbwertszeit
Im Beispiel Covid
In [21]:
m = 0.226
In [22]:
t = np.log(2) / m
t
Out[22]:
3.067022922831616
Die Verdoppelungszeit beträgt 3.07 Tage