Library

Daten analysieren, auswerten und visualisieren – Das Zertifikatsstudium ‚Data Science & Big Data‘ der TU Dortmund

Das Zertifikatsstudium ‚Data Science & Big Data‘ der Technischen Universität Dortmund
Kursstart: Februar 2023

Durch die Digitalisierung stehen Daten heutzutage in unendlichem Maße zur Ver­fü­gung: interne Kundendaten, externe Daten aus sozialen Me­di­en, Markt-, Produktions- oder Logistikdaten, Daten aus dem Internet der Dinge oder aus öf­fent­lich verfügbaren Quellen. Mit Hilfe von großen Datenmengen können beispielsweise das Kaufverhalten von Kunden oder Prozesse in der Logistikbranche analysiert werden. Es genügt nicht, diese Daten bloß zu sammeln – sie müssen ausgewertet und miteinander in Zusammenhang gebracht werden. Es braucht Ex­per­tin­nen und Experten, die die Daten aufbereiten, analysieren, auswerten und vor allem auch darstellen und interpretieren kön­nen, kurzum: Data Scientists.
Das weiterbildende Studium ‚Data Science & Big Data‘ der Technischen Universität Dortmund setzt dort hier an. Datenanalyse, Datenmanagement und die zielgerichtete Darstellung der Ergebnisse sind die Hauptinhalte des Kurses. Vom Management über die Analyse der Daten bis zur zielgerichteten Darstellung der Ergebnisse lernen die Teilnehmenden dabei Methoden der Disziplinen Statistik und Informatik kennen. Dabei vermittelt der Kurs folgende Inhalte:

Datenmanagement (Informationssysteme, Bearbeitung großer Datenmengen in R)
Datenwissenschaft Theorie (z. B. Datendarstellung, Clusteranalyse, Klassifikation, Regression)
Präsentation und Praxis (z. B. Visualisierung, Statistische Versuchsplanung, Fallstudie mit großem Datensatz)

Tiefergehende Informationen zu den Inhalten gibt es unter: https://wb.zhb.tu-dortmund.de/storages/wb-zhb/r/Formulare/Data_Science/Modulinhalte_2020.pdf
Die Übungen mit realen Datensätzen sowie die Option, die Abschlussarbeit auf Basis von eigenen Daten (‚bring your own data‘) zu verfassen, unterstützen den Transfer des Gelernten in die berufliche Praxis.
Der Kurs richtet sich an alle Berufsgruppen, die sich mit dem Management und der Analyse von Daten beschäftigen, wie z. B. Data Scientists, Business Analysten, Softwareentwickler, Consultants, wissenschaftliche Mitarbeitende (universitär oder außeruniversitär) o.ä.
Das Zertifikatsstudium umfasst zehn Termine und dauert neun Monate. Nach erfolgreicher Abschlussprüfung vergibt die Technische Universität Dortmund ein Zertifikat, mit dem der Kompetenzausbau nachgewiesen werden kann. Näheres finden Sie unter:
https://wb.zhb.tu-dortmund.de/datascience
Die Anmeldefrist endet am 18. November 2022; die Kosten betragen 6.900 € (zahlbar in 3 Raten). Wir bieten außerdem zwei Rabattangebote an:

Early Bird: Sie erhalten 5% Preisnachlass auf das Teilnahmeentgelt bei Anmeldung bis zum 30. September 2022.
Weitersagen lohnt sich: Wenn Sie gemeinsam mit einer/einem Kollegin/Kollegen oder mehreren Personen aus Ihrem Unternehmen am Kurs teilnehmen, reduziert sich das Teilnahmeentgelt bei bis zu zwei angemeldeten Personen um 5 % pro Person, darüber hinausgehend zahlt jede weitere Person 10 % weniger.

Kontakt: Daniel Neubauer, daniel.neubauer@tu-dortmund.de / 0231 755 6632
 
 
 

MATPLOTLIB: Charts und Plots in Python

Hej Leute,
in diesem Artikel geht es darum, wie ihr Diagramme und Charts in Python erstellt. Dafür gibt es verschiedene Packages wie Matplotlib, Seaborn, Altair usw, wobei Matplotlib sowas wie der Standard ist. Ein Scatterplot (Punktwolke) oder ein Barplot (Säulendiagramm) mit Matplotlib zu erstellen ist eigentlich ganz einfach. Der Teufel steckt aber im Detail, wenn man Anpassungen wie z.B. Farben, Achsenbeschriftungen vornehmen möchte.
Dieser Artikel gibt Euch einen ersten Einstieg in Python-Charts mit Matplotlib. Aber fangen wir bei den Datenvisualisierungs-Packages an:
 
Welche Daten-Visualisierungs-Bibliothek ist die beste?
Zuerst einmal haben wir die Qual der Wahl, denn Libraries zum Erzeugen von Charts und Diagrammen in Python gibt es einige. Die Frage nach der besten ist so natürlich nicht wirklich zu beantworten, denn alle haben ihre Stärken und Schwächen.
Wichtig ist am Anfang, dass ihr euch auf eine Visualisierungs-Bibliothek festlegt. Später könnt ihr dann weitere in euer Repertoire aufnehmen.

Matplotlib ist der Quasi-Standard, also die am weitesten verbreitete Bibliothek und kein Data Scientist, der in Python programmiert, kommt daran vorbei. Matplotlib kann fast alles. Das ist aber auch das Problem, denn dadurch ist das Interface recht komplex und man braucht mehr Zeilen Code, bis man ein schönes Diagramm gezaubert hat.
Seaborn basiert auf Matplotlib, d.h. es ruft im Hintergrund Matplotlib auf. Das Interface macht es leichter, insbesondere hat Seaborn deutlich schönere Standard-Einstellungen. Damit lassen sich viele Charts mit deutlich weniger Code erstellen. Auf der anderen Seite ist es nicht so flexibel wie Matplotlib und muss dann eben doch darauf zurückgreifen.
Plotly bietet neben vielen Charttypen einiges an Interaktivität wie Reinzoomen oder Mouse-Over-Tooltips out of the box. Plotly gibt es für mehrere Programmiersprachen, also für R, Julia und Javascript.
Bokeh unterstützt wie Plotly ebenfalls interaktive Diagramme und ist zum Beispiel auch für R verfügbar.
Altair bietet ein tolles Abstraktionslevel. Durch eine durchdachte „Grammar of Graphics“ macht es uns die Charterstellung und die Transformation von Daten einfacher. Zudem lassen sich auch mehrere Charts verlinken und interaktiv machen.
ggplot ist in der R-Community der geniale Platzhirsch, an dem kein Weg vorbeiführt. Die gute Nachricht für R-Umsteiger ist, dass es eine Adaption für Python gibt.
Holoviz ist ein ganzes Paket aus verschiedenen Visualisierungstools, also eine Ebene höher. Man kann neben dem mitgelieferten Holoview auch Bokeh, Plotly oder Matplotlib für die zugrundeliegende Visualisierung verwenden.

Ok, das sind ja viel zu viele Optionen, um die Anwendung zu verstehen und die Vor- und Nachteile gegeneinander abzuwägen.
Mein Rat: Fange mit Matplotlib an.
Diese Grafikbibliothek kann zum einen unglaublich viel. Zum anderen ist sie sehr weit verbreitet, dass man früher oder später im Data Science Umfeld auf Code stößt, der Matplotlib verwendet.

Installation von Matplotlib
Falls Du die Python-Distributionen Anaconda oder Miniconda verwendest, gehst Du einfach in das gewünschte Environment. Wenn Du conda-Anfänger bist, dann findest Du in meinem Artikel zur Installation von Anaconda eine Anleitung. Die aktuelle Version von matplotlib ist auf dem conda-forge Kanal zu finden, diesen kannst Du mittels folgenden Befehls als Standardkanal hinzufügen, falls Du das nicht sowieso schon gemacht hast.
conda config --add channels conda-forge
Dann installierst Du matplotlib einfach mit
conda install matplotlib
Falls Du pip als Paketmanager benutzt, dann geht die Installation über
pip install matplotlib
bzw.
python -m pip install matplotlib

Datenanalyse mit Python - 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Punktwolke / Scatterplot mit matplotlib
Ein Scatterplot ist immer dann sinnvoll, wenn man den Zusammenhang zwischen zwei (metrischen) Variablen darstellen möchte. Die Wertepaare (x,y) werden einfach als Punkte eingezeichnet.

Der Code dazu ist ganz einfach:
# Import der Bibliotheken
import matplotlib.pyplot as plt
import numpy as np

# Daten erzeugen
n = 100
x = np.random.normal(0,1,n)
y = np.random.normal(0,1,n)

# Scatterplot
plt.scatter(x, y)
plt.title('Scatter Plot')
plt.xlabel('x')
plt.ylabel('y')

plt.show()

Zuerst werden die Bibliotheken matplotlib.pyplot und numpy mit den üblichen Abkürzungen importiert. Numpy brauchen wir für die Erzeugung der Zufallswerte, denn im zweiten Schritt generieren wir 100 standard-normalverteilte Werte für x und für y.
Dann kommt die eigentliche Plot-Erstellung mittels plt.scatter. Wir versehen den Plot noch mit Titel, x-Achsen- und y-Achsen-Beschriftung. Dann wird er mit plt.show dargestellt.
In einem Jupyter Notebook (Endung .ipynb) wird die Grafik direkt im Notebook angezeigt, egal ob ihr Jupyter Lab oder VS Code benutzt. Als normales Python-Script (Endung .py) hängt es ein bisschen vom Editor ab. VS Code oder PyCharm öffnen unter Windows ein separates Fenster. Das ist das gleiche Verhalten wie direkt von der Konsole aus. Spyder hat einen Tab „Abbildungen“, wo die Grafik angezeigt wird. Spyder gibt aber auch den Hinweis, dass man das auf die Konsole umstellen kann.
Warum habe ich oben eigentlich geschrieben, dass ein Scatterplot nur für metrische Variablen sinnvoll ist? Na ja, hat eine oder beide Variablen nur wenige Werte (also z.B. nur 0 und 1) oder ist kategoriell, dann kann man zwar so einen Scatterplot zeichnen, sieht aber nicht viel, weil es auf der einen Achse bzw. auf beiden Achsen nur wenige Werte gibt. Daher liegen viele Punkte übereinander.

# Daten erzeugen
n = 100
x = np.random.binomial(1, 0.2, n)
y = np.random.binomial(3, 0.5, n)

# Scatterplot
plt.scatter(x, y)
plt.title("Scatter Plot")
plt.xlabel("x")
plt.ylabel("y")
plt.show()

Im Package seaborn gibt es Abhilfe, denn dort gibt es die Funktionen stripplot und swarmplot:

Stripplot mit seaborn

Swarmplot mit seaborn

Und hier der Code für die Stripplot und Swarmplot mittels des Python-Packages seaborn:
import seaborn as sns
import pandas as pd

# Daten erzeugen
n = 100
x = np.random.binomial(1, 0.2, n)
y = np.random.binomial(3, 0.5, n)
df = pd.DataFrame({'x':x, 'y':y})

sns.swarmplot(x='x',y='y',data=df)
# despine entfernt den oberen und rechten Rand, es bleiben die Achsen
sns.despine()

sns.stripplot(x='x', y='y', data=df, size=16, alpha=.2, jitter=True, edgecolor='none')
sns.despine()

Barcharts/Säulendiagramme in Matplotlib bzw. Seaborn erstellen
Säulen- oder Balkendiagramme gehören zu den beliebtesten Charttypen, sind sie doch meist schnell erstellt und intuitiv zu verstehen.
In einem Säulendiagramm werden auf der x-Achse Kategorien abgetragen. Zu jeder Kategorie gibt es eine Säule, deren Höhe durch den darzustellenden Wert auf der y-Achse bestimmt ist. Nehmen wir zum Beispiel ein Säulendiagramm zu Haustieren in Deutschland. Dabei gibt es 4 Säulen für Katzen, Hunde, Kleintiere und Ziervögel. Die Höhe der Säulen entspricht der Anzahl der jeweiligen Art in Deutschland.

In Matplotlib ist das ganz einfach mit der Funktion plt.bar realisiert. Wir ergänzen noch die Beschriftung der Achsen sowie den Titel. Schließlich entfernen wir die Markierungsstriche auf der x-Achse.
tiere = ('Katzen', 'Hunde', 'Kleintiere', 'Ziervögel')
anzahl = [15.7, 10.7, 5, 3.5]

y_pos = np.arange(len(tiere))

plt.bar(y_pos, anzahl, align='center')
plt.xticks(y_pos, tiere)
plt.ylabel('Anzahl in Millionen')
plt.title('Haustiere in Deutschland (2020)')
# Striche auf x-Achse ausschalten
plt.tick_params(
axis='x',
which='both', #major und minor ticks
bottom=False # ticks auf der x-Achse (unten)
)
plt.show()

Statt eines umschließenden Rands, also einem Diagramm in einer Box, wollen wir nur die x- und y-Achse haben. Wir müssen dazu den rechten und oberen Rand entfernen. Das geht in Matplotlib mit dem Attribut spines, allerdings ist das ein Attribut der Achsen. Diese müssen wir uns also mit der Funktion gca() erst holen.

ax = plt.gca()
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)

Mit dem Package seaborn geht es einfacher, denn dort gibt es die Funktion despine, die genau die rechte und obere Achse entfernt.

# Barplot in Seaborn
df = pd.DataFrame({'Tiere':tiere, 'Anzahl':anzahl})

sns.set_theme(style="ticks", palette=None)
g = sns.barplot(x='Tiere', y='Anzahl', data=df, color='#69d')
g.set(xlabel = None, ylabel='Anzahl in Millionen', title='Haustiere in Deutschland (2020)')
g.tick_params(bottom=False)
sns.despine()

Balkendiagramm in Matplotlib
Ein Balkendiagramm ist übrigens einfach nur ein Säulendiagramm mit vertauschten Achsen. Dann befinden sich die Kategorien auf der y-Achse und die Länge der Balken entspricht dem Wert auf der x-Achse. Balkendiagramme eignen sich besonders, wenn man lange Kategorienamen hat oder wenn man viele Kategorien hat.
In Matplotlib gibt es für Balkendiagramme die Funktion barh(). Natürlich müssen wir jetzt die Anpassungen der Achsen vertauschen.

# Balkendiagramm in matplotlib
plt.barh(y_pos, anzahl, align='center')
plt.yticks(y_pos, tiere)
plt.xlabel('Anzahl in Millionen')
plt.title('Haustiere in Deutschland (2020)')
plt.tick_params(
axis='y',
which='both', #major und minor ticks
left=False # ticks auf der y-Achse (links)
)
ax = plt.gca()
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)

plt.show()

Matplotlib Colors – Bringt Farbe in Eure Python Charts
Der aufmerksame Leser (Du bist bestimmt einer 😉) hat schon entdeckt, dass ich im Seaborn-Barplot Codebeispiel die Füllfarbe der Säulen mittels color gesetzt habe. Das geht auch in den normalen Matplotlib-Diagrammen, also als Parameter in der Funktion plt.bar() bzw. plt.barh().
Dabei hat man mehrere Möglichkeiten, die Farbe anzugeben:

Als Tupel mit RGB-Werten zwischen 0 und 1, also zuerst der Wert für Rot, dann für Grün und schließlich für Blau: (0.4, 0.2, 0.1)
Als Tupel mit RGBA-Werten zwischen 0 und 1. Hier kommt zu den RGB-Werten noch ein vierter Wert, nämlich der alpha-Wert für die Sichtbarkeit/Transparenz. Dabei bedeutet 1 undurchsichtig und 0 vollständig transparent, bei 0 sieht man also die Farbe gar nicht mehr.
Man kann auch einen String mit den RGB-Werten in Hexadezimal-Schreibweise benutzen. Dabei hat man für jede der drei Grundfarben Werte zwischen 0 und 255, damit diese aber in zwei Zeichen passen, benutzt man das 16er-System mit den Ziffern 0-9, A, B, C, D, E, F. Die Zahl 11 entspricht also B, die Zahl 44 entspricht 2C (= 2*16 + 12) und 255 ist FF. Aber keine Sorge, fast jedes Grafikprogramm oder Browser-Plugins geben Euch den Code für eine Farbe aus. Der sieht dann so aus: „#33AF43“
Wollen wir wieder Transparenzen hinzufügen, dann ergänzen wir zwei Hexadezimal-Ziffern am Ende für den Alpha-Wert.
Es sind auch eine ganze Reihe von Farben definiert, die man einfach per Namen benutzen kann, z.B. „aquamarine“, „mediumseegreen“ usw. Diese entsprechen dem X11/CSS4-Standard (ohne Leerzeichen) und man findet eine Liste z.B. auf Wikipedia in dem X11 color names Artikel

plt.bar(y_pos, anzahl, align='center', color='#AA007F')
plt.xticks(y_pos, tiere)
plt.ylabel('Anzahl in Millionen')
plt.title('Haustiere in Deutschland (2020)')
plt.tick_params(
axis='x',
which='both', #major und minor ticks
bottom=False # ticks auf der x-Achse (unten)
)
ax = plt.gca()
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)

plt.show()

Fazit
Kenntnisse in matplotlib sind ein Muss für jeden Data Scientisten, der in Python programmiert. Auch wenn andere Packages zum Teil eleganter und systematischer sind, so ist die Popularität von Matplotlib ungebrochen. D.h. in der Praxis begegnet einem irgendwann auf jeden Fall Matplotlib-Code, den man verstehen bzw. anpassen muss.
Matplotlib ist eine umfangreiche Bibliothek. Wir haben hier natürlich nur an der Oberfläche gekratzt. Aber so habt ihr schon mal einen ersten Eindruck, wie die Erstellung von Charts in Matplotlib funktioniert.
Happy Data Visualisierung,
Euer Holger

Datenanalyse mit Python - 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Glossar: barplot R (Programmiersprache) Anaconda

ggplot2 – so erstellst Du Charts in R

Um Charts in R zu stellen, führt eigentlich kein Weg an dem R-Paket ggplot2 vorbei. Egal, ob Du ein barplot in R, also Säulen- bzw. Balkendiagramm, oder ein pie chart aus Deinen Daten erstellen willst. Für die meisten Charttypen hat ggplot eine entsprechende Visualisierung.
Natürlich können viele Charts auch schon mit Base-R erstellt werden, aber ggplot2 hat durch die „grammar of graphics“ eine etwas klarere Struktur. Man programmiert eher, wie der Graph aussehen soll (deklarativ) und weniger, welche Schritte man machen muss (iterativ). Wer möchte, kann auf Englisch über die Vor- und Nachteile in den Artikeln „Why I use ggplot2“ von David Robinson oder „Why I don’t use ggplot2“ von Jeff Leek nachlesen. Meiner Meinung nach lohnt es sich aber auf jeden Fall, die Syntax von ggplot2 zu lernen.
 
Das R-Package ggplot2 installieren
Sofern Du eine Internet-Verbindung hast, wie alle Packages mit der Funktion install.packages, also
install.packages("ggplot2")
Bei Packages ist es so, dass sie einmalig installiert werden müssen. Willst Du deren Funktionen dann in einem R-Skript verwenden, bindest Du das Package mit library oder require am Anfang vom Skript ein. Hierbei sind die Anführungsstriche nicht mehr nötig.
library(ggplot2)
#oder
require(ggplot2)

 
Scatterplots bzw. Punktwolken mit ggplot2
Eine Punktwolke (Scatterplot) stellt ist einfach eine Ansammlung von Punkten, welcher aus zwei Werten besteht. Jeder Punkt wird in einem Koordinatensystem dargestellt, indem der eine Wert auf der x-Achse und der andere auf der y-Achse abgetragen wird.
Scatterplots sind gut geeignet, um die Beziehung zwischen zwei Variablen zu visualisieren. Haben wir zum Beispiel einen Datensatz, in dem Größe und Gewicht von Studienteilnehmern erhoben wurden, können wir die Größe auf die x-Achse und das Gewicht auf die y-Achse legen. Jeder Punkt entspricht dabei einem Studienteilnehmer, also einer Zeile in unserem Datensatz. Haben wir verschiedene Gruppen (z.B. Treatment- und Kontrollgruppe), können wir die Punkte entsprechend färben, um Unterschiede zu verdeutlichen.
Scatterplots funktionieren nur bei metrischen Merkmalen gut. Haben wir zum Beispiel zwei ordinale Merkmal mit jeweils 3 Ausprägungen, würden alles Punkte mit denselben Ausprägungen übereinanderliegen. Man kann umgehen, indem man die Punkte zufällig ein bisschen verschiebt. Meistens ist aber ein Bubblechart besser geeignet, indem nur ein Punkt (eine Bubble) gezeichnet wird, dessen Größe aber der Anzahl der Datensätze mit dieser Ausprägung entspricht.
In ggplot2 zeichnet man ein Scatterplot mit geom_point(). Die Variablen, die wir auf die x- und y-Achse legen wollen, werden in der Hauptfunktion in den aesthetics angegeben.

n <- 100
df <- data.frame(x = rnorm(n), y = rnorm(n, sd=0.5))

ggplot(df, aes(x = x, y=y)) +
geom_point()

Um zwei Gruppen per Farbe zu uterscheiden, wählt man in den aesthetics die Gruppe als Farbe (color). Dabei muss man beachten, dass das Merkmal ein Faktor ist, ansonsten bekommen wir eine kontinuierliche Farbskala.

n <- 100
df <- data.frame(x = rnorm(n), y = rnorm(n, c(0,1), 0.5), gruppe = 1:2)

ggplot(df, aes(x = x, y=y, color=as.factor(gruppe))) +
geom_point() +
labs(color = "Gruppe")

GRATIS 5-Tage Minikurs: Datenanalyse in R

Du kennst Dich noch nicht so gut damit aus, wie man einen Datensatz in R analysiert? Ich bin da, um Dir zu helfen. Hole Dir jetzt meinen kostenlosen Datenanalyse mit R – Kurs und fange an, Dir diese zukunftsweisenden Skills anzueignen.

Ein Barplot in R erstellen – Säulendiagramme und Balkencharts
Mit Barplot meint man Balken- oder Säulendiagramm. Das Säulendiagramm hat vertikale Säulen, das Balkendiagramm ist um 90° gedreht und hat dementsprechend horizontale Balken. Jede Säule/Balken steht für eine Kategorie. Die Höhe der Säule bzw. Länge des Balkens entspricht dem Wert, den man visualisieren will, zum Beispiel den Umsatz.
Meistens lässt sich ein Säulendiagramm intuitiv erfassen. Bei vielen Kategorien bzw. langen Kategorienamen ist das Balkendiagramm besser geeignet.
In ggplot2 erzeugt man einen barplot mit geom_bar(). Fügt man keine Parameter hinzu, dann wird als Höhe die Anzahl der Datenpunkte mit der entsprechenden Ausprägung verwendet.
df <- data.frame(lieblingsfarbe = c("rot","grün","rot","blau","grün","blau","blau"))
ggplot(df, aes(x = lieblingsfarbe)) +
geom_bar()

Um die Säulen entsprechend der Lieblingsfarbe zu färben, setzen wir den Parameter fill ebenfalls auf die Variabe. Zusätzlich geben wir mit scale_fill_manual noch an, mit welchen Farben wir die Säulen füllen wollen.

df <- data.frame(lieblingsfarbe = c("rot","grün","rot","blau","grün","blau","blau"))
ggplot(df, aes(x = lieblingsfarbe, fill = lieblingsfarbe)) +
geom_bar() +
scale_fill_manual(values = c("rot" = "darkred", "grün" = "darkgreen", "blau" = "darkblue"))

Hat man schon eine Spalte mit Werten, die der Höhe entsprechen soll, ergänzt man diese Variable als y-Wert in den aesthetics und muss zudem in geom_bar die Zählmethode (stat) auf identity stellen. Wir wollen ja nichts berechnen, sondern einfach die Werte nehmen.

df <- data.frame(quartal = c("2021-Q1","2021-Q2","2021-Q3","2021-Q4"),
umsatz = c(150000,180000,160000,200000))
ggplot(df, aes(x = quartal, y = umsatz)) +
geom_bar(stat = "identity")

LERNE DATA SCIENCE mit R

Ein Data Science Experte ist in der heutigen datengetriebenen Welt viel gefragt. Mit der entsprechenden Erfahrung kann man sich den gutbezahlten, interessanten Job aussuchen. In meinem Onlinekurs Data Science mit R lernst Du die Grundlagen.

Jetzt informieren

Balkendiagramm in R
Wie gesagt ist ein Balkendiagramm nur ein um 90° gedrehter Säulenchart, wir können also den gleichen Befehl zum Erstellen eines barplots in R nutzen und vertauschen dann einfach nur die Achsen. Das geht über den Befehl coord_flip().

df <- data.frame(quartal = c("2021-Q1","2021-Q2","2021-Q3","2021-Q4"),
umsatz = c(150000,180000,160000,200000))
ggplot(df, aes(x = quartal, y = umsatz)) +
geom_bar(stat = "identity") +
coord_flip()

Ein Chart aus ggplot als Datei abspeichern
Es gibt zwei Möglichkeiten, ein Diagramm als Datei abzuspeichern. Entweder benutzt man die in R eingebauten Funktionen, die auch für die Base-R-Grafiken verwendet werden oder man ruft die Funktion ggsave() auf.
Grafik mit ggplot speichern
Ggplot liefert die Funktion ggsave() mit, um ein Diagramm in eine Datei zu schreiben. Der minimale Aufruf bekommt einfach nur einen Dateinamen. Ggsave erkennt an der Endung das Format und speichert den letzten Plot in die Datei. Man kann aber natürlich mehr Parameter übergeben:

filename: der Dateiname
plot: die Variable, die das Diagramm enthält
path: Ordner, in dem die Datei gespeichert werden soll
width, height, units, dpi: Mit diesen 4 Parametern kann man die Größe des Charts definieren. Unit kann dabei als „in“, „cm“, „mm“ oder „px“ gewählt werden. Dpi (dots per inch) gibt die Auflösung an, also zum Beispiel 300 für gute Druckqualität
scale: Alternativ bzw. zusätzlich kann noch ein Skalierungsfaktor angegeben werden. Wählt man zum Beispiel scale=2, dann verdoppelt man die Größe der Grafik.

g <- ggplot(df, aes(x = quartal, y = umsatz)) +
geom_bar(stat = "identity") +
coord_flip()
g

# minimaler Aufruf: speichert das letzte Diagramm
ggsave("grafik.png")

# und hier mit einigen Parametern versehen
ggsave(filename="grafik.png", plot=g, width=6, height=4, unit="cm", dpi=300)
 
Grafik mittels Base-R speichern
Der in Base-R vorgesehene Weg, eine Grafik zu speichern, sieht vor, zuerst ein sogenanntes „graphic device“ zu öffnen, dann über print die Grafik dorthin zu drucken und dann das device wieder zu schließen. So ein Device ist im Prinzip einfach eine Verbindung zu einer Datei und gibt es für viele verschiedene Formate:

pdf("grafik.pdf")
svg("grafik.svg")
png("grafik.png")
jpeg("grafik.jpg")
tiff("grafik.tiff")

Mit dev.off() wird das device wieder geschlossen.
Im Ganzen sieht das dann so aus. Wir erstellen ein ggplot-Diagramm und speichern es in der Variable g. Das Device wird geöffnet, g gedruckt und das Device wieder geschlossen
g <- ggplot(df, aes(x = quartal, y = umsatz)) + geom_bar(stat = "identity") + coord_flip()g
svg("grafik.svg")print(g)dev.off()
 
 

Ggplot2 color - So änderst Du die Farbe
Je nach Diagramm-Typ lässt sich die Farbe mit den Parametern fill und/oder color verändern. Die Farbe könnt ihr entweder als Wort wie „darkred“ oder über den Hex-RGB-Code „#AA00BB“ angeben. Die in R definierten Farbworte findet ihr zum Beispiel in diesem PDF der Columbia University.
Der Hex-Code setzt sich aus den drei Farben Rot, Grün und Blau zusammen, die jeweils Werte von 0-255 haben. Damit die Zahl aber zweistellig bleibt, benutzt man das Hexadezimal- (16er-)System. Da folgt auf die Ziffern 0-9 noch die Buchstaben A, B, C, D, E, F. Nach 9 kommt also nicht 10, sondern A. Aber keine Sorge, fast jedes Grafikprogramm kann den Hexcode ausgeben. Es gibt auch Browser-Plugins, die das können.
Bei mehreren Farben, zum Beispiel für verschiedene Gruppen, könnt ihr auf vordefinierte Paletten zugreifen oder die Farben selber definieren. Letzteres haben wir oben schon im Lieblingsfarben-Beispiel gehabt. Das geht über die Funktion scale_fill_manual bzw. scale_color_manual.
 
Das Package RColorBrewer liefert viele Farbpaletten mit. Diese können per  + scale_fill_brewer(palette=“Palettenname“) aktiviert werden.

Welche ggplot2 themes gibt es?
Ggplot kommt mit einigen Standard-Themes, die aber natürlich alle weiter angepasst werden können.

theme_grey() bzw. theme_gray(): Das Standard-Theme von ggplot2 mit grauem Hintergrund und weißen Gitterlinien
theme_bw(): weißer Hintergrund, keine Gitterlinien und schwarzer Rahmen um die Grafik
theme_linedraw(): wie theme_bw, aber mit schwarzen Gitterlinien
theme_light(): wie theme_linedraw, aber Rahmen und Gitterlinien sind hellgrau
theme_dark(): wie theme_light, aber mit dunkelgrauem Hintergrund
theme_minimal(): minimalistisch, weißer Hintergrund, weder Rahmen, Achsen noch Gitterlinien
theme_classic(): weißer Hintergrund, schwarze Achsen
theme_void(): leeres Theme, um darauf weiter aufzubauen

