Mathematik für Biologiestudierende¶

Wintersemester 2023/24

  1. November 2023

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

Python¶

  • python, seaborn, jupyter: Was ist das?
  • python ist eine Programmiersprache
  • Wir wollen aber gar nicht programmieren
  • Wir wollen fertige Bibliotheken anwenden
  • Für Naturwissenschaftlerinnen und Naturwissenschaftler sind das pandas, numpy, seaborn und noch einige andere
  • Das sind für alle Teilnehmenden dieses Kurses dieselben Bibliotheken
  • In der Frage der Oberfläche gibt es verschiedene Möglichkeiten, je nach persönlichem Geschmack
  • Hier benutze ich jupyter notebook auf meinem Rechner
  • Eine andere Möglichkeit ist https://colab.research.google.com
  • Dort läuft ebenfalls jupyter

Installation auf eigenem Rechner¶

  • weil wir mehr als nur python brauchen, gibt es auf https://www.math.uni-duesseldorf.de/~internet/bio2324/software.html eine Installationsanweisung
  • in der offenene Fragestunde am letzten Freitag habe ich das vorgemacht

Warum nicht Excel?¶

  • Hilft uns nur auf der ersten Hälfte unseres Weges
  • Ist schon bei mittelkomplizierten Fragestellungen nicht wirklich einfacher
  • Spreadsheets sind sehr, sehr schwer zu verifizieren
  • Daten und Programmlogik sind nicht getrennt: Fehlerquelle

Wofür Excel gut ist:

  • Einmalrechnungen, die nicht reproduziert weden müssen
  • gutes Eingabeformat

Praktische Vorführung Excel¶

In [1]:
import pandas as pd

Die Bibiothek zur Bearbeitung von Tabellen heißt pandas

Einlesen von Daten¶

sns.load_dataset() für die Beispieldatensätze, die bei seaborn mitgeliefert werde

für echte Datensätze

  • pd.read_csv() Daten im csv-Format
  • pd.read_excel() Daten in einem der Excel-Formate

Einlesen von der Festplatte

In [2]:
iris = pd.read_csv("iris/iris_extended.csv")

https://www.kaggle.com/datasets/samybaladram/iris-dataset-extended/

© Samy Baladram, CC-BY-4.0

In [3]:
iris
Out[3]:
species elevation soil_type sepal_length sepal_width petal_length petal_width sepal_area petal_area sepal_aspect_ratio ... sepal_to_petal_length_ratio sepal_to_petal_width_ratio sepal_petal_length_diff sepal_petal_width_diff petal_curvature_mm petal_texture_trichomes_per_mm2 leaf_area_cm2 sepal_area_sqrt petal_area_sqrt area_ratios
0 setosa 161.8 sandy 5.16 3.41 1.64 0.26 17.5956 0.4264 1.513196 ... 3.146341 13.115385 3.52 3.15 5.33 18.33 53.21 4.194711 0.652993 41.265478
1 setosa 291.4 clay 5.48 4.05 1.53 0.37 22.1940 0.5661 1.353086 ... 3.581699 10.945946 3.95 3.68 5.90 20.45 52.53 4.711051 0.752396 39.205087
2 setosa 144.3 sandy 5.10 2.80 1.47 0.38 14.2800 0.5586 1.821429 ... 3.469388 7.368421 3.63 2.42 5.66 24.62 50.25 3.778889 0.747395 25.563910
3 setosa 114.6 clay 4.64 3.44 1.53 0.17 15.9616 0.2601 1.348837 ... 3.032680 20.235294 3.11 3.27 4.51 22.91 50.85 3.995197 0.510000 61.367166
4 setosa 110.9 loamy 4.85 2.87 1.23 0.26 13.9195 0.3198 1.689895 ... 3.943089 11.038462 3.62 2.61 4.03 21.56 40.57 3.730885 0.565509 43.525641
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1195 virginica 268.8 loamy 5.36 2.51 5.16 1.93 13.4536 9.9588 2.135458 ... 1.038760 1.300518 0.20 0.58 11.61 11.52 59.46 3.667915 3.155757 1.350926
1196 virginica 125.4 clay 7.49 3.06 7.68 2.17 22.9194 16.6656 2.447712 ... 0.975260 1.410138 -0.19 0.89 13.85 6.99 77.12 4.787421 4.082352 1.375252
1197 virginica 73.6 clay 6.79 3.25 4.72 2.26 22.0675 10.6672 2.089231 ... 1.438559 1.438053 2.07 0.99 13.13 9.16 74.39 4.697606 3.266068 2.068725
1198 virginica 239.6 sandy 6.38 2.24 5.30 1.71 14.2912 9.0630 2.848214 ... 1.203774 1.309942 1.08 0.53 11.01 6.46 73.90 3.780370 3.010482 1.576873
1199 virginica 201.5 loamy 5.16 3.20 5.64 1.43 16.5120 8.0652 1.612500 ... 0.914894 2.237762 -0.48 1.77 12.09 8.59 64.31 4.063496 2.839930 2.047314

