Pandas ist eine Datenanalysebibliothek; sie beruht auf NumPy
import pandas as pd
Beispiel:
Area | Population | Capital | |
---|---|---|---|
CN | 9.6 | 1386 | Beijing |
RU | 17 | 144 | Moscow |
US | 9.8 | 327 | Washington, D.C. |
area = pd.Series({'CN': 9.6, 'RU': 17, 'US': 9.8})
population = pd.Series({'CN': 1386, 'RU': 144, 'US': 327})
area = pd.Series([9.6, 17, 9.8], ["CN", "RU", "US"])
population = pd.Series([1386, 144, 327], ["CN", "RU", "US"])
auslesen eines Werts anhand des Index-Werts:
area['CN'] # 9.6
Jede series hat einen bestimmten Datentyp
area.dtype # float64
manuelles Setzen des Datentyps:
area = pd.Series(
{"CN": 9.6, "RU": 17, "US": 9.8}, dtype="float32"
)
countries = pd.DataFrame(
{"area": area, "population": population}
)
Datenformate:
Die folgenden Funktionen können Daten importieren / exportieren. Beim Importieren können Daten auch aus dem Internet gelesen werden.
Import: pd.read_csv
, pd.read_excel
, ...
Export: df.to_csv
, df.to_excel
, ...
Beispiel: Euribor (Zinsen für europäische Anleihen)
euribor = pd.read_csv(
"https://raw.githubusercontent.com/datasets/euribor/master/data/euribor-12m-monthly.csv"
)
Mögliche Schlüsselwortargumente für read_csv
:
index_col
: identifiziert eine Spalte, die als Index verwendet werden sollheader
: übergeben des Werts None
zeigt an, dass es keine Header-Zeile gibtnames
: Spaltennamen zur Verwendung im neuen DataFrame
sep
: Angeben anderer Trennzeichen als ein Kommausecols
: um nur bestimmte Spalten zu importierenparse_dates
: erwartet eine Liste von Spaltennamendtype
: kann ein Dictionary sein, das Datentypen für bestimmte Spalten spezifiziertSiehe auch: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html
Fortgeschrittenes Euribor-Beispiel:
euribor = pd.read_csv(
"https://raw.githubusercontent.com/datasets/euribor/master/data/euribor-12m-monthly.csv",
parse_dates=["date"],
index_col="date",
usecols=["date", "rate"]
)
Aufgabe: Importiere die folgenden Datenquellen und achte dabei auf passendes Format:
mögliche Lösungen:
sp500 = pd.read_csv(
"https://raw.githubusercontent.com/datasets/s-and-p-500/main/data/data.csv",
index_col="Date",
parse_dates=["Date"],
)
iris = pd.read_csv(
"http://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data",
header=None,
names=["sepal_length", "sepal_width", "petal_length",
"petal_width", "species"],
)
titanic = pd.read_csv(
"https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv",
index_col="PassengerId",
)
benötigt das Paket openpyxl
lesen / schreiben eines einzelnen Excel-Sheets:
pd.read_excel
df.to_excel
lesen / schreiben eines ganzen Dokuments (inklusive Formatierung):
pd.ExcelFile
pd.ExcelWriter
siehe: Dataquest: Tutorial Using Excel with Python and Pandas
benötigt PyTables (Name des Pakets: tables)
euribor.to_hdf("data.hdf5", "euribor")
sp500.to_hdf("data.hdf5", "sp500")
euribor = pd.read_hdf("data.hdf5", "euribor")
für viele Array-Operationen gibt es äquivalente Funktionalität auf Pandas DataFrames / Series:
df.abs()
df1 + df2
df.shape
Umwandlung in NumPy-Arrays:
df.to_numpy()
series.to_numpy()
titanic["Age"].describe()
count 714.000000
mean 29.699118
std 14.526497
min 0.420000
25% 20.125000
50% 28.000000
75% 38.000000
max 80.000000
Name: Age, dtype: float64
(Siehe nächste Folie für Erklärungen)
titanic["Age"].describe()
obiges berechnet die folgenden Daten:
.count()
.mean()
.std()
.quantile(0)
or .min()
.quantile(0.25)
.quantile(0.5)
or .median()
.quantile(0.75)
.quantile(1)
or .max()
Liste einzigartiger Werte:
titanic["Pclass"].unique()
[2, 3, 1]
Zählen einzelner Vorkommen:
titanic["Pclass"].value_counts()
3 491
1 216
2 184
df.index
: Indexwerte der Zeilendf.columns
: Spaltennameneine Spalte (als Series) auswählen:
titanic["Age"]
mehrere Spalten (als DataFrame) auswählen:
titanic[["Name", "Age"]]
kürzere Notation (funktioniert nicht für alle Spaltennamen):
titanic.Age
Fälle, in denen die kürzere Notation nicht verwendet werden kann:
df["first name"] # space in name
df["class"] # reserved word
df["mean"] # existing method
einzelne Zeile als Series:
sp500.loc["1872-01-01"]
mehrere Zeilen als DataFrame (beide Grenzen inklusive):
sp500.loc["1872-01-01" : "1872-12-31"]
wenn die Indexspalte als Datum geparsed wurde:
sp500.loc["2009"]
einzelne Zeile als Series:
sp500.iloc[0]
mehrere Zeilen als DataFrame:
sp500.iloc[0 : 10]
titanic[titanic["Pclass"] == 1]
titanic[titanic["Age"] >= 70]
df.sample()
- ein zufälliger Eintrag)df.sample(5)
- fünf Einträgedf.sample(frac=0.1)
- 10% aller Einträgesp500.iloc[0]
sp500.iloc[-1]
sp500.iloc[-10:]
sp500.sample(10)
sp500.loc["2009-01-01"]
sp500.loc["2009-01-01": "2009-12-31"]
sp500[sp500["Long Interest Rate"] > 14]
wann war der S&P 500 am höchsten Wert? (Bestimme das Maximum, dann suche die zugehörige Zeile im DataFrame)
sp500_max = sp500["SP500"].max()
# returns a DataFrame
sp500_max_row = sp500[sp500["SP500"] == sp500_max]
kürzere Alternative: (via .idxmax()
):
# returns a Series
sp500_max_row = sp500.loc[sp500["SP500"].idxmax()]
titanic[titanic["Survived"] == 0]
titanic[titanic["Age"] == 60]
titanic["Survived"].value_counts()
titanic[titanic["Pclass"] == 1]["Survived"].value_counts()
nach Zeile und Spalte auswählen:
df.loc["2009-01-02", "rate"]
df.iloc[5, 1]
series.sort_values()
df.sort_values("column_name")
df.sort_values(["col1", "col2"])
df.sort_index(ascending=False)
Grundlegende Methode:
titanic[titanic["Pclass"] == 1]
titanic[titanic["Age"] >= 70]
männliche Passagiere in der zweiten oder dritten Klasse:
titanic[(titanic["Pclass"] >= 2) & (titanic["Sex"] == "male")]
Passagiere, die in Southampton oder Queenstown an Bord gingen:
titanic[titanic["Embarked"].isin(["S", "Q"])]
titanic.query("Pclass >= 2 and Sex == 'male'")
titanic.query("Embarked in ['S', 'Q']")
erwachsene (>= 18) Männer, sortiert nach Alter:
titanic[
(titanic["Age"] >= 18) & (titanic["Sex"] = "male")
].sort_values("Age")
erwachsene Ãœberlebende:
titanic[(titanic["Age"] >= 18) & (titanic["Survived"] == 1)]
iris.sort_values(by="petal_length")
iris[iris["species"] == "Iris-setosa"].sort_values(
by="petal_length"
)
Plotting-Funktionalität von pandas basiert auf pyplot (ähnliche Befehle)
grundlegende Funktionalität von pyplot:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([0, 1, 2, 3])
y1 = x*2
y2 = x**2
plt.plot(x, y1)
plt.plot(x, y2)
Resultat:
grundlegende Arten von Plots:
Beispiel für Pyplot-Optionen:
plt.plot(x, y1, color="C3", marker="X", linestyle="dashed")
Wrapper für pyplot-Funktionen, die auf Series- und DataFrame-Objekten existieren:
data.plot()
oder data.plot.line()
data.plot.bar()
data.plot.scatter()
data.plot.hist()
data.plot.box()
data.plot.pie()
Beispiele:
euribor.plot.line()
sp500["SP500"].plot.line()
Beispiel:
euribor.iloc[-12:].plot.bar()
Übung: Stelle den Median der sepal-width und sepal-length für alle drei Arten von Blumen dar
Ãœbung: Histogramm der sepal length
Ãœbung: Box Plots aller Iris-Abmessungen
iris.plot.scatter(
x="sepal_length",
y="sepal_width",
)
mit Größe (s) und Farbe (c):
iris.plot.scatter(
x="sepal_length",
y="sepal_width",
s="petal_length",
c="petal_width"
)
Übung: Scatter plot für iris setosa
data = pd.Series({"a": 50, "b": 30, "c": 20})
data.plot.pie(ylabel="Data")
Verteilung von Titanic-Passagieren in Klassen (1 - 3):
titanic["Pclass"].value_counts().plot.pie()
df.columns = ["name1", "name2"]
Zeilen entfernen:
sp500_new = sp500.drop(["1871-01-01", "1871-02-01"])
Spalten entfernen:
sp500_new = sp500.drop(columns=["Real Earnings", "PE10"])
Konvertieren von Typen:
titanic["Survived"] = titanic["Survived"].astype("bool")
Ersetzen von Werten:
titanic["Female"] = titanic["Sex"].replace(
{"female": True, "male": False}
)
Hinzufügen einer neuen Spalte:
iris["sepal_ratio"] = iris["sepal_length"] / iris["sepal_width"]
iris["sepal_ratio"].mean()
iris["sepal_ratio"].std()
iris_setosa = iris.loc[
iris["name"] == "Iris-setosa"
]
iris_setosa["sepal_ratio"].mean()
iris_setosa["sepal_ratio"].std()
Aufgabe:
Analysiere die monatlichen S&P 500 Daten und berechne den monatlichen Gewinn / Verlust
Hinweis: Verwende die Methode .diff()
, um die Differenz zwischen der vorherigen und der aktuellen Zeile zu berechnen
sp500["Diff"] = sp500["SP500"].diff()
sp500["Gain"] = sp500["Diff"] / sp500["SP500"]
def classifier(age):
if age < 18:
return "youth"
elif age < 60:
return "adult"
else:
return "senior"
titanic["AgeCls"] = titanic["Age"].apply(classifier)
(effizientere Alternative: pd.cut()
)
iris.iloc[0, 0] = 6
iris.loc[:, "sepal_ratio"] = float('nan')
Werte, die fehlende Daten symbolisieren (ab pandas 1.0):
NaN
(wie allgemein in Python üblich)NA
(aus dem Pandas-Paket)titanic["Age"].shape
# (891,)
titanic["Age"].count()
# 714
Anzeigen aller Zeilen mit fehlenden age-Einträgen:
titanic[titanic["Age"].isna()]
Entfernen aller Zeilen mit fehlenden Daten:
titanic = titanic.dropna()
Entfernen aller Zeilen mit fehlenden Daten in der Spalte age:
titanic = titanic.dropna(subset=["Age"])
Ersetzen fehlender Daten durch Nullen:
titanic["Age"] = titanic["Age"].fillna(0)
Ersetzen fehlender Daten durch den letzten gültigen Wert:
titanic["Age"] = titanic["Age"].fillna(method="ffill")
Ersetzen fehlender Daten durch den nächsten gültigen Wert:
titanic["Age"] = titanic["Age"].fillna(method="bfill")
data = pd.Series(
[1, 2, 4, np.nan, 16, 32, np.nan, np.nan, 256]
)
data.interpolate("nearest")
data.interpolate("linear") # default
data.interpolate("slinear")
data.interpolate("quadratic")
data.interpolate("cubic")
Ãœbung:
Verwende die Daten aus sp500 und euribor, um die Entwicklungen der europäischen und amerikanischen Zinssätze einander gegenüberzustellen.
Bemerkung:
sp500 hat Daten für den ersten Tag jedes Monats, euribor hat daten für den ersten Arbeitstag jedes Monats
Lösung:
interest = pd.DataFrame({
"us": sp500["Long Interest Rate"],
"eu": euribor["rate"]
})
interest["eu"] = interest["eu"].interpolate("slinear")
interest = interest.dropna()
Index-Spalte: Spalte, anhand deren Einträge die Zeilen eindeutig identifiziert werden können
Multi-Index: Kombination aus mehreren Spalten zur eindeutigen Identifikation
Beispiel: Exchange rates
Date | Country | Exchange rate |
---|---|---|
1971-01-01 | Australia | 0.894 |
1971-02-01 | Australia | 0.890 |
1971-03-01 | Australia | 0.890 |
Eine Zeile kann durch Kombination von date und country eindeutig identifiziert werden.
Importieren mit Multi-Index:
exchange_rates = pd.read_csv(
"https://datahub.io/core/us-euro-foreign-exchange-rate/r/monthly.csv",
index_col=["Country", "Date"],
parse_dates=["Date"])
In manchen Fällen kann durch einen Multi-Index eine Series anstatt eines DataFrames verwendet werden:
exchange_rates_series = exchange_rates["Exchange rate"]
Abfragen des ersten Teils eines Multi-Index (gitbt eine Series mit nur dem restlichen Index zurück):
exchange_rates_series.loc["France"]
Abfragen mehrerer Teile des Index:
exchange_rates_series.loc["France", "1971-01-01":"1971-12-31"]
Abfragen in einem DataFrame:
exchange_rates.loc[("Australia", "1990"), :]
exchange_rates.loc[(slice(None, None), "1990-01-01"), :]
Bemerkung: x[a:b]
ist in Python äquivalent zu x[slice(a, b)]
Bemerkung: die Date-Spalte könnte aus dem Index via reset_index
entfernt werden
Join: Zusammenführen von mehreren DataFrames oder Series zu einem _DataFrame
Typen:
Joins anhand des Index bei Series
-Objekten:
outer Join:
interest_rates = pd.DataFrame({
"usd": sp500["Long Interest Rate"],
"eur": euribor["rate"]
})
inner Join:
interest_rates = pd.DataFrame({
"usd": sp500["Long Interest Rate"],
"eur": euribor["rate"]
}).dropna()
Joins anhand des Index bei DataFrame-Objekten:
inner Join:
pd.merge(sp500, euribor, left_index=True, right_index=True)
outer Join:
pd.merge(sp500, euribor, left_index=True, right_index=True,
how="outer")
Join anhand bestimmter Spalten (nicht anhand des Index):
sp500_no_index = pd.read_csv(
"https://datahub.io/core/s-and-p-500/r/data.csv",
parse_dates=["Date"],
)
euribor_no_index = pd.read_csv(
"https://datahub.io/core/euribor/r/euribor-12m-monthly.csv",
parse_dates=["date"],
usecols=["date", "rate"]
)
pd.merge(sp500_no_index, euribor_no_index, left_on="Date",
right_on="date")
Kurzform, wenn zugehörige Spalten gleiche Namen haben:
pd.merge(sp500_no_index, euribor_no_index, on="date")
Resultat hat eine date
-Spalte statt zwei
Übung: Ländervergleich (Scatter Plot):
Datenquellen:
Lösung:
gdp = pd.read_csv(
"https://raw.githubusercontent.com/owid/owid-datasets/master/datasets/Maddison%20Project%20Database%202020%20(Bolt%20and%20van%20Zanden%20(2020))/Maddison%20Project%20Database%202020%20(Bolt%20and%20van%20Zanden%20(2020)).csv",
index_col=["Entity", "Year"]
)
gdp_series = gdp["GDP per capita"]
gdp_2018 = gdp_series[:, 2018]
vac = pd.read_csv(
"https://raw.githubusercontent.com/owid/covid-19-data/master/public/data/vaccinations/vaccinations.csv",
index_col=["location", "date"]
)
vac_series = vac["total_vaccinations_per_hundred"]
vac_2021_08 = vac_series[:, "2021-08-01"]
data = pd.DataFrame({"gdp": gdp_2018, "vaccinations": vac_2021_08}).dropna()
data.plot.scatter(x="gdp", y="vaccinations")
siehe auch: https://jakevdp.github.io/PythonDataScienceHandbook/03.07-merge-and-join.html
Beispiele zu den Titanic-Daten:
Aggregation: Berechnung abgeleiteter Werte basierend auf mehreren Einträgen
Funktionen und Methoden:
series.value_counts()
series.groupby()
/ df.groupby()
pd.crosstab()
pd.pivot_table()
Anzahl von Passagieren pro Klasse:
titanic["Pclass"].value_counts()
# 3 491
# 1 216
# 2 184
Mediane aller numerischen Werte der Passagiere je Klasse:
titanic.groupby("Pclass").median()
Median der Alter pro Klasse:
titanic.groupby("Pclass")["Age"].median()
# 1 37.0
# 2 29.0
# 3 24.0
Anzahl der Passagiere nach Klasse und Geschlecht (Kontingenztabelle oder Kreuztabelle)
pd.crosstab(titanic["Pclass"], titanic["Sex"])
sex female male
pclass
1 94 122
2 76 108
3 144 347
Durchschnittliches Alter nach Geschlecht und Klasse:
pd.crosstab(
index=titanic["Pclass"],
columns=titanic["Sex"],
values=titanic["Age"],
aggfunc=np.mean)
pd.pivot_table(
data=titanic,
values="Age",
index=["Pclass"],
columns=["Sex"],
aggfunc=np.mean)
Durchschnittswerte der Iris-Daten basierend auf dem Namen der Art
Durchschnittliche USD-Wechselkurse für jede Währung in den 90ern basierend auf den folgenden Daten:
exchange_rates = pd.read_csv(
"https://datahub.io/core/us-euro-foreign-exchange-rate/r/monthly.csv",
index_col=["Country", "Date"],
parse_dates=["Date"])
iris.groupby("species").mean()
er_90s = exchange_rates.loc[
(exchange_rates["Date"] >= "1990-01-01") &
(exchange_rates["Date"] <= "1999-12-31")
]
er_90s_means = er_90s.groupby("Country").mean()
Basierend auf dem Movielens-Datensatz, finde die top-bewerteten Filme, die von zumindest 10 Nutzern bewertet wurden
ratings = pd.read_csv(
"https://files.grouplens.org/datasets/movielens/ml-100k/u.data",
sep="\t",
header=None,
usecols=[0, 1, 2],
names=["user_id", "movie_id", "rating"],
)
movie_titles = pd.read_csv(
"https://files.grouplens.org/datasets/movielens/ml-100k/u.item",
sep="|",
header=None,
encoding="latin1",
usecols=[0, 1],
names=["movie_id", "title"],
)
movie_names = movie_titles.groupby("movie_id")["title"].first()
movie_mean_ratings = ratings.groupby("movie_id")["rating"].mean()
movie_num_ratings = ratings.groupby("movie_id")["rating"].count()
movie_ratings = pd.DataFrame({
"name": movie_names,
"mean_rating": movie_mean_ratings,
"num_ratings": movie_num_ratings
})
movie_ratings.query(
"num_ratings >= 10 and 4.2 < mean_rating"
).sort_values(by="mean_rating", ascending=False)
Datentypen:
erstellen von Datumsfolgen (als Index-Objekte):
every_day = pd.date_range("2000-01-01", "2000-12-31")
last_of_each_month = pd.date_range(
"2000-01-01", "2000-12-31", freq="M"
)
first_of_each_month = pd.date_range(
"2000-01-01", "2000-12-31", freq="MS"
)
every_10_days = pd.date_range(
"2000-01-01", "2000-12-31", freq="10D"
)
Konvertieren zwischen time stamps und time periods:
.to_period()
.to_timestamp()
(funktioniert auf Index-Objekten und auf Series / DataFrame - Objekten)
Resampling: Berechnen abgeleiteter Daten für andere Zeitintervalle
Beispiel: basierend auf monatlichen Daten:
sp500.resample("Y").mean()
sp500.resample("D").interpolate()
Überprüfen, ob der erste Tag jedes Monats in den S&P 500 Daten vorhanden ist:
sp500.index.equals(
pd.date_range(
sp500.index[0], sp500.index[-1], freq="MS"
)
)
# True
Pandas Cheat Sheet: https://pandas.pydata.org/Pandas_Cheat_Sheet.pdf