theme_gray()

theme_bw()

theme_linedraw()

theme_light()

theme_dark()

theme_minimal()

theme_classic()

theme_void()

Mit dem theme()-Befehl könnt ihr alles so verändern, wie ihr es benötigt. Es ist allerdings ein bisschen aufwändig, da man logischerweise jede Änderung definieren muss. Man kann sich aber auch ein theme definieren und in einer Variablen abspeichern. Beim ggplot-Aufruf fügt man dann einfach die Variable hinzu. Doch dazu ein anderes Mal mehr.
 
Das waren nur einige wenige Aspekte von ggplot2. Es gibt aber unzählige Charttypen und Individualisierungsoptionen.
Happy charting,
Euer Holger

LERNE DATA SCIENCE mit R

Ein Data Science Experte ist in der heutigen datengetriebenen Welt viel gefragt. Mit der entsprechenden Erfahrung kann man sich den gutbezahlten, interessanten Job aussuchen. In meinem Onlinekurs Data Science mit R lernst Du die Grundlagen.

Jetzt informieren

Glossar: barplot R (Programmiersprache) Anaconda rnorm

Buchreview: Praktische Statistik für Data Scientists

In diesem Review möchte ich Euch das Buch „Praktische Statistik für Data Scientists“ von Peter & Andrew Bruce sowie Peter Gedeck vorstellen. Das Buch ist 2021 im O’Reilly Verlag erschienen, kostet als Taschenbuch 39,90€ und ist auch als Ebook erhältlich.
Inhalte von „Praktische Statistik“
Wie der Titel schon verrät, enthält das Buch eine Übersicht der wichtigsten statistischen Konzepte, mit denen Data Scientisten arbeiten. Dabei unterteilen die Autoren ihr Buch in diese Kapitel:

Explorative Datenanalyse
Daten- und Stichprobenverteilungen
Statistische Versuche und Signifikanztests
Regression und Vorhersage
Klassifikation
Statistisches maschinelles Lernen
Unüberwachtes Lernen

Jedes Kapitel enthält verschiedene Unterkapitel, zu denen auch immer weiterführende Literatur angegeben ist und am Ende eines Kapitels eine Zusammenfassung. Zudem gibt es viele Kästchen mit Schlüsselbegriffen oder den Kernideen. Zudem gibt es Abschnitte mit den typischen O’Reilly Tiersilhouetten mit wertvollen Tipps und Warnungen:

Das gesamte Inhaltsverzeichnis findet ihr auf der hier verlinkten dpunkt-Seite.
Explorative Datenanalyse
In diesem Kapitel werden die Statistik-Basics erklärt, also z.B. was sind Mittelwert, Median und Standardabweichung. Auch einige Visualisierungen wie Boxplot oder Histogramm, natürlich mit zugehörigem Code, werden gezeigt, um die Daten(-verteilung) besser zu verstehen. Schließlich geben die Autoren noch Methoden an, um den Zusammenhang zwischen zwei oder mehr Variablen zu berechnen oder in Grafiken darzustellen.
Daten- und Stichprobenverteilungen
Im Wesentlichen werden die verschiedenen Verteilungen wie Normal-, t-, Binomialverteilung vorgestellt. Besonders wichtig ist aber der Anfang vom Kapitel, in dem über Stichprobengröße, Verzerrungen, Konfidenzintervalle und alles, was dazugehört, berichtet wird. Dieser Part hätte aus meiner Sicht noch ausführlicher sein können, denn da stecken einige der wichtigsten Kernideen der Statistik dahinter, die erfahrungsgemäß Einsteigern Probleme bereiten.
Statistische Versuche und Signifikanztests
Das Kapitel könnte auch Hypothesentests heißen. Es geht also darum, wie man Unterschiede oder Gleichheiten anhand von Stichproben statistisch signifikant beweisen kann. Die wichtigsten Standardtests wie t-Test, Chi-Quadrat-Test oder auch der exakte Test nach Fisher sind aufgeführt.
Regression und Vorhersage
Die Klasse der Regressionsalgorithmen ist eines der Standardwerkzeuge von Data Scientists, denn damit lassen sich Zusammenhänge zwischen Variablen untersuchen, aber auch Prognosen treffen. In diesem Kapitel geht es vor allem um die lineare Regression für metrische Variablen (Größe, Gewicht, Preis) und die Interpretation der zugehörigen Kennzahlen wie Residual Standard Error, R² usw.
Klassifikation
In der Realität hat man es meist nicht mit metrischen Merkmalen zu tun, sondern mit Variablen, die nur einige Ausprägungen haben, z.B. ja oder nein, Kategorien (nominalen oder ordinalen Merkmale). Hierbei kommen Klassifikations-Verfahren wie Naive Bayes oder logistische Regression zum Einsatz.
Statistisches maschinelles Lernen
In diesem Kapitel werden einige Algorithmen vorgestellt, die zur Klasse des überwachten Lernens gehören. Dabei werden anhand eines Trainingsdatensatz die Parameter des Algorithmus so eingestellt, dass Fehlklassifikationen möglichst selten vorkommen. In diesem Kapitel werden k-nearest-neighbor, Entscheidungsbäume und Ensemble-Algorithmen wie Random Forest oder XGBoost erklärt.
Unüberwachtes Lernen
Beim unüberwachtem Lernen geht es allgemein gesagt darum, Muster in den Daten zu finden. Clustering-Algorithmen wie der k-Means-Algorithmus sortieren die Datenpunkt anhand der „Nähe“ zueinander in Klassen einzuteilen.
 „Praktische Statistik für Data Scientists“ in Zahlen

Autoren: Peter Bruce, Andrew Bruce, Peter Gedeck
Erscheinungsdatum:04.2021 (Übersetzung der 2. Auflage)
Seitenanzahl: 374
Format: 23,3 x 16,7 cm, 2,5cm dick
Verlag: O’Reilly
Codebeispiele: R und Python
Preis: Taschenbuch 39,90€, Ebook 31,99€
ISBNs:

Print: 978-3-96009-153-0
Bundle (print + digital): 978-3-96010-470-4
PDF: 978-3-96010-467-4
ePub: 978-3-96010-468-1
Mobi: 978-3-96010-469-8

Auf Amazon kaufen!

Codebeispiele in R und Python
Zu jedem Konzept gibt es auch immer ein kurzes Codebeispiel in R und in Python. Meine Vermutung ist, dass zuerst die R-Beispiele vorhanden waren und dann eine „Übersetzung“ für Python gemacht wurde, da Python im Data Science Bereich immer populärer wird. Trotzdem ist auch der Python-Code von guter Qualität. Code, der zum Laden der benötigten Pakete und Datensätze nötig ist, ist nicht mit abgedruckt, um Platz zu sparen und Wiederholungen zu vermeiden. Das ist sehr zu begrüßen. Den vollständigen Code findet ihr in einem zugehörigen Githib-Repository.

Um die Beispiel zu verstehen, sollte man schon ein bisschen mit der Programmiersprache gearbeitet haben. Es werden keine Grundlagen wie Datentypen oder Standard-Funktionen von R oder Python erklärt, aber das würde auch den Rahmen sprengen und es gibt genug Quellen dafür. Zum Beispiel hier auf dem databraineo-Blog, zum Beispiel Datentypen in R – einfach erklärt oder Erste Schritte mit Python.
Fazit
Um es vorweg zu nehmen: „Praktische Statistik für Data Scientists“ ist ein sehr gelungenes Buch, dass ich jedem angehenden Data Scientisten empfehlen kann.
Die populärsten, für die Praxis relevanten statistischen Konzepte und Grundzüge des maschinellen Lernens werden angesprochen. Dieser umfassende Ansatz ist vielleicht gleichzeitig ein Nachteil, denn bei diesem Umfang kann nicht groß in die Tiefe gegangen werden. Auf der anderen Seite bekommt man so einen hervorragenden Überblick über dieses umfangreiche Thema. Und das ist vermutlich für die Praxis genau das richtige, denn zuerst muss man wissen, welche Methode oder Algorithmus für die Problemstellung geeignet ist. Will man dann weiter optimieren, betreibt man eh noch einmal Recherche zu dem speziellen Verfahren. Im Prinzip muss jeder selber wissen, ob er lieber mit einem Überblicksbuch arbeiten möchte oder direkt tiefer in weniger Themen einsteigen will.
Bleibt noch zu klären, ob das Buch auch für Statistik-Neulinge geeignet ist. Das fällt mir ehrlich gesagt ein bisschen schwer zu beurteilen, denn man vergisst schnell, welche Mühe einige Konzepte einem am Anfang machen. Beim Lesen des Buchs konnte ich dementsprechend meist einfach nicken und in meiner mentalen Checkliste abhaken, dass die wichtigsten Punkte genannt wurden. Ich denke aber, wenn man das Buch intensiv liest und nicht einfach überfliegt, kommt man auch als Anfänger gut damit klar.
Also mein Fazit: „Praktische Statistik für Data Scientists“ lohnt sich, hier kann man ohne Reue zugreifen.
 
Happy reading, Euer Holger

Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median

Overfitting im Machine Learning – Was ist das und wie vermeidet man es?

Overfitting ist eine der größten Stolpersteine im Machinellen Lernen. Jeder, der mit Daten zu tun hat, ist in diese Falle schon mal gelaufen. Hoffentlich wurde es bemerkt, denn ansonsten waren die gefunden Zusammenhänge oder der Prognose-Algorithmus für die Tonne. Muss man so hart sagen.
In diesem Artikel erfährst Du alles über Overfitting, aber auch Underfitting, und warum es so wichtig ist, das Problem in den Griff zu bekommen.

Inhalt
ToggleWas ist Overfitting?Ist Underfitting eigentlich auch ein Problem?Wie vermeidet man Overfitting?Aufteilung in Trainings- und TestdatensatzUnd was ist der Validierungsdatensatz?
Was ist Overfitting?
Overfitting bedeutet übersetzt Überanpassung und bezeichnet eben die Überanpassung von Algorithmen bzw. deren Parameter an die beobachteten Daten. Im Machine Learning Kontext bedeutet das, der Algorithmus lernt im Prinzip den Datensatz „auswendig“, erkennt aber nicht das zugrundeliegende Muster oder System. Damit sind Prognosen, die der Algorithmus aus noch unbekannten Daten liefern soll, nicht sonderlich gut.
Auch in der Datenanalyse kommt es häufig zu Overfitting. In diesem Kontext werden Muster und Zusammenhänge erkannt, die aber eigentlich gar nicht vorhanden sind.
Nehmen wir als Beispiel eine Kurve durch vier Punkte. Statt einer Geraden durch die Punkte zu legen (als Python-Nutzer kannst Dir mein Praxis-Tutorial zur linearen Regression anschauen) könnten wir auch ein Polynom dritten Grades durch die Punkte legen. Das passt ja viel besser, denn die Kurve führt genau durch die Punkte, dementsprechend ist der Fehler 0.

Ok, also was ist eigentlich das Problem hinter der Sache? Im Prinzip verwendet man ein zu komplexes Modell, das zwar genau auf den vorhandenen Datensatz passt, aber keine Verallgemeinerungskraft besitzt.
y = a*x³ + b*x² + c*x + d
Aber Moment, wenn wir a und b gleich Null setzen, haben wir ja die einfache Geradengleichung. Also theoretisch sollte auch das komplexere Modell den richtigen Zusammenhang finden. Das eigentliche Problem liegt also nicht direkt in der Modellwahl, sondern in der Anzahl verfügbarer Parameter. Dabei geht es nicht um die absolute Anzahl Parameter, sondern um das Verhältnis zwischen der Anzahl Parameter und der Anzahl Beobachtungen. Gibt es genug Beobachtungen, sollte der Algorithmus erkennen, dass die Koeffizienten a und b Null oder nahe bei Null sein sollten.
Nehmen wir an, wir haben 100 Beobachten. Dann scheint es zu funktionieren. Das Verhältnis zwischen 100 Beobachtungen und 4 Parametern ist gut genug.

 

a

b

c

d

tatsächlicher Wert

0

0

3

0

Regression mit Polynom 3.Grades

0,007271

0,004726    

2,987975    

0,078643    

Neuronale Netze, die aktuell modernste Form der Machine Learning Algorithmen, sind strukturell zwar komplizierter als so eine lineare Regression, aber das Prinzip ist das Gleiche. Wir haben Parameter, welche anhand eines Datensatzes bestimmt werden. Jetzt ist es aber so, dass die Anzahl Parameter mit der Größe bzw. Tiefe des neuronalen Netzes explodiert. Die große Version von OpenAI GPT-3, der aktuell wahrscheinlich mächtigsten künstlichen Texterzeugung, hat stolze 175 Milliarden Parameter. Dementsprechend wurde GPT-3 mit den größten Textdatensätzen gefüttert, die zur Verfügung stehen, insgesamt waren das auch mehrere hundert Milliarden Wörtern.
Das ist vielleicht ein Extrembeispiel, aber viele sich im Einsatz befindenden neuronalen Netze haben mehrere Millionen Parameter. Und damit wird dann auch klar, warum man so große Datenmengen benötigt, um diese Machine Learning Algorithmen vernünftig zu trainieren. Irgendwie müssen diese vielen Parameter eingestellt werden. Der Mensch hingegen ist ziemlich gut darin, aus wenigen Beispielen zu lernen. Daher wird auch daran geforscht, wie das mit Machine Learning gehen könnte (siehe meinen kurzen Artikel über One-Shot-Learning)
Aber auch im Kleinen ist Overfitting ein Problem. Habt ihr auch schon so häufig gehört: „Ich habe 10 Leute befragt und möchte nun diese 5 Variablen statistisch untersuchen“? Also nochmal:
Das Verhältnis zwischen der Anzahl Parameter und der Datensatzgröße ist entscheidend!
 
Ist Underfitting eigentlich auch ein Problem?
Underfitting bedeutet interessanterweise nicht das direkte Gegenteil: „Zu viele Daten und zu wenig Parameter“. Zu viele Daten kann man nie haben 😉. Mit Underfitting ist gemeint, dass das Modell zu den beobachteten Daten passt bzw. zu einfach ist, also irgendwie doch wieder zu wenig Parameter.
Stellt Euch vor, es liegt in der Realität ein quadratischer Zusammenhang vor (z.B. Bremsweg zu Geschwindigkeit), wir legen aber nur eine Gerade an.

Wie vermeidet man Overfitting?
Ok, nun wissen wir also, was Overfitting im Machine Learning bedeutet. Aber wie können wir es vermeiden?
Einen ersten Ansatz kennt Ihr bereits: mehr Daten. Das hilft auf jeden Fall schon mal weiter, ist aber nicht immer realisierbar oder mit hohen Kosten (z.B. Umfragen) verbunden.
Der zweite Ansatz ist auch aus dem vorherigen Abschnitt klar: weniger Parameter. Erst kürzlich hatte ich bei einer Analyse einige Variablen, die jeweils für eine bestimmte Vorerkrankung mit Werten ja oder nein standen. Anstatt alle diese Variablen in das statistische Modell zu kippen, habe ich diese Variablen zu einer Variablen zusammengefasst, die nur zählt, wie viele Vorerkrankungen der Patient hat. Solche Ansätze werden übrigens auch als Feature Engineering bezeichnet.
 
Aufteilung in Trainings- und Testdatensatz
Wie überprüft man, ob ein Modell gut ist bzw. das zugrundeliegende Muster abbildet? Man testet es an frischen Daten und analysiert das Ergebnis!
Wenn ich jetzt aber den gesamten Datensatz für das Training (also die Parameterbestimmung/-optimierung) verbraten habe, habe ich ein Problem. Ich kann nämlich nicht den gleichen Datensatz zur Bestimmung der Qualität verwenden, denn diese Daten lagen dem Algorithmus schon vor. Da beißt sich die Katze in den Schwanz. Ich müsste also irgendwoher neue Daten sammeln.
Deshalb unterteilt man den vorhandenen Datensatz in einen Trainings- und einen Testdatensatz auf. Nur mit dem Trainingsdatensatz wird der Machine Learning Algorithmus gefüttert. Der Testdatensatz kommt erst zum Einsatz, wenn der Algorithmus ausgelernt hat. Der Testdatensatz ist ausschließlich zur Bestimmung der Güte da, für nichts anderes.
Meist wird im Verhältnis 70/30, 80/20 oder bei großen Datensätzen auch mal 90/10 aufgeteilt, also 70%, 80% oder 90% für das Training und der Rest entsprechend für den Test.
 
Und was ist der Validierungsdatensatz?
Im Zusammenhang mit ML-Algorithmen wie neuronalen Netzen gibt es noch einen weiteren Typ, nämlich den Validierungsdatensatz. Dieser wird verwendet, um die sogenannten Hyperparameter des ML-Algorithmus zu optimieren. Bei neuronalen Netzen versteht man darunter zum Beispiel die Topologie des neuronalen Netzes, also wie viele Ebenen, Knoten, Art der Ebenen usw. es besitzt.
Denn auch diese Parameter müssen festgelegt werden. Hyperparameter deshalb, weil sie noch vor dem eigentlichen Training gesetzt werden.
Das Vorgehen ist dann so, dass für die Hyperparameter mehrere mögliche Werte definiert werden. D ann wird für jede Kombination anhand des Trainingsdatensatzes gelernt. Anschließend wird mit Hilfe des Validierungsdatensatz die Qualität bestimmt und dadurch die beste Wahl der Hyperparameter herausgefunden. Der Testdatensatz kommt erst wieder ganz zum Schluss zum Einsatz, wenn alle Parameter festgelegt sind und die finale Qualität beurteilt werden soll.
 
 
Also, haltet euch fit, aber niemals overfit 😉
So long,
Euer Holger

Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter

Shiny Tutorial: Erstelle ein Dashboard in R

Ist es nicht cool, die Daten, die man mühsam aufbereitet hat, schön zu visualisieren anstatt nur langweilige Tabellen zu erstellen? Und das bitteschön interaktiv, dann kann man tiefer in die Daten einsteigen. Genau das zeige ich Euch in diesem R Shiny Tutorial. Wir erstellen zusammen eine Shiny App in R, und das ist ganz easy.
Was ist R Shiny?
Shiny ist eigentlich nur ein Package für R, aber es ermöglicht uns, interaktive Dashboards in R zu erstellen, die dann als Webseite im Browser angezeigt werden. Wenn man Webseite hört, denkt man an HTML- und CSS-Programmierung. Und ja, ein paar Grundlagen zu wissen ist nicht verkehrt, aber das benötigte Wissen hält sich wirklich in Grenzen.
Um mal einen Eindruck zu bekommen, was Shiny Apps so alles können, solltet ihr die Shiny Gallery besuchen, die einige wirklich tolle Showcases beinhaltet.
Da Shiny ein R-Package ist, programmiert Ihr also Euer Dashboard einfach in R. Dazu teilt man das Skript in einen Anzeige- und einen Interaktionsteil auf, aber dazu mehr im nächsten Abschnitt. Will man dann das Programm starten, drückt man einfach auf „Run App“ und schon sieht man es im Browser.
Shiny wurde von RStudio entwickelt und ist dementsprechend gut in die RStudio IDE integriert. Ich empfehle also auf jeden Fall, RStudio zu benutzen, wenn Ihr eine Shiny App programmieren wollt. Natürlich geht es aber auch in anderen Entwicklungsumgebungen wie VS Code.
Das Deployment, also das Veröffentlichen in der Cloud, so dass andere Benutzer darauf zugreifen können, kann durchaus etwas komplexer sein, das hängt aber vom Anbieter ab. Für den Anfang gibt es aber eine einfache, kostenlose Möglichkeit. Mehr dazu am Ende von diesem R Shiny Tutorial, also dranbleiben.
Gibt es Alternativen zu R Shiny?
In R nicht wirklich, da ist Shiny einfach die beste Möglichkeit, um Dashboard-Apps zu erstellen. Die Python-Community schielt sogar ein wenig neidisch auf dieses tolle R-Package. Ähnliche Funktionalitäten gibt es in Plotly Dash, das in Python recht weit verbreitet ist, aber auch in R und Julia läuft. In meinem Einsteiger-Tutorial zu Plotly Dash in Python erfährst Du mehr darüber.
Natürlich gibt es auch noch Anbieter, bei denen man sich mehr oder weniger per Point & Click seine Dashboards zusammenstellt. Die grafischen Oberflächen zum Erstellen der Dashboards sind Fluch und Segen. Es ist wirklich einfach und schnell, sich damit ein Dashboard zu bauen. Aber will man eine spezielle Interaktivität oder Verhaltensweise haben, muss man sich durch viele Optionen wühlen und häufig irgendwelche Tricks einsetzen, damit es klappt. Auch die Wartbarkeit ist eher bescheiden: Wo war nochmal die Option? Von Automatisierung, Modularisierung und Versionskontrolle ganz zu schweigen.
Mittels Shiny oder Plotly Dash ist das Erstellen der grafischen Elemente zwar etwas mühselig, aber dafür hat man es schön übersichtlich im Skript, kann Dinge in Funktionen auslagern, hat Git als Versionskontrolle usw.
Hier trotzdem eine Liste der wichtigsten Dashboard-Anbieter:

Microsoft PowerBI: Eher im Business Intelligence angesiedelt, daher ein bisschen behäbig und nicht so wirklich schön damit zu arbeiten. Ich habe aber auch schon tolle Dashboards in PowerBI gesehen. Die Desktop-Version ist kostenlos und da PowerBI Bestandteil des Office-Pakets ist, wird es in vielen Firmen eingesetzt.
QlikSense: Eine interessante Kombination von mächtigem Lade-Skript und interaktiver Oberfläche. D.h. in QlikSense kann man die Datentransformation und -bearbeitung gut in einem Skript, welches beim Aktualisieren ausgeführt wird, erledigen. Sind die Daten dann in der gewünschten Form, kommt Dashboard und die Interaktivitäten darauf. Man muss sich ein wenig daran gewöhnen, aber dann ist diese Kombination wirklich cool.
Tableau: Ich kenne es zu wenig, als dass ich wirklich eine Meinung dazu habe. Tableau galt lange Zeit als der Platzhirsch und ist insbesondere in den USA weit verbreitet. Die Visualisierungen sollen sehr gelungen sein.
Grafana: Eine tolle kostenlose Software und bei der IT sehr beliebt. Tatsächlich wird Grafana viel im Monitoring-Bereich eingesetzt, denn Echtzeit-Zeitreihen sind der Schwerpunkt.

GRATIS 5-Tage Minikurs: Datenanalyse in R

Du kennst Dich noch nicht so gut damit aus, wie man einen Datensatz in R analysiert? Ich bin da, um Dir zu helfen. Hole Dir jetzt meinen kostenlosen Datenanalyse mit R – Kurs und fange an, Dir diese zukunftsweisenden Skills anzueignen.

Die ersten Schritte zum Erstellen einer R Shiny App
Zuerst müsst Ihr Shiny wie jedes extra R-Package installieren. Das geht über install.packages(“shiny”).
Als nächstes erstellen wir ein Shiny Projekt. Also File -> New Project -> New Directory -> Shiny Web Application ausgewählt und den neuen Verzeichnisnamen und dessen Stammverzeichnis eingegeben.

In dem Verzeichnis wurde nun eine Datei app.R angelegt, welche als Ausgangspunkt für unsere eigene App dient und schon ein paar Demoelemente enthält. Schaut Euch erstmal an, was die Shiny App macht, klickt dafür auf „Run App“ rechts über dem Editorfenster.

In der Konsole seht ihr, dass dieser Button einfach den Befehl runApp() ausführt.

Es wird ein lokaler Webserver gestartet. Also ein Dienst, der auf Eurem Rechner läuft und eben die Shiny Webapp bereitstellt.
Dann öffnet sich ein RStudio-Browserfenster mit der Shiny Applikation. Ihr könnt aber auch die Adresse http://127.0.0.1:3906 im Browser Eurer Wahl eingeben. 127.0.0.1 ist die Adresse von Eurem Rechner und 3906 der Port, auf dem die App erreichbar ist.

So oder so ähnlich sollte das dann aussehen. Nach der Überschrift ist links ein Schieberegler, der die Anzahl Unterteilungen für das Histogramm auf der rechten Seite steuert. Schauen wir uns den zugehörigen Code an.

LERNE DATA SCIENCE mit R

Ein Data Science Experte ist in der heutigen datengetriebenen Welt viel gefragt. Mit der entsprechenden Erfahrung kann man sich den gutbezahlten, interessanten Job aussuchen. In meinem Onlinekurs Data Science mit R lernst Du die Grundlagen.

Jetzt informieren

Zweigeteilter Aufbau einer R Shiny App
Jede Shiny App besteht aus drei Teilen, der Benutzeroberfläche (UI = User Interface), dem Server, der für die Interaktionen zuständig ist und schließlich der Aufruf der shinyApp. Statt einer Datei app.R kann man übrigens auch die beiden ersten Teile trennen und eine Datei ui.R und eine Datei server.R anlegen.
So sieht der UI-Teil aus:
# Define UI for application that draws a histogram
ui <- fluidPage(

# Application title
titlePanel("Old Faithful Geyser Data"),

# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),

# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)

Also, das UI besteht aus einer sogenannten fluidPage, welche aus Zeilen und diese wiederum aus Spalten besteht. In diesem Fall ist die erste Zeile der Titel mittels titlePanel. In der zweiten Zeile definieren wir dann ein sidebarLayout, welches aus einem sidebarPanel und einem mainPanel besteht. Im sidebarPanel ist der Slider und im mainPanel das Histogramm.

In dieser Art lassen sich alle möglichen Strukturen realisieren: mehrere Seiten, Tabs, verschachtelte Zeilen/Spalten usw.
Die Server-Funktion der Shiny App
Im Server-Abschnitt müssen wir den Slider mit dem Plot verknüpfen bzw. den Plot überhaupt erstmal definieren. Denn im UI-Abschnitt steht ja nur plotOutput("distPlot"). Dabei ist distPlot der Name/die Identifikation des Plots.
# Define server logic required to draw a histogram
server <- function(input, output) {

output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)

# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}

Wir definieren also, dass distPlot die Ausgabe von renderPlot ist. Innerhalb der renderPlot-Funktion nutzen wir input$bins als Parameter für das Histogramm. Wir können darauf zugreifen, weil wir den Slider im UI als „bins“ benannt haben (sliderInput("bins",…)).
Das erste eigene interaktives Dashboard in R erstellen
Wir wollen ein kleines Aktiendashboard bauen. Dazu gibt es links eine Sidebar mit Auswahl des Zeitraums und der anzuzeigenden Aktie. Rechts soll dann das zugehörige Liniendiagramm oder eine Tabelle angezeigt werden. Um zu zeigen, dass auch mehrere Seiten möglich sind, bauen wir auch noch eine zweite Seite ein, die lassen wir aber erstmal leer.
So soll das Ganze aussehen:

Zuerst erzeugen wir ein neues, leeres Projekt. In dem Ordner erstellen wir die Dateien ui.R und server.R. Wir wählen also die Variante mit zwei Dateien.
Außerdem brauchen wir noch ein paar Packages, und zwar quantmod, gglot2, dplyr, DT und shinythemes. Mit Quantmod können wir Aktiendaten von Yahoo Finance laden, ggplot2 ist für Grafik, dplyr für Datentransformation (falls Du dplyr noch nicht kennst, schau mal in mein dplyr Tutorial rein), DT für interaktive Tabellen und schließlich shinythemes, um dem Dashboard ein anderes Farbschema überzustülpen. Prinzipiell funktioniert hier übrigens jedes Bootstrap-Theme, wir bleiben aber erstmal bei den in dem Package vorhandenen.
 

Mehrseitiges Layout einer Shiny App mittels navbarPage
Fangen wir mit der Datei ui.R an. Hier definieren wir uns die zwei Seiten als tabPanels und fügen diese am Ende mittels navbarPage zusammen. Seite 2 ist, wie gesagt, nur ein Dummy, den wir nicht weiter beachten. Seite 1 hat das Sidebar-Layout, bestehend aus sidebarPanel und mainPanel, das wir schon aus dem Standard-Beispiel kennen.
Im sidebarPanel definieren wir ein Datums-Picker, um den Zeitraum festzulegen. Dafür wollen wir eigentlich dateRangeInput verwenden, dieses Input-Element legen wir aber erst in der server.R-Datei fest. Daher gibt es hier nur den Platzhalfter uiOutput. Der Grund dafür ist, dass wir Variablen aus der server-Datei benutzen wollen und diese sind erstmal nicht in der ui.R verfügbar. UiOutput ist übrigens gut dafür geeignet, dynamische Inhalte zu erstellen, doch dazu später mehr.
uiOutput("ui_datumswahl")
Das zweite Element der Sidebar ist eine Gruppe von Checkboxen, mit denen man die Aktien-Symbole an- und abwählen kann. Das geht über ein checkboxGroupInput, aber wir müssen es wieder in die server.R schieben, da wir die Variable symbols benötigen.
uiOutput("ui_aktienwahl")
Und so sieht dann unsere gesamte ui.R aus:
library(shinythemes)
library(DT)

seite1 <- tabPanel("Seite 1",
sidebarLayout(
sidebarPanel(
uiOutput("ui_datumswahl"),
uiOutput("ui_aktienwahl")
),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Chart", plotOutput("chart")),
tabPanel("Tabelle", DTOutput("table")))
)
))

seite2 <- tabPanel("Seite 2",
h1("TODO"))

ui <- navbarPage("Mein Dashboard",
theme = shinytheme("darkly"),
seite1,
seite2
)

 

Die Server-Seite unserer Shiny App
Zuerst laden wir die benötigten Packages und definieren uns drei Parameter. Symbols ist ein Vektor mit den Aktien-Symbolen, die von Yahoo Finance geholt werden soll. Zudem gibt es noch das Start- und Enddatum.
library(quantmod)
library(ggplot2)
library(dplyr)

