Zum Hauptinhalt springen

Scikit-Learn Tutorial: Baseball-Analytics Teil 1

Ein scikit-learn-Tutorial zur Vorhersage von MLB-Siegen pro Saison mit KMeans-Clustering und linearen Regressionsmodellen.
· 14 Min. lesen

Entdecke KI

Die Programmiersprache Python ist eine hervorragende Wahl für Data Science und Predictive Analytics. Sie bringt zahlreiche Pakete mit, die die meisten Anforderungen deiner Datenanalyse abdecken. Für Machine Learning in Python ist Scikit-Learn (sklearn) eine sehr gute Option. Es basiert auf NumPy, SciPy und Matplotlib (für N-dimensionale Arrays, wissenschaftliches Rechnen und Datenvisualisierung).

In diesem Tutorial lädst du Daten mit sqlite3 aus einer Datenbank, explorierst sie und verbesserst ihre Qualität mit pandas und matplotlib, und nutzt anschließend Scikit-Learn, um belastbare Erkenntnisse aus den Daten zu gewinnen.

Wenn du einen Kurs zu Machine Learning machen möchtest, schau dir den DataCamp-Kurs Supervised Learning with scikit-learn an.

Teil 1: MLB-Team-Siege pro Saison vorhersagen

In diesem Projekt testest du mehrere Machine-Learning-Modelle aus sklearn, um die Anzahl der Spiele vorherzusagen, die ein Major-League-Baseball-Team in einer Saison gewinnt – basierend auf Teamstatistiken und weiteren Variablen dieser Saison. Wäre ich ein Wettfreund (und das bin ich durchaus), könnte ich ein Modell mit historischen Daten aus früheren Saisons bauen, um die nächste Saison zu prognostizieren. Aufgrund der Zeitreihen-Natur der Daten ließen sich etwa Indikatoren wie durchschnittliche Siege der letzten fünf Jahre bilden, um das Modell weiter zu schärfen. Das liegt hier jedoch außerhalb des Umfangs: Du behandelst jede Zeile unabhängig. Jede Zeile repräsentiert ein bestimmtes Team in einem spezifischen Jahr.

Sean Lahman hat diese Daten auf seiner Website zusammengetragen; eine sqlite-Datenbank wurde daraus generiert.

Daten importieren

Du liest die Daten, indem du eine sqlite-Datenbank mit dem Paket sqlite3 abfragst und das Ergebnis mit pandas in ein DataFrame umwandelst. Die Daten werden so gefiltert, dass nur aktuell aktive, moderne Teams enthalten sind und nur Jahre, in denen das Team 150 oder mehr Spiele absolviert hat.

Lade zunächst die Datei „lahman2016.sqlite“ (hier) herunter. Lade dann Pandas und benenne es der Effizienz halber in pd um. Du erinnerst dich: pd ist der gängige Alias für Pandas. Lade schließlich sqlite3 und verbinde dich so mit der Datenbank:

# import `pandas` and `sqlite3`import pandas as pdimport sqlite3# Connecting to SQLite Databaseconn = sqlite3.connect('lahman2016.sqlite')

Als Nächstes schreibst du eine Query, führst sie aus und holst die Ergebnisse ab.

# Querying Database for all seasons where a team played 150 or more games and is still active today. query = '''select * from Teams inner join TeamsFranchiseson Teams.franchID == TeamsFranchises.franchIDwhere Teams.G >= 150 and TeamsFranchises.active == 'Y';'''# Creating dataframe from query.Teams = conn.execute(query).fetchall()

Tipp: Wenn du mehr über SQL mit Python lernen möchtest, probiere den DataCamp-Kurs Introduction to Databases in Python.

Mit pandas wandelst du die Ergebnisse in ein DataFrame um und gibst mit der Methode head() die ersten 5 Zeilen aus:

# Convert `Teams` to DataFrame
teams_df = pd.DataFrame(_____)

# Print out first 5 rows
print(_______________)

