Autor: Stefan Herbek

Supervised Learning in R: Logistische Regression

Supervised Learning in R: Logistische Regression

Bei der linearen Regression wird versucht eine beobachtete abhängige Variable durch eine oder mehrere unabhängige Variablen zu erklären.

Bei logistischer Regression wird vorher gesagt ob etwas zutrifft oder nicht. Das Ergebnis der logistischen Regression liegt zwischen 0 und 1 und stellt die Wahrscheinlichkeit dar.

In folgendem Beispiel wird das donors.csv Dataset von DataCamp verwendet. Es handelt sich dabei um eine Liste an Spendern mit Informationen über das Alter, Interessen etc. Anhand dieser Daten soll vorher gesagt werden, ob eine Spende zu erwarten ist oder nicht.

Die Daten werden geladen und mit head(), dim() und str() werfen wir einen Blick darauf um ein besseres Gefühl für die Daten zu bekommen. Die Spalte „donated“ ist 1 wenn die entsprechende Person eine Spende getätigt hat, 0 wenn nicht. Dies wird die zu bestimmende Variable in diesem Modell.

donors <- read.csv("https://assets.datacamp.com/production/course_2906/datasets/donors.csv")
head(donors)
dim(donors)
# [1] 93462    13
str(donors)
# 'data.frame':	93462 obs. of  13 variables:
#   $ donated          : int  0 0 0 0 0 0 0 0 0 0 ...
# $ veteran          : int  0 0 0 0 0 0 0 0 0 0 ...
# $ bad_address      : int  0 0 0 0 0 0 0 0 0 0 ...
# $ age              : int  60 46 NA 70 78 NA 38 NA NA 65 ...
# $ has_children     : int  0 1 0 0 1 0 1 0 0 0 ...
# $ wealth_rating    : int  0 3 1 2 1 0 2 3 1 0 ...
# $ interest_veterans: int  0 0 0 0 0 0 0 0 0 0 ...
# $ interest_religion: int  0 0 0 0 1 0 0 0 0 0 ...
# $ pet_owner        : int  0 0 0 0 0 0 1 0 0 0 ...
# $ catalog_shopper  : int  0 0 0 0 1 0 0 0 0 0 ...
# $ recency          : Factor w/ 2 levels "CURRENT","LAPSED": 1 1 1 1 1 1 1 1 1 1 ...
# $ frequency        : Factor w/ 2 levels "FREQUENT","INFREQUENT": 1 1 1 1 1 2 2 1 2 2 ...
# $ money            : Factor w/ 2 levels "HIGH","MEDIUM": 2 1 2 2 2 2 2 2 2 2 ...

Mit der glm() Funktion erstellen wir ein Modell. „donated“ soll mit Hilfe von „bad_address“, „interest_religion“ und „interest_veterans“ modelliert werden.

donation_model <- glm(donated ~ bad_address + interest_religion + interest_veterans, data = donors, family = "binomial")
summary(donation_model)

Die Funktion predict() auf das Modell angewendet, gibt uns die Vorhersage für zukünftiges Verhalten. Als default werden log odds zurück gegeben. Der Parameter type = „response“ wandelt diese in Wahrscheinlichkeiten um. Die durchschnittliche Wahrscheinlichkeit einer Spende liegt bei 0,0504. Liegt die Wahrscheinlichkeit jeder einzelnen Person über dem Durchschnitt, wird in der Spalte „donation_pred“ 1 eingetragen. Mit mean() können wir die Genauigkeit des Modell berechnen.

donors$donation_prob <- predict(donation_model, type = "response")

mean(donors$donated)
# [1] 0.05040551

donors$donation_pred <- ifelse(donors$donation_prob > 0.0504, 1, 0)

mean(donors$donation_pred == donors$donated)
# [1] 0.794815

79,48 % Genauigkeit klingt zwar gut, ist es aber nicht! Wenn man für alle Personen 0 vorher gesagt hätte, hätte man schon eine Genauigkeit von 95 %! Die ROC Kurve kann uns zeigen, wie gut ein Modell wirklich ist. Die Area Under the Curve (AUC) gibt uns einen Wert der zwischen 0 und 1 liegt. Wir benötigen dazu das „pROC“ Package und die Funktionen roc() und auc().

library(pROC)
ROC <- roc(donors$donated, donors$donation_prob)
plot(ROC, col = "blue")
auc(ROC)
# Area under the curve: 0.5102

Die blaue Linie liegt sehr nahe an der Baseline. In diesem Fall ist das Modell nicht wirklich verwendbar.