symbols <- c("AAPL","NFLX","AMZN","MSFT")
start_datum = as.Date("2019-01-01")
end_datum = Sys.Date()
Im nächsten Schritt laden wir die benötigten Daten herunter und transformieren diese in einen data.frame, der für Tabelle und Chart taugt. Ich habe das ziemlich ineffizient mit einer for-Schleife programmiert, aber so ist es leicht nachzuvollziehen. Als erstes holen wir uns die Symbole, diese werden von Quantmod als Zeitreihe unter dem Symbolnamen abgelegt. Wir deklarieren uns einen leeren data.frame, den wir dann in jedem Schleifendurchgang mit den Daten eines Symbols ergänzen.
## Daten von Yahoo Finance holen ###################################
getSymbols(symbols, from = start_datum, to = end_datum)
df <- data.frame(Symbol=character(),
Datum=as.Date(character()),
Open=numeric(),
High=numeric(),
Low=numeric(),
Close=numeric(),
Volume=numeric(),
Adjusted=numeric())
for (s in symbols) {
temp <- data.frame(Symbol=s, Datum=index(get(s)), get(s))
colnames(temp) <- c("Symbol","Datum","Open","High","Low","Close","Volume","Adjusted")
df <- rbind(df,temp)
}
Code, der nicht in der server-Funktion steht, wird einmalig beim Start der R Shiny App ausgeführt.
Und schließlich folgt die eigentliche Server-Funktion. Wir haben vier Elemente: den Date-Picker, die Aktien-Checkboxen, das Liniendiagramm und die Tabelle.
Der Date-Picker ist ein dateRangeInput mit ein paar Parametern, die relativ selbsterklärend sind. Eigentlich wollen wir ihn ja in der UI haben, also kapseln wir ihn über renderUI.
output$ui_datumswahl <- renderUI(
dateRangeInput("datumswahl",
label = "Zeitauswahl:",
start = start_datum,
end = end_datum,
min = start_datum,
max = end_datum,
format = "dd.mm.yyyy",
language = "de",
separator = "bis")
)
Das Gleiche machen wir für die Aktien-Checkboxen
output$ui_aktienwahl <- renderUI(
checkboxGroupInput("aktienwahl",
label="Aktienauswahl:",
symbols,
selected=symbols[1])
)
Das Liniendiagramm wird über renderPlot und einen ggplot-Chart realisiert. Dazu nehmen wir den Datensatz, filtern ihn auf die ausgewählten Symbole (input$aktienwahl) und ausgewählten Zeitraum. Damit keine Fehlermeldung bei nicht gewähltem Zeitraum auftritt, habe ich noch per ifelse das minimale Anfangs- bzw. maximale Enddatum ergänzt.
# Das Liniendiagramm mit Filter abhängig von den Inputs
output$chart <- renderPlot({
df %>%
filter(Symbol %in% input$aktienwahl,
Datum >= ifelse(length(input$datumswahl[1])==0,start_datum,input$datumswahl[1]),
Datum <= ifelse(length(input$datumswahl[2])==0,end_datum,input$datumswahl[2])) %>%
ggplot(aes(x = Datum, y = High, color = Symbol)) +
geom_line()
})
Das vierte und letzte Element ist die Tabelle, ebenfalls mit dem identischen Filter wie der Chart versehen. Wichtig hierbei ist der Parameter style = „bootstrap“, denn ansonsten wird die Tabelle nicht an das gewählte dunkle shinytheme angepasst und man kann die Überschriften nicht lesen.
# Datentablle als DT
output$table <- renderDT({
df %>%
filter(Symbol %in% input$aktienwahl,
Datum >= ifelse(length(input$datumswahl[1])==0,start_datum,input$datumswahl[1]),
Datum <= ifelse(length(input$datumswahl[2])==0,end_datum,input$datumswahl[2])) %>%
datatable(style = "bootstrap", options = list(pageLength = 20))
})
Damit haben wir alles soweit fertig. Hier sind die Dateien server.R und ui.R auch nochmal zum Herunterladen. Das ist doch schon mal ziemlich cool, oder?

Ausblick: Möglichkeiten von Shiny
Dieses Tutorial gibt natürlich nur einen kleinen Einblick in die glänzende Shiny-Welt. Es gibt tausende Möglichkeiten und wahrscheinlich habt Ihr auch schon Ideen, wie man unsere kleine App erweitern könnte. Also mir fällt jedenfalls noch eine Menge ein, zum Beispiel:

Abspeichern der Daten in einer kleinen Datenbank (z.B. SQLite) bzw. noch besser eine Trennung in Datenholen (dann täglich automatisiert) und dem Dashboard.
Verschiedene Charttypen (z.B. Candlesticks)
Zusammenfassende Statistiken zu den ausgewählten Aktien
Tabelle im Responsive Design

Und dann gibt es ja auch noch Performance-Überlegungen in Shiny. Welche Elemente müssen reactive sein, welche nicht, …
Deployment
Und schließlich das Deployment einer Shiny App, also das Hochladen in die Cloud, damit man es von jedem Rechner aus ansehen kann. Mit shinyapp.io könnt ihr kostenlos die ersten Schritte machen, muss dann aber recht schnell monatlich etwas zahlen. Shinyapp.io ist der bequemste Weg. Aber wenn ihr Zugang zu einem Linux-Server habt, könnt ihr darauf auch selber einen Shiny Server installieren. Wollt Ihr Eure Applikation bei anderen Anbietern hosten, dann ist es am besten, die App in einen Docker-Container zu packen. Das ist eigentlich ganz einfach, aber dazu ein anderes Mal mehr.
 
So, und nun ran an die Dashboards und viel Spaß beim Coden,
Euer Holger

LERNE DATA SCIENCE mit R

Ein Data Science Experte ist in der heutigen datengetriebenen Welt viel gefragt. Mit der entsprechenden Erfahrung kann man sich den gutbezahlten, interessanten Job aussuchen. In meinem Onlinekurs Data Science mit R lernst Du die Grundlagen.

Jetzt informieren

Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist

Interaktive Dashboards in Python – Plotly Dash Tutorial

Interaktive Dashboards sind ideal, um vielfältige Daten übersichtlich darzustellen. In diesem Tutorial zu Plotly Dash zeige ich Euch, wie man diese in Python programmiert.
Die Aufgaben eines Data Scientist umfassen nämlich nicht nur Analysen, sondern häufig auch die Darstellung der Ergebnisse. Und wie cool ist es, wenn man nicht nur ein statisches PDF erzeugt oder sich manuell Powerpoint-Folien bastelt, sondern ein interaktives Dashboard baut. Mit diesem kann dann der Nutzer interagieren und sich so die Kennzahlen, gefiltert nach seinen Wünschen, anzeigen lassen. Zudem lassen sich Dashboards leicht aktualisieren, wenn neue Daten verfügbar sind. Wer monatlich oder wöchentlich Excel- oder Powerpoint-Reports bastelt, weiß, wovon ich rede.
Software, um Dashboards zu erstellen
Es gibt eine Reihe kommerzieller, aber auch kostenlose Angebote, mit denen man Dashboards erstellen kann.

Microsoft Power BI: Recht schwerfällig, eher für Business Intelligence geeignet als für polierte Dashboards mit viel Interaktivität. Die Desktop-Version ist kostenlos. Um jedoch Reports vernünftig zu teilen (also nicht nur Dateien hin- und herzuschieben), werden Lizenzen für die Cloud-Lösung fällig. Auf der anderen Seite haben viele Firmen eh ein Office-Paket, bei dem PowerBI enthalten ist.
Qlik bzw. QlikSense: Finde ich persönlich ziemlich gut, allerdings sind die Lizenzen relativ teuer. Fluch und Segen zugleich sind die umfangreichen Skripting-Möglichkeiten. Damit kann man richtiges Datenmanagement machen, aber die Mischung zwischen Programmieren und Zusammenklicken gestaltet die Übersicht schwierig.
Tableau: Hat in der Anfangszeit viel Lob bekommen. Die Stärken liegen vor allem in der Datenvisualisierung. Der Einsatz ist aber auch nicht ganz preiswert.
Grafana: Eine tolle kostenlose Software, die vor allem für Zeitreihen (Monitoring von Servers etc.) eingesetzt wird

Dashboards mit Python programmieren
Der Vorteil und gleichzeitig Nachteil von all diesen Klick-basierten Lösungen ist eben das visuelle Arbeiten. Das macht es für den Nicht-Programmierer zwar einfacher bzw. überhaupt erst möglich, Dashboards zu erstellen. Aber die Wartbarkeit ist unübersichtlich bis nicht vorhanden. Gerade bei komplexeren Projekten möchte man verschiedene Dateien für verschiedene Module und Definitionen usw.
Hier kommen die komplett programmierbaren Dashboards ins Spiel. Vorteil solcher Frameworks ist die Kontrollierbarkeit. Nachteil ist, dass man schon ein paar Programmier-Fähigkeiten besitzen muss und auch ein paar Grundlagen in HTML/CSS haben sollte.
Wer in R programmiert, für den ist Shiny das Framework, an dem man nicht vorbeikommt. Für Python gibt es zwei größere Frameworks, Plotly Dash und Bokeh. Die Beliebtheit von Dash steigt stetig und anscheinend ist es etwas einfacher zu lernen. Bokeh benötigt für einige Interaktionen auch Javascript-Kenntnisse. Deshalb geht dieses Einsteiger-Tutorial um Plotly Dash.
Was ist Plotly Dash?
Dash ist ein Framework der Firma Plotly, um Webapps zur Datenanalyse-/visualisierung in Python, R oder Julia zu programmieren. Dash basiert auf React, einem bekannten Javascript-Web-Framework und Flask, einem der bekanntesten Webserver in Python.
Was alles mit Dash möglich ist, kann man sich in der Dash App Galerie anschauen.
Dash ist komplett kostenlos und open-source. Plotly bietet aber kommerzielle Lösungen zum Hosting der Webapps an. Eines muss Euch aber klar sein: Damit jemand anderes Euer Dashboard im Browser sehen kann, braucht ihr einen Server, der Python unterstützt. Für erste Versuche gibt es ein paar kostenlose Schnupperangebote im Netz (pythonanywhere, Heroku). Wollt ihr mehrere Apps erstellen, dann solltet Ihr Euch eine virtuelle Maschine im Netz zulegen. Das kostet zum Glück nicht viel. Ich empfehle Euch dafür Linode*, bei denen man für 5$ pro Monat bereits eine kleine Maschine bekommt.
 
Installation von Plotly Dash
Die Installation ist ganz einfach, da man sie über pip bzw. conda machen kann.
pip install dashbzw.conda install dash

Das erste Dashboard mit Plotly Dash
Nach dem Import von Dash und zugehörigen HTML-Funktionen wird die App erzeugt. Anschließend definieren wir das Layout der Seite, welches erstmal nur aus der H1-Überschrift „Willkommen zu Dash!“ besteht. Und schließlich wird in der Main-Routine der Server gestartet.
import dash
import dash_html_components as html

app = dash.Dash(__name__)

app.layout = html.H1(children="Willkommen zu Dash!")

if __name__ == "__main__":
app.run_server(debug=True)

Lässt Du nun dieses Programm laufen, sollte die Konsole folgendes ausgeben. Damit hast Du einen flask-Server auf Deinem Rechner gestartet, der unter http://127.0.0.1:8050 über den Webbrowser erreichbar ist (nur von Deinem Rechner aus, 127.0.0.1 ist die Adresse des localhosts, also des Rechners selbst)

Und so sollte das dann im Browser aussehen:

Ist noch ziemlich unspektakulär, aber immerhin haben wir schon mal eine Webseite erzeugt. Ändert Ihr etwas im Code und speichert die Datei ab, dann wird die Webseite automatisch neu geladen. Manchmal hängt es aber ein bisschen, dann einfach im Webbrowser nochmal laden.
Grundsätzlich wird das Layout über app.layout definiert, d.h. dort können wir alle möglichen HTML-Abschnitte & -Strukturen, Charts oder Gadgets einbauen. Das wollen wir jetzt im zweiten Beispiel ausbauen. Allerdings bleibt alles erstmal ohne Funktion, denn die bauen wir erst im nächsten Abschnitt ein.

Datenanalyse mit Python - 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Steuerungselemente wie Dropdowns in Plotly Dash
Wir ergänzen einige Elemente aus der HTML-Library dash_html_components und einige aus der Dash Core Library dash_core_components.
Zuerst müssen wir diese also importieren. Außerdem wollen wir noch eine Grafik mittels plotly.express und Zufallszahlen mit numpy erzeugen.

import dash
import dash_html_components as html
import dash_core_components as dcc
import plotly.express as px
import numpy as np

 
Anschließend schreiben wir eine Funktion hist(verteilung, n), die eine Stichprobe aus einer Verteilung zieht und daraus ein Histogramm macht. Als Parameter wird der Name einer Verteilung (normal, binomial oder chisquared ) und die Stichprobengröße n übergeben. Per np.random.xxx wird dann die Zufallsstichprobe gezogen und mit der plotly-express-Funktion px.histogram das Histogramm erzeugt.

def hist(verteilung, n):
data = None
if verteilung == "normal":
data = np.random.normal(loc=0, scale=1, size=n)
elif verteilung == "binomial":
data = np.random.binomial(n=10, p=0.5, size=n)
elif verteilung == "chisquared":
data = np.random.chisquare(df=5, size=n)
else:
print("Diese Verteilung wird noch nicht unterstützt!")
return
return px.histogram(data)

 
Nun kommt der Dash-Block, also

app = dash.Dash(__name__)

app.layout = …

if __name__ == "__main__":
app.run_server(debug=True)

Und jetzt definieren wir das Layout, welches sich wie gesagt aus dash_html_components und dash_core_components zusammensetzt. Im Prinzip ist das Layout einfach eine Liste von solchen Objekten. Wer ein bisschen HTML kennt, erkennt diese Komponenten: html.H1 bzw. html.H2 für die Überschriften, html.Div für die Abschnitte (divisions). Komplexere Element sind dcc.Dropdown (ein Dropdown), dcc.Input (Inputfeld) und dcc.Graph für die Grafik.
Die Komponenten kann mit mittels des Parameters style per CSS formatieren. Dabei wird ein dictionary mit den CSS-Einstellungen übergeben. Der Syntax ist minimal verändert, da Bindestriche hier nicht funktionieren würden. Statt CSS „background-color“ benutzt man also „backgroundColor“.
Achtung, wir haben erstmal nur das Layout definiert. Verteilungs-Dropdown und Eingabefeld für die Stichprobengröße werden zwar angezeigt, sind aber noch nicht „verdrahtet“, machen also erstmal gar nichts.
So sieht die Layout-Definition dann aus:

app.layout = html.Div(
children=[
html.H1(children="Verteilungen"),
html.Div(
children=[
html.H2("Inputs"),
html.Div(
children=[
html.P("Verteilung"),
dcc.Dropdown(
id="verteilung-dropdown",
options=[
{"label": "Normal", "value": "normal"},
{"label": "Binomial", "value": "binomial"},
{"label": "Chi²", "value": "chisquared"},
],
value="normal",
),
],
),
html.Div(
children=[
html.P("Stichprobengröße"),
dcc.Input(
id="n-input",
placeholder="Stichprobengröße",
type="number",
value=100,
),
],
),
],
# mit style kann man CSS-Formatierungen verwenden
style={
"backgroundColor": "#DDDDDD",
"maxWidth": "800px",
"padding": "10px 20px",
},
),
html.Div(
children=[
html.H2("Histogramm"),
dcc.Graph(id="histogramm", figure=hist("normal", 100)),
],
style={
"backgroundColor": "#DDDDDD",
"maxWidth": "800px",
"marginTop": "10px",
"padding": "10px 20px",
},
),
]
)

 
Und so wird unser Dashboard im Browser dargestellt:

Erste Interaktivität in unserem Plotly Dash Dashboard
So, nun wird es langsam interessant. Denn nun geht es an die Interaktivität. Diese wird über Decorators bei den entsprechenden Funktionen erreicht.
Dazu definiert man zum einen den Output, also welches Element des Layouts von der Funktion zurückgegeben wird. In unserem Fall ist es der Parameter figure der Grafik dcc.Graph. Damit wir diese identifizieren können, benutzen wir die id-Parameter aus dem Layout.
Dann definieren wir die Inputs, also bei Änderung welcher Elemente die Funtion aufgerufen werden soll. Da das mehrere sein können, wird das als Liste realisiert. In unserem Fall ist es einmal das Verteilungsdropdown mit ID „verteilung-dropdown“ und das Input-Feld mit ID „n-input“.
Unsere Funktion hist bekommt also einfach den Decorator aufgesetzt. Dafür müssen wir noch zwei Komponenten importieren, nämlich Input und Output. Die Import-Zeile sollte bei den anderen Import-Zeilen oben im Skript stehen.

from dash.dependencies import Input, Output

@app.callback(
Output("histogramm", "figure"),
[Input("verteilung-dropdown", "value"), Input("n-input", "value")],
)
def hist(verteilung, n):
data = None
if verteilung == "normal":
data = np.random.normal(loc=0, scale=1, size=n)
elif verteilung == "binomial":
data = np.random.binomial(n=10, p=0.5, size=n)
elif verteilung == "chisquared":
data = np.random.chisquare(df=5, size=n)
return px.histogram(data)

Eine kleine Änderung machen wir noch in unserem Layout. In der dcc.Graph-Funktion definieren wir nur die id, lassen also den figure-Parameter weg. Durch unseren Decorator wird die Funktion hist sowieso beim Start aufgerufen und so vermeiden wir den zweifachen Aufruf.
dcc.Graph(id="histogramm")
Und nun können wir im Browser Dropdown und das Input-Feld nutzen. Die Grafik wird direkt aktualisiert.

Deployment von Plotly Dash in der Cloud
Nun wollen wir unser Dashboard ja nicht nur auf unserem Rechner laufen lassen. Und dass jemand anderem erstmal Python und die benötigten Libraries installiert, ist auch ziemlich umständlich. Also wollen wir das Plotly Dashboard in der Cloud hosten, damit man bequem per Browser darauf zugreifen kann. Theoretisch kann man auch den eigenen Rechner oder einen Raspberry Pi als Server missbrauchen, aber der müsste dann ja immer laufen. Da ist eine Cloud-Lösung die bessere Wahl.
Leider ist das „Ins-Internet-stellen“ (deployment genannt) nicht ganz so einfach, denn man braucht eine vernünftige Umgebung mit den benötigten Packages und einen Webserver. Der Webserver, der bei dash bzw. flask dabei ist, ist für die produktive Umgebung nicht so geeignet.
Eine schöne, kostenlose Möglichkeit für die ersten Schritte war pythonanywhere. Das funktioniert aber aktuell nicht mehr vernünftig, denn das Package numpy zickt mit dem dortigen Webserver uWSGI herum. Aber als Data Scientist auf numpy und pandas zu verzichten, geht nicht wirklich.
Eine zweite kostenlose Möglichkeit ist heroku. Dafür muss man sich aber die Heroku-Kommandozeile herunterladen und ein bisschen was von git verstehen (hier mein Blogpost über Git). Das folgt dann mal in einem separaten Tutorial.
Als dritte Möglichkeit und gute Alternative zu AWS empfehle ich Euch Linode*, wo Ihr eine virtuelle Linux-Maschine für wenig Geld bekommt.
 
So long, so good. Viel Spaß beim Entdecken der unzähligen Möglichkeiten von Plotly Dash.
Euer Holger

Datenanalyse mit Python - 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist

Wie funktioniert Reinforcement Learning? Bestärkendes Lernen erklärt

Maschinellen Lernen kann man in drei Klassen unterteilen: überwachtes Lernen (supervised learning), unüberwachtes Lernen (unsupervised learning) und bestärkendes Lernen (reinforcement learning). Diese drei Lernarten decken unterschiedliche Fragestellungen ab, auch wenn es natürlich Überschneidungen gibt. In diesem Blogartikel geht es um das reinforcement learning, aber klären wir zuerst die anderen beiden Arten.
Supervised Learning: Die populärste ML-Klasse
Supervised Learning, auf Deutsch überwachtes Lernen, fasst die Algorithmen zu einer Klasse zusammen, welche anhand eines gelabelten Datensatzes lernen. D.h. es steht ein Datensatz inklusive Ergebnisse zum Lernen zur Verfügung.

Will man zum Beispiel der Computer beibringen, zu erkennen, ob ein Hund auf einem Bild ist. Dann füttert man den Algorithmus mit vielen Bildern, auf denen mal ein Hund und mal kein Hund abgebildet ist. Zusätzlich bekommt der Algorithmus noch zu jedem Bild die Information, ob eben dort ein Hund abgebildet ist oder nicht.

Die meisten Algorithmen des maschinellen Lernens gehören zur Klasse des überwachten Lernens. Aber das Problem ist der benötigte Datensatz. Denn ML-Algorithmen, allen voran neuronale Netze, sind datenhungrig. Da sie so viele Parameter haben, die eingestellt werden müssen, brauchen sie eine enorm große Menge an Trainingsdaten. Nun muss man also einen großen Datensatz bereitstellen, der eben auch die gewünschten Ergebnisse enthält. Und das auch noch möglichst ohne Fehler, denn der Algorithmus ist immer nur so gut wie der zugrundeliegende Trainingsdatensatz.
Bei Hundebildern kann man vielleicht noch mit einigem Aufwand einen Datensatz mit 1 Millionen Bildern bereitstellen. Bei Röntgenaufnahmen inklusive korrekter Diagnose ist das deutlich aufwändiger. Solch einen Datensatz zur Verfügung zu haben, ist viel wert und meist entscheidend, ob ein ML-Algorithmus erfolgreich eingesetzt werden kann. Das wird in Zukunft ein interessanter Markt sein, in dem viel Geld steckt. Mittlerweile gibt es für viele Themen schon einige große, gelabelte Datensätze. Viele sogar kostenlos, da sie aus Forschungsprojekten entstanden sind.
Anhand des Trainingsdatensatzes dreht der Algorithmus an seinen Parametern, um eine Kostenfunktion zu minimieren. Solch eine Kostenfunktion kann in unserem Hundebild-Beispiel einfach die Anzahl falsch klassifizierter Bilder sein.
Aber gibt es nicht auch Algorithmen, die die Labels nicht benötigen? Kommen wir zur Klasse des unüberwachten Lernens.
Unsupervised Learning: Datenstrukturen erkennen
Viele Unternehmen sammeln schon seit einiger Zeit jede Menge Daten, sei es über Produktionsabläufe oder Kundenverhalten. Wäre es nicht cool, diese einfach fürs maschinelle Lernen zu verwenden? Und zwar ohne umfangreiches händisches Labeln? Hier schlägt die Stunde der unsupervised learning Algorithmen. Denn diese benötigen zwar einen Datensatz, erkennen aber selbstständig Muster und Strukturen in den Daten.
Ein typisches Beispiel ist die Ausreißer-Erkennung (anomaly detection), die unter anderem bei der Betrugserkennung in Banken eingesetzt wird. Hierbei braucht der Algorithmus nicht unbedingt die zusätzliche Information, ob es sich um einen Betrug handelt oder nicht. In den Daten steckt, ob eine Transaktion aus dem Rahmen fällt und dementsprechend als auffällig markiert werden sollte.

Weitere wichtige Anwendungsgebiete von unüberwachtem Lernen sind die Gruppierung von Kunden oder Objekten (Clustering) sowie das Feature Engineering.

Reinforcement Learning: Aktion und Belohnung
Reinforcement Learning, auf Deutsch bestärkendes Lernen, funktioniert etwas anders als die beiden anderen Maschine Learning Algorithmen-Klassen. Denn es wird nicht aus einem Datensatz gelernt, sondern durch Aktionen in einer Umgebung und darauffolgende Belohnungen oder Bestrafungen.

Bestärkendes Lernen erscheint als eine sehr natürliche Art des Lernens. Denn Kinder lernen auf diese Weise: sie machen etwas und erfahren daraufhin ein Feedback, zum Beispiel dass ihr Lachen beim Gegenüber ebenfalls ein Lachen hervorzaubert.
Reinforcement Learning kann also immer dann zum Einsatz kommen, wenn ein Algorithmus/Agent in einer Umgebung (engl. Environment) handeln kann und diese Handlungen direkt oder auch später bewertet werden können. Je später das Feedback kommt, desto schwieriger ist es natürlich für den Agenten.
Machen wir ein einfaches Beispiel und stellen uns eine selbstlernende Schiebetür vor. Diese soll sich öffnen, wenn Menschen sich nähern und schließen, wenn keine Menschen in der Nähe sind. Die Tür hat vier Zustände: geschlossen, geöffnet, wird geschlossen, wird geöffnet. Zudem ist sie mit einem Sensor ausgestattet, der jede Sekunde überprüft, ob sich Menschen in einem 2m-Bereich vor oder hinter der Tür befinden. Daraus ergeben sich also insgesamt 8 Zustände:

Im Endeffekt ist hier ein ML-Algorithmus natürlich völlig übertrieben, denn die optimale Handlung kann man mit einfachen Wenn-Dann-Regeln programmieren, aber es geht ja ums Veranschaulichen. Das Belohnungssystem ist dementsprechend auch so ausgelegt, dass die richtige Handlung 100 Punkte bringt und die falschen Handlungen 0 Punkte. Der Algorithmus kann in diesem Fall einfach alle Handlungsmöglichkeiten durchprobieren und hat so nach einigen Versuchen die gewünschte Handlung gelernt.

AlphaGo Zero: Das Paradebeispiel für bestärkendes Lernen
In der Realität kommt Reinforcement Learning für deutlich komplexere Problemstellungen als die obige Schiebetür zum Einsatz. Gerade bei Brett- oder Computerspielen, welche klare Regeln haben, funktioniert Reinforcement Learning besonders gut und konnte beachtliche Erfolge erzielen.
Paradebeispiel ist Googles/DeepMinds AlphaGo Zero, ein Go-Programm, welches der Nachfolger von AlphaGo ist und diesen vernichtend schlagen konnte. AlphaGo war das erste Computerprogramm, welches 2016 den Go-Großmeister Lee Sedol, der als einer der stärksten menschliche Spieler galt, 4-1 besiegen konnte. Das war eine Sensation, denn Go hat durch das 19×19 große Spielfeld viel mehr (Faktor 10100) mögliche Spielzüge. Dadurch fällt das Durchprobieren aller möglichen Züge (Brute-Force) aus. Zudem gibt es keine gute Heuristik, um eine Stellung zu bewerten.
Während AlphaGo zwar auch schon Neuronale Netze einsetzte, ist die Besonderheit bei AlphaGo Zero, dass letzteres nur die Spielregeln einprogrammiert bekommen hat und Go nur durch das Spielen gegen sich selbst zur Meisterschaft gebracht hat. Nach 3 Tagen Lernen konnte AlphaGo Zero dann die Version von AlphaGo schlagen, die Lee besiegt hatte. Nach 40 Tagen schlug AlphaGo Zero auch die zu der Zeit beste Version von AlphaGo namens AlphaGo Master. Wobei Tage hier eigentlich nichts aussagen, denn es geht ja um die Rechenleistung, die verbraten wurde. Und davon hat Google ja fast unbegrenzt zur Verfügung.

Lernen im Simulator
Reinforcement Learning funktioniert durch Agieren in einer Umgebung. Das geht bei Spielen wie Go, aber nicht in der Wirklichkeit. Man kann nicht einfach ein Auto mit initialen zufälligen Aktionen in den Straßenverkehr stellen und tausende Handlungen abwarten, dass es sich mal etwas vernünftiger verhält und nicht gegen das nächste Auto fährt. Oder einen teuren Roboter in eine Fertigungsstraße einbauen und sehr lange nur Ausschuss produzieren.
Daher wird zuerst in einer Simulation gelernt, in der nichts kaputt gehen kann. Das hat neben den geringeren Kosten und Risiken auch den entscheidenden Vorteil, dass das Lernen in Zeitraffer ablaufen kann und die Geschwindigkeit eigentlich nur von der Rechenpower beschränkt ist. Denn wenn wir neuronale Netze einsetzen, müssen tausende oder Millionen Parameter optimiert werden und das braucht normalerweise einen riesigen Datensatz bzw. im bestärkenden Lernen sehr viele Durchgänge.
Ist in der Simulation das Lernen ausgereizt, kann dieses Wissen genommen werden und in einen realen Roboter übertragen werden und dann in der Realität weiter verbessert werden. Dieses Vorgehen nennt man Transfer Learning, wobei der Begriff Transfer Learning weiter gefasst ist.
Die bekannteste Trainingshalle für künstliche Intelligenz mit anschaulichen Videoclips findet man bei OpenAI, die OpenAI Gym. Dafür gibt es auch zahlreiche Erweiterungen für andere Bereiche wie Recommendation Engines, Aktien-Trading, Kartenspiele und viele weitere.
Ein mathematisches Modell hinter Reinforcement Learning
Ein Basismodell hinter Reinforcement Learning ist das sogenannte Markov Entscheidungsproblem bzw. der Markov Entscheidungsprozess (engl. Markov decision process = MDP). Dieser besteht aus folgenden Zutaten:

Einer Menge von Zuständen
Einer Menge von Aktionen
Ein Aktionsmodell, welches eine Funktion ist. Diese ordnet jeder Kombination aus vorherigem Zustand, Aktion und Folgezustand eine Wahrscheinlichkeit zu.
Eine Belohnungsfunktion , welche jeder Kombination aus letztem Zustand, Aktion und aktuellem Zustand einen Wert (reelle Zahl) zuweist.
Eine Startverteilung, wiederum als Funktion . Die Funktion bestimmt also die Wahrscheinlichkeit, in einem Zustand zu starten.