Jede Spalte enthält Daten zu einem bestimmten Team und Jahr. Einige der wichtigsten Variablen sind unten aufgeführt. Eine vollständige Liste findest du hier.

  • yearID - Jahr
  • teamID - Team
  • franchID - Franchise (verweist auf die TeamsFranchise-Tabelle)
  • G - Spiele
  • W - Siege
  • LgWin - Ligameister (Y oder N)
  • WSWin - World-Series-Sieger (Y oder N)
  • R - Erzielt Punkte (Runs)
  • AB - At Bats (Schlagversuche)
  • H - Hits der Schlagleute
  • HR - Homeruns der Schlagleute
  • BB - Walks der Schlagleute
  • SO - Strikeouts der Schlagleute
  • SB - Stolen Bases
  • CS - Caught Stealing
  • HBP - Hit by Pitch
  • SF - Sacrifice Flies
  • RA - Gegners Runs
  • ER - Earned Runs zugelassen
  • ERA - Earned Run Average
  • CG - Complete Games
  • SHO - Shutouts
  • SV - Saves
  • IPOuts - Outs gepitcht (Innings × 3)
  • HA - Zugelassene Hits
  • HRA - Zugelassene Homeruns
  • BBA - Zugelassene Walks
  • SOA - Strikeouts der Pitcher
  • E - Errors
  • DP - Double Plays
  • FP - Fielding Percentage
  • name - Vollständiger Teamname

Falls du mit Baseball nicht so vertraut bist, hier eine kurze Erklärung des Spiels – inklusive einiger oben genannter Variablen.

Baseball wird zwischen zwei Teams mit jeweils neun Spielern gespielt (in den Daten findest du sie unter name oder teamID). Die Teams wechseln sich im Schlagrecht und in der Feldverteidigung ab. Das schlagende Team versucht, Runs zu erzielen, indem es den vom Pitcher des Feldteams geworfenen Ball schlägt und dann gegen den Uhrzeigersinn die vier Bases umläuft: First, Second, Third und Home Plate. Das Feldteam versucht, Runs zu verhindern, indem es Schlagmänner oder Baserunner auf verschiedene Arten out macht. Ein Run (R) wird erzielt, wenn ein Spieler alle Bases umläuft und zur Home Plate zurückkehrt. Wer sicher eine Base erreicht, versucht oft, bei den folgenden Schlägen weiter vorzurücken – z. B. durch einen Hit (H), eine Stolen Base (SB) oder andere Spielzüge.

baseball

Die Teams wechseln, sobald das Feldteam drei Outs erzielt. Je eine Schlagrunde beider Teams – beginnend mit dem Auswärtsteam – ergibt ein Inning. Ein Spiel besteht aus neun Innings; das Team mit mehr Runs gewinnt. Baseball hat keine Spieluhr: Endet das Spiel nach neun Innings unentschieden, geht es in Extra-Innings weiter, bis ein Team am Ende eines Extra-Innings führt.

Eine ausführliche Erklärung liefert das offizielle Regelwerk der Major League Baseball.

Daten bereinigen und vorbereiten

Wie du oben siehst, hat das DataFrame keine Spaltenüberschriften. Du kannst Header hinzufügen, indem du dem Attribut columns von pandas eine Liste mit Spaltennamen übergibst.

# Adding column names to dataframe
cols = ['yearID','lgID','teamID','franchID','divID','Rank','G','Ghome','W','L','DivWin','WCWin','LgWin','WSWin','R','AB','H','2B','3B','HR','BB','SO','SB','CS','HBP','SF','RA','ER','ERA','CG','SHO','SV','IPouts','HA','HRA','BBA','SOA','E','DP','FP','name','park','attendance','BPF','PPF','teamIDBR','teamIDlahman45','teamIDretro','franchID','franchName','active','NAassoc']
teams_df.columns = ____

# Print the first rows of `teams_df`
print(______________)

# Print the length of `teams_df`
print(len(________))

Die Funktion len() zeigt dir, wie viele Zeilen vorliegen: 2.287 sind nicht allzu viele Datenpunkte – hoffentlich gibt es also nicht zu viele fehlende Werte.