.

Supervised Learning in R: Bayesian Methods

Supervised Learning in R: Bayesian Methods

Mobiltelefone tracken mittlerweile jeden Schritt von uns. Diese Daten geben nicht nur Aufschluss an welchen Orten wir waren, sondern auch wo wir uns mit einer großen Wahrscheinlichkeit zukünftig befinden werden.

Angenommen das Handy hat festgehalten, dass wir uns 3 Mal in einem Restaurant, 10 Mal zu Hause, 4 Mal in einem Shop und 23 Mal bei der Arbeit befunden haben. Mit einer Wahrscheinlichkeit von 57,5 % (23/40) befinden wir uns also bei der Arbeit. Nicht besonders aussagekräftig für zukünftige Zeitpunkte. Kommt allerdings eine weitere Variable dazu, z.B. die Zeit, dann können schon um einiges genauere Vorhersagen getroffen werden.

Der Satz von Bayes wurde nach dem Mathematiker Thomas Bayes benannt. Er beschreibt die Berechnung von bedingten Wahrscheinlichkeiten. Also z.B. wie wahrscheinlich ist es, dass ich bei der Arbeit bin, wenn gerade Montag 9 Uhr ist.

In folgendem Beispiel wird der Datensatz locations.csv von DataCamp und die library „e1071“ verwendet. Zuerst werden die Daten eingelesen und mit head(), dim() und str() erhalten wir einen Überblick über die Daten.

library(e1071)

locations <- read.csv("R/locations.csv", header = TRUE, sep = ",")
head(locations)
# month day   weekday daytype hour hourtype location
# 1     1   4 wednesday weekday    0    night     home
# 2     1   4 wednesday weekday    1    night     home
# 3     1   4 wednesday weekday    2    night     home
# 4     1   4 wednesday weekday    3    night     home
# 5     1   4 wednesday weekday    4    night     home
# 6     1   4 wednesday weekday    5    night     home
dim(locations)
# [1] 2184    7

str(locations)
# 'data.frame':	2184 obs. of  7 variables:
#   $ month   : int  1 1 1 1 1 1 1 1 1 1 ...
# $ day     : int  4 4 4 4 4 4 4 4 4 4 ...
# $ weekday : Factor w/ 7 levels "friday","monday",..: 7 7 7 7 7 7 7 7 7 7 ...
# $ daytype : Factor w/ 2 levels "weekday","weekend": 1 1 1 1 1 1 1 1 1 1 ...
# $ hour    : int  0 1 2 3 4 5 6 7 8 9 ...
# $ hourtype: Factor w/ 4 levels "afternoon","evening",..: 4 4 4 4 4 4 3 3 3 3 ...
# $ location: Factor w/ 7 levels "appointment",..: 3 3 3 3 3 3 3 3 3 4 ...

Dann erstellen wir mit naiveBayes() unser Model. Wir wollen die Location vorher sagen anhand der Tages Art und der Stunde. Mit laplace = 1 wir die Berechnung etwas geglättet. Das heißt, auch Ereignisse, welche in den Trainingsdaten nicht vorkommen werden mit einbezogen.

locationmodel <- e1071::naiveBayes(location ~ daytype + hour, data = locations, laplace=1)

Jetzt wollen wir natürlich überprüfen, was unser Model für einen bestimmten Zeitpunkt in der Zukunft vorhersagt. Als Beispiel habe ich ein DataFrame mit „weekday“ und 6 Uhr erstellt.

daytype <- "weekday"
futurelocation <- data.frame(daytype)
futurelocation$hour <- 6

Die predict() Funktion gefüttert mit dem Model und dem zu vorhersagenden Zeitpunkt, liefert uns als Ergebnis „home“. Wird der Parameter „type“ der predict Funktion auf „raw“ gesetzt, sehen wir die Wahrscheinlichkeiten aller möglichen Orte.

predict(locationmodel, futurelocation)
# [1] home

predict(locationmodel, futurelocation, type="raw")
# appointment     campus      home     office restaurant        store      theater
# [1,] 0.0004453673 0.02000083 0.9327182 0.03388309 0.01295256 9.182049e-23 9.926374e-49
DataCamp Podcast: Einblicke in Data Science, Glücksspiel und Buchmacherei

DataCamp Podcast: Einblicke in Data Science, Glücksspiel und Buchmacherei