Eine Strategie (engl. policy) ist dann eine Funktion , die jedem Zustand eine Aktion zuweist. Man kann das auch nicht-deterministisch formulieren, d.h. der Agent entscheidet sich in einem Zustand für eine Aktion mit einer gewissen Wahrscheinlichkeit. Dann ist pi eine Funktion . Als Lösung bzw. optimale Strategie wird eine Strategie bezeichnet, die die Summe der Belohnungen (engl. reward) maximiert. In der nicht-deterministischen Variante ist es der Erwartungswert der Summe der Belohnungen. Die Summe der Belohnungen kann man noch mit einem Diskontierungsfaktor (wie beim Zinseszins) versehen, um eine Gewichtung zwischen sofortiger und späterer Belohnung zu erreichen. Das ist zum Beispiel notwendig, wenn keine zeitliche Begrenzung vorliegt (denn dann könnte die Summe unendlich groß werden).
Dieses Modell kann man aber nicht für alle Problemstellungen verwenden, denn es hat die sogenannte Markov-Eigenschaft, dass es sich nicht erinnert. Der Zeitpunkt ist also egal, das Aktionsmodell und die Belohnungsfunktion hängen nur vom direkt vorherigen Zustand ab, nicht von dem vor zwei Zeiteinheiten oder dem bisherigen Verlauf.
Reinforcement Learning umgesetzt: Q-Learning
Der bekannteste Algorithmus des bestärkenden Lernens nennt sich Q-Learning. Man kann beweisen, dass Q-Learning für jeden endlichen Markov Entscheidungsprozess (also mit endlich vielen Zuständen und endlich vielen Handlungen) eine optimale Policy finden kann, sofern er unendlich viel Zeit dafür hätte. Aber auch in der Praxis funktioniert der Algorithmus meist ziemlich gut.
Es geht ja darum, eine Funktion zu finden, die jede Zustand-Aktion-Kombination bewertet. Haben wir diese, dann kann sich der Algorithmus in einem Zustand einfach für die Aktion entscheiden, die die höchste Bewertung hat.
Das Ganze funktioniert iterativ, d.h. zuerst wird Q zufällig oder mittels Vorwissen initialisiert und anschließend in jedem Schritt optimiert. In dem Optimierungsschritt i wird ein neuer Wert gebildet, der sich aus dem alten Wert und geschätzten Gesamtbelohnung zusammensetzt. Diese zwei werden mit der Lernrate gewichtet, also . Die Lernrate bestimmt, wie wichtig neue Information ist. Bei lernt der Agent nichts, bei werden nur die neuesten Informationen berücksichtigt. ist sinnvoll, wenn die Umgebung deterministisch ist, also kein Zufall bezüglich des nächsten Zustands im Spiel ist. In der Praxis wird also ein Wert zwischen 0 und 1 gewählt, der sich ggf. auch über die Zeit verändert.
Die Belohnung wiederum setzt sich aus der sofortigen Belohnung und der maximalen Belohnung in Zustand , noch mit einem Diskontierungsfaktor gamma versehen, zusammen. Der Diskontierungsfaktor bestimmt, wie gierig der Agent ist. Ist die jetzige Belohnung (kleiner Faktor nahe 0) oder zukünftige Belohnungen (Faktor nahe 1) wichtiger? Häufig wird auch mit einem kleinen Diskontierungsfaktor angefangen, der dann im Laufe der Zeit erhöht wird.
Die komplette Formel lautet dann:
   

 

Q-Learning und neuronale Netze
AlphaGo und all die anderen erfolgreichen Reinforcement Learning Programme basieren aber auf neuronalen Netzen. Wie kommen diese jetzt ins Spiel? Die Idee ist einfach, die Funktion Q durch ein neuronales Netz lernen zu lassen. Wir füttern es also mit dem aktuellen Zustand und ggf. weiteren Informationen der Umgebung und es spuckt die Aktion bzw. für jede Aktion eine Bewertung aus.
Das Problem mit dem ursprünglichen Algorithmus ist nämlich, dass er einfach zu viel Rechen- und Speicherkapazität benötigt, wenn die Zustandsmenge S und die Aktionsmenge A größer sind. Das neuronale Netz approximiert die Funktion Q.
Der erste bekannte Algorithmus dieser Art heißt DQN für Deep-Q-Network und wurde von DeepMind entwickelt, um dem Computer das Computer-Spielen (genauer gesagt Atari 2600). Das Original-Paper Playing Atari with Deep Reinforcement Learning von 2013 ist auf arXiv zu finden.
Mittlerweile gilt A3C (Asynchronous Advantage Actor Critic), ebenfalls aus der Schmiede von DeepMind, als überlegener Algorithmus, da er schneller und robuster ist. Dabei heißt asynchronous hier, dass mehrere Agenten parallel losgeschickt werden und so von den Erfahrungen der anderen profitieren können. Advantage meint, dass nicht die diskontierte Belohnung betrachtet wird, um Aktionen zu bewerten, sondern wieviel besser die Belohnung gegenüber der erwarteten Belohnung ist. Und schließlich bedeutet Actor Critic, dass sowohl die Policy als auch die Value Function, welche einen Zustand bewertet, benutzt werden. Auch darüber könnt ihr auf arXiv im Artikel Asynchronous Methods for Deep Reinforcement Learning von 2016 nachlesen.
Dieser Blogartikel kratzt natürlich nur an der Oberfläche der faszinierenden Machine Learning-Klasse Reinforcement Learning. Willst Du mehr darüber wissen, dann hinterlasse doch einen Kommentar oder schreib mir auf Twitter.
Seid bestärkt Freunde,
Euer Holger

Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz

Eigene Funktionen in R programmieren

R-Funktionen sind für die R-Experten ein alter Hut, aber für die Newbies unter Euch ein wichtiges Werkzeug. Ja, Funktionen sind eigentlich elementar in der R-Programmierung, schließlich handelt es sich bei R um eine funktionale Programmiersprache.
Warum soll man überhaupt eigene R-Funktionen programmieren?
Es gibt direkt mehrere Vorteile, warum Funktionen so nützlich beim Programmieren in R sind. Funktionen werden eigentlich immer dann eingesetzt, wenn man gleichen oder ähnlichen Programmcode an mehreren Stellen im Skript benutzt. Statt viele Zeilen identischen Codes zu haben, wird dieser Code in eine Funktion ausgelagert, so dass dann nur noch die Funktion aufgerufen werden muss.
Damit verringern wir nicht nur die Zeilen Code und machen das Ganze übersichtlicher, sondern es sinkt auch die Fehlerwahrscheinlichkeit, denn es gibt nur noch eine Stelle, an der Änderungen oder Bugfixes gemacht werden müssen.
Funktionen erhöhen die Übersichtlichkeit des R-Codes, insbesondere, wenn sie verständlich benannt sind. Statt sich durch x Zeilen Code zu kämpfen, steht dann im Hauptteil einer Datenanalyse vielleicht nur noch folgende paar Zeilen.
datum_von <- "01.01.2020"
datum_bis <- "30.09.2020"
daten <- daten_einlesen(datum_von, datum_bis)
ergebnisse <- daten_analysieren(daten)
daten_visualieren(ergebnisse, speichern = TRUE)

Damit ist für jeden klar, was in diesem Skript gemacht wird. Natürlich ist der vermutlich komplexe Code in den Funktionen versteckt und muss bei Fehlern genauso analysiert werden, aber die Vorteile sind klar. Und da haben wir noch gar nicht von Tools wie automatischen Unit Tests gesprochen.
Und durch die Übergabe von Parametern sind Funktionen total flexibel. Besonders komfortabel wird es, wenn ihr Standard-Werte für die Parameter definiert, so dass die Parameter nicht unbedingt angegeben werden müssen.
Ihr könnt euch auch eure nützlichsten Funktionen in ein R-Skript packen oder sogar ein eigenes R-Package bauen. Das wird dann am Anfang eines Skripts eingelesen bzw. eingebunden und schon stehen sie euch zur Verfügung.

GRATIS 5-Tage Minikurs: Datenanalyse in R

Du kennst Dich noch nicht so gut damit aus, wie man einen Datensatz in R analysiert? Ich bin da, um Dir zu helfen. Hole Dir jetzt meinen kostenlosen Datenanalyse mit R – Kurs und fange an, Dir diese zukunftsweisenden Skills anzueignen.

Wie definiere ich eine Funktion in R?
Eine eigene Funktion zu definieren ist ganz einfach
meine_funktion <- function() {
#hier kommt der Code rein
print("meine_funktion wurde aufgerufen")
}

Der Aufruf erfolgt dann mittels meine_funktion(). Das ist natürlich eine ziemlich langweilige Funktion, denn sie hat weder Parameter noch wird etwas zurückgegeben. Von dem auszuführenden Code ganz zu schweigen 😉
Die Rückgabe von einer Variable v erfolgt mittels return(v). Dabei kann die Variable ein beliebiges R-Objekt sein, also nicht nur ein Wert, sondern auch Listen, data.frames oder sogar Funktionen. Code nach einem return-Befehl wird nicht mehr ausgeführt, sondern es direkt wird zum Ende gesprungen. Das ermöglicht es zum Beispiel, am Anfang Fehler in den Parametern abzufangen.
Nehmen wir als Beispiel die Überprüfung, ob eine Zahl eine ganze Zahl ist. Das geht leider nicht mit is.integer, denn diese Funktion überprüft nicht den Wert, sondern nur, ob es sich schon um den Typ integer handelt. Daher machen wir es so, dass wir von der gegebenen Zahl die Nachkommastellen runden (mittels round) und uns dann die Differenz zu der ursprünglichen Zahl anschauen. Ist diese 0 bzw. sehr klein, dann ist durch das Runden nichts passiert. Der Ausdruck stimmt dann.
Für den Toleranzparameter tol geben wir einen Default-Wert an, so dass dieser nicht beim Aufruf übergeben werden muss. Warum brauchen wir so einen Toleranzparameter überhaupt? Das hängt mit Rundungsungenauigkeiten zusammen. Ist x als 2/49*49 definiert, dann stimmt der direkte Vergleich zum Beispiel nicht mehr.
is.integer(3)
is.integer(3L)

x = 2/49*49
round(x)==x

istGanzeZahl <- function(zahl, tol = 0.000000001) {
return(round(zahl)-zahl < tol)
}

istGanzeZahl(3)
istGanzeZahl(3.5)

Wie oben geschrieben, beendet R beim Schlüsselwort return direkt die Funktion. Das ist ganz praktisch, um Abfragen bezüglich fehlerhafter Parameter am Anfang abzufragen. Hier ein Beispiel dazu, dass die obige Funktion istGanzeZahl nutzt.
wiederhole <- function(wort, anzahl = 1) {
if (!is.character(wort)) {
print("Bitte gib als ersten Parameter eine Zeichenkette ein")
return()
}
if (anzahl<1) {
print("Bitte gib eine Anzahl größer oder gleich 1 ein")
return()
}
if (!istGanzeZahl(anzahl)) {
print(paste("Die Anzahl",anzahl,"ist keine ganze Zahl"))
return()
}
return(rep(wort, anzahl))
}

wiederhole("Hallo")
wiederhole("Hallo",3)
wiederhole("Hallo",0)
wiederhole("Hallo",-3)
wiederhole("Hallo",3.5)

Zwei Parameter in einer R-Funktion zurückgeben
Eine Funktion in R kann immer nur ein Objekt zurückgeben. Um mehrere Variablen zurückzugeben, müssen wir diese also zu einem Objekt verbinden. Und das geht am besten mit einer Liste.
Wenn ihr zum Beispiel schon mal eine lineare Regression in R gerechnet habt, kennt ihr das schon.
n <- 100
x <- rnorm(n, 3, 4)
y <- 3 * x + rnorm(n, 0, 0.5)
l <- lm(y ~ x)

Die Ausgabe von l (also der print-Befehl) sieht zwar nicht unbedingt nach einer Liste aus, davon sollte man sich aber nicht täuschen lassen.
> print(l)

Call:
lm(formula = y ~ x)

Coefficients:
(Intercept)            x
-0.05468      3.00677

Wenn wir uns das Objekt l aber im Environment-Fenster von RStudio ansehen, dann steht dort Liste mit 12 Einträgen.

Das können wir auch leicht mit is.list(l) überprüfen. Mit names(l) bekommen wir die Namen der Elemente, auf die wir dann mit der eckigen Doppelklammer oder dem Dollarzeichen zugreifen können.
is.list(l)
names(l)
l[["coefficients"]]
l$coefficients

 
Warum sieht die Ausgabe mittels print dann so gar nicht nach Liste aus? Das liegt aber daran, dass die Programmierer von lm der Ausgabe die Klasse „lm“ gegeben hat, welche eine eigene print-Funktion besitzt und die Standard-Print-Funktion der Liste überschreibt. Abfragen kann man den Typ eines Objekts übrigens mittels class.

LERNE DATA SCIENCE mit R

Ein Data Science Experte ist in der heutigen datengetriebenen Welt viel gefragt. Mit der entsprechenden Erfahrung kann man sich den gutbezahlten, interessanten Job aussuchen. In meinem Onlinekurs Data Science mit R lernst Du die Grundlagen.

Jetzt informieren

Wie gibt man mehrere Parameter in einer Funktion zurück?
Dazu bauen wir uns einfach in der Funktion eine Liste und geben diese mittels return zurück. Die folgende Funktion erzeugt einen data.frame und berechnet dann dazu eine lineare Regression. Zurückgegeben wird sowohl der data.frame als auch das lm-Objekt, also eine Liste bestehend aus data.frame und wiederum einer Liste (bzw. ein Objekt der Klasse lm).
erzeuge_lm <- function(n = 100, seed = NA) {
if (!is.na(seed)) set.seed(seed)
df <- data.frame(x = rnorm(n, 3, 4))
df$y <- 3 * x + rnorm(n, 0, 0.5)
l <- lm(y ~ x, df)
liste <- list(daten = df, lm = l)
return(liste)
}

a <- erzeuge_lm()
a$daten
a$lm

Der Phantasie sind hierbei kaum Grenzen gesetzt. Wir könnten jetzt noch sämtliche verwendeten Parameter als Parameter übergeben. Oder per Parameter steuern, aus welcher Verteilung die Daten stammen. Das führt uns zum nächsten Kapitel, denn Verteilungen haben unterschiedlich viele Parameter. Die t-Verteilung hat nur einen Freiheitsgrad, die Normalverteilung hat zwei.
Beliebige Anzahl Parameter in R-Funktionen mittels …
Um die Parameter bei der Funktionsdefinition nicht explizit anzugeben, kann man auch … verwenden. Das ist praktisch, wenn man in der Funktion wieder eine Funktion aufruft und ihr diese Parameter übergeben will.
Greifen wir das letzte Beispiel nochmal auf und definieren uns eine Funktion, die als Parameter die Stichprobengröße und den Namen der Verteilung bekommt und anschließend folgen die Parameter für die Verteilung. Also bei der Normalverteilung Mittelwert und Standardabweichung, bei der t- oder χ²-Verteilung die Freiheitsgrade.
erzeuge_daten <- function(n = 100, verteilung = "normal", ...) {
if (verteilung == "normal") x = rnorm(n, ...)
else if (verteilung == "t") x = rt(n, ...)
else if (verteilung == "chi2") x = rchisq(n, ...)
else {
print("Aktuell werden nur Normal-, t- und Chi²-Verteilung unterstützt")
return()
}
return(x)
}

erzeuge_daten(n = 10, verteilung = "normal", 3, 1)
erzeuge_daten(n = 10, verteilung = "normal", 3)
erzeuge_daten(n = 10, verteilung = "t")

Wollen wir ein bisschen mehr Kontrolle haben, wann welcher Parameter eingesetzt wird, können wir das mit zwei Punkten und der Position angeben, also ..1 für den ersten Parameter, ..2 für den zweiten Parameter usw.
erzeuge_daten <- function(n = 100, verteilung = "normal", ...) {
if (verteilung == "normal") x = rnorm(n, ..1, ..2)
else if (verteilung == "t") x = rt(n, ..1)
else if (verteilung == "chi2") x = rchisq(n, ..1)
else {
print("Aktuell werden nur Normal-, t- und Chi²-Verteilung unterstützt")
return()
}
return(x)
}
erzeuge_daten(n = 10, verteilung = "normal", 3, 1)
erzeuge_daten(n = 10, verteilung = "normal", 3)
erzeuge_daten(n = 10, verteilung = "t")

Machen wir das so, sehen wir beim Aufruf, dass die Default-Werte kaputt gegangen sind, d.h. für die Normalverteilung muss man nun zwei Parameter angeben.
Achtung: Der Einsatz von … in R-Funktionen sollte mit Bedacht gewählt sein. Denn nicht oder falsch benannte Parameter erzeugen keine Fehlermeldung.
Wir können natürlich fordern, dass die zusätzlichen Parameter benannt sind. Man muss sich allerdings selber darum kümmern und das artet dann in einige Zeilen Code mit unschönen if-Bedingungen aus. Die Länge bzw. Namen der Parameter bekommt man , indem man … in eine Liste umwandelt, wie das im folgenden Beispiel in der ersten Zeile der Funktion passiert.
erzeuge_daten <- function(n = 100, verteilung = "normal", ...) {
args = list(...)
if (verteilung == "normal") {
if (length(args)==0 |
(length(args) <= 2 & ("mean" %in% names(args) | "sd" %in% names(args)))) {
x = rnorm(n, ...)
}
else {
print("Für die Normalverteilung gibt es die optionalen Parameter mean und sd")
return()
}
}
else if (verteilung == "t") {
if (length(args) == 1 & "df" %in% names(args)) {
x = rt(n, ...)
}
else {
print("Für die t-Verteilung muss der Parameter df angegeben werden")
return()
}
}
else if (verteilung == "chi2") {
if (length(args) == 1 & "df" %in% names(args)) {
x = rchisq(n, ...)
}
else {
print("Für die Chi²-Verteilung muss der Parameter df angegeben werden")
return()
}
}
else {
print("Aktuell werden nur Normal-, t- und Chi²-Verteilung unterstützt")
return()
}
return(x)
}
erzeuge_daten(n = 10, verteilung = "normal", 3, 1)
erzeuge_daten(n = 10, verteilung = "normal", mean = 3)
erzeuge_daten(n = 10, verteilung = "t", df = 4)

Noch da? Bei dem ganzen Aufwand ist schon die Frage, ob man nicht einfach die Parameter explizit angibt. Dabei Default-Werte für die Parameter vergeben, dann müssen nur die benötigten angegeben werden.
erzeuge_daten <- function(n = 100, verteilung = "normal", mean = 0, sd = 1, df = 3) {
if (verteilung == "normal") x = rnorm(n, mean, sd)
else if (verteilung == "t") x = rt(n, df)
else if (verteilung == "chi2") x = rchisq(n, df)
else {
print("Aktuell werden nur Normal-, t- und Chi²-Verteilung unterstützt")
return()
}
return(x)
}

Oder ihr macht es ganz anders und gestaltet die Funktion ganz allgemein, indem man ihr als ersten Parameter die Zufalls-Erzeugungsfunktion (ist das ein Wort?) übergibt. Dann ist es nämlich nur ein Einzeiler:
erzeuge_daten <- function(zufallsfunktion, ...) {
return(do.call(zufallsfunktion, list(...)))
}
erzeuge_daten(rnorm, n=10, mean = 3)

Rekursive Funktionen in R
Als rekursiv bezeichnen wir eine Funktion, wenn sie sich selbst wieder aufruft. Dabei sollte natürlich irgendein Parameter gesetzt werden, so dass wir nicht in einer Endlos-Schleife gefangen sind.
Dieses Konstrukt ist ganz elegant (obwohl nicht immer mit der besten Performance), wenn man mathematische Folgen nachbauen möchte, die selber schon rekursiv sind.
Ein Beispiel ist die Fakultätsfunktion n!, die alle natürlichen Zahlen bis zu n miteinander multipliziert. Würde man (n-1)! kennen, müsste man es nur noch mit n multiplizieren und hätte das Ergebnis
n! = 1 * 2 * … * n = (n-1)! * n
Zusätzlich ist 0! = 1 definiert. Die Umsetzung in R ist kein großes Problem.
fac <- function(n) {
if(n == 0 | n ==1) return(1)
else return(fac(n-1))
}

Ein weiteres beliebtes Beispiel sind die Fibonacci-Zahlen. Die n-te Fibonacci-Zahl ist definiert als die Summe der beiden Vorgänger. Zudem sind die ersten beiden Fibonacci-Zahlen als 1 definiert.
fibo <- function(n) {
if(n == 1 | n == 2) return(1)
else return(fibo(n-1) + fibo(n-2))
}

Hier sehen wir schon, dass das zwar elegant, aber nicht sonderlich effizient ist, denn die beiden Vorgänger werden einzeln berechnet. In der Praxis sind rekursive Funktionen auch eher die Ausnahme.

Operatoren in R definieren
Ok, jetzt habt ihr es bis hierhin geschafft. Dann gibt es als Belohnung noch eine Möglichkeit, Funktionen zu definieren. Und zwar kennt ihr vermutlich Operatoren, die zwischen zwei Objekten stehen. Also zum Beispiel 5 %in% 1:5, wobei geprüft wird, ob der erste Wert in dem zweiten Vektor enthalten ist. Solche Operatoren können wir auch selber definieren. Vielleicht nervt euch ja auch das Verbinden von Zeichenketten mittels paste. Wir könnten ja einen Operator definieren, der das für uns erledigt. Das geht ganz einfach, wenn man weiß wie. Dafür muss nämlich der Operator zum einen mit % anfangen und enden, zum anderen muss er bei der Definition in schräge Hochkommata eingepackt werden. Unser String-Verkettungs-Operator sieht dann folgendermaßen aus:
`%+%` <- function(str1, str2) {
return(paste0(str1, str2))
}
"Hans" %+% "wurst" %+% " ist da!"

Aber Achtung: Viele eigene Operatoren können das Nachvollziehen für jemand anderen erschweren, da man sich quasi eine ganz eigene Syntax bastelt.
Ein R-Skript mit nützlichen Funktionen einbinden
Habt ihr eine Sammlung eigener Funktionen angelegt, von denen ihr die eine oder andere in fast jedem Skript braucht. Dann habt ihr zwei Möglichkeiten, diese einzulesen. Am einfachsten geht es mit dem source-Befehl. Dazu einfach am Anfang eines Skripts source(„Meine_Funktionen.R“) schreiben und fertig!
Ihr könnt natürlich auch direkt ein Package daraus machen. Das ist auch nicht so schwer, wie es sich anhört, aber das heben wir uns für einen anderen Artikel auf.
Happy functioning, Euer Holger

LERNE DATA SCIENCE mit R

Ein Data Science Experte ist in der heutigen datengetriebenen Welt viel gefragt. Mit der entsprechenden Erfahrung kann man sich den gutbezahlten, interessanten Job aussuchen. In meinem Onlinekurs Data Science mit R lernst Du die Grundlagen.

Jetzt informieren

Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean

Python-Tutorial für ein Kommandozeilen-Tool mit argparse

Möchtest Du ein Kommandozeilen-Tool (CLI = command line interface) in Python bauen? Mir ging es vor kurzem so. Ich hatte einige nützliche Funktionen geschrieben und die IT von einem Kunden wollte diese Funktionen direkt von der Kommandozeile aus nutzen. Die Funktionen haben natürlich Parameter, die übergeben werden müssen.

Was ist ein „command line interface“ (CLI)?

Jeder, der schon mal mit der Eingabeaufforderung (Command Prompt oder Shell) gearbeitet hat, sei es unter Windows oder in einer Linux-Shell, kennt es. Nach dem Programm folgen noch ein oder mehrere Parameter, z.B. ls –l, cd .. oder conda install pandas. Für Linux-User, die sowieso viel in einer Shell unterwegs sind, braucht man den Nutzen gar nicht zu erklären. Für viele Windows-User ist es ungewohnt, sind sie doch eher mit der Maus unterwegs. Als Python-Programmierer kommt man aber sowieso nicht drum herum, schließlich benötigen wir Environments und müssen Packages installieren (entweder über virtualenv und pip oder mittels conda).

Prinzipiell sind der Komplexität von CLIs keine Grenzen gesetzt. Auch verschachtelte Menüs sind denkbar, durch die der Nutzer navigieren kann. Dabei stellt sich allerdings die Frage, ob eine grafische Benutzeroberfläche nicht besser geeignet ist. Auf der anderen Seite ist eine textbasierte Benutzeroberfläche nötig, wenn es sich um einen Cloud-Rechner handelt, auf den man nur per Terminal zugreift. So gibt es CLIs für Azure und AWS.

Als besonders praktisch haben sich aber solche Kommandozeilen-Tools herausgestellt, die direkt alle Optionen in ihrem Aufruf abdecken. Die meisten Betriebssystem-Befehle funktionieren so, auch viele Programmier-Tools wie git, pip oder conda. Der Vorteil gegenüber einem Benutzermenü ist, dass solche Programme in Skripten (Batch- bzw. Bash), aus anderen Programmiersprachen oder von einer GUI aufgerufen werden können.

Arten von Parametern
Man kann drei Arten von Parametern unterscheiden:

positional: hier ist die Position entscheidend, also an welcher Stelle der Parameter steht.
optional: Die häufigste Art, der Parameter wird über ein Schlüsselwort (mit – oder — davor) sowie den Wert angegeben. Dadurch ist die Reihenfolge unwichtig. Meist wird — mit dem vollständigen Parameternamen und alternativ – mit der Abkürzung verwendet. Zum Beispiel der Namensparameter beim Erzeugen eines Environments in conda: conda create –name myenv conda create -n myenv. Interessant bei conda ist, dass das erste Argument create positional ist. Das liegt daran, dass conda im Prinzip viele Befehle in ein einziges CLI packt. Der erste Parameter wählt also wie in einem Menü aus, welcher Befehl dran ist, erst danach folgen die Parameter zu dem Befehl. Wie man diese Art von CLIs programmiert, erkläre ich im Kapitel Komplexere Kommandozeilen-Tools.
flag: Das sind Parameter, die nur ja/nein bzw. true/false als Ausprägungen haben. Insofern ist es meist so realisiert, dass die Abwesenheit des Flags FALSE bedeutet und die Anwesenheit TRUE. In conda zum Beispiel die Parameter –all und –y in conda update –all -y, um alle Packages upzudaten bzw. die Nachfrage im Skript zu überspringen.

Wer coole Tricks zu Linux-CLIs sucht, schaut mal auf Twitter bei @climagic vorbei.

Datenanalyse mit Python - 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Wie erstellt man ein command line interface (CLI) in Python?
Ein Kommandozeilen-Interface in Python zu bauen ist überhaupt nicht schwer. Ein bisschen hängt es natürlich davon ab, welche Komplexität man benötigt. Aber für (fast) jeden Anwendungsfall gibt es ein Package, welches einem die Arbeit erleichtert.
Wir wollen uns den Programmaufruf mit Parametern ansehen. Wie oben geschrieben ist das ein ganz typischer Fall, denn er erlaubt uns, unsere Python-Programme flexibel aufzurufen oder in Batch-Skripten zu nutzen.
Fangen wir einfach an. Wir wollen einen Würfel simulieren (Im Blog gibt es übrigens ein Würfelsimulations-Tutorial) und übergeben als Parameter die Anzahl Würfe.
Der manuelle Weg
Die Parameter beim Aufruf des Programms heißen übrigens arguments und sind in fast allen Programmiersprachen über eine Variable, die mit arg beginnt, abzugreifen. In Python ist es eine Liste mit Namen argv aus der Standardbibliothek sys.
Mit den folgenden zwei Zeilen Python-Code geben wir also einfach die Parameter aus:
import sys
print(sys.argv)
Wenn wir dieses Mini-Programm unter miniargs.py abspeichern und aufrufen, wird eine Liste mit den Parametern ausgegeben. Beachte, dass der erste Eintrag (Index 0) das Programm selber ist.
Nun geht es an die Würfelsimulation. Dazu definieren wir die Funktion wuerfeln mittels dem Zufallsgenerator von Numpy. Dann folgt die Abfrage, ob es einen Parameter gibt (die Länge muss also zwei sein, da als erster Eintrag das Python-Skript selber übergeben wird) und ob dieser Parameter eine ganze Zahl ist. Sind die Bedingungen erfüllt, wird die wuerfel-Funktion aufgerufen und ausgegeben, andernfalls kommt die Fehlermeldung.
import numpy as np
import sys

def wuerfeln(wuerfe=1, seiten=6):
return np.random.choice(np.arange(1, seiten + 1), size=wuerfe)

if len(sys.argv) == 2 and sys.argv[1].isdigit():
    wuerfe = int(sys.argv[1])
    print(wuerfeln(wuerfe))
else:
    print("Bitte gib die Anzahl Würfe als Parameter an, z.B. python wuerfel 3")
Das war ja schon ganz nett, aber damit wir gerade bei komplexeren Abfragen nicht alles manuell machen müssen, gibt es das tolle Package argparse.
Würfelsimulation mit dem Python-Package argparse
Das Python-Package argparse ist wirklich sehr bequem, um Kommandozeilen-Tools zu bauen. Die Installation erfolgt wie gewohnt über pip oder conda, je nachdem was ihr nutzt, also
pip install argparse bzw. conda install argparse
Und dann können wir mit dem Würfelbau loslegen!
Natürlich brauchen wir wieder unsere wuerfel-Funktion. Dann definieren wir den Parser und fügen ein int-Parameter, nämlich die Anzahl Würfe hinzu. In den letzten zwei Zeilen passiert dann das eigentliche Aufdröseln der Parameter (ok, hier gibt es nicht viel zu tun) und der Aufruf der wuerfel-Funktion.
Praktischerweise wird auch direkt eine Hilfe-Funktion, allerdings auf Englisch, mitgeliefert.
import argparse
import numpy as np

