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.