Bevor du die Datenqualität bewertest, entferne zunächst Spalten, die unnötig sind oder direkt vom Ziel (Wins) abgeleitet werden. Hier zahlt sich Domänenwissen aus: Es ist egal, wie gut du in Code oder Statistik bist – ohne Verständnis für die Daten kommst du nicht weit. Mir hat meine lebenslange Baseball-Erfahrung hier sehr geholfen.

# Dropping your unnecesary column variables.
drop_cols = ['lgID','franchID','divID','Rank','Ghome','L','DivWin','WCWin','LgWin','WSWin','SF','name','park','attendance','BPF','PPF','teamIDBR','teamIDlahman45','teamIDretro','franchID','franchName','active','NAassoc']

df = teams_df.drop(drop_cols, axis=1)

# Print out first rows of `df`
print(_________)

Wie oben erwähnt, beeinträchtigen fehlende Werte die Datenqualität – und das kann wiederum zu Problemen bei ML-Algorithmen führen.

Deshalb entfernst du sie als Nächstes. Es gibt verschiedene Ansätze, aber sinnvoll ist, zunächst die Anzahl fehlender Werte pro Spalte auszugeben, um dann gezielt zu entscheiden.

# Print out null values of all columns of `df`
print(_________.sum(axis=0).tolist())

Hier zeigt sich der Trade-off: Du brauchst saubere Daten, aber die Datenmenge ist begrenzt. Zwei Spalten haben relativ wenige fehlende Werte: 110 in SO (Strikeouts) und 22 in DP (Double Plays). Zwei Spalten haben sehr viele: 419 in CS (Caught Stealing) und 1777 in HBP (Hit by Pitch).

Wenn du Zeilen mit wenigen fehlenden Werten entfernst, verlierst du etwas über fünf Prozent der Daten. Da du Siege vorhersagen willst, sind erzielte und zugelassene Runs stark mit dem Ziel korreliert – diese Spalten sollten möglichst akkurat sein.

Strikeouts (SO) und Double Plays (DP) sind weniger entscheidend.

Es ist sinnvoller, die Zeilen zu behalten und fehlende Werte spaltenweise mit dem Median zu füllen – mit fillna(). CS und HBP sind ebenfalls nicht sonderlich wichtig. Bei so vielen fehlenden Werten ist es am besten, diese Spalten komplett zu entfernen.

# Eliminating columns with null values
df = df.drop(['CS','HBP'], axis=1)

# Filling null values
df['SO'] = df['SO'].fillna(df['SO'].median())
df['DP'] = df['DP'].fillna(df['DP'].median())

# Print out null values of all columns of `df`
print(df.isnull().sum(axis=0).tolist())

Daten erkunden und visualisieren

Nachdem du die Daten bereinigt hast, kannst du sie explorieren. Ein paar einfache Visualisierungen geben dir schnell ein Gefühl für den Datensatz. matplotlib ist dafür bestens geeignet.

Importiere matplotlib.pyplot und benenne es in plt um. Wenn du mit einem Jupyter-Notebook arbeitest, nutze das Magic %matplotlib inline.

Starte mit einem Histogramm der Zielspalte, um die Verteilung der Siege zu sehen.

# import the pyplot module from matplotlibimport matplotlib.pyplot as plt# matplotlib plots inline  %matplotlib inline# Plotting distribution of winsplt.hist(df['W'])plt.xlabel('Wins')plt.title('Distribution of Wins')plt.show()

distribution graph

Hinweis: Wenn du kein Jupyter-Notebook verwendest, musst du plt.show() aufrufen, um die Plots anzuzeigen.

Gib die durchschnittlichen Siege (W) pro Jahr aus. Nutze dafür mean().

print(df['_'].______)

Beim Explorieren kann es hilfreich sein, Bins für die Zielspalte zu definieren. Wichtig: Solche aus dem Ziel abgeleiteten Features dürfen später nicht ins Training einfließen – das wäre, als würdest du dem Modell die Antworten vorab geben.

Für die Gewinn-Labels (win_bins) erstellst du eine Funktion assign_win_bins, die eine ganze Zahl (Siege) entgegennimmt und abhängig vom Wert eine Zahl von 1–5 zurückgibt.