def wuerfeln(wuerfe=1, seiten=6):
    return np.random.choice(np.arange(1, seiten + 1), size=wuerfe)

parser = argparse.ArgumentParser(description="Würfelsimulator")
parser.add_argument("wuerfe", type=int, help="Anzahl der Würfe")
args = parser.parse_args()
print(wuerfeln(args.wuerfe))
Auf einen Parameter, den ihr mit add_argument(„parametername“, …) hinzugefügt habt, könnt ihr mit args.parametername zugreifen.

Verschiedene Parametertypen in argparse
Es gibt ja mehrere Arten von Parametern, was ich oben in Was ist ein CLI? beschrieben habe. Wir haben bisher nur positionale Parameter gebaut. Flexibler ist man mit Optionen, da dann die Reihenfolge keine Rolle mehr spielt. Dafür brauchen sie einen Namen. Das zeige ich euch jetzt. Im Anschluss kommen noch Flags in Spiel, also ein Schalter.
Benannte Parameter in CLI
Gestalten wir das vorherige Beispiel um, so dass wir zwei Parameter übergeben, die Anzahl Würfe und die Seitenanzahl des Würfels. Und das setzen wir mit Optionen um. Der Aufruf soll also z.B. so aussehen:
python wuerfeln.py --wuerfe 3 --seiten 6
Meist gibt es auch Abkürzungen, die dann nur mit einem Minus geschrieben werden:
python wuerfeln.py -w 3 -s 6
Das ist ganz einfach, wir müssen nur die eine add_argument-Zeile anpassen und eine zweite hinzufügen. Dabei fügen wir direkt noch jeweils einen Default-Wert hinzu, so dass der Parameter nicht angegeben werden muss.

parser.add_argument("--wuerfe", "-w", type=int, default=1, help="Anzahl der Würfe")
parser.add_argument("--seiten", "-s", type=int, default=6, help="Seitenanzahl des Würfels")
Statt einer beliebigen Seitenzahl wollen wir vielleicht nur bestimmte Würfel zulassen. Dazu gibt es den Parameter choices, den wir einfach einfügen können und damit die zugelassene Würfel auf W6, W12 und W20 einschränken:

parser.add_argument("--seiten", "-s", type=int, choices=[6, 12, 20], default=6, help="Seitenanzahl des Würfels")
Schon gibt es eine Fehlermeldung wenn wir eine andere Zahl benutzen:error: argument –seiten/-s: invalid choice: 3 (choose from 6, 12, 20)
Flags mit argparse
Flags sind super einfach zu implementieren. Man muss nur einen Parameter mit add_argument hinzufügen, der mit action=store_true oder store_false initialisiert wird.
Also ans Werk: Wir bauen ein Flag –schummeln ein, welches die Wahrscheinlichkeit für die höchste Punktzahl verdoppelt. Also bei einem 6-seitigen Würfel würde die 6 die Wahrscheinlichkeit 1/3 statt 1/6 bekommen und die verbleibenden 5 Seiten entsprechend weniger, d.h. jede Seite (1- 1/3) * 1/5 2/15. Das Komplizierteste an diesem Beispiel ist, das für beliebige Seitenanzahlen umzusetzen.
Wir schreiben also zuerst die wuerfel-Funktion um und ergänzen dort den Schummel-Parameter. Die choose-Funktion von numpy erlaubt die Angabe eines Vektors mit den Wahrscheinlichkeiten, den müssen wir also zuerst konstruieren.

def wuerfeln(wuerfe=1, seiten=6, schummeln=False):
    if schummeln:
        w_max = 2 / seiten
        w_normal = (1 - w_max) / (1 - seiten)
        p = ([w_normal] * (seiten - 1)).append(w_max)
        return np.random.choice(np.arange(1, seiten + 1), size=wuerfe, p=p)
    else:
        return np.random.choice(np.arange(1, seiten + 1), size=wuerfe)
Ist das geschafft, ergänzen wir den Parameter in der Parser-Definiton, unter den Parameters für Anzahl Würfe und Seiten
parser.add_argument("--schummeln", "-sch", action="store_true", help="Schummel-Flag")

Datenanalyse mit Python – 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Komplexere Kommandozeilen mit mehreren Befehlen
Stellt euch vor, wir haben mehrere Befehle, die wir aber mit nur einer CLI aufrufen wollen. Dazu geben wir im ersten Argument den Befehl an, die Optionen zum entsprechenden Befehl folgend dann danach. So ist das z.B. bei conda, da gibt es conda activate, conda install packagename, conda create –name envname usw.

Solch eine komplexe Struktur ist mit argparse ziemlich leicht und bequem umzusetzen. Wir wollen unser Beispiel von oben erweitern, indem wir neben Würfeln auch noch Münzwurf und Lotto simulieren. Beim Lotto soll man seine Zahlen angeben müssen.
Wir wollen also, dass das CLI namens glueck.py folgendes kann:

python glueck.py wuerfeln -w 3 -s 6 -schummeln (wobei die Parameter wuerfe und seiten optional sind, da sie default-Werte haben und schummeln ein flag ist)
python glueck.py muenze -w 10 (wobei der Parameter wuerfe einen default-Wert hat)
python glueck.py lotto --zahlen 10 13 19 20 33 49 –superzahl 3

Zuerst definieren wir uns die eigentlichen Funktionen, die aufgerufen werden sollen:
import argparse
import numpy as np

def wuerfeln(wuerfe=1, seiten=6, schummeln=False):
    if schummeln:
        w_max = 2 / seiten
        w_normal = (1 - w_max) / (1 - seiten)
        p = ([w_normal] * (seiten - 1)).append(w_max)
        return np.random.choice(np.arange(1, seiten + 1), size=wuerfe, p=p)
    else:
        return np.random.choice(np.arange(1, seiten + 1), size=wuerfe)

def muenze(wuerfe=2):
    return np.random.choice(["W", "Z"], size=wuerfe)

def lotto(zahlen, superzahl):
    gezogen = np.random.choice(np.arange(1, 50), size=6)
    gezogen_sz = np.random.choice(np.arange(0, 10), size=1)
    anzahl_richtige = np.sum(zahlen == gezogen)
    nicht_sz = "" if superzahl == gezogen_sz else "nicht "
    ziehung_text = "Ziehung: " + str(gezogen) + ", Superzahl: " + str(gezogen_sz)
    print(ziehung_text)
    return "Anzahl Richtige: " + str(anzahl_richtige) + ", Superzahl stimmt " + nicht_sz + "überein"
Nun bauen wir die CLI zusammen. Dazu definieren wir uns für jeden Befehl (also den ersten Parameter) eine Funktion, der die Argumente args übergeben werden. Prinzipiell hätten wir auch in diesen Funktionen die eigentlichen Funktionen reinschreiben können, aber durch die Entkoppelung ist es zum einen übersichtlicher, zum anderen können die Funktionen oben auch innerhalb von Python genutzt werden.
def wuerfeln_fct(args):
    print(wuerfeln(args.wuerfe, args.seiten, args.schummeln))

def muenze_fct(args):
    print(muenze(args.wuerfe))

def lotto_fct(args):
    print(lotto(args.zahlen, args.superzahl))
Jetzt folgt noch die eigentliche Definition des ArgumentParsers. Dazu fügen wir Subparser hinzu, für jeden Befehl einen. Diesen Subparsern geben wir die jeweiligen Argumente mit.  Beim lotto-Parser haben wir noch eine Besonderheit, nämlich nargs, das angibt, ob ein Parameter mehrfach vorhanden sein darf/muss, in unserem Fall sollen es genau 6 Zahlen sein. Neben Zahlen funktionieren auch “*” für beliebig viele Argumente, “+” für mindestens ein Argument und noch ein paar andere Möglichkeiten. Schaut doch mal in die Dokumentation von argparse, was es alles für Parameter von add_argument gibt.
parser = argparse.ArgumentParser(description="Glücksspiel")
subparsers = parser.add_subparsers()

# wuerfeln-Befehle
parser_wuerfeln = subparsers.add_parser("wuerfeln", help="Simulation eines Würfels")
parser_wuerfeln.add_argument("--wuerfe", "-w", type=int, default=1, help="Anzahl der Würfe")
parser_wuerfeln.add_argument(
    "--seiten", "-s", type=int, choices=[6, 12, 20], default=6, help="Seitenanzahl des Würfels"
)
parser_wuerfeln.add_argument("--schummeln", "-sch", action="store_true", help="Schummel-Flag")
parser_wuerfeln.set_defaults(func=wuerfeln_fct)

# muenze-Befehl
parser_muenze = subparsers.add_parser("muenze", help="Simulation von Münzwürfen")
parser_muenze.add_argument("--wuerfe", "-w", type=int, default=1, help="Anzahl der Würfe")
parser_muenze.set_defaults(func=muenze_fct)

# lotto-Befehl
parser_lotto = subparsers.add_parser("lotto", help="Simulation von Lotto 6 aus 49")
parser_lotto.add_argument(
    "--zahlen", "-z", type=int, nargs=6, choices=np.arange(1, 50), required=True, help="Deine 6 Zahlen"
)
parser_lotto.add_argument(
    "--superzahl", "-sz", type=int, choices=np.arange(0, 10), required=True, help="Superzahl"
)
parser_lotto.set_defaults(func=lotto_fct)

args = parser.parse_args()
try:
    args.func(args)
except AttributeError:
    parser.print_help()
    parser.exit()
Noch eine kleine Besonderheit in den letzten Zeilen. Statt einfach nur args.func(args) zu verwenden, habe ich es in einen try-except-Block geschoben. Hintergrund ist, dass die Funktion einen Fehler ausgibt, wenn gar kein Argument übergeben wird, also einfach nur python glueck.py aufgerufen würde. Dann ist es aber für den Nutzer schöner, wenn die Hilfe angezeigt wird.
 Und was gibt es sonst noch
Habt Ihr immer noch nicht genug und wollt CLI-Experten werden. Ok, dann habe ich Euch noch ein paar Links zum Weiterlesen zusammengesucht. Es gibt auch einige Alternativen zu argparse, die Euch vielleicht besser gefallen bzw. andere Möglichkeiten haben:

Das Manual zu argparse
Ein Artikel über CLI Best Practices von Cody A. Ray auf Medium (auch wenn ich Medium sonst nicht mag).
Click ist eine Alternative zu argparse mit einer etwas anderen Herangehensweise. Der Parser wird nämlich über decorators definiert.
Wollt ihr interaktive Text-Menüs? Dann schaut Euch mal den PyInquirer an, der dieses coole Feature ermöglicht.
Clint ist ein Package, welches Farben, Einrückungen etc. unterstützt.

So, das war’s jetzt aber. Ich hoffe, Ihr konntet die Beispiele gut nachvollziehen und brennt nun darauf, selber ein Kommandozeilen-Tool in Python zu bauen.
Happy coding,Euer Holger
 
Photo by Dan LeFebvre on Unsplash

Datenanalyse mit Python - 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean ls

Datentypen in R – einfach erklärt (Teil 2)

So, liebe R-Braineos, hier kommt der zweite Teil zu Datentypen in R. Nachdem wir in Teil 1 die Basis-Datentypen von R erledigt haben, geht es nun datum, diese zu kombinieren.
Zusammengesetzte Datentypen in R
Die Power von R liegt nämlich nicht in den Basisdatentypen, sondern darin, dass fast alles auf Vektoren aufbaut. Vector und data.frame (Tabellen) sind die Objekte, die ich als Data Scientist ständig gebrauche. Aber auch list ist nicht zu verachten.
Mehrere Elemente eines Datentyps – Der Datentyp VECTOR in R
Vektoren sind eine durchnummerierte Kette von Objekten eines Datentyps. Wichtig: Es geht nur ein Datentyp pro Vektor, man kann nicht bunt mischen (dafür benötigt man dann Listen). Und in R ist jeder der Basisdatentypen automatisch ein Vektor, das erkennt man an der 1 in eckigen Klammern vor dem Output. Eckige Klammern sind das Stichwort, denn so können wir die einzelnen Elemente ansprechen. Die Funktion zum Verbinden von Elementen zu einem Vektor heißt einfach c (für combine). Mit length bekommt man die Länge des Vektors zurück.
# Einen Vektor x mit drei Elementen erzeugen
x = c(3,4,5)
# Die Klasse eines Vektors ist der zugrundeliegende Datentyp, hier numeric
class(x)
# length gibt die Anzahl Elemente des Vektors zurücl
length(x)
# die Elemente spricht man über Indizes in den eckigen Klammern an
x[1]
# das erste und dritte Element
x[c(1,3)]

Operationen und Vergleiche werden für jedes Element durchgeführt. Und hier kommt die Power von R ins Spiel, die manchmal leider auch schwierig sein kann. Es geht um die vektorielle Auswertung. Anstatt zum Beispiel eine Schleife zu programmieren, mit der jedes Element von x um 1 erhöht wird, schreibt man einfach x+1. Solche Vektoroperationen haben übrigens auch einen enormen Geschwindigkeitsvorteil und sollten (fast) immer einer Schleife vorgezogen werden.
# Operationen wie Addition wird auf jedes Element angewandt
y <- x + 1
y
# auch Vergleiche sind Operationen und werden auf jedes Element angewandt
z = y > 4
class(z)
# Auswahl über einen boolschen Vektor der gleichen Länge
y[z]
# Das geht natürlich auch direkt, ohne eine andere Variable zu erzeugen
y[y > 4]

GRATIS 5-Tage Minikurs: Datenanalyse in R

Du kennst Dich noch nicht so gut damit aus, wie man einen Datensatz in R analysiert? Ich bin da, um Dir zu helfen. Hole Dir jetzt meinen kostenlosen Datenanalyse mit R – Kurs und fange an, Dir diese zukunftsweisenden Skills anzueignen.

Vektoren lassen sich von jedem Grunddatentyp erzeugen. Im nächsten Beispiel ist der Vektor a vom Typ character. Negative Indizes entfernen die entsprechende Stelle. a[-1] entspricht also a[2:length(a)]. Mit dem Doppelpunkt erzeugt man übrigens einen integer-Vektor mit alles ganzen Zahlen zwischen den beiden angegeben Zahlen, also 1:3 entspricht also c(1L, 2L, 3L).
a = c("H","a","l","l","o")
class(a)
a[1]
# Der Doppelpunkt erzeugt einen Vektor von ganzen Zahlen
1:3
a[1:3]
a[c(1,2,3)]
# Ein negativer Wert entfernt das Element aus dem Vektor
a[-1]
a[-3:-1]
length(a)
 
# nchar wird auf jedes Element angewandt
b = c("Ha","llo")
nchar(b)
# paste verbindet mehrere Strings
paste(a, collapse ="")

# implizite Umwandlung von numeric in character, damit der Vektor nur einen Datentyp hat
x = c("Hallo",1L, 3.14)
# Kombination von zwei Vektoren zu einem
z = c(x,y)

Mehrere Elemente verschiedener Datentypen – Der Datentyp LIST in R
Vektoren sind super, haben aber die Einschränkung, dass es sich immer um einen Datentyp handeln muss. Wollen wir verschiedene Datentypen in einem Objekt, dann benötigen wir eine Liste.
Auch Listen sind in R ganz einfach und schnell erstellt. Sie sind aber bei weitem nicht so performant wie Vektoren. Wenn es also möglich ist, sollten Vektoren verwendet werden. Dafür sind Listen aber soooo flexibel. Listen können Vektoren, wiederum Listen und eben jedes Objekt in R enthalten.
Die Elemente einer Liste lassen sich wie bei Vektoren über den Index ansprechen, wir brauchen hier aber doppelte eckige Klammern. Die Anzahl Elemente bekommt man wie bei Vektoren über die Funktion length.
l = list(1L, 1.34, "Hallo", 1:3)
# l ist vom Typ list
class(l)
is.list(l)
length(l)
l[[1]]
class(l[[1]])
l[[4]][1]

Eine super nützliche Sache ist das Benennen der Elemente einer Liste mit der Funktion names. Dazu einfach einen Character-Vektor der gleichen Länge übergeben. Dann lassen sich die Elemente per Namen, besonders praktisch in der $-Notation, ansprechen. Der Name eines Elements lässt sich auch einfach ändern, denn die Namen sind nur ein Vektor.
names(l) <- c("Tick","Tack","Toe","Foo")
l[["Tick"]]
l$Tick
# Benennung der Elemente direkt beim Erzeugen
l2 <- list(pi=3.14, euler=2.718, Toe="Hallo", Foo=1:3)
l2$Foo
names(l)[3] <- "Tock"
names(l)

Listen lassen sich wie Vektoren mit c einfach zusammenfügen. Beim Löschen gibt es zwei Varianten. Willst Du wirklich ein Element in der Liste löschen, also die Liste verändern, dann setzt man das Element auf NULL. Willst Du die Liste ohne ein Element übergeben, also die Liste selber nicht verändern, dann geht es wie bei Vektoren mit einem negativen Index.
l3 <- c(l, l2)
# Löschen eines Elements, Liste wird dadurch verändert
l3[[1]] <- NULL
# Element wird nicht mit übergeben, l3 aber nicht verändert
l4 <- l3[-1]

LERNE DATA SCIENCE mit R

Ein Data Science Experte ist in der heutigen datengetriebenen Welt viel gefragt. Mit der entsprechenden Erfahrung kann man sich den gutbezahlten, interessanten Job aussuchen. In meinem Onlinekurs Data Science mit R lernst Du die Grundlagen.

Jetzt informieren

Tabellen – Der Datentyp DATA.FRAME in R
Data.frames sind ein Muss für alle Datenanalyen. Im Endeffekt sind data.frames Tabellen, bei der jede Spalte von einem Datentyp ist. Stellt euch die Erfassung einer Befragung vor. Jede Zeile entspricht einem Befragten, die Spalten sind die einzelnen Fragen.
Einen data.frame erzeugt man, indem man die einzelnen Spalten der Funktion data.frame übergibt. Die Anzahl Spalten bzw. Zeilen bekommt man mit ncol bzw. nrow oder direkt beide mit dim.
df = data.frame(x = rnorm(10),
y = sample(c("Rot","Gelb","Grün"), 10, replace = TRUE),
z = 1L:10L)
class(df)
ncol(df)
nrow(df)
dim(df)

Der Zugriff auf die einzelnen Elemente oder Spalten bzw. Zeilen ist eine Mischung aus Vektor und Liste. Ein Element des data.frames bekommt man über Zeilen- und Spaltenangabe in eckigen Klammern. Lässt man einen der beiden Indizes weg (das Komma aber nicht), dann bekommt man die ganze Zeile bzw. Spalte. Die Spalten lassen sich wie bei Listen praktisch über den Spaltennamen ansprechen.
df[1,3]
df[1,]
df[,1]
df$x
df[,"x"]
df[1,1:2]
class(df$x)

# Filterung der Zeilen anhand einer Bedingung
df[df$y=="Gelb",]
# Mittelwert der Spalte x, wenn auf Gelb gefiltert wurde
mean(df$x[df$y=="Gelb"])

Die Spaltennamen lassen sich über colnames ansprechen. names wie bei Listen geht auch, aber colnames ist eindeutiger, es gibt auch rownames. Eine neue Spalte kann man einfach anfügen, indem man diese direkt benennt.
colnames(df)[1] <- "a"
colnames(df)
df$b <- rbinom(nrow(df),20,0.4)
df$b <- NULL

Spezielle Datentypen in R
Folge von kategoriellen Variablen – Der Datentyp FACTOR
R wurde für Datenauswertungen konzipiert. Und wer ein wenig Statistikerfahrung hat, weiß, dass Merkmale unterschiedliche Skalenniveaus haben können, also nominal, ordinal oder kardinal. Haben Daten ein nominales Skalenniveau, können also nur benannt werden wie z.B. Lieblingsfarbe, dann gibt es dafür in R den Datentyp factor.
f <- factor(c("Rot","Gelb","Rot","Blau","Blau","Blau"))
f
class(f)
is.factor(f)
length(f)
levels(f)
levels(f) <- c("Rot","Gelb","Blau","Grün")
f

Für ordinale Skalenniveaus, deren Ausprägungen geordnet werden können, kann das auch mit angegeben werden. Wir erhalten dann ein Objekt, was zwei Klassen angehört, nämlich factor und ordered.
auspraegungen <- c("nie","selten","oft","sehr oft")
of <- factor(c(1,1,2,2,4,4,3),labels = auspraegungen, ordered = TRUE)
of
class(of)
table(of)

# Mittelwert gibt es bei Faktoren nicht
mean(of)
# Median ist eigentlich bei ordinalen Skalen erlaubt
# in R funktioniert median nicht, man kann aber das 50%-Quantil verwenden
median(of)
quantile(of, .5, type=1)

Matrizenrechnung – Der Datentyp MATRIX
In R gibt es einen extra Datentyp Matrix. Im Prinzip wie ein data.frame, nur dass alle Elemente von einem Datentyp sein müssen. Besser ist daher der Vergleich mit einem Vektor, der zusätzlich Angaben zu den Dimensionen hat (so ist es auch in R realisiert).
Eine Matrix initialisiert man also durch Angabe eines Vektors und einer Spalten- oder Zeilenanzahl. Die Elemente des Vektors werden dann spaltenweise verwendet. Alternativ setzt man byrow auf TRUE, dann wird der Vektor zeilenweise verwendet.
Der Zugriff auf einzelne Elemente, Spalten und Zeilen erfolgt über einen Doppelindex in eckigen Klammern.
M = matrix(c(1,2,3,4,5,6),nrow=2)
class(M)
ncol(M)
nrow(M)
dim(M)
M
M[1,2]
M[1,]
M[,2]
M = matrix(c(1,2,3,4,5,6),nrow=2, byrow = TRUE)
M

Quadratische Matrizen können miteinander multizipliert werden. Achtung, dabei muss man zwischen der elementweisen Multiplikation * und der echten mathematische Matrixmultiplikation %*% unterscheiden. Die elementweise Multiplikation multipliziert jeden Eintrag der einen Matrix mit dem entsprechenden Eintrag der zweiten Matrix. M*M entspricht also dem quadrieren jedes Eintrags.
M = matrix(1:9,nrow=3, byrow = TRUE)
M
M * M
M %*% M
diag(M)

So, damit ist auch der zweite Teil geschafft und ihr seid nun R-Datentypen-Experten. Wenn ihr mit den Erklärungen und Beispielen etwas anfangen konntet, dann helft mir auch, indem ihr den Beitrag teilt. Danke!
Happy Coding,
Euer Holger

GRATIS 5-Tage Minikurs: Datenanalyse in R

Du kennst Dich noch nicht so gut damit aus, wie man einen Datensatz in R analysiert? Ich bin da, um Dir zu helfen. Hole Dir jetzt meinen kostenlosen Datenanalyse mit R – Kurs und fange an, Dir diese zukunftsweisenden Skills anzueignen.

LERNE DATA SCIENCE mit R

Ein Data Science Experte ist in der heutigen datengetriebenen Welt viel gefragt. Mit der entsprechenden Erfahrung kann man sich den gutbezahlten, interessanten Job aussuchen. In meinem Onlinekurs Data Science mit R lernst Du die Grundlagen.

Jetzt informieren

Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean ls

Datentypen in R – einfach erklärt

Liebe Brainies,
hier kommt ein Grundlagen-Artikel, es geht um Datentypen in R. Für Anfänger besonders geeignet, aber die eine oder andere Variante, mit den Variablen umzugehen, findet auch der fortgeschrittene R-Programmierer. Teil 2 beschäftigt sich dann mit zusammengesetzten Datentypen wie Vektoren, Listen, Tabellen usw.
Was sind überhaupt Datentypen?
Das ist tatsächlich gar nicht so einfach zu erklären, ohne in Fachsprache abzugleiten. Im Prinzip kategorisiert es die Art einer Variablen. Also zum Beispiel ob diese Variable eine ganze Zahl, eine Kommazahl, eine Zeichenkette oder auch ein komplexerer Typ wie Matrix oder Liste ist. Wenn man also einen Wert, einen Text, eine Tabelle oder andere Strukturen später wieder verwenden will, legt man diese Struktur im Arbeitsspeicher ab. Das passiert, indem man einen Stück vom Speicher reserviert, diesem Stück einen Namen zuweist und dann die Daten dort ablegt. Dieses Speicherstück heißt dann Variable. Die Größe des Speicherstücks hängt vom Datentyp ab. Ein Text braucht mehr Speicher als eine Wahr/Falsch-Variable.
Zum Glück ist das in R ganz einfach und intuitiv. Man muss in R häufig sogar nicht den Datentyp angeben, sondern durch eine Zuweisung wie x = 3 erkennt R automatisch, dass es sich um eine Zahl handelt. Das hat aber manchmal auch seine Tücken, denn so wird hier die 3 als Datentyp Kommazahl und nicht als ganze Zahl definiert. Bei vielen Programmiersprachen muss man daher den Typ immer mit angeben. In R fährt man aber ziemlich gut mit der automatischen Erkennung, nur in einigen Fällen muss man aufpassen.
Die meisten Programmiersprachen bieten einige Standard-Datentypen an, R ist da natürlich keine Ausnahme.
Der Zuweisungsoperator <- oder =
Um einen Wert in einer Variablen zu speichern, benutzt man in R entweder den Pfeil nach links <- oder das Gleichheitszeichen =. Es funktioniert sogar der Pfeil nach recht ->. Was man verwendet, macht in den allermeisten Situationen keinen Unterschied. Im R tidyverse styleguide wird allerdings der Linkspfeil dem Gleichheitszeichen vorgezogen. Es ist aber so, dass fast alle Programmiersprachen nur das Gleichheitszeichen kennen und somit R-Code für andere schwerer lesbar ist.
Tatsächlich waren früher nur die Pfeile möglich, das Gleichheitszeichen kam erst 2001 dazu. Die Pfeil-Zuordnung hat in erster Linie historische Gründe, denn R stammt von S ab und S wiederum ist inspiriert von APL. APL wurde in den 1960ern für IBM-Rechner entwickelt und die hatten diese Pfeile als Tasten auf der Tastatur.
Aus mathematischer Sicht schöner ist der Pfeil, denn er macht die Richtung der Zuordnungsrichtung klar. Shortcut für den Linkspfeil in R-Studio ist übrigens Alt + – (siehe auch Shortcuts in RStudio).
In dem Post Why do we use arrow as an assignment operator? von Colin Fay findet ihr auch Beispiele, wann nur der Pfeil funktioniert.
Ein Beispiel (zugegebenermaßen kein sauberer Programmierstil) ist die Zuordnung einer Variable innerhalb einer Funktion.
mean(y = 1:5)
#Fehler in mean.default(y = 1:5) : Argument "x" fehlt (ohne Standardwert)

mean(y <- 1:5)
#[1] 3

Die Lesbarkeit erhöht sich aber durch Verwendung des Pfeils, wenn ein Vergleich gemacht wird.
a = 5
b = 5.1
gleich = a == b
gleich <- a == b

GRATIS 5-Tage Minikurs: Datenanalyse in R

Du kennst Dich noch nicht so gut damit aus, wie man einen Datensatz in R analysiert? Ich bin da, um Dir zu helfen. Hole Dir jetzt meinen kostenlosen Datenanalyse mit R – Kurs und fange an, Dir diese zukunftsweisenden Skills anzueignen.

Einfache Datentypen
Ganze Zahl – Der Datentyp INTEGER
Die Überschrift sagt eigentlich schon alles. Es geht um positive und negative ganze Zahlen, in den meisten Programmiersprache integer oder int genannt. Wie oben geschrieben ist es in R etwas tückisch, denn mit x = 3 erzeugt man keinen integer, sondern eine Gleitkommazahl (numeric). Um explizit einen integer zu generieren, muss man noch ein L hinter der Zahl ergänzen. Mit is.integer prüft man, ob eine Variable vom Typ integer ist, sie gibt TRUE oder FALSE zurück. Solche Funktionen is.XXX gibt es für jeden Datentyp, also zum Beispiel auch is.numeric. Die Funktion class gibt mir den Datentyp zurück.
x <- 3
is.integer(x)
is.numeric(x)
class(x)

x <- 3L
is.integer(x)
# Besonderheit: Jeder integer ist gleichzeitig auch numeric
is.numeric(x)
class(x)

Achtung: Jede Zahl ist in R gleichzeitig auch ein Vektor der Länge 1. D.h. is.integer prüft nicht, ob es sich um eine einzelne Zahl handelt, sondern gibt auch TRUE zurück, wenn es sich um eine Folge von ganzen Zahlen handelt.
x <- 3L
is.vector(x)
# Vektor (1, 2, 3) erzeugen
x = c(1L, 2L, 3L)
is.integer(x)
is.numeric(x)
class(x)

Mit as.integer lassen sich andere Datentypen in integer verwandeln
as.integer(3)
as.integer(3.14)
as.integer(„3“)
as.integer(„3.14“)

Das L steht übrigens für long, was in der Programmiersprache C einem 32-bit integer entspricht (int ist dort 16-bit integer). Wer sich weiter verwirren möchte, in Java bezeichnet long einen 64-bit integer.
Das heißt also, dass für jede Zahl 32 Bit im Speicher reserviert sind, also 32 Nullen und Einsen. Da wir sowohl positive als auch negative Zahlen darstellen können, brauchen wir schon mal ein Bit für das Vorzeichen. Man spricht von einem signed int. Mit den restlichen 31 Bits können wir 2^31-1 Zahlen darstellen, d.h. der Wertebereich des integers in R reicht von -2147483647 bis +2147483647. In der System-Variablen .Machine$integer.max ist der maximale Wert gespeichert. Wollen wir dazu noch 1 addieren, dann erzeugen wir einen Überlauf und bekommen NA (not available) zurück.
2^31-1
.Machine$integer.max
as.integer(-.Machine$integer.max)
as.integer(.Machine$integer.max) + 1L

