Mathematik für Biologiestudierende¶
Wintersemester 2025/26
27.01.2026
© 2026 Prof. Dr. Rüdiger W. Braun
Wiederholung (interaktiv)¶
Gehen Sie auf die Website
und geben Sie folgende Zugangsnummer ein
- 670719
oder scannen Sie den QR-Code

Themen¶
- Korrelation
- empirischer Korrelationskoeffizient
- Lineare Modelle
- Interpretation der Ausgabe
- Lineare Modelle mit mehreren erklärenden Variablen
import numpy as np
np.set_printoptions(legacy='1.21')
import seaborn as sns
sns.set_theme()
sns.set_context('talk')
import pandas as pd
from scipy import stats
Korrelation¶
- Eine Korrelation zwischen zwei Datensätzen ist eine gemeinsame oder gegenläufige Tendenz.
- Beispielsweise steigt der Blutdruck tendenziell mit dem Alter.
- Gemessen wird die Korrelation durch den empirischen Korrelationskoeffizienten.
- Der empirischen Korrelationskoeffizient beantwortet die Frage
Gibt es eine Korrelation?
Beispiel für zwei unkorrelierte Größen¶
- formal ist es auch möglich, Regressionsplot für zwei unkorrelierte Größen auszurechnen
zufall = pd.DataFrame()
zufall['Zufall1'] = stats.norm.rvs(size=30)
zufall['Zufall2'] = stats.norm.rvs(size=30)
zufall.head()
| Zufall1 | Zufall2 | |
|---|---|---|
| 0 | 0.164799 | 0.077285 |
| 1 | 1.013398 | 1.406283 |
| 2 | 0.928662 | 1.290372 |
| 3 | -0.384613 | 0.237726 |
| 4 | 0.013443 | 1.244510 |
sns.regplot(zufall, x='Zufall1', y='Zufall2');
Empirischer Korrelationskoeffizient¶
- Kennzahl zur Überprüfung gemeinsamer Tendenz
- $s_x$ sei die Stichprobenstreuung der $x_j$ und $s_y$ die Stichprobenstreuung der $y_j$
- dann ist der empirische Korrelationskoeffizient gleich $$ r = \frac{\text{covar}_{\text{emp}}(x,y)}{s_x \cdot s_y} $$
- Der Korrelationskoeffizient ist dimensionslos
Beispiel "Zufall"¶
zufall.cov()
| Zufall1 | Zufall2 | |
|---|---|---|
| Zufall1 | 0.695244 | 0.095882 |
| Zufall2 | 0.095882 | 0.898639 |
sx = zufall.Zufall1.std()
sx
0.8338131297677042
sy = zufall.Zufall2.std()
sy
0.9479659332898845
covar = zufall.Zufall1.cov(zufall.Zufall2)
covar
0.09588167830193078
r = covar / (sx*sy)
r
0.1213037333236191
Interpretation des empirischen Korrelationskoeffizienten¶
Der Korrelationskoeffizient zeigt an, ob zwei Datensätze eine gemeinsame Tendenz aufweisen
- wenn er nahe bei $1$ liegt, dann wachsen $x$ und $y$ gemeinsam (gemeinsame Tendenz)
- wenn er nahe bei $-1$ liegt, dann fällt $y$, wenn $x$ wächst (gegenläufige Tendenz)
- wenn er nahe bei $0$ liegt, dann gibt es kein gemeinsames Verhalten
- auch ein negativer Korrelationskoeffizient hat eine Bedeutung
- Beispiel: Je weniger Pestizide ich im Garten ausbringe, desto mehr Bienen habe ich
Berechnung mit pandas¶
zufall.corr()
| Zufall1 | Zufall2 | |
|---|---|---|
| Zufall1 | 1.000000 | 0.121304 |
| Zufall2 | 0.121304 | 1.000000 |
Beispiel: Blutdruckdaten¶
Wir hatten in der letzten Woche die Kovarianzen für die Blutdruckdaten bestimmt
blutdruck = pd.read_csv('blutdruckdaten.csv')
blutdruck.cov()
| Alter | Blutdruck | Größe | |
|---|---|---|---|
| Alter | 231.131034 | 348.572414 | 36.128966 |
| Blutdruck | 348.572414 | 750.271264 | 69.805057 |
| Größe | 36.128966 | 69.805057 | 28.617195 |
Jetzt bestimmen wir die Korrelationskoeffizienten
blutdruck.corr()
| Alter | Blutdruck | Größe | |
|---|---|---|---|
| Alter | 1.000000 | 0.837056 | 0.444235 |
| Blutdruck | 0.837056 | 1.000000 | 0.476392 |
| Größe | 0.444235 | 0.476392 | 1.000000 |
- Alter und Blutdruck sind korreliert (aber nicht stark)
- die anderen Größen sind nicht korreliert
Beispielgraph mit sehr guter Korrelation¶
df1 = pd.DataFrame()
P = stats.norm(0.005, 0.005)
stoerung = P.rvs(size=30) # ganz kleine Störung
df1['Länge'] = np.arange(30)
df1['Breite'] = 5 - 0.002*df1.Länge + stoerung
df1.head()
| Länge | Breite | |
|---|---|---|
| 0 | 0 | 5.003245 |
| 1 | 1 | 4.996957 |
| 2 | 2 | 5.000589 |
| 3 | 3 | 5.000714 |
| 4 | 4 | 4.986621 |
sns.regplot(df1, x='Länge', y='Breite');
df1.corr()
| Länge | Breite | |
|---|---|---|
| Länge | 1.00000 | -0.94136 |
| Breite | -0.94136 | 1.00000 |
Regression zum Mittelwert¶
- Der Begriff Regression kommt von Francis Galton, einem Neffen von Charles Darwin
- Er hatte den auf der nächsten Folie gezeigten Datensatz analysiert
- Auf der $x$-Achse stehen die Größen der Väter in Zoll
- Auf der $y$-Achse stehen die Größen der Söhne in Zoll
galton = pd.read_csv('galton.csv')
galton.head()
| family | father | mother | midparentHeight | children | childNum | gender | childHeight | |
|---|---|---|---|---|---|---|---|---|
| 0 | 001 | 78.5 | 67.0 | 75.43 | 4 | 1 | male | 73.2 |
| 1 | 002 | 75.5 | 66.5 | 73.66 | 4 | 1 | male | 73.5 |
| 2 | 002 | 75.5 | 66.5 | 73.66 | 4 | 2 | male | 72.5 |
| 3 | 003 | 75.0 | 64.0 | 72.06 | 2 | 1 | male | 71.0 |
| 4 | 004 | 75.0 | 64.0 | 72.06 | 5 | 1 | male | 70.5 |
- Aufbereitung eines Datensatzes von Galton. Die Aufbereitung stammt aus den Begleitdaten zum Buch "Linear Models with Python" von Faraway
sns.regplot(galton, x='father', y='childHeight');
Die Steigung dieser Geraden ist positiv, aber deutlich kleiner als 1
m = galton.father.cov(galton.childHeight) / galton.father.var()
m
0.44652260468787525
Regression zum Mittelwert: Interpretation¶
- Die Söhne ungewöhnlich großer oder kleiner Väter sind im Mittel selbst zwar auch größer bzw. kleiner als der Mittelwert, aber diese Differenz ist kleiner als bei den Vätern
- Galton bezeichnet dies (ziemlich unfreundlich) als "Regression to mediocrity"
- Das gilt aber nur für die Individuen, nicht für die Population als Ganzes
- auch in der nächsten Generation gibt es wieder ungewöhnlich große Individuen, aber in anderen Familien
Korrelation ≠ Kausalität¶
- Wenn der Korrelationskoeffizient von $x$ und $y$ nahe $0$ liegt, dann gibt es keinen kausalen Zusammenhang zwischen ihnen (seltene nichtlineare Pänomene mal ausgenommen)
- Man kann aber im umgekehrten Fall von einem Korrelationskoeffizienten nahe bei $1$ nicht auf einen kausalen Zusammenhang schließen
- Zum Beispiel nimmt seit Jahrzehnten in Deutschland sowohl die Zahl der Geburten als auch die Zahl der Störche ab
- Der kausale Zusammenhang ist aber umstritten
- Beispiel aus der Schlafforschung: Mittagsschlafdauern über 90 Minuten sind ungesund