Dann erzeugst du die neue Spalte win_bins, indem du apply() auf der Siegspalte aufrufst und die Funktion assign_win_bins() übergibst.

# Creating bins for the win column
def assign_win_bins(_):
    if W < 50:
        return 1
    if W >= 50 and W <= 69:
        return 2
    if W >= 70 and W <= 89:
        return 3
    if W >= 90 and W <= 109:
        return 4
    if W >= 110:
        return 5
        
# Apply `assign_win_bins` to `df['W']`    
df['win_bins'] = df['_'].apply(______________)

Erstelle nun ein Scatter-Plot mit dem Jahr auf der x-Achse und den Siegen auf der y-Achse und hebe die win_bins-Spalte farblich hervor.

# Plotting scatter graph of Year vs. Winsplt.scatter(df['yearID'], df['W'], c=df['win_bins'])plt.title('Wins Scatter Plot')plt.xlabel('Year')plt.ylabel('Wins')plt.show()

scikit-learn project

Wie du siehst, gibt es vor 1900 nur wenige Saisons, zudem war das Spiel damals deutlich anders. Es ergibt Sinn, diese Zeilen aus dem Datensatz zu entfernen.

# Filter for rows where 'yearID' is greater than 1900
df = df[___________________]

Bei stetigen Variablen in linearen Modellen können ganzzahlige Werte wie ein Jahr Probleme machen. Es ist unwahrscheinlich, dass „1950“ dieselbe Beziehung im Modell repräsentiert, wie man intuitiv annehmen würde.

Um das zu umgehen, kannst du neue Variablen erstellen, die Daten basierend auf yearID labeln.

Wer MLB verfolgt, weiß: Im Lauf der Zeit gab es Epochen mit deutlich unterschiedlichen durchschnittlichen Runs pro Spiel. Die „Dead-Ball“-Ära Anfang des 20. Jahrhunderts war z. B. niedrigpunktreich; die Steroid-Ära um die Jahrtausendwende hingegen sehr hochpunktreich.

Lass uns eine Grafik erstellen, die zeigt, wie viel in jedem Jahr gescort wurde.

Beginne mit den Dictionaries runs_per_year und games_per_year. Iteriere mit iterrows() über das DataFrame. Fülle runs_per_year mit Jahren als Keys und der Anzahl der in diesem Jahr erzielten Runs. Fülle games_per_year mit Jahren als Keys und der Anzahl der in diesem Jahr gespielten Spiele.

# Create runs per year and games per year dictionaries
runs_per_year = {}
games_per_year = {}

for i, row in df.iterrows():
    year = row['yearID']
    runs = row['R']
    games = row['G']
    if year in runs_per_year:
        runs_per_year[year] = runs_per_year[year] + runs
        games_per_year[year] = games_per_year[year] + games
    else:
        runs_per_year[year] = runs
        games_per_year[year] = games
        
print(runs_per_year)
print(games_per_year)

Als Nächstes erstellst du das Dictionary mlb_runs_per_game. Iteriere mit items() über games_per_year. Befülle mlb_runs_per_game mit Jahren als Keys und der ligaweiten Zahl der Runs pro Spiel als Wert.

# Create MLB runs per game (per year) dictionary
mlb_runs_per_game = {}
for k, v in games_per_year.items():
    year = k
    games = v
    runs = runs_per_year[year]
    mlb_runs_per_game[year] = runs / games
    
print(mlb_runs_per_game)

Jetzt erstellst du den Plot aus mlb_runs_per_game, mit den Jahren auf der x-Achse und den Runs pro Spiel auf der y-Achse.

# Create lists from mlb_runs_per_game dictionarylists = sorted(mlb_runs_per_game.items())x, y = zip(*lists)# Create line plot of Year vs. MLB runs per Gameplt.plot(x, y)plt.title('MLB Yearly Runs per Game')plt.xlabel('Year')plt.ylabel('MLB Runs per Game')plt.show()

baseball analytics scikit-learn

Neue Features hinzufügen