Der Datentyp numeric benutzt 64 Bit und kann daher größere Zahlen darstellen.
.Machine$integer.max + 1
.Machine$double.xmax

Aber auch hier ist etwas Vorsicht geboten. numeric repräsentiert eine Zahl nämlich intern als Gleitkommazahl, welche aufgrund der Darstellung mit Mantisse und Exponent manchmal komische Resultate liefert. Mehr dazu im nächsten Abschnitt.
Echte 64-Bit Ganzzahlen gibt es standardmäßig in R noch nicht (siehe auch R in a 64-Bit World auf R-Blogger). Es gibt aber alternativen. Für echte 64 Bit Ganzzahlen kann man das Package bit64 verwenden. Damit erweitert man den Wertebereich auf -9.223.372.036.854.775.807 bis +9.223.372.036.854.775.807 (=2^63 – 1). Man stößt tatsächlich schneller an die integer-Beschränkung als man so denkt. Zum Beispiel bei Datenbank-Tabellen, die die Zeilen durchnummerieren. Die Tabellen müssen noch nicht einmal besonders „groß“ sein, sondern sind vielleicht im Längsformat, bei der jedes Attribut eine eigene Zeile bekommt. In meinem Artikel über das Längs- und Querformat und wie man diese in R ineinander überführt könnt ihr darüber mehr erfahren.

LERNE DATA SCIENCE mit R

Ein Data Science Experte ist in der heutigen datengetriebenen Welt viel gefragt. Mit der entsprechenden Erfahrung kann man sich den gutbezahlten, interessanten Job aussuchen. In meinem Onlinekurs Data Science mit R lernst Du die Grundlagen.

Jetzt informieren

Kommazahlen – Der Datentyp NUMERIC
Wie wir schon im vorherigen Abschnitt gesehen haben, ist Numeric der Standard-Datentyp in R für Zahlen aller Art. Dieser entspricht dem C-Datentyp double, ist also eine Gleitkommazahl mit 64 Bit.
So eine Gleitkommazahl setzt sich aus Vorzeichen s, Mantisse m, Basis b und Exponent e zusammen:
x = (-1)^s * m * b^e
Intern wird als Basis 2 gewählt, auf dem Binärsystem basieren schließlich unsere Computer. Wenn man sich aber so eine Zahl anzeigen lässt, dann wird die Basis 10 gewählt.
print(23476132999423)
#[1] 2.347613e+13

Diese Darstellung ist eine Kurzform für 2,347613 * 10^13 = 23476130000000. Aber das ist nur die Darstellung, nicht die interne Genauigkeit. Mittels format oder sprintf kann man die Anzahl Stellen setzen, mit der eine Zahl ausgedruckt wird.
format(x, digits=14)
#[1] "23476132999423"
sprintf("%.0f",x)
#[1] "23476132999423"
sprintf("%.1f",x)
#[1] "23476132999423.0"
sprintf("%.2f",x)
#[1] "23476132999423.00"
sprintf("%.6f",x)
#[1] "23476132999423.000000"

Alternativ kann man in R eine „Bestrafung“ für diese Exponentialschreibweise einstellen:
options(scipen=999)
print(x)
#[1] 23476132999423

Wie gesagt, damit ändert man aber nur die Darstellung bei der Anzeige in der Konsole. Die tatsächliche Genauigkeit ist durch die 64 Bit gegeben. Diese 64 Bit werden so für eine Gleitkommazahl genutzt, wie es der Standard IEEE 754 festlegt: 1 Bit für das Vorzeichen, 52 Bit für die Mantisse und 11 Bit für den Exponenten. Um noch ein bisschen mehr aus den Bits herauszuholen, soll die Mantisse größer oder gleich 1 und kleiner als 2 sein, also 1,XXX. Das kann man durch Normalisierung erreichen. Da jetzt also die Mantisse nun immer mit einer 1 beginnt, kann diese 1 einfach weggelassen werden.
Der genaue Aufbau kann uns als R-Nutzer aber recht egal sein. Man sollte sich nur bewusst sein, dass diese Darstellung Grenzen hat. Das liegt aber nicht an R, sondern an der Definition der Gleitkommazahlen. So lässt sich 0,1 zum Beispiel nicht exakt als Gleitkommazahl darstellen, so dass das folgende passiert:
0.1 * 0.1
#[1] 0.01
0.1 * 0.1 == 0.01
#[1] FALSE

Bei sehr großen Zahlen rundet R automatisch, ohne das eine Warnung ausgegeben wird
x <- 999999999999456781
format(x, digits=14)
#[1] "999999999999456768"

x <- 999999999999456500
format(x, digits=14)
#[1] "999999999999456512"

Wahr oder Falsch – Der Datentyp LOGICAL
1 oder 0, wahr oder falsch, darauf basiert alles digitale. Genau diese zwei Werte, nämlich TRUE oder FALSE kann eine Variable vom Typ logical annehmen. Andere Programmiersprachen nennen diesen Datentyp auch bool oder eine Variable von dem Typ boolsche Variable.
In R erzeugt man eine boolsche Variable, indem man den Wert TRUE oder FALSE zuweist.
b <- TRUE
class(b)
#[1] "logical"
is.integer(b)
#[1] FALSE
is.numeric(b)
#[1] FALSE
as.integer(b)
#[1] 1
as.numeric(FALSE)
#[1] 0
as.character(b)
#[1] "TRUE"

Auch wenn der Test auf integer oder numeric falsch ergibt, kann man doch ganz normal damit rechnen. So steht TRUE für 1, FALSE für 0.
3 * TRUE - 3 * FALSE
#[1] 3

Wörter / Zeichenketten – Der Datentyp CHARACTER
Nun brauchen wir noch einen Datentyp, in dem wir Text speichern können. Statt Text spricht man von Zeichenketten oder englisch strings, einzelne Zeichen heißen character oder char. Der R-Datentyp für Strings heißt character.
Die Definition einer character-Variable in R ist einfach. Man stellt dafür den Text in Anführungsstriche (einfache oder doppelte). Mit nchar bekommt man die Anzahl Zeichen zurück (Achtung: length macht etwas anderes, siehe Vektoren)
a = "Hallo"
class(a)
#[1] "character"
is.character(a)
#[1] TRUE
nchar(a)
#[1] 5

Mit Strings kann oder muss man viele Dinge machen. Die wichtigsten sind:

Strings verbinden mittels paste und paste0
Teile von Strings extrahieren oder ändern mittels substring bzw. substr
Filtern mittels regulärer Ausdrücke. Reguläre Ausdrücke sind mächtig und bei allem, was mit Text zu tun hat, kaum wegzudenken. Es ist allerdings kein ganz leichtes Thema. Daher habe ich für Euch einen ganzen Blogpost über reguläre Ausdrücke in R geschrieben

substr(a,1,2)
#[1] "Ha"
substring(a,2) <- "ey"
toupper(a)
#[1] "HEYLO"
tolower(a)
#[1] "heylo"
paste(a, "Du da")
#[1] "Heylo Du da"
paste(a, " Du da",sep=",")
#[1] "Heylo, Du da"
grepl("e.l",a)
#[1] TRUE

Neben den Standard-Funktionen in R helfen vor allem die Packages stringi und stringr weiter, wobei stringr auf stringi aufbaut.
Datum und Zeitstempel – Die Datentypen DATE und POSIXCT
Um die Basis-Datentypen zu vervollständigen, dürfen Datum und Uhrzeit nicht fehlen. Tatsächlich ist der Umgang mit diesen beiden Typen ein wenig komplizierter. Am besten schaut ihr mal in mein R-Tutorial zu Datum und Uhrzeit.
# aktuelles Datum
d <- Sys.Date()
class(d)
format(d,"%Y")
as.Date("2020-03-11")
as.Date("11.03.2020", format = "%d.%m.%Y")

# aktueller Zeitstempel
ts <- Sys.time()
class(ts)
format(ts,"%Y")

So, damit haben wir die Basis-Datentypen INTEGER, NUMERIC, LOGICAL, CHARACTER, DATE und POSIXCT durch. Aber damit fangen wir gerade erst an, denn nun lassen sich diese Datentypen zu Vektoren, Matrizen, Tabellen und Listen zusammensetzen. Dazu findet ihr hier in Teil 2 Erklärungen und Code-Beispiele.
Happy coding,
Euer Holger

GRATIS 5-Tage Minikurs: Datenanalyse in R

Du kennst Dich noch nicht so gut damit aus, wie man einen Datensatz in R analysiert? Ich bin da, um Dir zu helfen. Hole Dir jetzt meinen kostenlosen Datenanalyse mit R – Kurs und fange an, Dir diese zukunftsweisenden Skills anzueignen.

LERNE DATA SCIENCE mit R

Ein Data Science Experte ist in der heutigen datengetriebenen Welt viel gefragt. Mit der entsprechenden Erfahrung kann man sich den gutbezahlten, interessanten Job aussuchen. In meinem Onlinekurs Data Science mit R lernst Du die Grundlagen.

Jetzt informieren

Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean ls

Lineare Regression in Python

Hallo liebe Brainies,
ich erkläre euch hier, was lineare Regression ist und wie ihr lineare Regression in Python umsetzen könnt. Natürlich liefere ich den Python-Code direkt mit, so dass ihr diesen direkt übernehmen könnt.
Lineare Regression ist den meisten vermutlich schon einmal begegnet. Grundsätzlich geht es darum, eine Variable Y durch eine oder mehrere andere Variablen X1, X2, …, Xn zu bestimmen bzw. vorherzusagen. Die zu bestimmende Variable Y nennt man auch Regressant, Kriterium oder einfach abhängige Variable (weil sie von den X abhängt), die für die Vorhersage verwendeten Variablen nennt man Prädiktoren oder Regressoren.
Die Abhängigkeit zwischen dem Regressant Y und den Prädiktoren X wird als linear angenommen. Y sollte metrisch sein, also so etwas wie Alter, Gewicht, Größe, Preis usw. Für Kategoriale Variablen wie Geschlecht, Lieblingsfarbe oder ja/nein-Fragen eignet sich die lineare Regression nicht, da kommt dann zum Beispiel die logistische Regression ins Spiel.
Es gibt noch viele Varianten der Regression, zum Beispiel in denen Polynome höheren Grads statt Geraden (das sind übrigens Polynome 1.Grads) verwendet werden.
Was ist lineare Regression?
Fangen wir einfach an. Nehmen wir erstmal nur eine Prädiktor-Variable X. Der Zusammenhang zwischen X und Y wird als linear angenommen. Haben wir nun einen Datensatz mit Beobachtungen, dann wollen wir eine Gerade durch die Punkte (xi, yi) legen. Und zwar so, dass die Gerade möglichst nahe an den Punkten liegt. D.h. die Summe der Abweichungen zwischen Gerade und den Punkten soll minimiert werden. Nun benutzt man nicht die einfache Abweichung, sondern die quadrierte, weil eine solche Minimierung statistisch schönere Eigenschaften hat. Man spricht daher von einem Kleinste-Quadrate-Schätzer (engl. OLS = ordinary-least-square).
Man kennt vielleicht noch die Geradengleichung aus der Schule: g(x) = m*x + c, wobei m die Steigung und c der y-Achsen-Abschnitt ist.
Bei der linearen Regression sieht es ganz ähnlich aus:
Y ~ b1*X + b0 + ε
Hier schreibt man kein Gleichheitszeichen hin, weil X und Y Zufallsvariablen sind. Man sagt dann, dass Y verteilt ist wie b1*X + b0 + ε. Die bs heißen Regressionskoeffizienten. Im Vergleich zur Geradengleichung kommt noch der Term ε (= epsilon) dazu. Damit wird der Störterm oder Fehler bezeichnet, weil die Punkte ja nicht direkt auf der Geraden liegen.
Haben wir nun eine Stichprobe aus Paaren (xi,yi), man spricht auch von Realisierung der Zufallsvariablen, dann gilt yi = b1*xi + b0 + εi.
Nun versucht man, b1 und b0 so zu bestimmen, dass die Summe der quadrierten Fehler minimal wird. Zum Glück müssen wir das nicht per Hand machen, sondern lassen den Computer rechnen.
Das Bestimmtheitsmaß R²
Für die Güte der linearen Regression benutzt man das Bestimmtheitsmaß R². Das liegt zwischen 0 (= überhaupt kein linearer Zusammenhang) und 1 (= perfekter linearer Zusammenhang). Hast Du einen negativen Wert oder etwas über 1 raus, dann ist es garantiert falsch.
R² kann aber auch trügerisch sein, wie Du in den Beispielen sehen wirst. Da bekommen wir ein hohes R², aber trotzdem ist das Modell eigentlich falsch, weil der Zusammenhang nicht linear ist.

Im ersten Bild ist ein linearer Zusammenhang zu sehen. Das Bestimmtheitsmaß R² ist mit 0.91 sehr hoch und zeigt, dass x und y stark zusammenhängen. Im zweiten Bild besteht ein quadratischer Zusammenhang von x und y, d.h. die Punkte (x,y) liegen auf einer Parabeln. Die lineare Regression malt trotzdem einfach eine Gerade durch die Punkte. Damit unterschätzen wir die y-Werte für kleine und große x, für mittlere x wird y überschätzt. Trotzdem ist das Bestimmtheitsmaß mit 0.94 sogar noch höher.

Datenanalyse mit Python - 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Multiple lineare Regression
Meistens hat man nicht nur einen Prädiktor X, sondern eine ganze Reihe davon. Das Prinzip bleibt aber gleich. Hat man zwei Prädiktoren X1 und X2, dann legt man eine Ebene durch die Punkte (x1i, x2i, yi) und bestimmt die Regressionskoeffizienten b0, b1, b2 mit der Gleichung yi = b0 + b1*x1i + b2 * x2i + εi.
Allgemein schreibt man Y ~ B*X + ε.
Was sind die Voraussetzungen für lineare Regression?
Damit die lineare Regression vernünftige Ergebnisse liefert, müssen einige Voraussetzungen erfüllt sein. Natürlich kann man immer eine Gerade so gut wie möglich durch eine Punktwolke legen, aber man möchte ja auch einige Statistiken wie das Bestimmtheitsmaß haben oder vielleicht einen Hypothesentest machen, der prüft, ob die Regressionskoeffizienten ungleich 0 sind.
Lineare Beziehung zwischen den Variablen
Das haben wir schon weiter oben gesehen. Y sollte linear von X abhängen, sonst macht das ganze Modell keinen Sinn.
Wenig Mulitkolinearität
Haben wir mehr als einen Prädiktor, dann sollten die Prädiktoren nicht zu stark miteinander zusammenhängen. Das Problem ist nämlich sonst, das die Regressionskoeffizienten nicht eindeutig sind.
Homoskedastizität der Residuen
Na, auf Anhieb richtig ausgesprochen? Kann ich mir kaum vorstellen. Der Zungenbrecher Homoskedastizität der Residuen bedeutet einfach nur, dass die Varianz des Fehlers ε überall gleich ist. Es sollte nicht sein, dass kleine Werte von y auch eine kleinere Fehlerstreuung bedeutet und große Werte von y dann mit deutlich größerer Fehlerstreuung einhergeht, oder umgekehrt. Im Bild sieht man es, wenn die Breite der Punktwolke (xi,yi) überall ungefähr gleich ist.
Normalverteilung der Residuen
Die Fehler εi sollten in etwa normalverteilt sein. Sind sie es, dann ist übrigens auch die Homoskedastizität erfüllt, da die Fehler alle aus der gleichen N(0, σ²)-Verteilung stammen. Auch große Ausreißer, auf die die Regression sensibel reagiert, sollten dann nur sehr selten auftreten.
Regression mit dem Package scikit-learn
Es gibt natürlich verschiedene Möglichkeiten, die lineare Regression in Python umzusetzen. Eine Möglichkeit ist mit dem Package scikit-learn gegeben. Das Tolle an scikit-learn ist, dass in dem Package auch noch jede Menge weiterer Algorithmen implementiert sind, die alle genauso funktionieren.
Scikit-learn setzt auf numpy auf, d.h. Daten sollten als Arrays vorliegen und auch Ausgabewerte sind im numpy-Format, wie wir nachher sehen werden
Mit der Funktion LinearRegression wird zuerst ein Modell erzeugt, das dann mit fit an die Daten angepasst wird. Dabei muss der Prädiktor x als zweidimensionales Array vorliegen (auch wenn x in dem Beispiel eigentlich eindimensional ist), daher müssen wir x noch mit reshape in die benötigte Form bringen. In dem meisten Fällen ist x ja sowieso mehrdimensional, weil man eine multiple Regression macht.
import numpy as np
from sklearn.linear_model import LinearRegression

x = np.array([1, 2, 3, 4])
x = x.reshape(-1, 1)

y = np.array([2, 5, 7, 9])

model = LinearRegression()
model.fit(x, y)

Nun, bisher sieht man noch nichts. Die Regressions-Koeffizienten wurden aber durch fit berechnet, sie sind im Modell gespeichert und zwar in den Variablen intercept_ und coef_.
print("y-Achsen-Abschnitt:", model.intercept_)
print("Steigung:", model.coef_)
print("R²:", model.score(x, y))

Achtung, coef_ ist hier ein Array mit einer Zahl drin, während intercept_ nur eine Zahl ist. Auch hier sieht man wieder, dass der Algorithmus auf mehrere Prädiktoren X ausgelegt ist.
print(type(model.intercept_))
# <class 'numpy.float64'>
print(type(model.coef_))
# <class 'numpy.ndarray'>

Datenanalyse mit Python - 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Beispielcode für scikit-learn Linear Regression
Im folgenden Codebeispiel habe ich die Erzeugung von x und y angepasst. Zudem gibt es am Ende eine kleine Grafik mit den Punkten und der Regressionsgerade. Den gesamten Code könnt ihr euch auch hier herunterladen: linreg.py
Zuerst ziehen wir x aus einer Normalverteilung mit Mittelwert mu1 und Standardabweichung sigma1. Anschließend erzeugen wir y genau so, wie es laut Modell von x abhängt:
yi = b0 + b1 * xi + εi, wobei εi aus einer Normalverteilung mit Mittelwert 0 und Standardabweichung sigmaError gezogen wird.
import numpy as np
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt

# Stichprobengröße
n = 100

# ziehe x aus Normalverteilung
mu1 = 10
sigma1 = 3
x = np.random.normal(loc=mu1, scale=sigma1, size=n)

# erzeuge y
b1 = 2
b0 = 5
sigmaError = 2
y = b1 * x + b0 + np.random.normal(loc=0.0, scale=sigmaError, size=n)
formelText = (
"y = "
+ str(b1)
+ "*x+"
+ str(b0)
+ "+ ε mit ε~N(0,"
+ str(sigmaError * sigmaError)
+ ")"
)

# für die lineare Regression aus sklearn muss x eine Spalte sein
x = x.reshape((-1, 1))

# berechne lineare Regression
model = LinearRegression()
model.fit(x, y)

r_sq = model.score(x, y)
intercept = model.intercept_
slope = model.coef_
print("intercept:", intercept)
print("slope:", slope)
print("coefficient of determination:", r_sq)

# plot
plt.scatter(x, y, alpha=0.5)
plt.title(formelText)
plt.xlabel("x")
plt.ylabel("y")
t = (min(x), max(x))
plt.plot(t, model.predict(t), "-r")
ax = plt.gca()
plt.text(
0.95,
0.05,
"R² = " + str(round(r_sq, 2)),
horizontalalignment="right",
verticalalignment="center",
transform=ax.transAxes,
)
plt.show()

Die Grafik habe ich hier über matplotlib erzeugt. Eine Punktwolke entspricht dem Scatterplot plt.scatter. Ergänzt habe ich Titel und Achsenbeschriftungen. Dann folgt die Regressionsgerade, für die ich zuerst das Minimum und Maximum von x nehme und für diese beiden Werte die y-Werte der Regressionsgerade berechne (mit model.predict). Als letztes folgt noch ein Text mit dem Bestimmtheitsmaß R². Damit dieser unten rechts in der Grafik erscheint, musste ich mit ax die Achsen auf Prozent konvertieren.
Statt des linearen Zusammenhangs können wir y auch anders erzeugen, zum Beispiel als quadratischer Zusammenhang. So können wir schauen, wie die lineare Regression auf Verletzung der Grundvoraussetzung „linearer Zusammenhang“ reagiert.
# alternativ quadratischer Zusammenhang zwischen x und y
x = np.random.uniform(-1, 3, n)
sigmaError = 1
y = 3 * x * x + 1 + np.random.normal(loc=0.0, scale=sigmaError, size=n)
formelText = "y = 3*x² + 1" + "+ ε mit ε~N(0," + str(sigmaError * sigmaError) + ")"

Eurer Phantasie sind hier keine Grenzen gesetzt. Hier noch ein Beispiel für einen Wurzel-Zusammenhang.
# alternativ Wurzel-Zusammenhang zwischen x und y
x = np.random.uniform(-1, 200, n)
sigmaError = 0.5
y = np.sqrt(3 * x + 5) + np.random.normal(loc=0.0, scale=sigmaError, size=n)
formelText = "y = sqrt(3*x+5) " + "+ ε mit ε~N(0," + str(sigmaError * sigmaError) + ")"

Codebeispiel Lineare Regression mit mehreren Variablen
Kommen wir zu einem realistischeren Datensatz. Hier habe ich den Fish Market Datensatz von Kaggle heruntergeladen. Dieser kleine Datensatz mit 159 Datenpunkten besteht aus Gewicht, mehreren Größe-Messungen und Art. Einlesen geht ganz einfach mit pandas read_csv.
Machen wir zuerst nochmal eine einfach Regression, also mit einer Variablen (Python-Code: linreg2.py). Interessant ist das Bild, bei dem man schön sehen kann, dass der Zusammenhang nicht wirklich linear ist.

import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt

fish = pd.read_csv("fish.csv")
print(fish.shape)
print(fish.columns)

x = pd.DataFrame(fish["Length1"])
y = pd.DataFrame(fish["Weight"])

model = LinearRegression()
model.fit(x, y)

intercept = model.intercept_[0]
slope = model.coef_[0, 0]
r_sq = model.score(x, y)
print("intercept:", intercept)
print("slope:", slope)
print("coefficient of determination:", r_sq)

# Plot
plt.scatter(fish["Length1"], fish["Weight"], alpha=0.7)
plt.title("Fisch Markt")
plt.xlabel("Länge1")
plt.ylabel("Gewicht")
# Regressionsgerade hinzufügen
t = np.array([min(x.loc[:, "Length1"]), max(x.loc[:, "Length1"])])
t = t.reshape(-1, 1)
plt.plot(t, model.predict(t), "-r")
plt.show()

Wollen wir nun das Gewicht anhand der Größen vorhersagen, dann müssen wir einfach nur das x anpassen und ein Array aus mehreren Attributen basteln. Hier der Code linreg3.py als Download
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
import matplotlib.lines as mlines
import matplotlib.transforms as mtransforms

fish = pd.read_csv("fish.csv")
print(fish.shape)
print(fish.columns)

x = fish[["Length1", "Length2", "Length3", "Height"]]
y = pd.DataFrame(fish["Weight"])

model = LinearRegression()
model.fit(x, y)

intercept = model.intercept_[0]
slope = model.coef_[0, 0]
r_sq = model.score(x, y)
print("intercept:", intercept)
print("slope:", slope)
print("coefficient of determination:", r_sq)

yhat = model.predict(x)
yhat[yhat < 0] = 0

# Plot
plt.scatter(fish["Weight"], yhat, alpha=0.7)
plt.title("Fisch Markt")
plt.xlabel("Gewicht")
plt.ylabel("Prognose")
plt.xlim(0, 1700)
plt.ylim(0, 1700)
ax = plt.gca()
line = mlines.Line2D([0, 1], [0, 1], color="red")
transform = ax.transAxes
line.set_transform(transform)
ax.add_line(line)
plt.show()

Bei mehr als 3 Dimensionen können wir nicht mehr als Grafik darstellen. Was man aber machen kann, ist ein Plot mit den tatsächlichen Y-Werten auf der einen Achse und den vorhergesagten Y-Werten auf der anderen Achse. Bei einem linearen Zusammenhang streuen die Punkte gleichmäßig um die Winkelhalbierende.

Hier sehen wir gut, dass die Form der Punktwolke eher an eine Wurzelfunktion erinnert. Das heißt, kleinere Gewichte werden eher überschätzt, da die Punkte über der Winkelhalbierenden sind. Größere Gewichte hingegen werden eher unterschätzt, weil die Punkte sich unter der Winkelhalbierenden befinden.
So, ich hoffe, ihr habt ein bisschen was über einen der Brot- und Butter-Algorithmen jedes Data Scientisten gelernt.
Happy coding,
Euer Holger
Titelfoto by Anders Jildén on Unsplash

Datenanalyse mit Python - 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean ls

Geld verdienen als Data Scientist-Freelancer – Die Freelancer-Börse Malt.de im Interview

Hej meine Braineos,
heute mal etwas ganz anderes als meine Data Science-Tutorials. Es geht um’s Geld verdienen. Der eine oder andere von Euch hat sicherlich schon mal daran gedacht, seine Fähigkeiten als Freelancer anzubieten. Aber wie kommt man an interessante Projekte? Zum einen natürlich über das eigene Netzwerk. Aber wenn man frisch in die Selbstständigkeit startet, dann hat man das noch nicht. Dann sind Freelance-Börsen genau das richtige. Die Freelance-Plattform Malt.de ist schon in Frankreich und Spanien erfolgreich und ist nun 2019 in Deutschland gestartet.
Ich konnte David von Malt.de ein paar Fragen stellen, die Euch hoffentlich genauso interessieren wie mich.
 
Was ist Malt.de und warum lohnt es sich, mich dort anzumelden?
Malt bringt Freelancer und Unternehmen jeder Größe zusammen und ermöglicht ihnen eine direkte Zusammenarbeit über die Plattform – ohne Agentur oder Personalvermittlung.
Alles was Unternehmen und Freelancer für ein konkretes Angebot brauchen ist ein Malt-Profil, das innerhalb von Minuten erstellt ist. Die Anmeldung und Nutzung der Plattform ist für beide Seiten komplett kostenlos. Erst wenn eine Zusammenarbeit zustande kommt, erhält Malt eine Provision. Man kann sich also komplett risikofrei anmelden. Ein aussagekräftiges Profil ist dabei das A und O. Dafür fällt eine aufwändige Kundenakquise weg. Auf Malt kontaktieren die Unternehmen die Freelancer. Über die intelligente Suchfunktion können Unternehmen nach spezifischen Fähigkeiten filtern und geeignete Freelancer direkt kontaktieren, um ein Projekt vorzuschlagen. Der Freelancer schreibt daraufhin ein Angebot, das das Unternehmen annehmen oder ablehnen kann. Nach Abschluss jedes Projektes erhalten die Freelancer eine Referenz des Auftraggebers, sodass sie sukzessive ihre Reputation steigern können. Die Bezahlung des Freelancers erfolgt dann innerhalb von 48 Stunden nach Projektabschluss.
 
Wie unterscheidet sich Malt.de von anderen Freelancer-Börsen?
Auf Malt werden keine Projekte von Unternehmen veröffentlicht. Daher sehen wir uns auch nicht als Börse, sondern eher als Marktplatz. Der Freelancer präsentiert sich auf Malt mit einem aussagekräftigen Profil und die Unternehmen suchen anhand der Profile nach dem für sie passenden Experten. Diesen Suchprozess halten wir für beide Seiten für zielgerichteter.
Zusätzlich gehen wir noch einen Schritt weiter und ermöglichen Freelancern und Unternehmen eine Zusammenarbeit über unsere Plattform. Hier beginnt unser eigentlicher Service. Unser Marktplatz unterstützt beide Seiten bei den administrativen Aufgaben, die eine Zusammenarbeit mit sich bringt. Akquise, Angebot, Vertragsabschluss sowie Zahlungsabwicklung können komplett digitalisiert über die Tools von Malt abgewickelt werden. Unternehmen können damit ihre kompletten Freelancer-Aktivitäten über Malt steuern und verwalten.  Zusätzlich sind die Freelancer auf Malt automatisch über eine Berufshaftpflicht versichert.
Der wichtigste Punkt ist für uns aber der direkte Ansatz. Unternehmen und Freelancer gehen ein direktes Vertragsverhältnis ein. Viele Probleme von klassischen Personalvermittlungen wie Scheinselbständigkeit gegenüber dem Provider und illegale Arbeitnehmerüberlassung werden dadurch weitgehend vermieden.  Als Plattform stellen wir mit unseren Tools nur sicher, dass auf beiden Seiten so wenig Bürokratie wie möglich entsteht.
 
Welche Voraussetzungen muss ich erfüllen, um mich als Freelancer anzumelden? Kann ich das neben meinem Beruf machen?
Wenn es der aktuelle Arbeitsvertrag erlaubt – klar 😉 Von unserer Seite ist für die Anmeldung als Freelancer nur eine Steuernummer notwendig. Die kann beim Finanzamt relativ einfach beantragt werden.
 
