Montag, 20. April 2015

Datenanalyse mit R

Kürzlich bin ich auf einer News-Website über einen Artikel der Website experimental 361 gestolpert: English Premier League - Attacking effectiveness, Defense effectiveness.

Ben Mayhew erklärt anhand von schönen Graphen welche Teams besonders effektiv in der Offensive und Defensive sind. Effektiv bedeutet in diesem Kontext aus wenigen Torchancen ein Tor zu erzielen, bzw. dass der Gegner viele Torchancen benötigt um ein Tor zu schiessen.

experimental 3-6-1


Dadurch inspiriert wollte ich eine leicht abgeänderte Frage für die Schweizer Fussballliga beantworten:
Welche Stürmer der Super League sind besonders effizient?
Konkreter: Welcher Stürmer macht die wenigsten Schüsse pro erzieltem Tor?

Die Programmiersprache R eignet sich perfekt um eine solche Aufgabenstellung zu erfüllen.

Die Analyse skizziere ich mir etwa so:
  1. Laden der Daten
  2. Bereinigung und Transformation der Daten
  3. Graphische Darstellung
  4. Interpretation

Laden der Daten


Als Datenquelle nutze ich die öffentlich verfügbaren Statistiken der offiziellen Website der Swiss Football League. Für jeden Spieler wird schön aufgeschlüsselt wie viele Minuten er gespielt hat, wie viele Tore er schoss und sogar wie viele Schüsse er abgab.

Leider sind die Daten nicht in perfekt strukturierter Form erhältlich, sondern nur eingebettet in der Website. Zum Glück bringt R im Package XML bereits gute Funktionen zum Parsen von HTML mit.

Zuerst lade ich die Website des Teams:




R-Code dazu:


name <- "fc-zuerich"
url <- paste0("http://www.sfl.ch/superleague/klubs/",name,"/season/201415/")
download.file(url, paste0("teams/",name,".html"))


Auf der Website des Teams sind alle Spieler aufgelistet und verlinkt. Diesen Links folge ich und lade die Daten ebenfalls von der Website. Das Parsen der Spielerdaten sieht in R dann in etwa so aus:

# alle Tabellen aus dem HTML-Dokument lesen
library(XML) 
tables <- readHTMLTable(document, stringsAsFactors = FALSE, header = FALSE)
# Kombination von 2 Tabellen der Seite
player.data <- rbind(tables[[1]], tables[[3]])

Dann lade und parse ich eine einzelne Spielerseite


R-Code:

filename <- paste0("players/", name, ".html")
download.file(link, filename) 
# Parsen von HTML Tabellen 
tables <- readHTMLTable(filename, stringsAsFactors = FALSE, header = FALSE)
# Zusammenfassen von mehreren Data Frames 
player.by_row <- rbind(player.by_row, data.frame(V1 = c("name"), V2 = c(name)))
# Zuweisen der Spaltennamen 
row.names(player.by_row) <- player.by_row$V1
# Erstellen eines Data Frames 
player <- data.frame(t(select(player.by_row, V2)), stringsAsFactors = F)

Natürlich lade ich für die ganze Analyse die Daten aller Spieler der zehn Mannschaften der Liga:
  • BSC Young Boys
  • FC Aarau
  • FC Basel 1893
  • FC Luzern
  • FC Sion
  • FC St. Gallen
  • FC Thun
  • FC Vaduz
  • FC Zürich
  • Grasshopper Club

Bereinigung und Transformation

Die Daten der SFL-Website sind konsistent.
Dies bedeutet wenig Aufwand um die gewünschten Felder herauszufiltern und die Statistiken zu generieren.
Ich beschränke an dieser Stelle die Analyse auf Spieler welche mindestens drei Tore erzielt haben, weil das Diagramm am Schluss sonst zu unübersichtlich wird.

library(dplyr)
min.goals <- 3
# filtern, berechnen, sortieren 
player.statistics <- players %>%
  filter(goals >= min.goals) %>%
  filter(minutes.played > 0) %>%
  mutate(shots.per.goal = shots/goals) %>%
  mutate(minutes.per.shot = minutes.played/shots) %>%
  mutate(minutes.per.goal = minutes.played/goals) %>%
  mutate(bmi = weight/(height/100)^2) %>%
  arrange(shots.per.goal, goals) %>%
  select(name, goals, shots, minutes.played, team, shots.per.goal, minutes.per.shot, minutes.per.goal)

Graphische Darstellung

Mit der Library ggplot2 kann man relativ schnell sehr schöne Graphen erstellen. Die Feinjustierung benötigt dann aber doch noch einige Zeit.


library(ggplot2)
library(grid)
ggplot(player.statistics, aes(minutes.per.shot, shots.per.goal)) + 
    ggtitle("Analyse Superleague-Torschützen (>3 Tore)") + 
    labs(x = "Minuten pro Torschuss", y = "Schüsse pro Tor") +
    scale_y_continuous(limits = c(3,11), breaks=seq(2,11,0.5)) + 
    scale_x_continuous(limits = c(25,75), breaks=seq(0, 90, 5))  +
    geom_point(size=4, alpha=1/2, color="steelblue") + 
    geom_text(aes(label=paste0(name," (",goals,")")),hjust=0, vjust=-0.5) + 
    geom_hline(yintercept=5.25, linetype="solid", alpha=0.75) +
    geom_vline(xintercept=46.3, linetype="solid", alpha=0.75) +
    geom_rect(xmin=0, xmax=34.3, ymin=0, ymax=Inf, alpha=0.0025, fill='red') +
    geom_rect(xmin=0, xmax=Inf, ymin=0, ymax=4.0, alpha=0.0025, fill='red') +
    geom_text(label="Viele Chancen", x=24.25, y=11.1, colour = "red", hjust=0, alpha=0.075) + 
    geom_text(label="Effizient", x=73.5, y=2.75, colour = "red", hjust=0, alpha=0.075) + 
    theme(legend.position="none")

Interpretation


Dieses Diagram wurde mit dem obigen Code generiert. 
Die roten Bereiche markieren die Top-25% auf der jeweiligen Achse.



Die Spieler im linken unteren Quadrant sind besonders effizient und benötigen wenige Schüsse um ein Tor zu erzielen. Die Spieler im Quadrant oben rechts benötigen verhältnismässig viele Chancen um ein Tor zu erzielen.

Eine Interpretation hat bereits in einem vorherigen Blogpost stattgefunden.

Der ganze Source-Code und die Analyse als R-Markdown-File ist auf Github zu finden.