1200 rows × 21 columns

Einlesen aus dem Internet

In [4]:
fish = pd.read_csv("https://stats.idre.ucla.edu/stat/data/fish.csv")
fish
Out[4]:
nofish livebait camper persons child xb zg count
0 1 0 0 1 0 -0.896315 3.050405 0
1 0 1 1 1 0 -0.558345 1.746149 0
2 0 1 0 1 0 -0.401731 0.279939 0
3 0 1 1 2 1 -0.956298 -0.601526 0
4 0 1 0 1 0 0.436891 0.527709 1
... ... ... ... ... ... ... ... ...
245 1 1 1 2 0 -0.755236 2.324209 0
246 0 1 1 4 3 1.794859 -5.625944 0
247 0 1 1 2 1 -0.392649 0.677275 0
248 1 1 1 3 2 1.374641 -2.595630 0
249 1 1 1 2 1 0.828834 -1.457115 0

250 rows × 8 columns

Ein DataFrame ist eine Tabelle, wie etwa in Excel auch.

Auf Spalten greift man mit Indizierung zu:

In [5]:
iris['soil_type']
Out[5]:
0       sandy
1        clay
2       sandy
3        clay
4       loamy
        ...  
1195    loamy
1196     clay
1197     clay
1198    sandy
1199    loamy
Name: soil_type, Length: 1200, dtype: object

Alternativ auch mit dem Punkt, wenn die Spaltenüberschrift nur aus Buchstaben, Zahlen und Unterstrich besteht

In [6]:
bluetenblattlaenge = iris.petal_length
In [7]:
bluetenblattlaenge
Out[7]:
0       1.64
1       1.53
2       1.47
3       1.53
4       1.23
        ... 
1195    5.16
1196    7.68
1197    4.72
1198    5.30
1199    5.64
Name: petal_length, Length: 1200, dtype: float64

Spalten sind vom Typ pd.Series

Auf Zeilen greift man über den Index zu. In der Regel zählt der Index die Zeilen einfach durch.

In [8]:
iris.loc[1100]
Out[8]:
species                            virginica
elevation                              108.4
soil_type                              loamy
sepal_length                            6.34
sepal_width                             3.09
petal_length                             5.7
petal_width                             2.17
sepal_area                           19.5906
petal_area                            12.369
sepal_aspect_ratio                   2.05178
petal_aspect_ratio                  2.626728
sepal_to_petal_length_ratio         1.112281
sepal_to_petal_width_ratio          1.423963
sepal_petal_length_diff                 0.64
sepal_petal_width_diff                  0.92
petal_curvature_mm                      9.46
petal_texture_trichomes_per_mm2         11.5
leaf_area_cm2                          73.17
sepal_area_sqrt                     4.426127
petal_area_sqrt                     3.516959
area_ratios                         1.583847
Name: 1100, dtype: object

Deskriptive Statistik¶

Lageparameter¶

Arithmetisches Mittel¶