Mit dem besseren Verständnis der Scoring-Trends kannst du nun Variablen erstellen, die die jeweilige Ära jeder Zeile anhand von yearID kennzeichnen. Du gehst ähnlich vor wie bei der Spalte win_bins.

Diesmal erzeugst du jedoch Dummy-Spalten – eine neue Spalte pro Ära. Dafür eignet sich get_dummies().

# Creating "year_label" column, which will give your algorithm information about how certain years are related 
# (Dead ball eras, Live ball/Steroid Eras)

def assign_label(____):
    if year < 1920:
        return 1
    elif year >= 1920 and year <= 1941:
        return 2
    elif year >= 1942 and year <= 1945:
        return 3
    elif year >= 1946 and year <= 1962:
        return 4
    elif year >= 1963 and year <= 1976:
        return 5
    elif year >= 1977 and year <= 1992:
        return 6
    elif year >= 1993 and year <= 2009:
        return 7
    elif year >= 2010:
        return 8
        
# Add `year_label` column to `df`    
df['year_label'] = df['yearID'].apply(___________)

dummy_df = pd.get_dummies(df['year_label'], prefix='era')

# Concatenate `df` and `dummy_df`
df = pd.concat([df, dummy_df], axis=1)

print(df.head())

Da du bereits die Runs pro Spiel pro Jahr bestimmt hast, füge diese Daten dem Datensatz hinzu.

# Create column for MLB runs per game from the mlb_runs_per_game dictionary
def assign_mlb_rpg(year):
    return mlb_runs_per_game[year]

df['mlb_rpg'] = df['yearID'].apply(assign_mlb_rpg)

Nun wandelst du die Jahre in Jahrzehnte um, indem du Dummy-Spalten pro Jahrzehnt erstellst. Danach kannst du nicht mehr benötigte Spalten droppen.

# Convert years into decade bins and creating dummy variables
def assign_decade(year):
    if year < 1920:
        return 1910
    elif year >= 1920 and year <= 1929:
        return 1920
    elif year >= 1930 and year <= 1939:
        return 1930
    elif year >= 1940 and year <= 1949:
        return 1940
    elif year >= 1950 and year <= 1959:
        return 1950
    elif year >= 1960 and year <= 1969:
        return 1960
    elif year >= 1970 and year <= 1979:
        return 1970
    elif year >= 1980 and year <= 1989:
        return 1980
    elif year >= 1990 and year <= 1999:
        return 1990
    elif year >= 2000 and year <= 2009:
        return 2000
    elif year >= 2010:
        return 2010
    
df['decade_label'] = df['yearID'].apply(assign_decade)
decade_df = pd.get_dummies(df['decade_label'], prefix='decade')
df = pd.concat([df, decade_df], axis=1)

# Drop unnecessary columns
df = df.drop(['yearID','year_label','decade_label'], axis=1)

Am Ende zählt im Baseball, wie viele Runs du erzielst und wie viele du zulässt. Du kannst die Modellgüte oft deutlich steigern, indem du Verhältnis-Features bildest. Runs pro Spiel und zugelassene Runs pro Spiel sind hervorragende Ergänzungen.

Mit Pandas ist das simpel: Erzeuge eine neue Spalte, indem du R durch G teilst – so entsteht R_per_game.

# Create new features for Runs per Game and Runs Allowed per Game
df['R_per_game'] = df['R'] / df['G']
df['RA_per_game'] = df['RA'] / df['G']

Untersuche nun in zwei Scatterplots, wie die beiden neuen Variablen mit den Siegen zusammenhängen: Ein Plot mit Runs pro Spiel auf der x-Achse, ein weiterer mit zugelassenen Runs pro Spiel. Auf der y-Achse jeweils W.

# Create scatter plots for runs per game vs. wins and runs allowed per game vs. winsfig = plt.figure(figsize=(12, 6))ax1 = fig.add_subplot(1,2,1)ax2 = fig.add_subplot(1,2,2)ax1.scatter(df['R_per_game'], df['W'], c='blue')ax1.set_title('Runs per Game vs. Wins')ax1.set_ylabel('Wins')ax1.set_xlabel('Runs per Game')ax2.scatter(df['RA_per_game'], df['W'], c='red')ax2.set_title('Runs Allowed per Game vs. Wins')ax2.set_xlabel('Runs Allowed per Game')plt.show()

