8.3 Statistik mit Pandas#

Lernziele#

Lernziele

  • Sie können sich mit describe eine Übersicht über statistische Kennzahlen verschaffen.

  • Sie wissen, wie Sie die Anzahl der gültigen Einträge mit count ermitteln.

  • Sie kennen die statistischen Kennzahlen Mittelwert und Standardabweichung und wissen, wie diese mit mean und std berechnet werden.

  • Sie können das Minimum und das Maximum mit min und max bestimmen.

  • Sie wissen wie ein Quantil interpretiert wird und wie es mit quantile berechnet wird.

Schnelle Übersicht mit .describe()#

So wie die Methode .info() uns einen schnellen Überblick über die Daten eines DataFrame-Objektes gibt, so liefert die Methode .describe() eine schnelle Übersicht über statistische Kennzahlen. Wir bleiben bei unserem Beispiel der Spielerdaten der Top7-Fußballvereine der Bundesligasaison 2020/21.

import pandas as pd

data = pd.read_csv('bundesliga_top7_offensive.csv', index_col=0)
data.head(10)
Club Nationality Position Age Matches Starts Mins Goals Assists Penalty_Goals Penalty_Attempted xG xA Yellow_Cards Red_Cards
Name
Manuel Neuer Bayern Munich GER GK 34 33 33 2970 0 0 0 0 0.00 0.01 1 0
Thomas Müller Bayern Munich GER MF 30 32 31 2674 11 19 1 1 0.24 0.39 0 0
David Alaba Bayern Munich AUT DF,MF 28 32 30 2675 2 4 0 0 0.04 0.08 4 0
Jérôme Boateng Bayern Munich GER DF 31 29 29 2368 1 1 0 0 0.01 0.02 6 0
Robert Lewandowski Bayern Munich POL FW 31 29 28 2458 41 7 8 9 1.16 0.13 4 0
Joshua Kimmich Bayern Munich GER MF 25 27 25 2194 4 10 0 0 0.10 0.27 4 0
Kingsley Coman Bayern Munich FRA FW,MF 24 29 23 1752 5 10 0 0 0.21 0.34 1 0
Benjamin Pavard Bayern Munich FRA DF 24 24 22 1943 0 0 0 0 0.02 0.09 3 0
Alphonso Davies Bayern Munich CAN DF 19 23 22 1763 1 2 0 0 0.01 0.04 2 1
Serge Gnabry Bayern Munich GER FW,MF 25 27 20 1644 10 2 0 0 0.44 0.25 4 0

Die Anwendung der .describe()-Methode liefert fogende Ausgabe:

data.describe()
Age Matches Starts Mins Goals Assists Penalty_Goals Penalty_Attempted xG xA Yellow_Cards Red_Cards
count 177.000000 177.000000 177.000000 177.000000 177.000000 177.000000 177.000000 177.000000 177.000000 177.000000 177.000000 177.000000
mean 24.903955 19.858757 14.740113 1321.604520 2.542373 2.005650 0.214689 0.271186 0.157571 0.106328 2.254237 0.056497
std 4.309983 10.116219 10.526494 899.843857 4.911681 3.117941 0.976548 1.115447 0.226989 0.130900 2.258267 0.231534
min 15.000000 1.000000 0.000000 5.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
25% 22.000000 13.000000 5.000000 456.000000 0.000000 0.000000 0.000000 0.000000 0.020000 0.010000 0.000000 0.000000
50% 25.000000 22.000000 15.000000 1359.000000 1.000000 1.000000 0.000000 0.000000 0.090000 0.080000 2.000000 0.000000
75% 28.000000 29.000000 24.000000 2044.000000 3.000000 3.000000 0.000000 0.000000 0.220000 0.160000 4.000000 0.000000
max 36.000000 34.000000 34.000000 3060.000000 41.000000 19.000000 8.000000 9.000000 2.020000 1.230000 10.000000 1.000000

Da es sich eingebürgert hat, Daten zeilenweise abzuspeichern und die Eigenschaft pro einzelnem Datensatz in den Spalten zu speichern, wertet .describe() jede Spalte für sich aus. Für jede Eigenschaft werden dann die statistischen Kennzahlen

  • count

  • mean

  • std

  • min

  • max

  • Quantile 25 %, 50 % und 75 %

  • max

ausgegeben.

Die Bedeutung der Kennzahlen wird in der Pandas-Dokumentation/DataFrame.describe erläutert. Wir gehen dennoch jede Kennzahl einzeln durch.

Anzahl count#

