Mathematik für Biologiestudierende II¶

Sommersemester 2024

09.07.2024

© 2024 Prof. Dr. Rüdiger W. Braun

Themen heute¶

  • Elektrophorese als Beispiel für Regression im exponentiellen Modell
  • logistische Regression
  • graphische logistische Regression
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')

Regression im exponentiellen Modell¶

Beispiel Elektrophorese¶

Elektrophoreseapparatur¶

Elektrophoreseapparatur

© Prof. Dr. Schmitt-Wrede, HHU Düsseldorf

Proteinanalyse durch Elektrophorese¶

  • Die Molekülmasse eines Proteins wird bestimmt, indem man seinen Laufweg in einem Gel misst, an welches eine Spannung angelegt wird.
  • Dazu muss das Protein zuerst aufbereitet werden; dieser Aspekt ist Thema von Biologie 110.
  • Das aufbereitete Protein wird zusammen mit sechs Referenzproteinen bekannter Massenzahl und einem Farbstoff in der Elektrophoreseapparatur einer Spannungsdifferenz ausgesetzt. Die Spannung wird abgeschaltet, sobald der Farbstoff die Apparatur durchlaufen hat.

Laufwege¶

Laufwege im Gel

© Prof. Dr. Schmitt-Wrede, HHU Düsseldorf

  • Die linke Spur zeigt zuunterst die Lauffront des Farbmarkers und darüber die Lauffronten der Referenzproteine.
  • Die Zahlen bedeuten jeweils die Molekülmassen der Referenzproteine in Dalton sowie ihren relativen Laufweg.
  • Die rechte Spur stammt von einem bakteriellen Proteinextrakt. Bestimmt werden soll die Molekülmasse des mit * gekennzeichnete Bestandteils.
  • Ein Dalton ist das Gewicht eines Nukleons.
  • Der Laufweg ist so normiert, dass der Laufweg des Farbmarkers die Länge 1 hat. Der kürzeste Laufweg ist oben.
  • Es besteht eine lineare Beziehung zwischen dem Logarithmus der Molekülmasse und der Laufstrecke des Proteins.
  • Zum Eichen werden die Referenzpunkte auf halblogarithmisches Papier aufgetragen.
In [2]:
df = pd.DataFrame()
df['Laufweg'] = [0.11, .25, .38, .48, .61, .82]
df['Molekülmasse_in_kD'] = [70., 55, 40, 35, 25, 15]
ax = sns.scatterplot(df, x='Laufweg', y='Molekülmasse_in_kD')
ax.set_yscale('log')
No description has been provided for this image
  • Wir bestimmen die Eichkurve durch Regression im exponentiellen Modell
  • Dies geschieht zeichnerisch, indem man auf halblogarithmischem Papier die beste Gerade nach Augenschein bestimmt
  • oder rechnerisch, indem man die lineare Regressionsgerade zu den Logarithmen der Molekülmassen berechnet. Welchen Logarithmus man hier wählt, ist unerheblich. Wir entscheiden uns für den Zehnerlogarithmus.
