Mathematik für Biologiestudierende II¶
Sommersemester 2024
23.04.2024
© 2024 Prof. Dr. Rüdiger W. Braun
In [1]:
import numpy as np
import pandas as pd
from scipy import stats
import seaborn as sns
sns.set_theme()
Data Snooping¶
- "Snooping" = "Schnüffeln"
- Data Snooping bedeutet, dass man den Test für dieselben Daten rechnet, die man auch für die Formulierung der Hypothese benutzt hat
- Jemand stellt fest, dass in einer Stadt von 50 Neugeborenen 35 weiblich sind.
- Wir machen den entsprechenden Binomialtest
In [2]:
stats.binomtest(35, 50)
Out[2]:
BinomTestResult(k=35, n=50, alternative='two-sided', statistic=0.7, pvalue=0.006600447966810918)
- Die Nullhypothese, dass die Wahrscheinlichkeiten von Jungs- und Mädchengeburten gleich sind, kann abgelehnt werden. Der $p$-Wert beträgt $0.0066$
- Was bedeutet das?
Szenario 1¶
- Theorie: Bekanntlich werden die Babies von den Weißstörchen gebracht. Eine neue Theorie besagt, dass Schwarzstörche das zwar auch tun, aber nicht im korrekten Geschlechterverhältnis.
- Vorgehen: Die Forscher wählen daher einen Ort mit einer großen Population an Schwarzstörchen aus und untersuchen dort das Verhältnis von Mädchen- zu Jungsgeburten.
- Bewertung: Wenn dort das Zahlenverhältnis 35:15 beträgt, ist die Theorie zum Signifikanzniveau $p = 0.0066$ bestätigt.
Szenario 2¶
- Theorie: Keine. Man will bloss mal gucken.
- Vorgehen: In 100 Gemeinden mit mehr als 50 Geburten wird das Verhältnis zwischen Mädchen- und Jungsgeburten untersucht. Tatsächlich findet sich eine Gemeinde mit dem Zahlenverhältnis 35:15
- Bewertung: Das ist Data Snooping, weil die Hypothese aus denselben Daten generiert worden ist, mit denen anschließend der Test gerechnet wird.
ANOVA¶
- ANOVA: Analysis of Variance
- Ziel: Vergleich bei Vorliegen von mehr als zwei Gruppen
Welche Daten hat man?
- Eine Zielvariable. Das ist die kontinuierliche Größe, die gemessen wird.
- Ein oder zwei Faktoren. Das sind kategorielle (also qualitative oder diskrete quantitative) Größen, von denen man nachweisen will, dass sie die Zielvariable beeinflussen
Beispiel Schadstoffkonzentration¶
- An fünf verschiedenen Messstellen wurde die Konzentration eines Schadstoffs gemessen
- Hat die Messstelle einen Einfluss auf die Konzentration?
- Die Messstelle ist der Faktor
- Die Konzentration ist die Zielvariable
- Wir haben also nur einen Faktor: Einfaktorielle ANOVA
In [3]:
u_schad = "https://www.math.uni-duesseldorf.de/~braun/bio2324/data/schadstoffe.csv"
df = pd.read_csv(u_schad, index_col=0)
df
Out[3]:
Messstelle | Konzentration | |
---|---|---|
0 | 5 | 0.000867 |
1 | 3 | 0.000490 |
2 | 1 | 0.000589 |
3 | 1 | 0.000950 |
4 | 4 | 0.001152 |
... | ... | ... |
75 | 5 | 0.000918 |
76 | 3 | 0.000528 |
77 | 3 | 0.000961 |
78 | 4 | 0.001272 |
79 | 3 | 0.001012 |
80 rows × 2 columns
In [4]:
df.Messstelle.value_counts()
Out[4]:
Messstelle 4 19 1 17 3 16 5 14 2 14 Name: count, dtype: int64
- Der Faktor nimmt 5 Werte an: Wir haben 5 Gruppen
- wir müssen sie mit
pandas
trennen
In [5]:
g1 = df[df.Messstelle==1].Konzentration
g1
Out[5]:
2 0.000589 3 0.000950 13 0.001301 14 0.001605 18 0.000927 22 0.001250 28 0.000965 33 0.000669 41 0.000712 42 0.001019 45 0.000780 54 0.001306 61 0.001006 64 0.001057 65 0.000381 70 0.000919 74 0.001323 Name: Konzentration, dtype: float64
In [6]:
g2 = df[df.Messstelle==2].Konzentration
g3 = df[df.Messstelle==3].Konzentration
g4 = df[df.Messstelle==4].Konzentration
g5 = df[df.Messstelle==5].Konzentration
In [7]:
res = stats.f_oneway(g1, g2, g3, g4, g5)
res
Out[7]:
F_onewayResult(statistic=0.8666121588849811, pvalue=0.48807057520065544)
- Der p-Wert ist 0.5
- Die Messstelle hat keinen Einfluss auf die Konzentration
Welche Verteilung benutzt dieser Test?
- Die F-Verteilung dient zum Vergleich zweier Varianzen
- Sie hat zwei Parameter:
- bei der einfaktoriellen ANOVA ist der erste Parameter gleich $g-1$, wenn $g$ die Anzahl der Gruppen ist
- und der zweite ist $n-g$, wenn $n$ der Stichprobenumfang ist
- Im Beispiel: $g=5$, $n=80$
In [8]:
P = stats.f(4, 75)
1 - P.cdf(res.statistic)
Out[8]:
0.48807057520065544
Zum Vergleich
In [9]:
res.pvalue
Out[9]:
0.48807057520065544
Haben unterschiedliche Pinguinarten unterschiedliche Schnabellängen?¶
In [10]:
df = sns.load_dataset("penguins")
df.head()
Out[10]:
species | island | bill_length_mm | bill_depth_mm | flipper_length_mm | body_mass_g | sex | |
---|---|---|---|---|---|---|---|
0 | Adelie | Torgersen | 39.1 | 18.7 | 181.0 | 3750.0 | Male |
1 | Adelie | Torgersen | 39.5 | 17.4 | 186.0 | 3800.0 | Female |
2 | Adelie | Torgersen | 40.3 | 18.0 | 195.0 | 3250.0 | Female |
3 | Adelie | Torgersen | NaN | NaN | NaN | NaN | NaN |
4 | Adelie | Torgersen | 36.7 | 19.3 | 193.0 | 3450.0 | Female |
In [11]:
df.species.value_counts()
Out[11]:
species Adelie 152 Gentoo 124 Chinstrap 68 Name: count, dtype: int64
In [12]:
gA = df[df.species=='Adelie'].bill_length_mm
gA
Out[12]:
0 39.1 1 39.5 2 40.3 3 NaN 4 36.7 ... 147 36.6 148 36.0 149 37.8 150 36.0 151 41.5 Name: bill_length_mm, Length: 152, dtype: float64
In [13]:
gG = df[df.species=='Gentoo'].bill_length_mm
gC = df[df.species=='Chinstrap'].bill_length_mm
In [14]:
stats.f_oneway(gA, gG, gC)
Out[14]:
F_onewayResult(statistic=nan, pvalue=nan)
- Was ist das Problem?
- Es gibt Einträge ohne Werte
In [15]:
res = stats.f_oneway(gA.dropna(), gG.dropna(), gC.dropna())
Also haben unterschiedliche Pinguinarten unterschiedliche Schnabellängen
Was hat das mit den Varianzen bzw. Stichprobenstreuungen zu tun?¶
In [16]:
df = pd.read_csv(u_schad)
df.describe()
Out[16]:
Unnamed: 0 | Messstelle | Konzentration | |
---|---|---|---|
count | 80.0000 | 80.000000 | 80.000000 |
mean | 39.5000 | 2.987500 | 0.000905 |
std | 23.2379 | 1.409675 | 0.000341 |
min | 0.0000 | 1.000000 | 0.000061 |
25% | 19.7500 | 2.000000 | 0.000701 |
50% | 39.5000 | 3.000000 | 0.000938 |
75% | 59.2500 | 4.000000 | 0.001158 |
max | 79.0000 | 5.000000 | 0.001605 |
In [17]:
g1.std()
Out[17]:
0.0003088278193577403
In [18]:
g2.std()
Out[18]:
0.0004360906113112883
In [19]:
g3.std()
Out[19]:
0.00033459177573784817
In [20]:
g4.std()
Out[20]:
0.00032047637643428304
In [21]:
g5.std()
Out[21]:
0.0003095504974203532
Die Stichprobenstreuung des gesamten Datensatzes ist ungefähr dieselbe wie die jeder einzelnen Gruppe
In [22]:
sns.scatterplot(df, y='Konzentration', x='Messstelle', hue='Messstelle', legend=False);
Jetzt dasselbe mit den Pinguinen
In [23]:
df = sns.load_dataset("penguins")
df.describe()
Out[23]:
bill_length_mm | bill_depth_mm | flipper_length_mm | body_mass_g | |
---|---|---|---|---|
count | 342.000000 | 342.000000 | 342.000000 | 342.000000 |
mean | 43.921930 | 17.151170 | 200.915205 | 4201.754386 |
std | 5.459584 | 1.974793 | 14.061714 | 801.954536 |
min | 32.100000 | 13.100000 | 172.000000 | 2700.000000 |
25% | 39.225000 | 15.600000 | 190.000000 | 3550.000000 |
50% | 44.450000 | 17.300000 | 197.000000 | 4050.000000 |
75% | 48.500000 | 18.700000 | 213.000000 | 4750.000000 |
max | 59.600000 | 21.500000 | 231.000000 | 6300.000000 |
In [24]:
gA.std()
Out[24]:
2.663404848368619
In [25]:
gC.std()
Out[25]:
3.3392558959358865
In [26]:
gG.std()
Out[26]:
3.0818573721142872
- Die Stichprobenstreuung im gesamten Datensatz ist größer als in den einzelnen Gruppen.
- Der Unterschied kommt daher, dass sich die Gruppenmittelwerte stärker unterscheiden, als sich das durch Variation innerhalb der Gruppen erklären lässt
In [27]:
sns.scatterplot(df, y='bill_length_mm', x='species', hue='species', legend=False);
In den tatsächlich benutzen Formel kommt anstelle der Stichprobenstreuung die Varianz vor, daher der Name "Analysis of Varianz"