Wieviel Provision nimmt Malt.de?
Für Freelancer berechnet Malt eine Provision von 10%, die automatisch in das Angebot des Freelancers einbezogen wird und bei Rechnungsstellung vom Auftragshonorar abgezogen wird. Für die laufende Zusammenarbeit mit einem Kunden wird nach dem dritten Monat nur noch 5% Provision berechnet. Die gestaffelte Provision wird dafür eingesetzt, die Freelancer bei der Akquise von attraktiven Kunden zu unterstützen und die Geschäftsbeziehung zu den Unternehmen abzusichern. Die Provision können Freelancer dann im Regelfall als Werbungskosten von der Steuer absetzen.
Für Unternehmen bewegen sich die Kosten für die Plattform zwischen 5 – 12% vom Projektvolumen, je nachdem welcher Leistungsumfang gewünscht ist. Die Standardfunktionen sind bereits für 5% verfügbar, für 7 – 12% gibt es dann weitere Service-Dienstleistungen wie z.B. einen dedizierten Account-Manager, Zugriff auf Malt Insights, ein umfangreiches Freelancer Management System, Unterstützung bei der Erstellung von eigenen Verträgen  oder die Möglichkeit zu eigenen Zahlungsfristen. Alle Details dazu findet ihr hier: https://www.malt.de/offers
 
Welche Fähigkeiten im Bereich Data Science / Data Analytics sind bei den Kunden besonders beliebt?
Von den Suchanfragen der Kunden auf Malt ausgehend, sind Python und C++ an der Spitze, wobei Python relevanter für den Bereich Data Analytics ist. Weit oben bei den Tools rankt Excel, R, Apache Spark, d3 und Tableau für Datenvisualisierungen, MATLAB, Hadoop und SAS. Außerdem Tensorflow und Pandas als Software-Bibliotheke für Python Datenmanipulationen und -analysen.
 
Wird eher nach Tagessatz oder Projekt abgerechnet? Welchen Tagessatz kann man als Data Scientist nehmen? 
Im Malt-Profil wird standardmäßig ein unverbindlicher Tagessatz hinterlegt. Allerdings kann auch eine Abrechnung nach Projekt individuell mit dem Kunden vereinbart werden. Die Tagessätze für Data Scientists bewegen sich meistens zwischen 700 und 1.200€ je nach Erfahrung und Umfang der Kenntnisse.
 
Sind die Aufträge meistens beim Kunden vor Ort oder remote?
Wir verfolgen einen lokalen Ansatz, bei dem Kunden die Möglichkeiten haben sollen Freelancer in Ihrer Nähe zu finden und persönlich zu treffen. Denn je nach Projektinhalt ist oft eine Arbeit vor Ort erwünscht, andere Projekte erlauben es wiederum remote zu arbeiten. Es ist also definitiv beides möglich. Hier wollen wir beiden Parteien möglichst viele Freiheiten lassen, um die Zusammenarbeit so zu gestalten, wie es für beide passt. Freelancer können dazu in ihrem Profil angeben, welche Form der Zusammenarbeit bevorzugt wird und ob sie remote oder vor Ort (und wo) zur Verfügung stehen. Unternehmen können ihre entsprechende Anforderung dann bei der Suche filtern.
Vielen Dank für das Interview, David.
 
So liebe Braineos, also worauf wartet Ihr? Meldet Euch direkt mal an und teilt das Interview mit anderen potentiellen Freiberuflern.
Happy freelancing,
Euer Holger
Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean ls Tensorflow

Datenimport in Python: Excel-Dateien einlesen und schreiben

Hej Leute,
wir wollen Daten analysen, oder? Sonst wärt ihr ja nicht hier! Dazu müssen aber erstmal die Daten in Python importiert werden. Neben Datenbanken sind Dateien das Mittel zum Zweck. Und im Data Science Umfeld sind die Dateien zum großen Teil im Format csv (comma separated value), aber erstaunlich oft eben auch im Excel-Format (xlsx), denn in fast allen Abteilungen einer Firma ist Excel immer noch die Software, mit der Tabellen bearbeitet werden.
Ich zeige euch, wie ihr Excel in Python einlesen könnt. Das ist mit dem richtigen Package überhaupt nicht schwer.

Python: Excel einlesen
Ihr habt die Qual der Wahl. Es gibt nämlich einige Möglichkeiten, xlsx-Dateien nach Python zu bringen. Wollt ihr nur schnell Daten aus einer Excel-Datei holen, dann ist pandas wohl am besten geeignet. Braucht ihr noch mehr Kontrolle oder wollt Formeln auslesen, dann schaut euch xlrd oder openpyxl an. Tatsächlich nutzt pandas xlrd im Hintergrund, um auf die Excel-Daten zuzugreifen.
Eine Jupyter Notebook-Datei mit dem Code für alle drei Möglichkeiten findest Du hier.
xlsx-Dateien mit pandas importieren
Eine populäre Methode, Excel-Dateien in Python einzulesen, ist mit der read_excel-Funktion von pandas. Wenn man als Data Scientist mit Python arbeitet, ist pandas sowieso unverzichtbar. Die read_excel-Funktion kann sowohl xls- (altes Format) als auch xlsx-Dateien verarbeiten und schreibt den Inhalt in ein DataFrame.
import pandas as pd
df = pd.read_excel(“Dateiname“)

dazu gibt es eine ganze Reihe von Parametern, die wichtigsten findet ihr hier:

sheet_name = 0
Hier kann man eine Zahl (beginnend bei 0) oder den Namen des Arbeitsblatts. Standardmäßig wird also das erste Arbeitsblatt eingelesen. Gibt man hier eine Liste an, dann wird ein Dictionary von DataFrames zurückgegeben (siehe unten)
skiprows = None
Will man die ersten Zeilen überspringen, was ja relativ typisch für Excel-Tabellen ist, denn oben sollte hoffentlich Titel und Beschreibung stehen, geht das mit diesem Parameter, der einfach sagt, wie viele Zeilen man überspringen will. Wie in Python üblich, fängt das Zählen bei 0 an, d.h. wenn ich ab der 4. Zeile einlesen will, benutze ich skiprows=3.
header = 0
Die Zeile, in der der Header, also die Spaltenüberschriften steht. Bei 0 wird also die erste Zeile verwendet. Gibt es keine Spaltenüberschriften, gibt man None an.
names = None
Diesem Parameter kann man eine Liste mit den Spaltennamen übergeben
usecols = None
Hier gibt man an, dass man nur ausgewählte Spalten einlesen möchte. Dafür übergibt man am besten eine Liste mit Spaltennummern oder Spaltennamen.
dtype = None
Möchte man andere Datentypen als die automatisch erkannten verwenden, kann man ein dictionary mit den Datentypen der Spalten angeben.
nrows = None
Möchte man nicht alle Zeilen einlesen, kann man das mit dem Parameter nrows begrenzen.

 
Das sollte die meisten Anwendungsfälle abdecken. Braucht ihr noch weitere Spezialisierungen, dann schaut in die API Referenz von read_excel.
Mehrere Excel-Arbeitsblätter gleichzeitig importieren
Wie bei der Erklärung zum Parameter sheet_name geschrieben, kann man dort auch eine Liste mit den Arbeitsblatt-Nummern oder –Namen angeben. Dann wird kein DataFrame zurückgegeben, sondern ein Dictionary von DataFrames.
Mappe = pd.read_excel("Beispiel-Excel.xlsx", sheet_name=['Tabelle1','Tabelle2','Tabelle3'], skiprows=3)
print(type(Mappe))
print(Mappe.keys())
print(Mappe['Tabelle3'].head())

Datenanalyse mit Python - 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Excel-Datei importieren mit dem Package xlrd
Mit dem Package xlrd habt ihr deutlich mehr Kontrolle über die Excel-Arbeitsmappe, aber es ist natürlich auch ein bisschen aufwändiger. Tatsächlich wird aber xlrd aktuell nicht mehr weiterentwickelt. Auf der GitHub-Seite steht, dass man doch besser openpyxl verwenden soll.
Neben xlrd zum Lesen gibt es auch xlwt zum Schreiben von xls-Dateien (Excel 97 – 2003) und xlutils, wenn man Excel-Dateien modifizieren will.
Leicht ist erstmal das Öffnen der Datei
wb = xlrd.open_workbook("Beispiel-Excel.xlsx")
Mit sheet_names bekommt man die Namen der Arbeitsblätter
sheet_names = wb.sheet_names()
Ein Arbeitsblatt kann man dann über den Namen ansprechen, also z.B.
Tab1 = wb.sheet_by_name('Tabelle1')
Die xlrd API ist sehr logisch aufgebaut und sollte für Leute, die schon mal APIs gelesen haben, kein Problem darstellen.

Das Modul book beinhaltet alles für den Umgang mit der gesamten Arbeitsmappe. Die Klasse xlrd.book.Book enthält den Inhalt der Arbeitsmappe.
Das Modul sheet beinhaltet alles für den Umgang mit einem Arbeitsblatt. Die zugehörige Klasse xlrd.sheet.Sheet enthält den Inhalt eines Arbeitsblatts
formatting ist noch erwähnenswert, wenn man die Formatierungen auslesen will
formula befasst sich (Achtung) nicht mit den Formeln einer Zelle, sondern mit dem Namensmanager. Will man die Formeln einzelner Zellen auslesen, geht das mit openpyxl oder
xldate hilft beim Umgang mit Datum und Zeit

Python-Package openpyxl: Excel-Dateien einlesen
Openpyxl scheint aktuell das Package zu sein, welches man nutzen sollte, will man mehr machen als Daten einlesen. Im letzteren Fall ist meiner Meinung nach pandas zu bevorzugen.
Eine Arbeitsmappe einzulesen ist auch hier super einfach.
from openpyxl import load_workbook
wb2 = load_workbook("Beispiel-Excel.xlsx")

Mit dem Flag data_only kann man einstellen, ob Formeln oder die berechneten Werte eingelesen werden sollen. Standardmäßig ist data_only = False, es werden also Formeln eingelesen.
Leider werden Bilder und Charts nicht mit eingelesen, so dass Modifikationen einer Vorlage oder das Einfüllen von Daten in bestehende Excel-Dashboards mit openpyxl nicht vernünftig funktionieren. Dafür scheint xlwings das richtige Tool zu sein, dazu demnächst mehr.
Aber zurück zu openpyxl. Die Arbeitsmappe enthält die Arbeitblätter, auf die dann einfach per Namen zurückgegriffen werden kann
print(wb2.sheetnames)
ws = wb2['Tabelle1']
for i in ws.values:
print(i)

Um die Daten in ein pandas DataFrame umzuwandeln, könnte man es folgendermaßen machen. In dem Beispiel fängt die Tabelle in Zeile 4 an.
import pandas as pd
df = pd.DataFrame(ws.values)
df.columns = df.iloc[[3]].values.tolist()[0]
df = df[4:]
df.head()

Auch hier wieder der Verweis auf die Dokumentation von openpyxl. Interessant ist auch das Kapitel 12 im kostenlosen Buch Automate the boring stuff, dort geht es tatsächlich um Anwendung vom Package openpyxl.
 
Python: Excel abspeichern
Logisch, neben dem Einlesen von Excel-Dateien wollen wir natürlich auch Excel-Dateien abspeichern können. Eine Jupyter Notebook-Datei mit dem Code für alle drei Möglichkeiten findest Du hier.
Einen DataFrame mit pandas in eine xlsx-Datei schreiben
Mit pandas ist es wieder sehr leicht, einen DataFrame in eine Excel-Datei zu schreiben. Das geht über die Funktion to_excel, also z.B.
diamonds.to_excel("Diamonds.xlsx", sheet_name='Diamonds')
Dabei gibt es folgende Parameter zur Individualisierung. Es gibt noch ein paar mehr, aber gebraucht habe ich die bisher nicht.

na_rep = ''
Wie sollen fehlende Werte dargestellt werden. Standard ist hier leer.
float_format=None
Hier kann das Format für Kommazahlen angegeben werden
columns = None
Wenn nicht alle Spalten geschrieben werden sollen, dann kann man diese hier spezifizieren
header = True
Sollen Spaltennamen geschrieben werden. Es geht auch eine Liste mit den Spaltennamen.
index = True
Flag, ob ein Zeilenindex geschrieben werden soll.
index_label = None
Der Spaltenname für die Index-Spalte
startrow = 0
Die Zeile in der Excel-Datei, ab der die Tabelle geschrieben werden soll
startcol = 0
Die Spalte in der Excel-Datei, ab der die Tabelle geschrieben werden soll

Datenanalyse mit Python – 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Mehrere Arbeitsblätter in eine Excel-Datei schreiben
Auch das ist mit pandas kein Problem. Allerdings muss man dazu einen ExcelWriter verwenden. Das geht folgendermaßen:
with pd.ExcelWriter('test.xlsx') as writer:
iris.to_excel(writer, sheet_name='iris')
tips.to_excel(writer, sheet_name='tips')

 
Eine Excel-Datei mit xlwt schreiben
Das Schreiben einer xls-Datei (Achtung, xlwt unterstützt nicht das neue xlsx-Format, welches seit Excel 2007 verwendet wird)
import xlwt
from datetime import datetime

wb = xlwt.Workbook()
ws = wb.add_sheet('Tabelle1')

datumStyle = xlwt.easyxf(num_format_str='DD.MM.YYYY')

ws.write(0, 0, 1)
ws.write(0, 1, 1)
ws.write(0, 2, xlwt.Formula("A1+B1"))

ws.write(1, 0, datetime.now(),datumStyle)
ws.write(1, 2, 3.1415)

wb.save('Beispiel-xlwt.xls')

Eine Excel-Datei mit openpyxl schreiben
Das Schreiben der Datei ist wieder überhaupt kein Problem:
from openpyxl import Workbook
wb = Workbook()
# … Arbeitsmappe befüllen …
wb.save("Beispiel-openpyxl.xlsx")

 
Als Zwischenteil können wir zum Beispiel folgendes machen:
# Das erste Arbeitsblatt aktivieren
ws = wb.active
# Man kann direkt in Zellen schreiben
ws['C1'] = 3.1415
# Auch ganze Zeilen können angehangen werden
ws.append([1, 2, 3])
# Datumsfelder funktionieren auch
import datetime
ws['E2'] = datetime.datetime.now()

 
Fazit zu Excel-Dateien mit Python
Nochmal kurz zusammengefasst, lässt sich sagen:
 
Wollt ihr nur Tabellen einlesen bzw in eine Excel-Datei schreiben, dann benutz am besten pandas. Die Import- bzw. Export-Funktion ist einfach anzuwenden und pandas Datentyp DataFrame ist sowieso ideal, um die Daten weiter zu verarbeiten.
 
Braucht ihr mehr Kontrolle und wollt einzelne Zellen, Formate etc. auslesen oder bearbeiten, benutzt openpyxl. Falls ihr aus unerfindlichen Gründen noch das xls-Format verwenden müsst (ja, das gibt es in manchen Firmen noch), dann verwendet xlrt/xlwt/xlutils.
 
Ich hoffe, ihr habt was Nützliches mitgenommen. Schreibt mir einen Kommentar, welches Package ihr am liebsten verwendet. Und wenn ihr helfen wollt, Data Science Wissen zu verbreiten und mich damit unterstützt, dann teilt den Beitrag auf Twitter oder Facebook.
 
Happy Exceling,
Euer Holger

Datenanalyse mit Python - 5 Tage Minikurs

In dem kostenlosen 5-Tage Minikurs Datenanalyse mit Python analysieren wir zusammen einen realen Datensatz: Von der richtigen Entwicklungsumgebung über erste Zusammenfassungsstatistiken mit pandas bis hin zu linearer Regression und schicken Grafiken mit seaborn.

Jetzt gratis anmelden

Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean ls Tensorflow

Jupyter Lab Shortcuts: Steigere Deine Produktivität – auch für Jupyter Notebook

Du hast gerade angefangen, Jupyter Notebook oder Jupyter Lab zu benutzen? Oder Du möchtest einfach schneller werden und nicht immer die Maus benutzen? Dann sind die folgenden Shortcuts genau das richtige für Dich. Eilige springen direkt zu den Shortcuts, vorher aber ein bisschen nützliches Hintergrundwissen.

Inhalt
ToggleWas ist Jupyter Notebook?Jupyter Notebook oder Jupyter Lab? Was ist besser?Aufbau eines NotebooksDie zwei Modi: Navigation und EditierenDie wichtigsten Shortcuts für Jupyter Lab
Was ist Jupyter Notebook?
Jupyter Notebook ist einerseits ein Datei-Format mit der Endung ipynb, um formatierten Text, Code und den Codeoutput wie Grafiken, Tabellen etc. in einem Dokument darzustellen. Im Prinzip ist es nur eine JSON-Datei. Ursprünglich für Julia, Python und R (daher der Name Jupyter) mit Schwerpunkt Python entwickelt, können die Dokumente jede beliebige Programmiersprache enthalten. Sinnvoll sind aber nur die, die auch von dem Programm Jupyter Notebook bzw. Jupyter Lab unterstützt werden. Es gibt aktuell ca. 50 Programmiersprachen, die einen sogenannten Kernel für Jupyter haben.
Jupyter Notebooks sind in der Data Science Welt recht verbreitet. Zum Beispiel findet man viele Data Science-Notebooks sowohl für Python als auch R auf Kaggle. Github unterstützt übrigens auch das Dateiformat, so dass die Dateien auf Github korrekt angezeigt werden. So gibt es das Buch Python Data Science Handbook komplett als Notebooks auf Github.
Die Software Jupyter Notebook ist eine webbasierte Oberfläche, um eben ipynb-Dateien zu erstellen. Sie als vollwertige Entwicklungsumgebung zu bezeichnen, wäre stark übertrieben. Aber gerade für die explorative Datenanalyse oder für eine Adhoc-Analyse mit Visualisierungen oder auch zum Lernen ist Jupyter Notebook bestens geeignet. Die fertigen Notebooks können dann auch als HTML oder PDF exportiert werden.
Jupyter Notebook ist in der Anaconda-Distribution enthalten, kann aber auch über pip oder conda installiert werden. Wenn Du mehr über Anaconda wissen willst, findest Du in meinem Blogartikel Die Python-Distribution Anaconda.
Nachfolger mit mehr und besseren Features ist Jupyter Lab.
Jupyter Notebook oder Jupyter Lab? Was ist besser?
Klare Sache, benutzt Jupyer Lab! Das ist der offizielle Nachfolger von Jupyter Notebook und wird diesen also bald komplett ersetzen. Jupyter Lab bietet zum Beispiel mehrere Tabs in einem Browserfenster. Auch kann eine Konsole zusätzlich angezeigt werden und nach und nach kann man auch auf verschiedene Erweiterungen zugreifen. Das Dateiformat hat sich nicht geändert, man arbeitet also immer noch mit ipynb-Dateien, nur der Editor ist sozusagen komfortabler geworden.
Aufbau eines Notebooks
Ein Notebook besteht aus Zellen, welche man mit Abschnitten oder Kapiteln übersetzen kann. Eine Zelle enthält entweder formatierten Text in Form von Markdown oder Code. Markdown-Zellen können also Überschriften, Links, Grafiken, mathematische Formeln (Latex) oder auch Tabellen enthalten. Hat man eine Codezelle ausgeführt, wird darunter der Output angezeigt, egal ob das nun Text aus der Konsole oder eine schicke Grafik ist.

Die zwei Modi: Navigation und Editieren
Entweder will man etwas in eine Zelle schreiben. Das ist der Editiermodus. Aus dem Navigationsmodus wechselt man in ihn durch Drücken der ENTER-Taste.
Oder man will zwischen den Zellen hin- und herspringen, neue Zellen einfügen, Zellen löschen, etc. Das ist der Navigationsmodus bzw. Befehlsmodus. In diesen wechselt man durch Drücken der ESC-Taste.
 
Die wichtigsten Shortcuts für Jupyter Lab
So, hier kommen nun die wichtigsten Shortcuts. Es sind gar nicht so viele, aber für das Programmieren sind sie extrem nützlich. Insbesondere die Navigation zwischen den Zellen, ohne Maus oder Touchpad zu benutzen, beschleunigt Deine Arbeit erheblich.

Shortcut
Modus
Beschreibung

ENTER
Navi
wechselt in den Editier-Modus

ESC
Edit
wechselt in den Navigations-Modus

B
Navi
eine neue Zelle unterhalb einfügen (B für below)

A
Navi
eine neue Zelle oberhalb einfügen (A für above)

D, D
Navi
Löschen einer Zelle (zweimaliges Drücken von D)

STRG + ENTER
beide
führt den Code aus und bleibt in der Zelle

SHIFT + ENTER
beide
führt den Code aus und springt in die nächste Zelle bzw. legt eine neue Zelle an

y
Navi
Wechselt den Zelltyp zu Code

m
Navi
Wechselt den Zelltyp zu Markdown

STRG + SHIFT + C
beide
Öffnet die Command Console (Achtung: Hat sich zu Jupyter Notebook geändert, dort war es STRG + SHIFT + P)

TAB
Edit
Autocomplete (angefangener Befehl wird ergänzt)

X
Navi
Zelle ausschneiden

C
Navi
Zelle kopieren

V
Navi
Zelle einfügen

SHIFT + TAB
Edit
Hilfe zu dem Befehl aus DocString

STRG + SHIFT + –
Edit
Teilt die Zelle an der Cursorposition

SHIFT + M
Navi
Fügt ausgewählte Zellen zusammen zu einer Zelle

STRG + B
beide
Blendet die Sidebar links aus/ein. So hat man mehr Platz für den Code

STRG + POS1
Edit
Springt an den Anfang der aktiven Zelle

STRG + ENDE
Edit
Springt an das Ende der aktiven Zelle

 
Natürlich kann man auch eigene Shortcuts definieren. Das geht im Menü unter Settings -> Advanced Settings Editor -> Keyboard Shortcuts. Ganz so bequem ist es allerdings nicht, man muss etwas JSON kopieren und anpassen. Links sind die Voreinstellungen vom System, rechts kann man eigene Definitionen benutzen. Dazu muss man wissen, wie das command heißt, das kann man aber leicht über die Command Console (STRG + SHIFT + C) herausfinden. Zudem muss man den selector kennen. Also am besten schaut man sich die System-Shortcuts an oder sucht im Internet.
Hier ein Beispiel, wie sowas aussehen kann:
{
"shortcuts": [
{
"command": "application:activate-next-tab",
"keys": ["Ctrl Shift ]"],
"selector": "body"
},
{
"command": "application:activate-previous-tab",
"keys": ["Ctrl Shift ["],
"selector": "body"
}
]
}
 
Die Dokumentation von Jupyter Lab ist ansonsten immer ein guter Ausgangspunkt, wenn man etwas verstehen möchte.
Happy Jupytering,
Euer Holger
Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean ls Tensorflow

SQL 1×1

Als Data Scientist haben wir mit Daten zu tun (wer hätte das gedacht) und in ziemlich vielen Fällen liegen diese Daten in einer relationalen Datenbank. Und die Abfragesprache dafür ist SQL. Also muss ein Data Scientist mindestens die Grundzüge von SQL beherrschen.
Aber zum Glück ist das SQL 1×1 gar nicht schwer, denn die am meisten verwendeten Befehle sind nicht viele und logisch aufgebaut. Natürlich steckt hinter relationalen Datenbanken und SQL wesentlich mehr, wenn es um Datenbank-Design oder komplizierte Berechnungen geht. Da gibt es ganze Regalmeter voll Fachwissen. Aber das soll Dich vorerst gar nicht kümmern. Mit dieser SQL Anleitung für Anfänger bekommst Du eine praktische Einführung und kannst direkt mit der Beispiel-Datenbank loslegen.

Inhalt
ToggleWas ist SQL?Zugriff auf eine SQL DatenbankDie SQL IDE DBeaverZugriff per ODBCAufbau einer SQL-QueryDer SELECT-BefehlFiltern mittels WHERE-BedingungSortieren mit ORDER BYEindeutige Ergebnisse mit dem Schlüsselwort DISTINCTBedingungen mittels CASE WHENAggregation mit GROUP BYEine Abfrage über mehrere Tabellen mittels JOINVerschachtelte AbfragenAusblick
Was ist SQL?
SQL steht für „Structured Query Language“, wurde in den 1970ern entwickelt und ist laut Wikipedia eine Datenbanksprache zur Definition von Datenstrukturen in relationalen Datenbanken sowie zum Bearbeiten (Einfügen, Verändern, Löschen) und Abfragen von darauf basierenden Datenbeständen. Es gibt also drei Aufgabengebiete:

Definition von Datenstrukturen, sprich das Design und Anlegen einer Datenbank mit ihren Tabellen, Sichten (Views), Indizes, Trigger usw.
Das Bearbeiten von Daten
Die Abfrage von Daten (query), also Anzeige/Export einer Tabelle

Auf Punkt 3 gehen wir in diesem Tutorial ein, denn als Data Scientist wollen wir ja Daten in unsere R- oder Python-Skripte importieren, um dann darauf Analysen zu machen.
Es gibt zwar gewisse SQL-Standards (ANSI), jedoch gibt es viele Dialekte, je nachdem welches Datenbank-System (MSSQL, PostgreSQL, DB, MySQL, …) im Einsatz ist. Insofern muss man bei der Suche nach Anleitungen im Internet immer schauen, für welchen Dialekt das Beispiel geschrieben ist.
Zugriff auf eine SQL Datenbank
Auf einem Server läuft ein Datenbankmanagement-System (DBMS), z.B. PostgreSQL, MS-SQL oder MySQL. Das sind ziemlich komplexe Softwaresysteme, die die Datenbanken verwalten. Zum Beispiel habe ich eine MySQL-Datenbank bei meinem Webhost, die alle Daten der databraineo-Website enthält. Auf dieses DBMS kann ich nun per SQL zugreifen.
Man kann sich auch lokal auf dem PC ein Datenbankmanagement-System wie PostgreSQL installieren, allerdings ist dieses dann in der Regel auch nur vom lokalen PC zugreifbar.
Wir machen es uns einfach und benutzen SQLite. Das ist eine relationale Datenbank in einer einzigen Datei. Es gibt zwar ein paar Einschränkungen, dafür braucht man aber keine weitere Server-Software und kann sofort loslegen. Auch auf Mobiltelefonen oder in Webbrowsern kommt zum Beispiel SQLite zum Einsatz.
Die SQL IDE DBeaver
Ein sehr nützliches Tool, um SQL-Datenbanken zu verwalten, ist DBeaver. In der Community Edtion ist es kostenlos und unterstützt viele SQL-DBMS, also probiert es aus. In DBeaver können wir z.B. Verbindungen zu verschiedenen Datenbanken aufbauen, sehen, welche Tabellen es gibt, SQL-Code schreiben, Daten importieren oder exportieren.

Zugriff per ODBC
ODBC (open database connectivity) ist ein Standard für eine Datenbankschnittstelle. Man installiert den Treiber für das anzubindende DBMS. Fast jede Programmiersprache hat eine Bibliothek, mit dem man dann die Verbindung herstellen und SQL-Abfragen machen kann.
Für R gibt es beispielsweise die Packages odbc oder Rodbc. Für Python gibt es ebenfalls viele Möglichkeiten, z.B. pyodbc oder turbodbc. Im Python-Wiki gibt es eine Seite mit den ODBC-Libraries.
Aufbau einer SQL-Query
Wenn ihr DBeaver installiert habt, dann könnt ihr direkt loslegen und eigene Queries ausprobieren. In den folgenden Beispielen benutzen wir die Chinook-Datenbank, welche als Beispiel-Datenbank bei DBeaver dabei ist. Ansonsten kann man sich die sqlite-Datei aus dem Github-Repository herunterladen.

Nun wollen wir unsere erste Abfrage machen. Dazu wählst Du die Datenbank „DBeaver Sample Database“ aus, klickst rechts und wählst SQL Editor (Shortcut F3). Dadurch öffnet sich ein Textfenster, in das wir direkt die SQL-Befehle tippen können.

View the code on Gist.
 
Mit Strg + Eingabe bzw. dem Play-Button links (siehe Screenshot) wird die Zeile bzw. der markierte Bereich ausgeführt und unten kommt das Ergebnis.

Mit diesem Befehl wird die gesamte Tabelle Artist zurückgegeben.

Im Datenbanknavigator auf der linken Seite sehen wir übrigens, welche Tabelle es gibt und welche Spalten diese haben. Artist hat zwei Spalten, nämlich ArtistId und Name.
Der SELECT-Befehl
Jede Abfrage, welche Daten aus der Datenbank holt, fängt mit SELECT an. Dann folgen Spaltennamen oder Ausdrücke, gefolgt von FROM Tabellenname und einem Semikolon.
Statt dem * im obigen Beispiel könnten wir auch die Spaltennamen aufzählen, also
View the code on Gist.
Um den Spaltennamen in der Ausgabe zu ändern, benutzen wir das Schlüsselwort AS
View the code on Gist.
Filtern mittels WHERE-Bedingung
Meist sind Tabellen ja ziemlich groß, so dass wir die Daten filtern. Das passiert mit einer WHERE-Bedingung, die nach dem FROM kommt.
View the code on Gist.
substr steht für substring, wir pulen damit das erste Zeichen aus dem Namen raus. D.h. die Query gibt alle Künstler zurück, die mit A anfangen.
Eine sehr praktische Alternative zum Vergleichsoperator = ist LIKE. Auch LIKE vergleicht einfach nur zwei Strings. Das tolle daran sind  aber die zwei Wildcards % und _. Dabei steht % für beliebig viele Zeichen und _ für ein beliebiges Zeichen.
View the code on Gist.
Mehrere Bedingungen können mit AND und OR kombiniert werden und eine Bedingung kann mit NOT negiert werden.
View the code on Gist.
In dieser Query haben wir noch eine zweite Bedingung ergänzt: Der zweite Buchstabe darf kein c sein.
Sortieren mit ORDER BY
Um die Ausgabe-Tabelle zu sortieren, benutzen wir am Ende den Zusatz ORDER BY. Soll nach mehreren Spalten sortiert werden, trennt man diese mit Komma. Mit dem Keyword DESC wird die Reihenfolge umgedreht.
View the code on Gist.
In dem Beispiel wird also zuerst absteigend nach Composer sortiert, im Anschluss aufsteigend nach Name.