Quelle: http://xkcd.com/552
Beispiel: Bleibelastung im Gewebe von Ratten¶
- 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
ratten = pd.read_csv('ratten.csv')
ratten.head()
| Alter | Belastung | Gelände | |
|---|---|---|---|
| 0 | 10 | 63 | unkontaminiert |
| 1 | 12 | 67 | unkontaminiert |
| 2 | 6 | 55 | unkontaminiert |
| 3 | 6 | 42 | unkontaminiert |
| 4 | 11 | 73 | unkontaminiert |
kon = ratten[ratten.Gelände=='kontaminiert']
unk = ratten[ratten.Gelände=='unkontaminiert']
kon.describe()
| Alter | Belastung | |
|---|---|---|
| count | 10.000000 | 10.000000 |
| mean | 7.700000 | 66.500000 |
| std | 2.451757 | 10.384283 |
| min | 4.000000 | 50.000000 |
| 25% | 6.250000 | 61.000000 |
| 50% | 8.000000 | 66.000000 |
| 75% | 9.750000 | 75.250000 |
| max | 11.000000 | 81.000000 |
unk.describe()
| Alter | Belastung | |
|---|---|---|
| count | 10.000000 | 10.000000 |
| mean | 9.700000 | 62.500000 |
| std | 2.451757 | 11.017663 |
| min | 6.000000 | 42.000000 |
| 25% | 8.250000 | 55.750000 |
| 50% | 10.000000 | 65.000000 |
| 75% | 11.750000 | 72.000000 |
| max | 13.000000 | 75.000000 |
- Es gibt einen Unterschied in der Bleibelastung
- aber auch eine große Stichprobenstreuung
stats.ttest_ind(unk.Belastung, kon.Belastung, alternative='less')
TtestResult(statistic=-0.8354714854531734, pvalue=0.20720251637482168, df=18.0)
- Der Unterschied ist $\alpha = 0.05$ nicht signifikant.
- Es fällt aber auf, dass die Ratten von dem belasteten Gebiet im Mittel jünger als die anderen sind.
- Wir wollen das Alter herausrechnen
- Steigt die Bleibelastung mit dem Alter?
kon.corr(numeric_only=True) # ohne die Option gibt es einen ValueEror
| Alter | Belastung | |
|---|---|---|
| Alter | 1.000000 | 0.796465 |
| Belastung | 0.796465 | 1.000000 |
unk.corr(numeric_only=True)
| Alter | Belastung | |
|---|---|---|
| Alter | 1.00000 | 0.82883 |
| Belastung | 0.82883 | 1.00000 |
Wir zeigen beide Regressionen in einem Bild
sns.lmplot(ratten, x='Alter', y='Belastung', hue='Gelände');
- die Gerade zu den Daten des kontaminierten Geländes liegt klar oberhalb der Geraden des unkontaminierten Geländes
- für 8 Monate alte Ratten sind dir Konfidenzintervalle disjunkt
sns.lmplotvereint mehrere regplots, ähnlich wie dassns.displottut- es hat auch ähnliche Optionen
Lineare Modelle¶
- eine lineare Funktion einer Variablen ist eine Funktion der Form $$ y = m \cdot x + b $$
- bei der linearen Regression besteht die Aufgabe darin, $m$ und $b$ zu bestimmen
Das Konzept des linearen Modells erweitert dieses Verfahren in doppelter Hinsicht
- Konfidenzintervalle für $m$ und $b$ werden bestimmt
- die Zielvariable $y$ kann von mehr als einer Größe abhängen
- Literatur: "Linear Models with Python" von Faraway
- Statsmodels: https://www.statsmodels.org/stable/user-guide.html
Wir beginnen mit den Blutdruckdaten
sns.regplot(blutdruck, x='Alter', y='Blutdruck');
Formulierung des Modells¶
import statsmodels.formula.api as smf
formel = 'Blutdruck ~ Alter'
Das bedeutet:
- wir wollen den Blutdruck modellieren
- der Blutdruck ist die abhängige Variable (engl. dependent)
- das Alter ist die erklärende Variable
modell = smf.ols(formel, blutdruck)
ols: ordinary least squares- Lektion 25: die Regression ist "bestmöglich" in dem Sinn, dass $$ \sum_{j=1}^n (m \cdot x_j + b - y_j)^2 $$ minimal wird
- daher der Name "Methode der kleinsten Quadrate" (engl. "lest squares")
res = modell.fit()
Interpretation der Ausgabe¶
res.summary()
| Dep. Variable: | Blutdruck | R-squared: | 0.701 |
|---|---|---|---|
| Model: | OLS | Adj. R-squared: | 0.690 |
| Method: | Least Squares | F-statistic: | 65.54 |
| Date: | Tue, 03 Feb 2026 | Prob (F-statistic): | 8.17e-09 |
| Time: | 10:16:02 | Log-Likelihood: | -123.27 |
| No. Observations: | 30 | AIC: | 250.5 |
| Df Residuals: | 28 | BIC: | 253.3 |
| Df Model: | 1 | ||
| Covariance Type: | nonrobust |
| coef | std err | t | P>|t| | [0.025 | 0.975] | |
|---|---|---|---|---|---|---|
| Intercept | 80.3697 | 8.798 | 9.135 | 0.000 | 62.348 | 98.391 |
| Alter | 1.5081 | 0.186 | 8.096 | 0.000 | 1.127 | 1.890 |
| Omnibus: | 2.886 | Durbin-Watson: | 2.401 |
|---|---|---|---|
| Prob(Omnibus): | 0.236 | Jarque-Bera (JB): | 1.526 |
| Skew: | 0.390 | Prob(JB): | 0.466 |
| Kurtosis: | 3.782 | Cond. No. | 149. |
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
- Ich werde die wichtigsten Daten aus dieser Ausgabe erkären
- in der ersten Zeile steht der Name der abhängigen Variablen
zum Vergleich: wir hatten in Lektion 25 die lineare Regression zu Fuß gerechnet und für die Steigung den folgenden Wert erhalten:
cov = blutdruck.Alter.cov(blutdruck.Blutdruck)
var_x = blutdruck.Alter.var()
m = cov / var_x
np.round(m, 4)
1.5081
- Das ist genau die Zahl, die in der Spalte
coefder ZeileAltersteht
- Der Wert für den Ordinatenabschnitt (engl: "intercept") war damals
xq = blutdruck.Alter.mean()
yq = blutdruck.Blutdruck.mean()
b = yq - m*xq
np.round(b, 4)
80.3697
- Das ist die Zahl, die in der Spalte
coefund der ZeileInterceptsteht
Wir schauen uns die Zeile Alter weiter an:
- Der Eintrag
P>|t|bezeichnet den p-Wert für den zweiseitigen Test, dasscoefungleich 0 ist. - In der Zeile "Alter" ist
coefist die Steigung der linearen Regression, also das $m$
- wenn die Nullhypothese $H_0=\{m=0\}$ nicht abgelehnt werden kann, dann bedeutet das, dass zum Signifikanzniveau $\alpha=0.05$ nicht nachgewiesen wurde, dass das Alter überhaupt einen Einfluss auf den Blutdruck hat
- Der Eintrag
tist der Wert der Teststatistik, aus dem der p-Wert bestimmt worden ist
Konfidenzintervalle für die Koeffizienten¶
res.summary()
| Dep. Variable: | Blutdruck | R-squared: | 0.701 |
|---|---|---|---|
| Model: | OLS | Adj. R-squared: | 0.690 |
| Method: | Least Squares | F-statistic: | 65.54 |
| Date: | Tue, 03 Feb 2026 | Prob (F-statistic): | 8.17e-09 |
| Time: | 10:16:02 | Log-Likelihood: | -123.27 |
| No. Observations: | 30 | AIC: | 250.5 |
| Df Residuals: | 28 | BIC: | 253.3 |
| Df Model: | 1 | ||
| Covariance Type: | nonrobust |
| coef | std err | t | P>|t| | [0.025 | 0.975] | |
|---|---|---|---|---|---|---|
| Intercept | 80.3697 | 8.798 | 9.135 | 0.000 | 62.348 | 98.391 |
| Alter | 1.5081 | 0.186 | 8.096 | 0.000 | 1.127 | 1.890 |
| Omnibus: | 2.886 | Durbin-Watson: | 2.401 |
|---|---|---|---|
| Prob(Omnibus): | 0.236 | Jarque-Bera (JB): | 1.526 |
| Skew: | 0.390 | Prob(JB): | 0.466 |
| Kurtosis: | 3.782 | Cond. No. | 149. |
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
- Die Einträge
[0.025und0.975]geben die untere und die obere Vertrauensgrenze des Konfidenzintervalls zum Konfidenzniveau 0.95 für die Steigung an
- Variante: 99%-Konfidenzintervall
- Achtung: Für Konfidenzintervall zum Konfidenzniveau $1-\alpha$ muss $\alpha$ eingegeben werden
res.conf_int(alpha=.01)
| 0 | 1 | |
|---|---|---|
| Intercept | 56.058844 | 104.680629 |
| Alter | 0.993358 | 2.022874 |
- Der Wert für $m$ in der Formel für die lineare Regression liegt mit 99% Sicherheit zwischen 0.993 und 2.02
Korrelationskoeffizienten¶
In Lektion 25 hatten wir den Korrelationskoeffizienten bestimmt
r = 0.83705
np.round(r**2, 3)
0.701
res.summary()
| Dep. Variable: | Blutdruck | R-squared: | 0.701 |
|---|---|---|---|
| Model: | OLS | Adj. R-squared: | 0.690 |
| Method: | Least Squares | F-statistic: | 65.54 |
| Date: | Tue, 03 Feb 2026 | Prob (F-statistic): | 8.17e-09 |
| Time: | 10:16:02 | Log-Likelihood: | -123.27 |
| No. Observations: | 30 | AIC: | 250.5 |
| Df Residuals: | 28 | BIC: | 253.3 |
| Df Model: | 1 | ||
| Covariance Type: | nonrobust |
| coef | std err | t | P>|t| | [0.025 | 0.975] | |
|---|---|---|---|---|---|---|
| Intercept | 80.3697 | 8.798 | 9.135 | 0.000 | 62.348 | 98.391 |
| Alter | 1.5081 | 0.186 | 8.096 | 0.000 | 1.127 | 1.890 |
| Omnibus: | 2.886 | Durbin-Watson: | 2.401 |
|---|---|---|---|
| Prob(Omnibus): | 0.236 | Jarque-Bera (JB): | 1.526 |
| Skew: | 0.390 | Prob(JB): | 0.466 |
| Kurtosis: | 3.782 | Cond. No. | 149. |
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
- $r^2$ ist die Größe, die in
res.summary()alsR-squaredauftaucht
Mehrere erklärende Variablen¶
Lineares Modell mit einer abhängigen und mehreren erklärenden Variablen¶
$$ y = m_1 \cdot x_1 + m_2 \cdot x_2 + \dots + m_n \cdot x_n + b $$
- $y$ ist die abhängige und die $x_i$ sind die erklärenden Variablen
- $b$ ist das
Intercept - $m_i$ sind die Steigungen
Beispiel: Körpergröße der Söhne hängt von der Körpergröße von Vater und Mutter ab
formel = 'childHeight ~ father + mother'
Diese Formel hat 3 Unbekannte:
- den Koeffizienten von
father - den Koeffizienten von
mother - den Ordinatenabschnitt
modell = smf.ols(formel, galton)
res = modell.fit()
res.summary()
| Dep. Variable: | childHeight | R-squared: | 0.238 |
|---|---|---|---|
| Model: | OLS | Adj. R-squared: | 0.235 |
| Method: | Least Squares | F-statistic: | 74.62 |
| Date: | Tue, 03 Feb 2026 | Prob (F-statistic): | 6.25e-29 |
| Time: | 10:16:02 | Log-Likelihood: | -1080.7 |
| No. Observations: | 481 | AIC: | 2167. |
| Df Residuals: | 478 | BIC: | 2180. |
| Df Model: | 2 | ||
| Covariance Type: | nonrobust |
| coef | std err | t | P>|t| | [0.025 | 0.975] | |
|---|---|---|---|---|---|---|
| Intercept | 19.3128 | 4.095 | 4.716 | 0.000 | 11.266 | 27.359 |
| father | 0.4176 | 0.046 | 9.154 | 0.000 | 0.328 | 0.507 |
| mother | 0.3288 | 0.045 | 7.258 | 0.000 | 0.240 | 0.418 |
| Omnibus: | 10.653 | Durbin-Watson: | 1.592 |
|---|---|---|---|
| Prob(Omnibus): | 0.005 | Jarque-Bera (JB): | 14.542 |
| Skew: | -0.200 | Prob(JB): | 0.000695 |
| Kurtosis: | 3.752 | Cond. No. | 3.69e+03 |
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 3.69e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
- Regressiongleichung: childHeight = 0.4176 * father + 0.3288 * mother + 19.3128
- alle drei Koeffizienten haben statistisch signifikanten Einfluss
- Der Wert für $r^2$ beträgt 0.238
- Für das Modell, bei dem die Größe des Kindes nur über die Größe des Vaters modelliert wird, beträgt der Wert von $r^2$ nur 0.154
- In dem Modell, welches die Körpergrößen beider Eltern berücksichtigt, ist die Korrelation höher
- Das Modell erklärt die erklärende Variable besser
Beispiel: Hinzufügung einer Variablen ohne Einfluss¶
galton['Kontonummer'] = stats.randint(1, 999999).rvs(size=481)
formel = 'childHeight ~ father + mother + Kontonummer'
modell = smf.ols(formel, galton)
res = modell.fit()
res.summary()
| Dep. Variable: | childHeight | R-squared: | 0.240 |
|---|---|---|---|
| Model: | OLS | Adj. R-squared: | 0.235 |
| Method: | Least Squares | F-statistic: | 50.14 |
| Date: | Tue, 03 Feb 2026 | Prob (F-statistic): | 3.50e-28 |
| Time: | 10:16:02 | Log-Likelihood: | -1080.1 |
| No. Observations: | 481 | AIC: | 2168. |
| Df Residuals: | 477 | BIC: | 2185. |
| Df Model: | 3 | ||
| Covariance Type: | nonrobust |
| coef | std err | t | P>|t| | [0.025 | 0.975] | |
|---|---|---|---|---|---|---|
| Intercept | 19.4669 | 4.097 | 4.751 | 0.000 | 11.416 | 27.517 |
| father | 0.4169 | 0.046 | 9.141 | 0.000 | 0.327 | 0.507 |
| mother | 0.3301 | 0.045 | 7.286 | 0.000 | 0.241 | 0.419 |
| Kontonummer | -3.837e-07 | 3.61e-07 | -1.063 | 0.288 | -1.09e-06 | 3.25e-07 |
| Omnibus: | 9.718 | Durbin-Watson: | 1.590 |
|---|---|---|---|
| Prob(Omnibus): | 0.008 | Jarque-Bera (JB): | 13.120 |
| Skew: | -0.183 | Prob(JB): | 0.00142 |
| Kurtosis: | 3.721 | Cond. No. | 2.31e+07 |
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 2.31e+07. This might indicate that there are
strong multicollinearity or other numerical problems.
- Die Kontonummer hat keinen signifikanten Einfluss
- Das erkennt man auch daran, dass 0 im Konfidenzintervall liegt