In [3]:
df['lg'] = np.log10(df.Molekülmasse_in_kD)
formel = 'lg ~ Laufweg'
modell = smf.ols(formel, df)
res = modell.fit()
In [4]:
res.summary()
/3tb/git/bio/WS2324/internet/.pixi/envs/default/lib/python3.12/site-packages/statsmodels/stats/stattools.py:74: ValueWarning: omni_normtest is not valid with less than 8 observations; 6 samples were given.
  warn("omni_normtest is not valid with less than 8 observations; %i "
Out[4]:
OLS Regression Results
Dep. Variable: lg R-squared: 0.994
Model: OLS Adj. R-squared: 0.993
Method: Least Squares F-statistic: 680.9
Date: Tue, 21 Jan 2025 Prob (F-statistic): 1.28e-05
Time: 10:57:21 Log-Likelihood: 16.015
No. Observations: 6 AIC: -28.03
Df Residuals: 4 BIC: -28.45
Df Model: 1
Covariance Type: nonrobust
coef std err t P>|t| [0.025 0.975]
Intercept 1.9672 0.018 109.160 0.000 1.917 2.017
Laufweg -0.9424 0.036 -26.095 0.000 -1.043 -0.842
Omnibus: nan Durbin-Watson: 2.035
Prob(Omnibus): nan Jarque-Bera (JB): 0.447
Skew: 0.466 Prob(JB): 0.800
Kurtosis: 2.041 Cond. No. 5.19


Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
In [5]:
m = -0.9424
b = 1.9672

Die so bestimmte Regressionskurve ist $$ y = 10^{-0.942 \cdot x + 1.97} $$

In [6]:
x = np.linspace(0.1, 0.82, 50)
regrKurve = 10**(m*x + b)
In [7]:
sns.lineplot(x=x, y=regrKurve, ax=ax)
ax.figure
Out[7]:
No description has been provided for this image
  • Bisher haben wir nur unsere Apperatur geeicht. Jetzt malen wir noch den Punkt hinein.
  • Der beobachtete Laufweg beträgt 0.42
In [8]:
lweg = 0.42
masse = 10**(m*lweg+b)
masse    # Masse in kD
Out[8]:
37.27279837239035

Das unbekannte Protein hat eine Molekularmasse von 37300 Dalton.

In [9]:
sns.scatterplot(x=[lweg], y=[masse], ax=ax, color='red')
ax.figure
Out[9]:
No description has been provided for this image

Logistische Regression¶

  • Wenn die erklärte Variable nur die Werte 0 und 1 annehmen kann, kann eine logistische Regression durchgeführt werden
In [10]:
df = sns.load_dataset('titanic')
df.head()
Out[10]:
survived pclass sex age sibsp parch fare embarked class who adult_male deck embark_town alive alone
0 0 3 male 22.0 1 0 7.2500 S Third man True NaN Southampton no False
1 1 1 female 38.0 1 0 71.2833 C First woman False C Cherbourg yes False
2 1 3 female 26.0 0 0 7.9250 S Third woman False NaN Southampton yes True
3 1 1 female 35.0 1 0 53.1000 S First woman False C Southampton yes False
4 0 3 male 35.0 0 0 8.0500 S Third man True NaN Southampton no True
In [11]:
formula = "survived ~ sex + age + embark_town + C(pclass)"
In [12]:
modell = smf.logit(formula, df)
res = modell.fit()
Optimization terminated successfully.
         Current function value: 0.451318
         Iterations 6
In [13]:
res.summary()
Out[13]:
Logit Regression Results
Dep. Variable: survived No. Observations: 712
Model: Logit Df Residuals: 705
Method: MLE Df Model: 6
Date: Tue, 21 Jan 2025 Pseudo R-squ.: 0.3312
Time: 10:57:21 Log-Likelihood: -321.34
converged: True LL-Null: -480.45
Covariance Type: nonrobust LLR p-value: 1.013e-65
coef std err z P>|z| [0.025 0.975]
Intercept 4.0368 0.431 9.371 0.000 3.193 4.881
sex[T.male] -2.5158 0.209 -12.020 0.000 -2.926 -2.106
embark_town[T.Queenstown] -0.8142 0.568 -1.434 0.152 -1.927 0.299
embark_town[T.Southampton] -0.4937 0.267 -1.850 0.064 -1.017 0.029
C(pclass)[T.2] -1.1446 0.291 -3.938 0.000 -1.714 -0.575
C(pclass)[T.3] -2.4096 0.291 -8.275 0.000 -2.980 -1.839
age -0.0361 0.008 -4.677 0.000 -0.051 -0.021
In [14]:
anfrage = pd.DataFrame()
anfrage['sex'] = ['male', 'male', 'female']
anfrage['embark_town'] = ['Southampton', 'Southampton', 'Southampton']
anfrage['age'] = [35, 45, 45]
anfrage['pclass'] = [1,2,3]
anfrage
Out[14]:
sex embark_town age pclass
0 male Southampton 35 1
1 male Southampton 45 2
2 female Southampton 45 3
In [15]:
res.get_prediction(anfrage).summary_frame()
Out[15]:
predicted se ci_lower ci_upper
0 0.441399 0.054207 0.339307 0.548697
1 0.149196 0.030443 0.098769 0.219110
2 0.379875 0.059188 0.272391 0.500592

Beispiel Klausurergebnis und Übungspunkte¶

  • Die Zielvariable ist ein Klausurergebnis: bestanden ja (=0) und nein (=1)
  • Die Zielvariable ist kategoriell
  • muss aber als 0 und 1 kodiert sein
  • Erklärende Variablen können quantitativ oder kategoriell sein
  • im Beispiel: In die Klausur eingebrachte Übungspunkte ksp
  • quantitativ von 0 bis 6
In [16]:
df = pd.read_csv('bsp_logit.csv')
df.head()
Out[16]:
bestanden ksp
0 0 6.0
1 1 6.0
2 1 6.0
3 1 5.0
4 1 6.0
In [17]:
formel = "bestanden ~ ksp"
modell = smf.logit(formel, df)
res = modell.fit()
Optimization terminated successfully.
         Current function value: 0.513057
         Iterations 5
In [18]:
res.summary()
Out[18]:
Logit Regression Results
Dep. Variable: bestanden No. Observations: 205
Model: Logit Df Residuals: 203
Method: MLE Df Model: 1
Date: Tue, 21 Jan 2025 Pseudo R-squ.: 0.03635
Time: 10:57:21 Log-Likelihood: -105.18
converged: True LL-Null: -109.14
Covariance Type: nonrobust LLR p-value: 0.004851
coef std err z P>|z| [0.025 0.975]
Intercept -0.1671 0.509 -0.328 0.743 -1.164 0.830
ksp 0.2791 0.098 2.861 0.004 0.088 0.470
  • Der Einfluss der Übungspunkte auf das Klausurergebnis ist hochsignifikant
In [19]:
anfrage = pd.DataFrame()
anfrage['ksp'] = np.linspace(0, 6, 50)
sns.lineplot(x=anfrage.ksp, y=res.get_prediction(anfrage).summary_frame()['predicted']);
No description has been provided for this image

Wir sehen nur einen kleinen Ausschnitt aus der logistischen Kurve. Wir ergänzen den Datenbereich der erklärenden Daten um unsinnige Werte, um die Gestalt der logistische Kurve zu zeigen

In [20]:
anfrage = pd.DataFrame()
anfrage['ksp'] = np.linspace(-20, 25, 150)
sns.lineplot(x=anfrage.ksp, y=res.get_prediction(anfrage).summary_frame()['predicted']);
No description has been provided for this image
  • Die logistische Kurve ist $$ y = \frac1{1+e^{-b - m \cdot x}} $$
  • Logistische Regression findet die optimale Annäherung an die Datenpunkte durch eine logistische Kurve

jitter: Verwackeln der Datenpunkte, damit sich mehrere Punkte beim scatterplot nicht gegenseitig verdecken

In [21]:
sns.regplot(df, x='ksp', y='bestanden', logistic=True, y_jitter=0.08, x_jitter=0.2);
No description has been provided for this image

Nächste Woche Probeklausur¶

  • am Sonntag Abend werden auf https://www.math.uni-duesseldorf.de/~internet/bio2324 Aufgaben veröffentlicht
  • lösen Sie sie zuhause
  • am 16.07.2024 bespreche ich die Lösungen
  • bereiten Sie sich darauf vor, Fragen zu stellen
  • ob Sie jetzt schon alles gekonnt hätten, ist zu diesem Zeitpunkt nicht so wichtig