Eindeutige Ergebnisse mit dem Schlüsselwort DISTINCT
Häufig gibt es mehrere Einträge mit dem gleichen Wert in einer Spalte. Interessiert uns nur eindeutige Werte, ist das Schlüsselwort DISTINCT nützlich, welches direkt nach SELECT verwendet wird.
View the code on Gist.
 
Bedingungen mittels CASE WHEN
Wollen wir Bedingungen einbauen, dann benutzen wir in SQL eine CASE-WHEN-Struktur. In vielen anderen Sprachen entspricht das einer IF-ELSE-Bedingung.
View the code on Gist.
 
Schauen wir uns die CASE WHEN Bedingung an. Nach dem CASE WHEN kommt eine (oder mehrere Bedingungen mit AND, OR, NOT). Trifft diese zu, wird der Teil nach dem THEN zurückgegeben. Ein ELSE-Teil ist optional. Falls dieser nicht vorhanden ist, wird NULL zurückgegeben, ansonsten eben der Wert aus dem ELSE-Teil. Abgeschlossen wird CASE WHEN mit END.
 
Noch eine Sache: Wir haben Index in eckige Klammern gepackt. Das liegt daran, dass Index ein SQL-Schlüsselwort ist. Mit den eckigen Klammern sagen wir, dass es hier nur als Spaltenname verwendet werden soll. Das ist zwar kein so guter Stil, aber manchmal nötig, wenn man gewisse Spaltennamen im Export benötigt. Häufiger Kandidat ist auch Alter, welches auch ein SQL-Schlüsselwort ist. Auch Leerzeichen sind mit den eckigen Klammern in den Spaltennamen möglich.
 
Mehrere Bedingungen lassen sich einfach untereinander schreiben. Das END kommt erst am Ende von allen Bedingungen.
View the code on Gist.
 
Aggregation mit GROUP BY
Bisher haben wir nur Teile einer Tabelle angezeigt. Nun kommen wir zu einem der wichtigsten Hilfsmittel für Data Scientisten, nämlich die Aggregation von Zeilen. Wir fassen mehrere Zeilen zusammen, z.B. als Summe, Durchschnitt, Minimum oder Anzahl.
View the code on Gist.
In diesem Beispiel wird also der Mittelwert über die Länge aller Tracks in Minuten berechnet. Jetzt wollen wir aber nicht alle Zeilen zusammenfassen, sondern mehrere Kennzahlen für jeden Composer berechnen. Das geht mit dem Zusatz GROUP BY.
View the code on Gist.
Wollen wir bezüglich der Aggregate filtern, geht das nicht mit WHERE, denn die Filterung passiert vor der Gruppierung. Für die Filterung nach der Gruppierung benutzt man HAVING.
View the code on Gist.
Die Query oben filtert die Tabelle Track zuerst auf die Tracks, deren Namen mit einem Vokal anfangen. Dann berechnet sie für jeden Vokal separat die Anzahl und durchschnittliche Länge der Tracks. Danach wird nochmal gefiltert, nämlich auf mehr als 50 Tracks (dadurch fällt der Vokal u heraus).
 
Eine Abfrage über mehrere Tabellen mittels JOIN
In den seltensten Fällen genügt die Abfrage auf eine Tabelle, denn eine Datenbank ist relational aufgebaut, hat also Beziehungen zwischen den Tabellen. Wir sehen das gut in unsere Beispiel-Datenbank. In der Tabelle Track ist zwar eine AlbumId vorhanden, aber kein Albumname. Dazu müssen wir in der Tabelle Album nachschauen. Und das geht folgendermaßen:
View the code on Gist.
Es gibt vier Arten von JOIN:

INNER JOIN: Behält nur die Zeilen, die in beiden Tabellen vorhanden sind
LEFT JOIN: Behält alle Zeilen aus der ersten Tabelle
RIGHT JOIN: Behält alle Zeilen aus der zweiten Tabelle
FULL OUTER JOIN: Behält alle Zeilen aus beiden Tabellen

Ich habe für euch die vier JOIN-Typen auch als PDF-Cheatsheet dargestellt.

Man kann auch mehrere Tabellen miteinander verbinden. Hier habe ich zudem Aliases a, b, c, verwendet, um etwas Schreibarbeit zu sparen.
View the code on Gist.
Verschachtelte Abfragen
Man kann Abfragen ineinander verschachteln, also statt einer Tabelle nach FROM oder JOIN eine ganze SELECT-Query. Wir nehmen die vorherige Abfrage und bilden nun den Mittelwert der Bestellungen
View the code on Gist.
Ausblick
So, jetzt kennt ihr die wichtigsten Befehle für Datenbankabfragen. Natürlich braucht man manchmal noch ein bisschen mehr, z.B. wenn man eine Datums- oder Zeitstempel-Spalte umwandeln muss. Zudem kommt irgendwann die Performance-Optimierung ins Spiel, wenn die Queries zu lange dauern.
Aber mit den obigen SQL-Statements kommt ihr schon ziemlich weit.
Ein großes Thema ist das Design von Datenbanken, also welche Tabellen mit welchen Spalten angelegt werden. Das fängt dann mit Normalformen an und geht mit Triggern und Indizes weiter. Das ist eine ganze Welt für sich. Einige Grundkenntnisse hier helfen natürlich weiter, aber es hängt auch davon ab, ob man diese Sachen als Data Scientist selber machen muss oder IT-Support bekommt.
Daten einfügen und aktualisieren hingegen ist nicht sonderlich schwer, das machen wir in einem anderen Blogpost. Und dann wollen wir das alles ja nicht mit einem extra SQL-Skript, sondern SQL direkt aus R oder Python ausführen. Aber auch das ist mit den richtigen Packages ziemlich einfach.
Happy SQLing,
Euer Holger
Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean ls Tensorflow

Der t-Test – Vergleich von Mittelwerten

Hej Leute,
heute geht es um Statistik und zwar um den t-Test! Jetzt ist es raus, kreisch, schrei, Hilfe, renn weg. Ruhig Blut, so schwierig ist der Test gar nicht. Ich erkläre euch ganz in Ruhe, wie er funktioniert und worauf es ankommt.
Der t-Test ist einer der bekanntesten und häufigsten verwendeten Hypothesentest. Er dient dazu, statistisch zu prüfen, ob der Mittelwert einer Stichprobe einem vorgegebenen Wert entspricht. Ich könnte zum Beispiel prüfen, ob das mittlere Alter der Personen, die ich befragt habe, dem deutschen Altersdurchschnitt von 44,3 (im Jahr 2010) entspricht.
Das kann man auch auf zwei Stichproben erweitern. D.h. man prüft, ob die Mittelwerte zweier Stichproben übereinstimmen. So könnte man testen, ob in einer Stichprobe das mittlere Alter der befragten Frauen dem mittleren Alter der befragten Männern entspricht.

Inhalt
ToggleDie Geschichte des t-TestsWie funktioniert ein HypothesentestDer Z-Test – wenn es doch so einfach wäreDie Teststatistik ist t-verteiltVoraussetzungen zur Anwendung vom t-testEinseitiger vs. zweiseitiger t-TestEinstichproben- vs. Zweistichproben-t-TestUnabhängige Stichproben mit gleicher VarianzVerbundene/Abhängige StichprobenUnabhängige Stichproben mit ungleicher VarianzAnwendungen vom t-TestPrüfverfahrenBefragungenA/B-TestRegression
Die Geschichte des t-Tests
Der t-Test wurde ursprünglich von William Sealy Gosset, besser bekannt als Student, im Jahr 1908 entwickelt. Gosset arbeitete bei der Guiness-Brauerei, befasste sich dort mit Gerstenqualität und entdeckte dabei die t-Verteilung. Er veröffentlichte seine Erkenntnisse unter dem Pseudonym Student, da sein Arbeitgeber nicht erlaubte, wissenschaftliche Arbeiten zu veröffentlichen. Daher der Name Studentsche t-Verteilung. Ronald Aylmer Fisher erkannte die Bedeutung von Gossets Arbeit und entwickelte die heute gebräuchliche t-Prüfgröße.
Gosset hat herausgefunden, dass der Mittelwert einer normalverteilten Stichprobe nicht mehr normalverteilt ist, wenn man die Varianz schätzen muss. Aber nochmal ganz langsam.
Wie funktioniert ein Hypothesentest
Ich versuche in diesem Abschnitt ganz grob zu erklären, wie ein Hypothesentest funktioniert. Bald sollte ein eigener, ausführlicheren Artikel dazu folgen, den verlinke ich dann natürlich hier.
Zuerst brauchen wir eine Nullhypothese, also z.B. die Annahme, dass der Mittelwert des Alters der Grundgesamtheit, aus der wir die Stichprobe gezogen haben, 44,3 Jahre beträgt. Im Endeffekt will man das Gegenteil zeigen. Man sagt, dass man die Nullhypothese ablehnt. Man lehnt ab, wenn es sehr unwahrscheinlich ist, die Daten – gegeben die Nullhypothese – zu beobachten. Wir gehen aber erstmal von der Nullhypothese aus. Nun wird eine Prüfgröße, auch Test-Statistik genannt, berechnet. Unter der Annahme, dass die Nullhypothese stimmt, sollte die Prüfgröße einer bekannten Verteilung gehorchen, z.B. normal- oder t-verteilt sein.
Was heißt das nun wieder? Die Prüfgröße ist doch nur eine Zahl. Das ist so gemeint, dass wenn wir das Experiment (also die Auswahl einer Stichprobe und Berechnung der Prüfgröße) vielfach wiederholen, die Prüfgrößen der ganzen Experimente sich einer bekannten Verteilung nach verteilen.

Nun können wir berechnen, ob es (unter der angenommenen Nullhypothese) sehr unwahrscheinlich ist, die Stichprobe zu beobachten. Hier kommt das Signifikanzniveau ins Spiel. Wählen wir (ein typischer Wert), dann prüfen wir, ob wir diese Teststatistik in weniger als 5% der Fälle bekommen, wenn wir immer wieder eine Stichprobe ziehen würden. Ist das so, dann lehnen wir die Nullhypothese ab.
Mathematisch wird das über die Quantilsfunktion der bekannten Verteilung gemacht, weil die Quantilsfunktion die Umkehrfunktion zur Verteilungsfunktion ist. Es wird berechnet, ob die Prüfgröße Z am Rande der Verteilung liegt. Also bei einem einseitigem Test mit , ob Z im 5%- bzw. 95%-Quantil liegt (je nach Richtung).
Der Z-Test – wenn es doch so einfach wäre
So, dieser Teil hier ist tatsächlich mathematisch, kommen doch ein paar Formeln vor. Danach wird es aber wieder besser.
Der Mittelwert einer Stichprobe wird über das arithmetische Mittel berechnet, also die Summe aller Werte, geteilt durch die Anzahl
   
Stammt die Stichprobe aus einer Normalverteilung mit Mittelwert mu und Varianz sigma², dann ist das arithmetische Mittel wieder normalverteilt mit Mittelwert mu, aber mit Varianz sigma²/n.
Würden wir die Varianz kennen, dann könnten wir statt des t-Tests einen Gauß-Test, auch Z-Test genannt, machen, um zu prüfen, ob der Mittelwert einem vorgegebenen Wert mu_0 entspricht. Unter der Hypothese, dass der wahre Mittelwert mu_0 ist, können wir folgende Transformation machen, damit das Ergebnis standardnormalverteilt ist. Also Mittelwert = 0 und Varianz = 1
   
Nun können wir berechnen, ob es (unter der Nullhypothese) sehr unwahrscheinlich ist, die Prüfgröße Z zu beobachten.
 
Die Teststatistik ist t-verteilt
Da aber in der Praxis die Varianz nicht bekannt ist, müssen wir diese schätzen
   
Nun macht uns das aber unsere schöne Normalverteilung von Z kaputt, denn statt durch Konstante sigma teilen wir nun durch S. ist -verteilt. Und so kann man die t-Verteilung definieren, als Standardnormalverteilung durch Wurzel aus -Verteilung. Die -Verteilung hat einen Freiheitsgrad, also
   
mit n = Stichprobengröße
Jetzt kennen wir die Verteilung von T und können die übliche Transformation mit Quantilsfunktion machen.
Wir bekommen nur eine t-Verteilung, wenn die ursprüngliche Verteilung eine Normalverteilung ist. Ansonsten kommt der zentrale Grenzwertsatz ins Spiel, der besagt, dass X_quer einer Normalverteilung annähert. Typischerweise stellt man die Bedingung, dass die Stichprobengröße n>30 ist.
Voraussetzungen zur Anwendung vom t-test
Der vorherige Abschnitt gibt uns schon die Antwort

X ist normalverteilt oder
Der zentrale Grenzwertsatz wird erfüllt und die Stichprobengröße > 30

Einseitiger vs. zweiseitiger t-Test
Bei einem zweiseitigen Test lautet die Nullhypothese und die Alternative . Haben wir vorher schon eine Idee zur Richtung, dann können wir auch einen einseitigen Test machen. Da haben wir dann die Nullhypothese und als Alternative . Das ganze geht natürlich auch umgekehrt
Einstichproben- vs. Zweistichproben-t-Test
Beim Einstichproben-t-Test haben wir eine Stichprobe, deren Mittelwert wir mit einem vorgegebenen Wert vergleichen wollen.
Beim Zweistichproben-t-Test haben wir zwei Stichproben, deren Mittelwerte wir miteinander vergleichen wollen. Das macht die Sache leider etwas komplizierter. Wir unterscheiden drei Fälle:

zwei unabhängige Stichproben mit gleicher Varianz
zwei verbundene/abhängige Stichproben
zwei unabhängige Stichproben mit ungleicher Varianz

Unabhängige Stichproben mit gleicher Varianz
Wir betrachten die Differenz der beiden Mittelwerte und schauen, ob diese gleich ist. Für die Teststatistik schätzen wir noch die gemeinsame Varianz der beiden Stichproben.
   
mit
   
Voraussetzungen: Stichproben normalverteilt oder beide so groß, dass Mittelwert durch Normalverteilung approximiert wird
Verbundene/Abhängige Stichproben
Unter diesem Fall versteht man zwei Beobachtungen der gleichen Gruppe. Also zum Beispiel vor und nach einer Behandlung oder auch unter verschiedenen Bedingungen.
Man will nun wissen, ob sich die zwei Mittelwerte voneinander unterscheiden. Anders ausgedrückt, ob die Differenz gleich null ist. Und genauso macht man es dann auch, d.h. einen Einstichproben-t-Test, der auf die Differenz angewandt wird.
Hier muss natürlich wieder geschaut werden, dass die Differenz die Voraussetzungen erfüllt. Im Wesentlichen heißt das, dass die Stichprobe groß genug ist.
Unabhängige Stichproben mit ungleicher Varianz
Problem ist die Voraussetzung, dass Varianz beider Stichproben gleich ist. Das ist in der Realität meist nicht gegeben, daher verwendet man den Welch-Test, der diese Bedingung nicht stellt. Streng genommen ist die Teststatistik nicht t-verteilt, aber sie nähert sich einer t-Verteilung an.
   
Man kann auch die Freiheitsgrade mit folgender Formel bestimmen:
   
Anwendungen vom t-Test
Prüfverfahren
Wie oben geschrieben ist war die Untersuchung von Gerstenqualität tatsächlich der Ursprung der t-Verteilung. Das lässt sich natürlich auf alle möglichen Situationen verallgemeinern, ob Agrarwissenschaft, Biologie, Pharma oder Maschinenbau. Immer dann, wenn die Mittelwerte zweier Gruppen verglichen werden sollen, kommt der t-Test ins Spiel.
Befragungen
Alle Arten von Befragungen, bei denen ein Mittelwert sinnvoll ist. Aber Achtung: Verwendung von Mittelwerten bei Likert-Skalen sind umstritten. Der Modus ist hier die bessere Wahl.
A/B-Test
A/B-Tests sind im Online-Marketing in aller Munde. Dazu werden zwei Varianten gebildet, z.B. Buttonplatzierung oder –farbe oder zwei verschiedene Facebook-Werbeanzeigen. Diese werden nun den Nutzern gezeigt und das Verhalten gemessen. Dann können die beiden Varianten miteinander verglichen werden, um dann die bessere, d.h. meistens profitablere, Variante zu verwenden.
So könnte man zum Beispiel die Conversion-Rate zweier Anzeigen untersuchen, indem man mittels t-Test prüft, ob sie gleich sind oder eine doch signifikant höher ist.
Regression
In den Statistiken einer linearen Regression wird normalerweise für jeden Koeffizienten mittels t-Test geprüft, ob dieser sich signifikant von 0 unterscheidet.
So, habt ihr euch wirklich den ganzen Artikel durchgelesen? Jetzt seid ihr hoffentlich mit dem Grundlagenwissen ausgestattet, um t-Tests anwenden zu können. Schreibt einen Kommentar, in welchem Zusammenhang ihr schon einen t-Test gemacht habt.
Happy testing,
Euer Holger
Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean ls Tensorflow

Strings in Python

Hej Leute,
Zu Beginn ein kleiner Hinweis: Dieser Beitrag ist ein Auszug aus dem neuen Python Komplettkurs von Edley. Falls ihr innerhalb von 30 Tagen Python lernen wollt und ein übersichtliches Nachschlagewerk mit allen wichtigen Themen braucht, ist das eine empfehlenswerte Ressource.
Heute lernt ihr, was Strings sind und wie man mit Ihnen arbeitet:
Strings
Im Beitrag über Datentypen wurden die String-Variablen ja schon kurz vorgestellt. Diese dienen dazu, Zeichenketten aufzunehmen und wiederzugeben. Strings werden in Anführungszeichen (” oder ‘) gestellt. Um String-Variablen zu bearbeiten bzw. zu verändern, kommen 2 Operatoren besonders häufig zum Einsatz:
Das Stern-Symbol (*). Dieses kommt bei Zahlen für die Multiplikation zum Einsatz. Ihr könnt jedoch auch eine Zeichenkette mit einer Zahl “multiplizieren”, in diesem Fall erhaltet ihr bei der Ausgabe eine Wiederholung der entsprechenden Zeichen in der vorgegebenen Anzahl.
Außerdem kennt ihr aus dem Beitrag über Operatoren bereits das Pluszeichen (+). Dieses hat, neben der mathematischen Addition von Zahlen, zwei Zeichenketten miteinander verbunden.
In den folgenden Abschnitten lernt ihr weitere Befehle kennen, mit denen es möglich ist, String-Variablen zu bearbeiten.
Wichtig ist es zunächst, auf einen einzelnen Teil der Zeichenkette zugreifen zu können. Das ist möglich, indem man hinter den Variablennamen in eine eckige Klammer ([] bei Windows mit Alt Gr + 8 und Alt Gr + 9, bei macOS mit alt + 5 und alt + 6) die Position des entsprechenden Buchstabens schreibt. Dabei müsst ihr lediglich berücksichtigen, dass der erste Buchstabe den Index 0 hat. Daher muss die entsprechende Zahl immer um 1 kleiner sein, als die eigentliche Position.
Will man beispielsweise auf den Buchstaben auf Position 4 zugreifen, muss man diesen Buchstaben über den Index 3 ansteuern.

Häufig ist es nicht nur notwendig, einen einzelnen Buchstaben aus der Zeichenkette herauszulösen, sondern einen größeren Bereich. Auch das ist möglich. Hierfür müsst ihr ebenfalls eine eckige Klammer hinter den Variablennamen schreiben. Darin stehen der Start- und der Endpunkt mit einem Doppelpunkt  voneinander getrennt. Dabei müsst ihr berücksichtigen, dass das Zeichen, das ihr als Endpunkt angebt, nicht mehr ausgegeben wird, sondern nur alle Zeichen, die vor dieser Position stehen. Wenn ihr am Anfang der Zeichenkette beginnen wollt, dann könnt ihr dafür den Index 0 eingeben. Alternativ dazu ist es möglich, die Zahl vor dem Doppelpunkt wegzulassen. Dann beginnt das Programm automatisch am Anfang der Zeichenkette. Wenn man die Zahl nach dem Doppelpunkt weglässt, beginnt das Programm am angegebenen Startpunkt und gibt alle Zeichen bis zum Ende der Zeichenkette wieder.
Das folgende Beispielprogramm zeigt, wie man Teile aus einer String-Variablen herauslösen kann:
variable = "Herzlich Willkommen!"

print (variable[0])
print (variable[5])
print (variable[3:7])
print (variable[:8])
print (variable[9:])
print (variable[-1])

Wenn ihr dieses Programm ausführt, seht ihr genau, wie der Zugriff auf einzelne Teile der Zeichenkette erfolgt.
Interessant ist dabei der letzte Befehl. Man könnte meinen, dass es keine negativen Positionen geben kann. Das Minuszeichen steht jedoch dafür, dass das Programm beim Zählen der Position von hinten beginnt. Die Position -1 bezeichnet daher das letzte Zeichen, die Position -2 das vorletzte und so weiter.

Anmerkung: Eigentlich wäre es logisch, für das letzte Zeichen die Position -0 zu verwenden. Das ist mathematisch jedoch gleichbedeutend mit 0, sodass der Interpreter das erste Zeichen ausgibt. Daher muss man immer mit -1 beginnen, wenn man beim letzten Zeichen beginnen will.
 

String-Methoden
Neben diesen einfachen Operationen mit Zeichenketten gibt es noch viele weitere, “schlauere” Möglichkeiten der Bearbeitung: Es handelt sich um Funktionen, die in Python integriert sind und die sich durch einen ganz bestimmten Schlüsselbegriff abrufen lassen. Diese Funktionen werden als String-Methoden bezeichnet. Die Vielfalt ist dabei so groß, dass es in diesem Beitrag nicht sinnvoll wäre, jede einzelne Funktion zu beschreiben. Die wichtigsten sollen jedoch kurz vorgestellt werden.
Um diese Methoden anzuwenden, ist es in der Regel notwendig, die Variable, die die Zeichenkette enthält, dem entsprechenden Schlüsselbegriff durch einen Punkt getrennt voranzustellen. Danach steht eine Klammer, die jedoch in vielen Fällen leer bleiben kann. Manchmal, je nach Methode, ist es allerdings notwendig, hier einen bestimmten Parameter einzufügen, damit die Methode richtig funktioniert. Um sie auszuprobieren, soll ein kleines Programm mit verschiedenen Methoden als Beispiel dienen:
text = "herzlich willkommen!"

print (text.capitalize())
print (text.count("i"))
print (text.endswith("en!"))
print (text.find("e"))
print (text.isdigit())
print (text.upper())
print (text.replace("e","0"))
 
Führt das Programm durch einen Klick auf Run aus und ihr erhaltet folgendes Ergebnis in der Konsole:

Die Methode capitalize() sorgt dafür, dass der erste Buchstabe der Zeichenkette groß geschrieben wird. Wenn es sich dabei bereits um einen Großbuchstaben handelt, hat sie keine Auswirkungen.
Die Methode count() benötigt als Parameter eine weitere Zeichenkette innerhalb der Klammer. Sie gibt an, wie häufig die in der Klammer angegebene Zeichenkette in der ursprünglichen Variable vertreten ist. Damit lässt sich beispielsweise die Häufigkeit eines Buchstabens oder eines Wortteils bestimmen. In längeren Texten könnt ihr damit auch bestimmte Wörter zählen.
Die Methode endswith() benötigt ebenfalls eine Zeichenkette in der Klammer und gibt eine boolesche Variable zurück. Diese ist True, wenn die ursprüngliche Variable genau mit den angegebenen Zeichen endet. Tut sie das nicht, ist der Wert False.
Die Methode find() sucht nach einzelnen Zeichen oder Zeichenketten innerhalb der Variable und gibt deren Position zurück. Sollten sie mehrfach auftreten, erhält man den Wert, an dem sie das erste Mal erscheint. Sollte das Zeichen überhaupt nicht vorkommen, erhält man den Wert -1 zurück.
Die Methode isdigit() überprüft, ob eine Zeichenkette ausschließlich aus Ziffern besteht. Je nach Ergebnis der Überprüfung gibt sie True oder False zurück.
Die Methode upper() verwandelt alle Kleinbuchstaben in der Zeichenkette in Großbuchstaben. Bei Ziffern, Satzzeichen oder bei Großbuchstaben hat sie keinen Effekt.
Mit der replace()-Methode könnt ihr einen Buchstaben oder eine bestimmte Abfolge durch einen anderen Ausdruck ersetzen. Diese Methode benötigt zwei Parameter. Der erste von ihnen enthält die Buchstabenfolge, die man ersetzen möchte. Der zweite gibt den neuen Wert an.
Hierbei handelt es sich nur um einen kleinen Ausschnitt aus den vielfältigen Methoden, die ihr auf Zeichenketten anwenden könnt. Eine vollständige Übersicht der String-Methoden findet man in der offiziellen Python-Referenz:
https://docs.python.org/3/library/stdtypes.html#string-methods
Probiert an dieser Stelle selbst ein paar Methoden mit eigenem Beispieltext aus, ihr könnt dabei nichts kaputt machen!
(Auszug aus dem Python Komplettkurs von Edley)
 
Happy coding,
Euer Holger
Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean ls Tensorflow

Operatoren in Python

Hej Leute,
heute geht es um ein wichtiges Thema in Python: Operatoren. Ohne diese geht beim Programmieren gar nichts. Es ist also wichtig, dass Ihr die Funktionsweise von Operatoren verstanden habt, bevor es mit fortgeschrittenen Themen weitergeht. Aber keine Panik, im Endeffekt ist das Konzept ganz simpel, wie ihr gleich sehen werdet.
(Dieser Beitrag ist ein Auszug aus dem Python Komplettkurs* von Edley)
Eine Variable bleibt im Verlauf eines Programms nicht immer gleich. Stattdessen ist es häufig notwendig, ihren Wert zu verändern. Hierzu kommen sogenannte Operatoren zum Einsatz. Für euch sind für den Anfang erstmal 2 Arten von Operatoren wichtig:
Zuweisungsoperator
Der Zuweisungsoperator besteht aus dem Gleichheitszeichen (=).  Er ermöglicht es, einer Variablen einen Wert zuzuweisen. Das ist nicht nur zu Beginn des Programms möglich. Ihr könnt einer Variablen auch im weiteren Verlauf immer wieder einen neuen Wert zuweisen:
name = "Michael"
print ("Hallo, "+name)
name = "Susanne"
print ("Hallo, "+name)

Dabei wird der alte Wert überschrieben. Bei der zweiten Ausgabe gibt der print-Befehl daher die Begrüßung mit den neuen Namen (hier: Susanne) aus.
Mathematische Operatoren
Hinzu kommen mathematische Operatoren. Dabei handelt es sich um die vier Grundrechenarten, die ihr hoffentlich noch aus der Schule kennt 😉
Die Verwendung von Addition mit Plus (+) und Subtraktion mit Minus (-) funktioniert wie gewohnt. Für Multiplikationen kommt das Sternsymbol (*) und für Divisionen der Schrägstrich (/) zum Einsatz. Außerdem gibt es den Modulo-Operator. Dieser besteht aus dem Prozentzeichen (%) und gibt den Rest der ganzzahligen Division an. Beispiele:
x = 4
y = x + 2
x = y / 3
x = 5 % 2
x = x * 5

 
Auf diese Weise sind viele verschiedene Rechenoperationen zwischen Zahlen und Variablen möglich. Dabei kann eine Variable auch Bezug auf sich selbst nehmen. Das zeigt das letzte Beispiel. Dieser Befehl weist der Variablen x das Fünffache ihres bisherigen Werts zu. Da solche Ausdrücke in Python recht häufig vorkommen, gibt es dafür auch eine Kurzform: x *= 5
Analog dazu bestehen auch für die anderen Grundrechenarten entsprechende Ausdrücke:
x += y                 entspricht               x = x + y
x -= y                 entspricht               x = x – y
x *= y                 entspricht               x = x * y
x /= y                 entspricht               x = x / y
Wichtig: Mathematischen Operatoren sind teilweise auch auf Zeichenketten anwendbar. Allerdings haben sie dabei einen anderen Effekt:

Das Pluszeichen setzt zwei Zeichenketten zusammen.
Das Sternsymbol wiederholt die Zeichenkette mit der entsprechenden Anzahl.

Es ist wichtig, dass ihr dieses Prinzip versteht, also nichts wie ran an die Tasten!
Neben dem Zuweisungsoperator und den mathematischen Operatoren, die ihr in diesem Beitrag kennengelernt habt,  werden später die Vergleichsoperatoren eine sehr wichtige Rolle spielen.
Wie genau diese funktionieren, wird z. B. im oben erwähnten Python Komplettkurs* gut erklärt.
Happy coding,
Euer Holger
 
P.S.: Die mit Sternchen (*) versehene Links sind sogenannte Affiliate-Links. Du unterstützt mich, wenn Du auf einen solchen Link klickst und das Produkt kaufst, d.h. ich bekomme vom Anbieter eine Provision. Für dich ändert sich der Preis nicht.
Glossar: barplot R (Programmiersprache) Anaconda rnorm Maschinelles Lernen median Hyperparameter RStudio min hist überwachtes Lernen reinforcement learning Neuronales Netz paste set.seed mean ls Tensorflow

Wird geladen

Hol Dir mein Buch

Zertifikatsstudium “Data Science & Big Data”

Gratis für Dich

Data Science mit Python

 

Leider ist der Kurs noch nicht fertig, ich arbeite aber daran. Melde dich jetzt unverbindlich an und erhalte 25% Frühbucherrabatt auf meinen Onlinekurs Data Science mit Python. Du erfährst außerdem als Erste/r sobald ich den Kurs fertiggestellt habe.

Du hast Dich erfolgreich angemeldet!

0
    0
    Warenkorb
    Warenkorb ist leerzum Shop