Mit .count() wird die Anzahl der Einträge bestimmt, die nicht ‘NA’ sind. Der Begriff ‘NA’ stammt dabei aus dem Bereich Data Science. Gemeint sind fehlende Einträge, wobei die fehlenden Einträge verschiedene Ursachen haben können:

  • NA = not available (der Messsensor hat versagt)

  • NA = not applicable (es ist sinnlos bei einem Mann nachzufragen, ob er schwanger ist)

  • NA = no answer (eine Person hat bei dem Umfrage nichts angegeben)

Wir können auch direkt auf diesen Wert zugreifen, wenn wir beispielsweise wissen wollen, bei wie vielen Fußballspielern ein Alter eingetragen ist. Wird die Methode .count() direkt auf den kompletten DataFrame angewendet, so erhalten wir ein Pandas-Series-Objekt.

print( data.count() )
Club                 177
Nationality          177
Position             177
Age                  177
Matches              177
Starts               177
Mins                 177
Goals                177
Assists              177
Penalty_Goals        177
Penalty_Attempted    177
xG                   177
xA                   177
Yellow_Cards         177
Red_Cards            177
dtype: int64

Um jetzt an die Anzahl gültiger Altersangaben zu kommen, können wir entweder erst die Spalte mit dem Alter heraussgreifen und darauf .count() anwenden.

methode01 = data.loc[:, 'Age'].count()
print(methode01)
177

Oder wir wenden zuerst .count()an und wählen dann im Series-Objekt das Alter ‘Age’ aus.

methode02 = data.count().loc['Age']
print(methode02)
177

Mittelwert mean#

Mittelwert heißt auf Englisch mean. Daher ist es nicht verwunderlich, dass die Methode .mean() den Mittelwert der Einträge in jeder Spalte berechnet.

mittelwert = data.mean(numeric_only=True)
print(mittelwert)
Age                    24.903955
Matches                19.858757
Starts                 14.740113
Mins                 1321.604520
Goals                   2.542373
Assists                 2.005650
Penalty_Goals           0.214689
Penalty_Attempted       0.271186
xG                      0.157571
xA                      0.106328
Yellow_Cards            2.254237
Red_Cards               0.056497
dtype: float64

An der Stelle ist es wichtig, die Option numeric_only=True zu setzen, damit nur von numerischen Werten, also Zahlen, der Mittelwert gebildet wird.

Wir entnehmen der Statistik, dass Fußballer der Top7-Vereine im Mittel 24.9 Jahre alt sind und 1321.6 Minuten im Einsatz waren.

Falls Sie prinzipiell nochmal die Berechnung des Mittelwertes wiederholen wollen, können Sie folgendes Video ansehen.

Standardabweichung std#

Das ‘st’ in .std()für Standard steht, ist nachvollziehbar. Der dritte Buchstabe ‘d’ kommt von ‘deviation’, also Abweichung. Somit ist wiederum die Methode nach dem englischen Fachbegriff ‘standard deviation’ benannt. Welche Standardabweichung erhalten wir beim Alter?

standardabweichung = data.std(numeric_only=True)
print(standardabweichung)
Age                    4.309983
Matches               10.116219
Starts                10.526494
Mins                 899.843857
Goals                  4.911681
Assists                3.117941
Penalty_Goals          0.976548
Penalty_Attempted      1.115447
xG                     0.226989
xA                     0.130900
Yellow_Cards           2.258267
Red_Cards              0.231534
dtype: float64

Es sind 4.3 Jahre. Das haben wir jetzt der Ausgabe abgelsen. Wenn wir den Wert extrahieren wollen, gibt es wieder die beiden Methoden. Entweder erst Spalte und dann .std() oder erst .std()und dann Selektion nach ‘Age’. Probieren wir es aus.

alter_std = data.loc[:, 'Age'].std()
print(alter_std) 
4.309982619427105

Was war eigentlich nochmal die Standardabweichung? Falls Sie dazu eine kurze Wiederholung der Theorie benötigen, empfehle ich Ihnen dieses Video.

Minimum und Maximum mit min und max#

Die Namen der Methoden .min() und max() sind fast schon wieder selbsterklärend. Die Methode .min() liefert den kleinsten Werte zurück, der in einer Spalte gefunden wird. Umgekehrt liefert .max() den größten Eintrag, der in jeder Spalte gefunden wird. Wie häufig die minimalen und maximalen Werte vorkommen, ist dabei egal.

Schauen wir uns an, was die minimale Anzahl von Toren ist, die geschossen wurden (haben Sie eine Vermutung). Und dann schauen wir gleich nach, was die maximale Anzahl von Toren ist.

tore_min = data.loc[:, 'Goals'].min()
print(tore_min)

tore_max = data.loc[:, 'Goals'].max()
print(tore_max)
0
41