Ich bin ein begeisterter Hörer des DataCamp-Podcasts DataFramed. Wöchentlich werden dort Experten aus den Bereichen Data Analytics, Data Science und verwandten Feldern interviewt. Besonders spannend fand ich die neueste Episode mit dem Titel „Data Science, Gambling, and Bookmaking“, in der Marco Blume, der Trading Director von Pinnacle Sports, zu Gast war.

Postcast mit Pinnacle Trading Director Marco Blume

Pinnacle Sports ist weltweit bekannt für seine hohen Wettlimits, niedrigen Margen und die Politik „Winning Players accepted“. Anders als viele andere Buchmacher limitiert Pinnacle Spieler, die ihre Quoten schlagen, nicht. Stattdessen werden diese erfolgreichen Wetter, auch „Superforecaster“ genannt, aktiv genutzt, um die eigenen Quotenmodelle zu verbessern. Im Gespräch erwähnt Marco Blume auch das Buch Superforecasting: The Art and Science of Prediction von Philip Tetlock, das die Wissenschaft und Kunst präziser Vorhersagen beleuchtet.

Ein Aspekt, der für mich besonders interessant war, ist die Tatsache, dass Pinnacle für viele seiner Datenanalysen und Modellierungen auf die Programmiersprache R setzt. Dies unterstreicht, wie weit verbreitet und leistungsfähig R im Bereich der professionellen Datenanalyse ist, selbst in der komplexen Welt des Sportwettens.

Supervised Learning in R: k-Nearest Neighbors

Supervised Learning in R: k-Nearest Neighbors

Supervised Learning ist eine Unterkategorie des Machine Learnings. Mit Hilfe von gelabelten Daten wird ein Algorithmus gelernt, welcher dann auf ungelabelte Test-Daten angewendet werden kann. Eine Anwendungsmöglichkeit ist zum Beispiel Bilderkennung.

Der k-Nearest Neighbors (kNN) Algorithmus eignet sich hervorragend für Klassifikationsprobleme. Ein Datensatz wird anhand seiner nächsten Nachbarn klassifiziert. k gibt an wie viele Nachbarn in Betracht gezogen werden sollen. Für die Anwendung benötigt es das Package „class“, einen Training Datensatz, einen Test Datensatz und die passenden Labels.

Als Datensatz verwende ich Verkehrsschilder, welche von DataCamp zur Verfügung gestellt werden. Bei der Aufbereitung wurden die Bilder von den Verkehrsschildern in eine 4×4 Matrix aufgeteilt und in jedem Feld die RGB Werte gemessen. Das heißt, wir haben 48 Datenpunkte pro Bild. Unsere Aufgabe ist es, den Datensatz noch in einen Training Datensatz, Test Datensatz und die Labels aufzuteilen.

data <- read.csv("https://assets.datacamp.com/production/repositories/718/datasets/c274ea22cc3d7e12d7bb9fdc9c2bdabe9ab025f4/knn_traffic_signs.csv", header = TRUE, sep = ",")

signs <- subset(data, sample == "train")
signs$sample <- NULL
signs$id <- NULL

test.data <- subset(data, sample == "test")
test.data$id <- NULL
test.data$sample <- NULL

sign_types <- signs$sign_type
signs_actual <- test.data$sign_type

Dann kann der knn Algorithmus auf die Daten angewendet werden. [-1] weil in der ersten Spalte das Label steht und wir den Algo natürlich nicht mit diesem Wissen füttern wollen.

signs_pred <- knn(train = signs[-1], test = test.data[-1], cl = sign_types)
table(signs_pred, signs_actual)
mean(signs_pred == signs_actual)

kNN konnte 93,2 % der Straßenschilder richtig einteilen.

Als default verwendet der kNN Algorithmus vom class Package nur einen nearest neighbor. Mit dem Parameter k, können wir eine beliebige Anzahl an nearest neighbors angeben und versuchen so die Genauigkeit weiter zu verbessern.

k_1 <- knn(train = signs[-1], test = test.data[-1], cl = sign_types)
mean(k_1==signs_actual)
table(k_1, signs_actual)
# 0.9322034
# signs_actual
# k_1          pedestrian speed stop
# pedestrian         19     2    0
# speed               0    17    0
# stop                0     2   19

k_7 <- knn(train = signs[-1], test = test.data[-1], cl = sign_types, k = 7)
mean(k_7==signs_actual)
table(k_7, signs_actual)
# 0.9661017
# signs_actual
# k_7          pedestrian speed stop
# pedestrian         18     0    0
# speed               0    20    0
# stop                1     1   19