Das arithmetische Mittel (engl. "mean") ist der Durchschnitt der Messwerte

Formel: Beim Stichprobenumfang $n$ seien $ x_1, x_2, x_3, \dots, x_n $ die Messwerte, dann ist das arithmetische Mittel gleich

$$ \overline x = \frac1n \left( x_1 + x_2 + x_3 + \dots + x_n \right) $$

Man schreibt auch \begin{equation*} \overline x = \frac1n \sum_{j=1}^n x_j \end{equation*}

$\displaystyle \sum$ ist das Summenzeichen.

  • Unter dem Zeichen stehen zwei Informationen: Der Name der Zählvariablen (hier $j$) und der Startwert der Zählung (hier $1$).
  • Über dem Zeichen steht der Endpunkt der Zählung (hier die Variable $n$)
  • Rechts neben dem Zeichen steht, was aufzuzählen ist (hier $x_j$)

Beispiel¶

Bei fünf Mäusen sind die Gewichte 21.3g, 19.8g, 20.4g, 19.0g und 22.7g gemessen worden. Was ist der Mittelwert?

  • Die Summe beträgt 103.2g.
  • 103.2/5 = 20.64
  • Das arithmetische Mittel der Mausgewichte beträgt 20.64g

Das ist mit dem Taschenrechner kein Problem

Trotzdem mal mit pandas

In [9]:
maeuse = pd.DataFrame()  #  leerer DataFrame
In [10]:
maeuse['Gewicht'] = [21.3, 19.8, 20.4, 19.0, 22.7]
In [11]:
maeuse
Out[11]:
Gewicht
0 21.3
1 19.8
2 20.4
3 19.0
4 22.7
In [12]:
maeuse.mean()
Out[12]:
Gewicht    20.64
dtype: float64
In [13]:
bluetenblattlaenge.mean()
Out[13]:
3.80795

Median¶

Der Median ist ein Wert mit der Eigenschaft, dass in der Menge der nach Größe geordneten Messwerte gleich viele Daten unterhalb und oberhalb des Medians liegen.

Beispiel: 7 Messwerte

10 | 5 | 4 | 9 | 10 | 1 | 5

Nach Größe anordnen

1 | 4 | 5 | 5 | 9 | 10 | 10

Der Median ist $x_{\text{med}} = 5$

Median für geraden Stichprobenumfang¶

Falls die Anzahl der Daten gerade ist, stehen in der Menge der nach Größe geordneten Messwerte zwei Zahlen in der Mitte.

Der Median $x_{\text{med}}$ ist dann deren arithmetisches Mittel.

10 | 5 | 4 | 9 | 10 | 1 | 5 | 8

Nach Größe anordnen

1 | 4 | 5 | 5 | 8 | 9 | 10 | 10

Der Median ist $x_{\text{med}} = 6.5$

In [14]:
maeuse.median()
Out[14]:
Gewicht    20.4
dtype: float64

Bei normalverteilten Daten liegen arithmetisches Mittel und Median nahe beieinander

Robustheit¶

  • Ein Ausreißer ist ein Messwert, der weit von fast allen anderen Messwerten entfernt ist. Ausreißer können z.B. von Messfehlern herrühren.
  • Eine statistische Größe ist robust, wenn sie unempfindlich gegen Ausreißer ist.
  • Das arithmetische Mittel ist nicht robust. Ausreißer gehen genauso ein wie alle anderen.
  • Der Median ist robust

Beispiel zur Robustheit¶

In [15]:
maeuse2 = pd.DataFrame()
maeuse2['Gewicht'] = [21.3, 19.8, 20.4, 19.0, 22.7, 287]
In [16]:
maeuse.mean()
Out[16]:
Gewicht    20.64
dtype: float64
In [17]:
maeuse2.mean()
Out[17]:
Gewicht    65.033333
dtype: float64
In [18]:
maeuse.median()
Out[18]:
Gewicht    20.4
dtype: float64
In [19]:
maeuse2.median()
Out[19]:
Gewicht    20.85
dtype: float64