clusters

Bevor du Modelle trainierst, lohnt ein Blick auf die Korrelationen der Features mit dem Ziel. Mit Pandas geht das einfach über corr().

df.corr()['W']

Ein weiteres Feature, das du hinzufügen kannst, sind Labels aus einem K-Means-Clustering mit sklearn. K-Means ist ein einfaches Clustering-Verfahren, das die Daten anhand der vorgegebenen Anzahl k von Zentroiden partitioniert. Jeder Datenpunkt wird dem Cluster mit der geringsten euklidischen Distanz zum Zentroid zugewiesen.

Mehr über K-Means-Clustering erfährst du hier.

Erstelle zunächst ein DataFrame ohne die Zielvariable:

attributes = ['G','R','AB','H','2B','3B','HR','BB','SO','SB','RA','ER','ERA','CG',
'SHO','SV','IPouts','HA','HRA','BBA','SOA','E','DP','FP','era_1','era_2','era_3','era_4','era_5','era_6','era_7','era_8','decade_1910','decade_1920','decade_1930','decade_1940','decade_1950','decade_1960','decade_1970','decade_1980','decade_1990','decade_2000','decade_2010','R_per_game','RA_per_game','mlb_rpg']

data_attributes = df[attributes]

# Print the first rows of `df`
print(df.head())

Bei K-Means musst du die Anzahl der Cluster festlegen. Eine Orientierung bietet silhouette_score() aus sklearn. Die Funktion gibt den mittleren Silhouettenkoeffizienten über alle Stichproben zurück. Je höher, desto besser – der Wert sinkt meist, wenn du mehr Cluster hinzufügst.

# Import necessary modules from `sklearn` 
from sklearn.cluster import KMeans
from sklearn import metrics

# Create silhouette score dictionary
s_score_dict = {}
for i in range(2,11):
    km = KMeans(n_clusters=i, random_state=1)
    l = km.fit_predict(data_attributes)
    s_s = metrics.silhouette_score(data_attributes, l)
    s_score_dict[i] = [s_s]

# Print out `s_score_dict`
print(s_score_dict)

Initialisiere nun das Modell. Setze die Clusteranzahl auf 6 und den Random State auf 1. Bestimme die euklidischen Distanzen jedes Datenpunkts mit fit_transform() und visualisiere die Cluster in einem Scatterplot.

# Create K-means model and determine euclidian distances for each data pointkmeans_model = KMeans(n_clusters=6, random_state=1)distances = kmeans_model.fit_transform(data_attributes)# Create scatter plot using labels from K-means model as colorlabels = kmeans_model.labels_plt.scatter(distances[:,0], distances[:,1], c=labels)plt.title('Kmeans Clusters')plt.show()

clusters

Füge nun die Cluster-Labels als neue Spalte in den Datensatz ein. Ergänze außerdem den String „labels“ in der Liste attributes für die spätere Nutzung.

# Add labels from K-means model to `df` DataFrame and attributes list
df['labels'] = labels
attributes.append('labels')

# Print the first rows of `df`
print(_________)

Bevor du ein Modell baust, teilst du die Daten in Trainings- und Test-Set. Trainierst und testest du auf denselben Daten, droht Overfitting: Das Modell „merkt“ sich die Daten statt zu generalisieren – und performt bei neuen Daten schlecht.

Keine Sorge: Es gibt verschiedene Möglichkeiten zur Kreuzvalidierung.

Hier ziehst du einfach eine Zufallsstichprobe von 75 Prozent als train und nutzt die restlichen 25 Prozent als test. Erstelle eine Liste numeric_cols mit allen Spalten, die dein Modell verwenden soll. Erzeuge dann aus df ein neues DataFrame data mit genau diesen Spalten. Anschließend erstellst du train und test, indem du data entsprechend samplest.