k_15 <- knn(train = signs[-1], test = test.data[-1], cl = sign_types, k = 15)
mean(k_15==signs_actual)
table(k_15, signs_actual)
# 0.8813559
# signs_actual
# k_15         pedestrian speed stop
# pedestrian         13     0    0
# speed               1    20    0
# stop                5     1   19

Mit k = 7 konnte schon ein sehr gutes Ergebnis erzielt werden. 96,6 % der Schilder wurden richtig kategorisiert.

Automatisierte Surebet-Benachrichtigungen mit einem R-Script und einem Telegram-Bot

Automatisierte Surebet-Benachrichtigungen mit einem R-Script und einem Telegram-Bot

Ich habe ein R-Script entwickelt, das Surebets auf dem Wettmarkt identifiziert. Surebets, wie der Name schon sagt, sind sichere Wetten, bei denen man durch eine clevere Verteilung des Einsatzes garantiert Gewinn machen kann. Um dies zu verdeutlichen, nehmen wir ein klassisches Beispiel aus dem Tennis: Angenommen, Spieler A wird bei Buchmacher 1 zu einer Quote von 2,10 angeboten, und Spieler B ist bei Buchmacher 2 ebenfalls zu einer Quote von 2,10 spielbar. Setzt man jeweils 100 Euro auf beide Spieler, ergibt sich ein sicherer Gewinn von 10 Euro, unabhängig vom Ausgang des Spiels. Dieses Beispiel ist natürlich fiktiv, und in der Praxis müssen auch die speziellen Wettregeln, wie etwa die „w.o.“-Regel bei Tennisspielen, beachtet werden.

Bis jetzt hat mein Programm mich durch einen lauten Beep-Ton alarmiert, wenn eine Surebet entdeckt wurde. Um es komfortabler zu gestalten, möchte ich nun Benachrichtigungen direkt auf mein Smartphone erhalten. Eine praktische Lösung dafür ist die Verwendung eines Telegram-Bots.

Telegram bietet eine API, die die Erstellung und Integration solcher Bots ermöglicht, und es gibt ein passendes R-Package, um diese API zu nutzen. Der erste Schritt ist die Erstellung eines Bots über den „BotFather“ in Telegram.

Mit /newbot kann ein neuer Bot erstellt werden. Einfach ein paar Fragen des BotFather beantworten und schon erhält man einen Token für die API. Den Bot fügt man jetzt am besten der .Renviron File hinzu. Diese kann mit folgendem Code erstellt werden:

user_renviron = path.expand(file.path("~", ".Renviron"))
if(!file.exists(user_renviron)) # check to see if the file already exists
  file.create(user_renviron)
file.edit(user_renviron) # open with another text editor if this fails

Wer es genauer wissen will, kann hier mehr darüber erfahren. In diese File schreiben wir dann folgenden Befehl mit dem Token.

R_TELEGRAM_BOT_SurebetBot=Eigener_Token

Danach ist wichtig, dass RStudio neu gestartet wird. Mit folgendem Code kann dann eine Message versendet werden.

library(telegram)
bot <- TGBot$new(token = bot_token('Bot_Name'))
bot$set_default_chat_id(123456)
bot$sendMessage('Hallo, ich bin dein Telegram Bot')

Anstelle von 123456 muss die passende Chat ID eingefügt werden. Diese ID kann man durch die URL https://api.telegram.org/bot<API-access-token>/getUpdates?offset=0 herausfinden. Anstelle von <API-access-token> die eigene Token ID angeben. Zurück kommt ein JSON String in dem man unter chat: id: die passende ID herauslesen kann. Damit dies funktioniert, muss zuvor aber schon mindestens eine Nachricht an den Bot geschickt worden sein.

Shiny für Python

Shiny für Python

Ich habe im Sommer die ersten Erfahrungen mit Shiny in R gemacht. Da ich momentan Python lerne, möchte ich etwas gleichwertiges haben und bin dabei auf Dash gestoßen. Hier mein erster Gehversuch:

Zuerst mal die benötigten Packages installieren.

pip install dash==0.35.1 
pip install dash-html-components==0.13.4
pip install dash-core-components==0.42.1
pip install dash-table==3.1.11

Neue app.py File erstellen und Beispiel Code einfügen.