Streuungsparameter¶

Empirische Varianz und Stichprobenstreuung¶

  • Beim Stichprobenumfang $n$ seien $x_1, x_2, x_3, \dots, x_n$ die Messwerte, dann ist das empirische Varianz gleich \begin{equation*} s^2 = \frac{(x_1-\overline x)^2 + (x_2-\overline x)^2 + (x_3-\overline x)^2 + \dots + (x_n-\overline x)^2}{n-1} \end{equation*} Dabei ist $\overline x$ das arithmetische Mittel
  • Die empirische Varianz wird mit $s^2$ bezeichnet.
  • Die Zahl $s$ heißt empirische Standardabweichung oder Stichprobenstreuung
  • Die Stichprobenstreuung ist also die Quadratwurzel der empirischen Varianz

Konkrete Rechnung¶

Bei fünf Proben wurden die folgenden Massen in [g] gewogen:

Nummer 1 2 3 4 5
Masse 1.1 1.3 1.6 1.3 2.0

$$\displaystyle \sum_{j=1}^5 x_j = 7.3g$$ $$\overline x = \frac{7.3g}5 = 1.46g$$ $$\sum_{j=1}^5 (x_j-\overline x)^2 = 0.4920g^2$$ $$s^2 = \frac{0.4920g^2}4 = 0.1230g^2 \quad\text{und}\quad s = \sqrt{0.1230g^2} = 0.3507g$$

In [20]:
maeuse.var()  # empirische Varianz
Out[20]:
Gewicht    2.033
dtype: float64
In [21]:
maeuse.std()  # Stichprobenstreuung
Out[21]:
Gewicht    1.425833
dtype: float64

Stichprobenstreuung vs. Varianz¶

  • Der Vorteil der Stichprobenstreuung gegenüber der Varianz ist, dass die Stichprobenstreuung richtig skaliert
  • Das bedeutet folgendes: Wenn ich alle Daten mit 1000 multipliziere, dann
    • multipliziert sich das arithmetische Mittel mit 1000
    • multipliziert sich die Varianz mit 1000000
    • multipliziert sich die Stichprobenstreuung mit 1000
  • Das bedeutet auch, dass die Stichprobenstreuung in derselben Einheit angegegeben wird wie die Daten

Formeln für die Varianz¶

  • Die Definition ohne Pünktchen \begin{equation*} s^2 = \frac1{n-1} \sum_{j=1}^n \left(x_j - \overline x \right)^2 \end{equation*}
  • Eine etwas einfachere Formel, deren Richtigkeit leicht nachgerechnet werden kann \begin{equation*} s^2 = \frac1{n-1} \biggr( \Bigr( \sum_{j=1}^n x_j^2 \Bigr) - n {\overline x}^2 \biggr) \end{equation*}

Warum $n - 1$ im Nenner?¶

  • Das Stichwort ist ``erwartungstreuer Schätzer''
  • Das bedeutet ungefähr, dass man, wenn man für viele Datensätze die Varianz mit dieser Methode feststellt, im Mittel näher an der ``wahren'' Varianz ist, als wenn man den Nenner $n$ benutzt
  • Alle großen Software-Pakete machen das so

Software-Pakete:

  • python mit pandas und scipy.stats
  • R
  • SPSS

Überprüfung

In [22]:
maeuse.var()
Out[22]:
Gewicht    2.033
dtype: float64
In [23]:
((maeuse - maeuse.mean())**2).sum() / 4
Out[23]:
Gewicht    2.033
dtype: float64

Achten Sie auf Ihren Taschenrechner!

Zusammenfassungen¶

In [24]:
maeuse.describe()
Out[24]:
Gewicht
count 5.000000
mean 20.640000
std 1.425833
min 19.000000
25% 19.800000
50% 20.400000
75% 21.300000
max 22.700000
  • count: Anzahl
  • mean: arithmetisches Mittel
  • std: Stichprobenstreuung
  • min: kleinster Wert
  • 50%: Median
  • 25%, 75%: Quartile
  • max: größter Wert