# Create new DataFrame using only variables to be included in models
numeric_cols = ['G','R','AB','H','2B','3B','HR','BB','SO','SB','RA','ER','ERA','CG','SHO','SV','IPouts','HA','HRA','BBA','SOA','E','DP','FP','era_1','era_2','era_3','era_4','era_5','era_6','era_7','era_8','decade_1910','decade_1920','decade_1930','decade_1940','decade_1950','decade_1960','decade_1970','decade_1980','decade_1990','decade_2000','decade_2010','R_per_game','RA_per_game','mlb_rpg','labels','W']
data = df[numeric_cols]
print(data.head())

# Split data DataFrame into train and test sets
train = data.sample(frac=0.75, random_state=1)
test = data.loc[~data.index.isin(train.index)]

x_train = train[attributes]
y_train = train['W']
x_test = test[attributes]
y_test = test['W']

Fehlermetrik und Modell auswählen

Als Metrik nutzt du den Mean Absolute Error (MAE), um die Genauigkeit deines Modells zu bewerten. Er misst, wie nah die Vorhersagen an den tatsächlichen Ergebnissen liegen. Konkret bedeutet das hier: Der MAE gibt den durchschnittlichen absoluten Abstand deiner Vorhersage zum wahren Wert in Siegen an.

Wenn deine Vorhersagen im Schnitt um 5 Siege danebenliegen, beträgt der Fehler 5.

Als erstes trainierst du ein lineares Regressionsmodell. Importiere LinearRegression bzw. mean_absolute_error aus sklearn.linear_model und sklearn.metrics, erstelle das Modell lr, fitte es, erzeuge Vorhersagen und bestimme den MAE.

# Import `LinearRegression` from `sklearn.linear_model`
from sklearn.linear_model import ___________________

# Import `mean_absolute_error` from `sklearn.metrics`
from sklearn.metrics import mean_absolute_error

# Create Linear Regression model, fit model, and make predictions
lr = LinearRegression(normalize=True)
lr.fit(x_train, y_train)
predictions = lr.predict(x_test)

# Determine mean absolute error
mae = mean_absolute_error(y_test, predictions)

# Print `mae`
print(___)

Zur Einordnung: Der Durchschnitt lag bei etwa 79 Siegen. Das Modell liegt im Schnitt nur um 2,687 Siege daneben.

Probiere jetzt Ridge-Regression. Importiere RidgeCV aus sklearn.linear_model und erstelle rrm. RidgeCV erlaubt dir, den Alpha-Parameter zu setzen, der die Komplexität steuert (Shrinkage, mehr dazu hier). Das Modell wählt per Cross-Validation den besten Alpha-Wert aus deinen Vorgaben.

Anschließend wieder: fitten, vorhersagen, MAE bestimmen.

# Import `RidgeCV` from `sklearn.linear_model`
from sklearn.linear_model import _______

# Create Ridge Linear Regression model, fit model, and make predictions
rrm = RidgeCV(alphas=(0.01, 0.1, 1.0, 10.0), normalize=True)
rrm.fit(x_train, y_train)
predictions_rrm = rrm.predict(x_test)

# Determine mean absolute error
mae_rrm = mean_absolute_error(y_test, predictions_rrm)
print(________)

Dieses Modell ist minimal besser und liegt im Schnitt um 2,673 Siege daneben.

Sports Analytics & Scikit-Learn

Damit endet der erste Teil dieser Tutorial-Reihe. Du hast gesehen, wie du mit scikit-learn Sportdaten analysieren kannst: Daten aus einer SQLite-Datenbank importieren, bereinigen, visuell untersuchen und neue Features konstruieren. Außerdem hast du ein K-Means-Clustering, zwei Lineare Regressionsmodelle trainiert und deine Prognosen mit dem Mean Absolute Error bewertet.

Im zweiten Teil lernst du, mit Klassifikationsmodellen vorherzusagen, welche Spieler in die MLB Hall of Fame aufgenommen werden.

Themen

Ähnlich

Tutorial

OLS-Regression: Die wichtigsten Ideen erklärt

Tutorial

Loop-Schleifen in Python-Tutorial