import dash
import dash_core_components as dcc
import dash_html_components as html

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div(children=[
    html.H1(children='Hello Dash'),

    html.Div(children='''
        Dash: A web application framework for Python.
    '''),

    dcc.Graph(
        id='example-graph',
        figure={
            'data': [
                {'x': [1, 2, 3], 'y': [4, 1, 2], 'type': 'bar', 'name': 'SF'},
                {'x': [1, 2, 3], 'y': [2, 4, 5], 'type': 'bar', 'name': u'Montréal'},
            ],
            'layout': {
                'title': 'Dash Data Visualization'
            }
        }
    )
])

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

Die Datei app.py ausführen et voilà – die erste Dash App kann unter localhost:8050 im Browser geöffnet werden.

Der Code-Aufbau ähnelt sehr dem von Shiny. Wer als schon Erfahrung mit Shiny und R hat, sollte hier sehr schnell rein finden.

Dieses und weitere Code Beispiele gibt es auf der Webseite von Dash.

Soccer Analytics: Wie Daten den Fußball revolutionieren

Soccer Analytics: Wie Daten den Fußball revolutionieren

Die Amerikaner sind bekannt für ihre Begeisterung für Sport und ihre Verehrung von Sporthelden, deren Leistungen in einer Vielzahl von Statistiken und Rekorden dokumentiert werden. In den 1990er Jahren veränderte Billy Beane die Major League Baseball (MLB) grundlegend, indem er eine neue Methode zur Bewertung von Spielern einführte, die heute als Sabermetrics bekannt ist. Seine Geschichte wurde im Film Moneyball mit Brad Pitt in der Hauptrolle eindrucksvoll verfilmt.

Es dauerte jedoch einige Jahre, bis die Vorteile datengetriebener Analysen auch im Fußball erkannt wurden. Während Videoanalysen inzwischen zum Standardrepertoire eines jeden professionellen Vereins gehören, steckt die Nutzung fortschrittlicher Daten wie etwa Positionsdaten noch in den Kinderschuhen.

Die Möglichkeiten, die Datenanalysen im Fußball bieten, sind vielfältig. Ein spannender Anwendungsbereich ist die Prävention von Verletzungen. Mit den richtigen Datensätzen können Verletzungen vorhergesagt werden – ein Konzept, das dem Predictive Maintenance-Ansatz in der Industrie ähnelt. Das AC Milan Lab ist in diesem Bereich ein Pionier und hat dem Verein durch proaktive Maßnahmen zur Vermeidung von Spielerausfällen bereits Millionen eingespart.

Ein weiteres faszinierendes Beispiel ist Matthew Benham, Gründer von Smartodds. Benham hat ein Vermögen mit der Entwicklung von Algorithmen verdient, die die Wahrscheinlichkeiten von Fußballergebnissen berechnen. Seine Expertise hat er auf den Fußball übertragen: Als Besitzer des FC Brentford in England und des dänischen Vereins FC Midtjylland setzt er auf datengetriebene Strategien, die beiden Clubs einen Wettbewerbsvorteil verschaffen.

In den europäischen Top-Ligen ist Datenanalyse mittlerweile unverzichtbar. In der englischen Premier League zum Beispiel ist es üblich, ganze Abteilungen von Mathematikern und Statistikern zu beschäftigen, um datenbasierte Einblicke zu gewinnen. Manchester City organisiert sogar regelmäßig Hackathons, um innovative Ideen zu sammeln und stets einen Schritt voraus zu sein.

Dank großer Datenanbieter wie Opta Sports, STATS und Sportradar haben inzwischen auch kleinere Vereine Zugang zu hochwertigen Daten. Allerdings fehlen diesen Teams oft die Ressourcen, um diese Daten effektiv zu nutzen. Dennoch zeigt sich: Die Bedeutung von Soccer Analytics wächst stetig, und es ist nur eine Frage der Zeit, bis datengetriebene Strategien auch die unteren Ligen nachhaltig prägen.

Reinforcement Learning

Reinforcement Learning

Ich schreibe meine Bachelorarbeit über das Thema Reinforcement Learning. In diesem Blog Eintrag sammle ich die interessantesten Quellen. Die Liste wird laufend erweitert.

Reinforcement Learning: An Introduction (Second edition) von Richard S. Sutton und Andrew G. Barto -> Die Bibel des Reinforcement Learnings. Die passenden Code Beispiele zu diesem Buch gibt es hier.

RL Course from David Silver -> David Silver war einer der führenden Forscher von AlphaGo. Seine Vorlesungen sind sehr zu empfehlen. Die Folien zum Vortrag gibt es hier.

Awesome Reinforcement Learning -> Eine umfangreiche Linksammlung zu Literatur, Webseiten, Papers, Software, Frameworks,.. etc