Funktioniert auch für DataFrames

In [25]:
fish.describe()
Out[25]:
nofish livebait camper persons child xb zg count
count 250.000000 250.000000 250.000000 250.00000 250.000000 250.000000 250.000000 250.000000
mean 0.296000 0.864000 0.588000 2.52800 0.684000 0.973796 0.252323 3.296000
std 0.457407 0.343476 0.493182 1.11273 0.850315 1.440277 2.102391 11.635028
min 0.000000 0.000000 0.000000 1.00000 0.000000 -3.275050 -5.625944 0.000000
25% 0.000000 1.000000 0.000000 2.00000 0.000000 0.008267 -1.252724 0.000000
50% 0.000000 1.000000 1.000000 2.00000 0.000000 0.954550 0.605079 0.000000
75% 1.000000 1.000000 1.000000 4.00000 1.000000 1.963855 1.993237 2.000000
max 1.000000 1.000000 1.000000 4.00000 3.000000 5.352674 4.263185 149.000000

Quartile¶

  • Das Quartile $Q_1$ ist als derjenige Wert definiert, unter dem 25% und über dem 75% der Messwerte liegen
  • Das Quartile $Q_3$ ist als derjenige Wert definiert, über dem 25% und unter dem 75% der Messwerte liegen
  • Das Quartil $Q_2$ ist der Median
  • Bei den Mäusen: $Q_1 = 19.8$ und $Q_3 = 21.3$

Grafik mit Klausurdaten

Image

Zusammenhang zwischen Quartilen und Quantilen¶

  • Allgemeiner ist für $q$ zwischen $0$ und $1$ das $q$-Quantil derjenige Wert, so dass der Anteil der Messwerte unterhalb dieses Wertes gleich $q$ und der Anteil oberhalb gleich $1-q$ ist
  • Wenn $q$ in Prozent ausgedrückt wird, dann spricht man auch von Perzentilen
Quartil Quantil
1. Quartil 25%-Quantil
Median 50%-Quantil
3. Quartil 75%-Quantil

Beispiel

  • Leute, die zu den reichsten 1% der Bevölkerung gehören, haben ein Einkommen oberhalb des 99%-Quantils

Interquartilabstand¶

  • Der Interquartilabstand ist definiert als \begin{equation*} \text{IQR} = Q_3 - Q_1 \end{equation*}
  • Der Interquartilabstand ist ein robustes Maß für die Streuung

Berechnung des Interquartilabstands

In [26]:
bbl = bluetenblattlaenge.describe()
bbl
Out[26]:
count    1200.000000
mean        3.807950
std         1.765469
min         0.960000
25%         1.640000
50%         4.300000
75%         5.200000
max         7.840000
Name: petal_length, dtype: float64
In [27]:
bbl["75%"] - bbl["25%"]  # Interquartilabstand
Out[27]:
3.5600000000000005
In [28]:
(bbl["75%"] - bbl["25%"]).round(6)
Out[28]:
3.56

Box-Whisker-Plots¶

In [29]:
import seaborn as sns
In [30]:
sns.boxplot(iris, x="species", y="sepal_length");
No description has been provided for this image

Ein Boxplot, auch Box-Whisker-Plot genannt, zeigt von unten nach oben

  • untere Einzelpunkte
  • unterster Datenpunkt, der kein Einzelpunkt ist
  • $Q_1$
  • Median
  • $Q_3$
  • oberster Datenpunkt, der kein Einzelpunkt ist
  • obere Datenpunkte

Einzelpunkte sind solche, die weiter als 1.5 Interquartilabstände von $Q_1$ bzw. $Q_3$ weg sind

Manchmal werden die Einzelpunkte als "Ausreißer" bezeichnet. Das kann man aber nicht so einfach gleichsetzen.

In [31]:
sns.boxplot(maeuse2);
No description has been provided for this image

Das ist wirklich ein Ausreißer (engl. "outlier")