Wenig verwunderlich ist die minimale Anzahl an Toren 0 und die maximale Anzahl an Toren, die ein oder mehrere Spieler der Top7 2020/21 geschossen haben, war 41. (Wahrscheinlich wissen Sie aber, dass nur ein Spieler 41 Tore geschafft hat, natürlich Lewandowski).

Von Verteidigern wird nicht erwartet, Tore zu schieen, sondern von Stürmern. Was ist denn das Minimum an Toren bei den Stürmern? Die Positionen sind in der Spalte ‘Position’. Dabei bedeutet FW = forward = Stürmer, MF = mid field = Mittelfeld, DF = defensive = Verteidigung und GK = goalkeeper = Torwart. Bei manchen Spielern stehen zwei Positionen, konzentrieren wir uns auf diejenigen, bei denen nur ‘FW’ eingetragen ist.

filter = data.loc[:, 'Position'] == 'FW'
stuermer = data.loc[filter, 'Goals']

print('Stürmer')
print(stuermer)

print('==============')
print('Minimale Tore: {}'.format(stuermer.min()))
Stürmer
Name
Robert Lewandowski    41
Joshua Zirkzee         0
Mickaël Cuisance       0
Erling Haaland        27
Steffen Tigges         0
Yussuf Poulsen         5
Alexander Sørloth      5
Justin Kluivert        3
Wout Weghorst         20
Josip Brekalo          7
André Silva           28
Bas Dost               4
Patrik Schick          9
Lucas Alario          11
Demarai Gray           1
Paulinho               0
Taiwo Awoniyi          5
Joel Pohjanpalo        6
Petar Musa             1
Akaki Gogia            0
Leon Dajaku            0
Joshua Mees            0
Name: Goals, dtype: int64
==============
Minimale Tore: 0

Quantil mit quantile#

Das Quantil \(p \%\) ist der Wert, bei dem \(p %\) der Einträge kleiner als diese Zahl sind und \(100 \% - p \%\) sind größer. Meist werden nicht Prozentzahlen verwendet, sondern p ist zwischen 0 und 1, wobei die 1 für 100 % steht.

Angenommen, wir würden gerne das 0.5-Quantil (auch Median genannt) der gelben Karten wissen. Mit der Methode .quantile() können wir diesen Wert leicht aus den Daten holen.

gelbe_karten_50prozent_quantil = data.loc[:, 'Yellow_Cards'].quantile(0.5)
print(gelbe_karten_50prozent_quantil)
2.0

Das 50 % -Quantil liegt bei 2 gelben Karten. 50 % aller Spieler haben also weniger als 2 gelbe Karten kassiert. Und 50 % aller Spieler haben 2 oder mehr gelbe Karten kassiert. Wir schauen uns jetzt das 75 % Quantil an.

gelbe_karten_75prozent_quantil = data.loc[:, 'Yellow_Cards'].quantile(0.75)
print(gelbe_karten_75prozent_quantil)
4.0

75 % aller Spieler haben weniger als 4 gelbe Karten bekommen. SChauen wir uns die Gelbkarten-Spieler an. Ob da vielleicht mehrheitlich Defensivspieler dabei sind?

filter = data.loc[:, 'Yellow_Cards'] > 4.0
gelbkarten_spieler = data.loc[filter, ['Position', 'Yellow_Cards']]
print(gelbkarten_spieler.sort_values(by='Yellow_Cards', ascending=False))
                    Position  Yellow_Cards
Name                                      
Sebastian Rode            MF            10
Obite N'Dicka             DF            10
Christopher Trimmel       DF             9
Marcel Sabitzer           MF             8
Grischa Prömel            MF             7
Paulo Otávio              DF             7
Kevin Mbabu               DF             7
Xaver Schlager            MF             7
Maximilian Arnold         MF             7
Leon Bailey            FW,MF             6
Djibril Sow               MF             6
Mats Hummels              DF             6
Jérôme Boateng            DF             6
Kevin Kampl               MF             6
Dayot Upamecano           DF             6
Thomas Delaney            MF             6
Jude Bellingham           MF             6
Maxence Lacroix           DF             5
Edmond Tapsoba            DF             5
Robert Andrich            MF             5
Emre Can               DF,MF             5
Nadiem Amiri              MF             5
Moussa Diaby           FW,MF             5
David Abraham             DF             5
Aymen Barkok           FW,MF             5
John Brooks               DF             5
Amin Younes            MF,FW             5
Tuta                      DF             5
Nordi Mukiele             DF             5
Makoto Hasebe          DF,MF             5

Zusammenfassung#

In diesem Abschnitt haben wir uns mit einfachen statistischen Kennzahlen beschäftigt, die Pandas mit der Methode .describe() zusammenfasst, die aber auch einzeln über

  • .count()

  • .mean()

  • .std()

  • .min() und .max()

  • .quantile()

berechnet und ausgegeben werden können.