19. Pandas - Teil 2#

Im ersten Teil haben wir gesehen, wie wir eine .csv-Datei einlesen und grundlegende Eigenschaften erkunden. Hier werden wir jetzt noch einige Schritte weitergehen im Umgang mit (komplexen) Datensets.

19.1. Data cleaning#

Unter data cleaning versteht man das Umstellen und Bearbeiten von Daten mit dem Ziel, diese für die folgende Analyse besser nutzbar zu machen. Einen Schritt in diese Richtung haben wir letztes Mal bereits unternommen, indem wir die Anzahl der Spalten auf die wichtigsten reduziert haben.

import pandas as pd
import numpy as np
import os

root = os.getcwd()
filename = os.path.join(root, "../data", 'pokemon.csv')

data = pd.read_csv(filename, delimiter=",")

cols = [
    'name', 'type1', 'type2', 'speed', 'abilities','attack',
    'defense', 'height_m', 'hp', 'weight_kg',
    'generation', 'is_legendary'
]

data_selected = data[cols]

Mit data_selected.info() können wir sehen, das einige Spalten nicht die benötigten 801 Einträge enthalten.

data_selected.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 801 entries, 0 to 800
Data columns (total 12 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   name          801 non-null    object 
 1   type1         801 non-null    object 
 2   type2         417 non-null    object 
 3   speed         801 non-null    int64  
 4   abilities     801 non-null    object 
 5   attack        801 non-null    int64  
 6   defense       801 non-null    int64  
 7   height_m      781 non-null    float64
 8   hp            801 non-null    int64  
 9   weight_kg     781 non-null    float64
 10  generation    801 non-null    int64  
 11  is_legendary  801 non-null    int64  
dtypes: float64(2), int64(6), object(4)
memory usage: 75.2+ KB

Wenn wir uns die Tabelle anschauen (z.B. mit data_selected.head()) , sehen wir, dass einige Einträge NaN heißen. Dies steht für Not-a-Number und ist das Numpy Format für fehlende/unbekannte Einträge.

data_selected.head()
name type1 type2 speed abilities attack defense height_m hp weight_kg generation is_legendary
0 Bulbasaur grass poison 45 ['Overgrow', 'Chlorophyll'] 49 49 0.7 45 6.9 1 0
1 Ivysaur grass poison 60 ['Overgrow', 'Chlorophyll'] 62 63 1.0 60 13.0 1 0
2 Venusaur grass poison 80 ['Overgrow', 'Chlorophyll'] 100 123 2.0 80 100.0 1 0
3 Charmander fire NaN 65 ['Blaze', 'Solar Power'] 52 43 0.6 39 8.5 1 0
4 Charmeleon fire NaN 80 ['Blaze', 'Solar Power'] 64 58 1.1 58 19.0 1 0

Pandas bietet eine Reihe von Möglichkeiten mit solchen fehlenden Werten umzugehen. NaN’s gibt es auch in Numpy, nur haben wir sie uns dort nicht explizit angeschaut. In Numpy kann solch ein Eintrag erstellt werden als np.nan.

In Pandas können diese über .isnull() oder isna() abgefragt werden, wobei das .any() angibt das der Wert True ausgegeben werden soll wenn mindestens ein Element ein NaN ist. Beide Methoden machen hier das Gleiche auch wenn „isnull“ vielleicht verwirrend ist, denn es gibt nicht wieder ob ein Wert Null ist, sondern nur ob ein Wert nicht vorhanden ist (NaN –> True).

data_selected.isna().any()
name            False
type1           False
type2            True
speed           False
abilities       False
attack          False
defense         False
height_m         True
hp              False
weight_kg        True
generation      False
is_legendary    False
dtype: bool
data_selected.isnull().any()
name            False
type1           False
type2            True
speed           False
abilities       False
attack          False
defense         False
height_m         True
hp              False
weight_kg        True
generation      False
is_legendary    False
dtype: bool

Wir können nun alle Spalten anzeigen in denen einzelne Werte fehlen:

columns_with_nan = data_selected.columns[data_selected.isna().any()]
data_selected[columns_with_nan]
type2 height_m weight_kg
0 poison 0.7 6.9
1 poison 1.0 13.0
2 poison 2.0 100.0
3 NaN 0.6 8.5
4 NaN 1.1 19.0
... ... ... ...
796 flying 9.2 999.9
797 steel 0.3 0.1
798 dragon 5.5 888.0
799 NaN 2.4 230.0
800 fairy 1.0 80.5

801 rows × 3 columns

19.1.1. Und jetzt? Was tun mit NaNs?#

Je nachdem was wir mit den Daten vorhaben, gibt es verschiedene Strategien mit den fehlenden Einträgen umzugehen. In vielen Fällen können wir sie einfach ignorieren. Wenn wir Mittelwerte (.mean()) oder Ähnliches berechnen, werde diese Werte automatisch nicht mitgezählt.

In anderen Fällen wollen wir die Werte vielleicht ersetzten, z.B. durch „0“. Aber Vorsicht! Danach werden diese Werte nämlich doch mitgezählt wenn Summen oder Mittelwerte berechnet werden.

19.1.1.1. NaN ersetzen#

Das Ersetzen geht bei Pandas mit .fillna():

data_selected.fillna(0).head()
name type1 type2 speed abilities attack defense height_m hp weight_kg generation is_legendary
0 Bulbasaur grass poison 45 ['Overgrow', 'Chlorophyll'] 49 49 0.7 45 6.9 1 0
1 Ivysaur grass poison 60 ['Overgrow', 'Chlorophyll'] 62 63 1.0 60 13.0 1 0
2 Venusaur grass poison 80 ['Overgrow', 'Chlorophyll'] 100 123 2.0 80 100.0 1 0
3 Charmander fire 0 65 ['Blaze', 'Solar Power'] 52 43 0.6 39 8.5 1 0
4 Charmeleon fire 0 80 ['Blaze', 'Solar Power'] 64 58 1.1 58 19.0 1 0

Wir können aber auch Strings oder andere Formate benutzen:

data_selected.fillna("unknown").head()
name type1 type2 speed abilities attack defense height_m hp weight_kg generation is_legendary
0 Bulbasaur grass poison 45 ['Overgrow', 'Chlorophyll'] 49 49 0.7 45 6.9 1 0
1 Ivysaur grass poison 60 ['Overgrow', 'Chlorophyll'] 62 63 1.0 60 13.0 1 0
2 Venusaur grass poison 80 ['Overgrow', 'Chlorophyll'] 100 123 2.0 80 100.0 1 0
3 Charmander fire unknown 65 ['Blaze', 'Solar Power'] 52 43 0.6 39 8.5 1 0
4 Charmeleon fire unknown 80 ['Blaze', 'Solar Power'] 64 58 1.1 58 19.0 1 0

Das kann sinnvoll sein, wenn wir die „unknown“ explizit mitzählen möchten:

data_selected.fillna("unknown")["type2"].value_counts()
type2
unknown     384
flying       95
poison       34
ground       34
fairy        29
psychic      29
fighting     25
steel        22
dark         21
grass        20
water        17
dragon       17
ice          15
ghost        14
rock         14
fire         13
electric      9
bug           5
normal        4
Name: count, dtype: int64

19.1.2. NaN entfernen#

Falls NaN nicht einfach ersetzt werden können und für die weiteren Schritte nicht vorkommen sollen, dann müssen entweder die entsprechenden Spalten oder Zeilen aus der Tabelle entfernt werden. Das geht in Pandas mit .dropna().

data_selected.dropna().head()
name type1 type2 speed abilities attack defense height_m hp weight_kg generation is_legendary
0 Bulbasaur grass poison 45 ['Overgrow', 'Chlorophyll'] 49 49 0.7 45 6.9 1 0
1 Ivysaur grass poison 60 ['Overgrow', 'Chlorophyll'] 62 63 1.0 60 13.0 1 0
2 Venusaur grass poison 80 ['Overgrow', 'Chlorophyll'] 100 123 2.0 80 100.0 1 0
5 Charizard fire flying 100 ['Blaze', 'Solar Power'] 104 78 1.7 78 90.5 1 0
11 Butterfree bug flying 70 ['Compoundeyes', 'Tinted Lens'] 45 50 1.1 60 32.0 1 0

Oder für die Entfernung aller Spalten mit NaNs:

data_selected.dropna(axis=1).head()
name type1 speed abilities attack defense hp generation is_legendary
0 Bulbasaur grass 45 ['Overgrow', 'Chlorophyll'] 49 49 45 1 0
1 Ivysaur grass 60 ['Overgrow', 'Chlorophyll'] 62 63 60 1 0
2 Venusaur grass 80 ['Overgrow', 'Chlorophyll'] 100 123 80 1 0
3 Charmander fire 65 ['Blaze', 'Solar Power'] 52 43 39 1 0
4 Charmeleon fire 80 ['Blaze', 'Solar Power'] 64 58 58 1 0

19.1.3. Wichtig:#

In Python gibt es zwei Möglichkeiten für Methoden die „ihr“ Objekt verändern wollen:

  1. Objekt bleibt unverändert und veränderte Kopie wird über return ausgegeben.

  2. Objekt selbst wird verändert.

Bei Pandas findet in der Regel (1) statt, siehe auch https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#indexing-view-versus-copy.

Das bedeutet, wenn wir ein verändertes DataFrame erhalten wollen müssen wir dies mit = erstellen:

data_na_removed = data_selected.dropna()
data_na_removed.head()
name type1 type2 speed abilities attack defense height_m hp weight_kg generation is_legendary
0 Bulbasaur grass poison 45 ['Overgrow', 'Chlorophyll'] 49 49 0.7 45 6.9 1 0
1 Ivysaur grass poison 60 ['Overgrow', 'Chlorophyll'] 62 63 1.0 60 13.0 1 0
2 Venusaur grass poison 80 ['Overgrow', 'Chlorophyll'] 100 123 2.0 80 100.0 1 0
5 Charizard fire flying 100 ['Blaze', 'Solar Power'] 104 78 1.7 78 90.5 1 0
11 Butterfree bug flying 70 ['Compoundeyes', 'Tinted Lens'] 45 50 1.1 60 32.0 1 0

19.2. Data selection#

Gehen wir mit der Analyse der Daten einen Schritt weiter. Was, wenn wir mehr über einzelne Gruppen wissen möchten? Oder über Einträge die bestimmte Bedingungen erfüllen?

19.2.1. Option 1: Masken#

Über Masken können wir ganz gezielt einzelne Fragen adressieren:

mask = data_selected["type1"] == "bug"
data_selected[mask].head()
name type1 type2 speed abilities attack defense height_m hp weight_kg generation is_legendary
9 Caterpie bug NaN 45 ['Shield Dust', 'Run Away'] 30 35 0.3 45 2.9 1 0
10 Metapod bug NaN 30 ['Shed Skin'] 20 55 0.7 50 9.9 1 0
11 Butterfree bug flying 70 ['Compoundeyes', 'Tinted Lens'] 45 50 1.1 60 32.0 1 0
12 Weedle bug poison 50 ['Shield Dust', 'Run Away'] 35 30 0.3 40 3.2 1 0
13 Kakuna bug poison 35 ['Shed Skin'] 25 50 0.6 45 10.0 1 0

Über solche Masken können wir auch Eigenschaften über einzelne Gruppen abfragen:

data_selected[mask]["weight_kg"].mean()
np.float64(33.083333333333336)

19.2.2. Option 2: query#

Pandas bietet auch die Möglichkeit statt mit einer Maske direkt mit der Methode .query zu arbeiten. Das sieht eventuell etwas netter aus, bietet aber ansonsten keine Vorteile zu den Masken.

Da Masken sowohl bei Numpy wie auch bei Pandas gehen, bleiben wir im Folgenden bei den Masken.

data_selected.query("type1 == 'bug'").head()
name type1 type2 speed abilities attack defense height_m hp weight_kg generation is_legendary
9 Caterpie bug NaN 45 ['Shield Dust', 'Run Away'] 30 35 0.3 45 2.9 1 0
10 Metapod bug NaN 30 ['Shed Skin'] 20 55 0.7 50 9.9 1 0
11 Butterfree bug flying 70 ['Compoundeyes', 'Tinted Lens'] 45 50 1.1 60 32.0 1 0
12 Weedle bug poison 50 ['Shield Dust', 'Run Away'] 35 30 0.3 40 3.2 1 0
13 Kakuna bug poison 35 ['Shed Skin'] 25 50 0.6 45 10.0 1 0

19.2.3. Outlook: groupby#

Für analysen von bestimmten Untergruppen bietet Pandas noch eine Funktion die das noch einfacher macht als mit Masken oder query zu arbeiten: groupby().

19.3. Groupby#

Pandas grouby (siehe Pandas documentation).

Mit grouby können bei Pandas alle Einträge mit bestimmten Kategorien zusammengefasst werden. Damit lassen sich leicht und schnell viele Eigenschaften vergleichen.

data_selected.groupby("type1").mean(numeric_only=True)
speed attack defense height_m hp weight_kg generation is_legendary
type1
bug 63.569444 70.125000 70.847222 0.883333 56.722222 33.083333 3.763889 0.041667
dark 75.310345 87.793103 70.517241 1.296552 72.551724 69.096552 4.275862 0.103448
dragon 76.111111 106.407407 86.259259 1.937037 79.851852 107.125926 4.296296 0.259259
electric 85.410256 70.820513 61.820513 0.981579 60.512821 37.944737 3.461538 0.128205
fairy 53.666667 62.111111 68.166667 0.794444 73.944444 23.555556 4.277778 0.055556
fighting 64.285714 99.178571 66.392857 1.196429 71.428571 58.675000 3.750000 0.000000
fire 73.346154 81.500000 67.788462 1.168000 68.730769 66.096000 3.634615 0.096154
flying 99.666667 66.666667 65.000000 1.166667 68.000000 52.000000 5.666667 0.333333
ghost 58.333333 72.740741 79.518519 1.251852 63.370370 69.570370 4.370370 0.037037
grass 59.025641 73.769231 70.871795 0.938961 65.358974 33.255844 3.935897 0.051282
ground 59.968750 94.812500 83.906250 1.340741 73.187500 150.044444 3.343750 0.062500
ice 62.739130 73.304348 71.913043 1.208696 72.086957 103.260870 3.565217 0.086957
normal 69.533333 75.161905 59.695238 1.024752 76.723810 46.158416 3.495238 0.028571
poison 64.187500 72.656250 70.031250 1.160000 65.593750 33.830000 3.093750 0.000000
psychic 75.150943 65.566038 69.264151 1.063462 72.943396 57.328846 3.849057 0.320755
rock 57.422222 90.666667 96.266667 1.304878 66.333333 92.946341 3.800000 0.088889
steel 56.583333 93.083333 120.208333 1.875000 66.791667 188.841667 4.208333 0.250000
water 63.921053 73.307018 73.482456 1.283333 70.219298 51.071930 3.210526 0.052632

Hier sind die Einträge nach dem „type1“ alphabetisch sortiert. Um die Sortierung zu ändern fügen wir einfach ein sort_values()hinzu um nach der gewünschten Spalte zu sortieren:

data_selected.groupby("type1").mean(numeric_only=True).sort_values("speed")
speed attack defense height_m hp weight_kg generation is_legendary
type1
fairy 53.666667 62.111111 68.166667 0.794444 73.944444 23.555556 4.277778 0.055556
steel 56.583333 93.083333 120.208333 1.875000 66.791667 188.841667 4.208333 0.250000
rock 57.422222 90.666667 96.266667 1.304878 66.333333 92.946341 3.800000 0.088889
ghost 58.333333 72.740741 79.518519 1.251852 63.370370 69.570370 4.370370 0.037037
grass 59.025641 73.769231 70.871795 0.938961 65.358974 33.255844 3.935897 0.051282
ground 59.968750 94.812500 83.906250 1.340741 73.187500 150.044444 3.343750 0.062500
ice 62.739130 73.304348 71.913043 1.208696 72.086957 103.260870 3.565217 0.086957
bug 63.569444 70.125000 70.847222 0.883333 56.722222 33.083333 3.763889 0.041667
water 63.921053 73.307018 73.482456 1.283333 70.219298 51.071930 3.210526 0.052632
poison 64.187500 72.656250 70.031250 1.160000 65.593750 33.830000 3.093750 0.000000
fighting 64.285714 99.178571 66.392857 1.196429 71.428571 58.675000 3.750000 0.000000
normal 69.533333 75.161905 59.695238 1.024752 76.723810 46.158416 3.495238 0.028571
fire 73.346154 81.500000 67.788462 1.168000 68.730769 66.096000 3.634615 0.096154
psychic 75.150943 65.566038 69.264151 1.063462 72.943396 57.328846 3.849057 0.320755
dark 75.310345 87.793103 70.517241 1.296552 72.551724 69.096552 4.275862 0.103448
dragon 76.111111 106.407407 86.259259 1.937037 79.851852 107.125926 4.296296 0.259259
electric 85.410256 70.820513 61.820513 0.981579 60.512821 37.944737 3.461538 0.128205
flying 99.666667 66.666667 65.000000 1.166667 68.000000 52.000000 5.666667 0.333333

Groupby kann auch genutzt werden um die Anzahl der Elemente in den jeweiligen Gruppen zu zählen:

data_selected.groupby("type1").count()
name type2 speed abilities attack defense height_m hp weight_kg generation is_legendary
type1
bug 72 54 72 72 72 72 72 72 72 72 72
dark 29 20 29 29 29 29 29 29 29 29 29
dragon 27 15 27 27 27 27 27 27 27 27 27
electric 39 13 39 39 39 39 38 39 38 39 39
fairy 18 2 18 18 18 18 18 18 18 18 18
fighting 28 6 28 28 28 28 28 28 28 28 28
fire 52 25 52 52 52 52 50 52 50 52 52
flying 3 2 3 3 3 3 3 3 3 3 3
ghost 27 18 27 27 27 27 27 27 27 27 27
grass 78 41 78 78 78 78 77 78 77 78 78
ground 32 22 32 32 32 32 27 32 27 32 32
ice 23 11 23 23 23 23 23 23 23 23 23
normal 105 44 105 105 105 105 101 105 101 105 105
poison 32 19 32 32 32 32 30 32 30 32 32
psychic 53 18 53 53 53 53 52 53 52 53 53
rock 45 34 45 45 45 45 41 45 41 45 45
steel 24 20 24 24 24 24 24 24 24 24 24
water 114 53 114 114 114 114 114 114 114 114 114

Es ist sogar möglich, mehrere groupby Aktionen zu kombinieren und damit Gruppen und Untergruppen zu erstellen:

data_selected.groupby(["type1", "is_legendary"]).mean(numeric_only=True)
speed attack defense height_m hp weight_kg generation
type1 is_legendary
bug 0 61.565217 67.434783 70.000000 0.839130 55.579710 28.128986 3.652174
1 109.666667 132.000000 90.333333 1.900000 83.000000 147.033333 6.333333
dark 0 73.730769 85.538462 69.500000 0.953846 64.807692 33.165385 4.115385
1 89.000000 107.333333 79.333333 4.266667 139.666667 380.500000 5.666667
dragon 0 68.000000 98.650000 78.900000 1.390000 67.500000 65.065000 4.300000
1 99.285714 128.571429 107.285714 3.500000 115.142857 227.300000 4.285714
electric 0 82.411765 67.000000 59.558824 0.809091 57.294118 31.206061 3.323529
1 105.800000 96.800000 77.200000 2.120000 82.400000 82.420000 4.400000
fairy 0 51.000000 58.058824 66.588235 0.664706 70.882353 12.294118 4.176471
1 99.000000 131.000000 95.000000 3.000000 126.000000 215.000000 6.000000
fighting 0 64.285714 99.178571 66.392857 1.196429 71.428571 58.675000 3.750000
fire 0 72.063830 78.574468 64.553191 1.046667 65.787234 49.395556 3.702128
1 85.400000 109.000000 98.200000 2.260000 96.400000 216.400000 3.000000
flying 0 89.000000 50.000000 57.500000 1.000000 62.500000 46.500000 6.000000
1 121.000000 100.000000 80.000000 1.500000 79.000000 63.000000 5.000000
ghost 0 57.115385 70.923077 78.730769 1.126923 60.038462 43.400000 4.384615
1 90.000000 120.000000 100.000000 4.500000 150.000000 750.000000 4.000000
grass 0 56.554054 70.945946 69.391892 0.930137 64.567568 31.684932 3.837838
1 104.750000 126.000000 98.250000 1.100000 80.000000 61.925000 5.750000
ground 0 57.933333 90.300000 81.166667 1.248000 71.766667 121.328000 3.300000
1 90.500000 162.500000 125.000000 2.500000 94.500000 509.000000 4.000000
ice 0 62.285714 73.857143 69.238095 1.157143 70.857143 102.123810 3.714286
1 67.500000 67.500000 100.000000 1.750000 85.000000 115.200000 2.000000
normal 0 68.166667 73.372549 58.313725 0.979592 75.745098 39.954082 3.470588
1 116.000000 136.000000 106.666667 2.500000 110.000000 248.833333 4.333333
poison 0 64.187500 72.656250 70.031250 1.160000 65.593750 33.830000 3.093750
psychic 0 65.444444 50.138889 57.277778 0.869444 65.194444 24.561111 3.500000
1 95.705882 98.235294 94.647059 1.500000 89.352941 131.056250 4.588235
rock 0 53.975610 88.731707 94.756098 1.297297 64.756098 88.013514 3.658537
1 92.750000 110.500000 111.750000 1.375000 82.500000 138.575000 5.250000
steel 0 49.111111 91.833333 120.444444 1.394444 58.611111 128.483333 4.000000
1 79.000000 96.833333 119.500000 3.316667 91.333333 369.916667 4.833333
water 0 62.212963 71.898148 71.916667 1.227778 69.018519 45.149074 3.157407
1 94.666667 98.666667 101.666667 2.283333 91.833333 157.683333 4.166667

Damit können wir einsehen, welche mittleren Werte ein Pokemon von einem bestimmtem Typ hat, je nachdem ob er „legendary“ ist oder nicht.

19.4. Plotting#

Noch einige kurze Plotting-Beispiele zum Schluss.

Da wir eben groupby benutzt haben, können wir dies auch verwenden um einen Plot zu erzeugen. „stacked=True“ bedeutet hierbei übrigens, dass die verschiedenen Balken aneinander gehängt werden sollen.

cols = ["attack", "defense", "hp", "speed", "weight_kg"]
data_selected.groupby("type1").mean(numeric_only=True)[cols].plot.barh(stacked=True)
<Axes: ylabel='type1'>
../_images/50bae027a93734b23085c53416e0d0ae67ac49b9352b479e05c95572f6b3636e.png

Es gibt schönere Plots, aber zumindest sehen wir so sehr schnell, dass vor allem der Eintrag „weight_kg“ sehr stark von der jeweiligen type1-Gruppe abhängt! Also gleich noch einen Plot dafür hinterher:

data_selected.groupby("type1").mean(numeric_only=True)["weight_kg"].plot.barh()
<Axes: ylabel='type1'>
../_images/13c451150a7c2ae3bfd054e53d8847f36d0ade1282387dae945e24bcf92aa755.png

19.4.1. Intermezzo: data visualization#

Warum ist der Plot hier oben ziemlich mies?

–> Die Reihenfolge macht es sehr unübersichtlich! Stellen Sie sich vor ich frage, welcher Typ auf der Position 3, 4, oder 5 steht…

–> Die Axenbeschriftung bei der x-Achse fehlt.

Allgemein: Pandas plottet mit Hilfe von matplotlib. Für Aufwendigere Grafiken und Anpassungen werden die Plots darum auch mit matplotlib programmiert. Aber Pandas gibt eben einen schnellen Zugang um verschiedene Plots zu erkunden.

Einfache Anpassungen lassen sich auch durchaus gut mit Pandas machen, bzw. können auch matplotlib Befehle mit Pandas kombiniert werden.

Darum hier ein weiterer Versuch:

ax = data_selected.groupby("type1").mean(numeric_only=True)["weight_kg"].sort_values().plot.barh()
ax.set_xlabel("weight [kg]")
Text(0.5, 0, 'weight [kg]')
../_images/6a048947f1b4e4a8ee8e5c0e3e90769b1fc4421f3b387ba99a9e82b726e3d2e4.png

Bei Pandas werden solche Aufrufe schnell sehr lang und kompliziert, da immer mehr und mehr Funktionen/Methoden hintereinander gehangen werden können. Um es etwas übersichtlicher zu machen kann auch mit Zwischenschritten gearbeitet werden!

data_groupby_type = data_selected.groupby("type1")
data_mean_weight = data_groupby_type.mean(numeric_only=True)["weight_kg"]
ax = data_mean_weight.sort_values().plot.barh()
ax.set_xlabel("weight [kg]")
Text(0.5, 0, 'weight [kg]')
../_images/6a048947f1b4e4a8ee8e5c0e3e90769b1fc4421f3b387ba99a9e82b726e3d2e4.png

19.5. Pandas ist riesig!#

Zum Schluss noch der Hinweis, das wir in 2-3, ja auch nicht in 4-5 Vorlesung den Umfang von Pandas abdecken können. Es geht also v.a. darum, dass Sie sich mit dem Umgang mit Pandas und DataFrames vertraut machen und die einfachen Operationen damit ausführen können (z.B. slicing, Sortieren). Für alles weitere können Sie jederzeit in Foren oder auf der Pandas Dokumentation nachschauen, ob es für ihre spezielle Frage nicht schon eine passende Pandas-Methode gibt:

https://pandas.pydata.org/pandas-docs/stable/reference/frame.html