In Teil I dieses Tutorials stand die Vorhersage der Anzahl der Siege eines MLB-Teams in einer Saison im Fokus – auf Basis von Teamstatistiken und weiteren Variablen aus dieser Saison.
Im zweiten Teil testest du ein logistisches Regressionsmodell und ein Random-Forest-Modell aus Scikit-Learn (sklearn), um vorherzusagen, welche Spieler in die Hall of Fame gewählt werden – basierend auf Karrierestatistiken und Auszeichnungen. Jede Zeile steht für eine Spielerkarriere. Im Baseball gibt es vier Hauptpositionsgruppen: Infield, Outfield, Pitcher und Catcher. Wir konzentrieren uns hier auf Infielders und Outfielders.
Die National Baseball Hall of Fame and Museum befindet sich in Cooperstown, New York, und wurde 1939 eröffnet. Ein Spieler kann unter folgenden Bedingungen gewählt werden:
Mindestens zehn Saisons gespielt;
Seit mindestens fünf Saisons im Ruhestand;
Eine Screening-Kommission muss die Aufnahme auf den Wahlzettel befürworten; regelmäßige Spieler mit zehn oder mehr Jahren gelten in der Regel als würdig;
Nicht auf der Liste der Unzulässigen stehen (also kein lebenslanges Baseball-Verbot);
Gewählt ist, wer mindestens 75% der Stimmen erhält; und
Bei mindestens 5% der Stimmen bleibt ein Spieler im nächsten Jahr auf dem Wahlzettel – maximal zehn Jahre lang.
Spieler, die nicht gewählt werden, können später durch das Veterans Committee oder ein Sonderkomitee aufgenommen werden. In diesem Projekt betrachten wir jedoch nur Spieler, die durch die Wahl aufgenommen wurden. Im Kern willst du wissen:
„Kannst du ein Machine-Learning-Modell bauen, das zuverlässig vorhersagt, ob ein MLB-Spieler in die Hall of Fame gewählt wird?“
Im ersten Teil hast du Daten aus einer SQLite-Datenbank geladen. Diesmal lädst du sie aus CSV-Dateien. Sean Lahman hat die Daten auf seiner Website zusammengetragen.
Datenimport
Lies die Daten aus folgenden CSV-Dateien in pandas-DataFrames:
Master.csv mit Spielernamen, Geburtsdatum (DOB) und Bio-Daten;
Fielding.csv mit Fielding-Statistiken und
Batting.csv mit Batting-Statistiken;
AwardsPlayers.csv mit den Preisen der Spieler;
AllstarFull.csv mit allen All-Star-Einsätzen;
Wahldaten zur Hall of Fame in HallOfFame.csv; und
Appearances.csv mit Positions-Einsätzen der Spieler.
Keine Sorge, wenn noch nicht alles klar ist – die Details folgen Schritt für Schritt!
Lade zuerst die CSV-Dateien, indem du hier klickst. Lege sie idealerweise in einem Projektordner ab. Öffne dann dein Terminal oder starte Jupyter Notebook – und los geht’s!
Lade pandas als pd und lies die CSV-Dateien ein. Du wählst nur bestimmte Spalten – die verfügbaren Spalten findest du hier.
# Import data to DataFramesimport pandas as pd# Read in the CSV filesmaster_df = pd.read_csv('Master.csv',usecols=['playerID','nameFirst','nameLast','bats','throws','debut','finalGame'])fielding_df = pd.read_csv('Fielding.csv',usecols=['playerID','yearID','stint','teamID','lgID','POS','G','GS','InnOuts','PO','A','E','DP'])batting_df = pd.read_csv('Batting.csv')awards_df = pd.read_csv('AwardsPlayers.csv', usecols=['playerID','awardID','yearID'])allstar_df = pd.read_csv('AllstarFull.csv', usecols=['playerID','yearID'])hof_df = pd.read_csv('HallOfFame.csv',usecols=['playerID','yearid','votedBy','needed_note','inducted','category'])appearances_df = pd.read_csv('Appearances.csv')Bereitgestellt von
Hinweis: Für dieses Tutorial werden die Daten für dich geladen!
Datenbereinigung und -vorbereitung
Jetzt kannst du bereinigen und vorverarbeiten. Da du mit sieben CSV-Dateien arbeitest, gehst du sie nacheinander durch: batting_df, fielding_df, awards_df, allstar_df, hof_df, appearances_df und master_df.
batting_df
Starte mit batting_df. Gib mit head() die ersten Zeilen aus:
# Print first few rows of `batting_df`
batting_df.______
Tipp: Da du alle Spalten eingelesen hast, nutze das Attribut columns, um dir die Spalten von batting_df anzeigen zu lassen. Nutze gern weitere Pandas-Funktionen, um die Daten gründlich zu inspizieren!
Beim Inspizieren fallen drei Dinge auf:
Viele IDs. Das ist normal: Die Daten stammen aus einer relationalen Datenbank, Tabellen sind daher über Schlüssel verknüpft.
playerID für den Spieler-Identifikator
yearID für das Jahr
teamID für das Team
lgID für die Liga
Viele Spielstatistiken – zum Beispiel:
G Anzahl Spiele,
AB At Bats (Schlagversuche),
R Runs,
H Hits,
HR Home Runs,
RBI Runs Batted In,
SO Strikeouts.
Die Daten sind noch nicht „tidy“. Wenn dir „Tidy Data“ nichts sagt, lies die Erläuterung hier. Kurz: Jede Zeile sollte eine Beobachtung sein (hier: eine Spielerkarriere), jede Spalte eine Variable. Aktuell beziehen sich viele Zeilen auf einzelne Saisons, die zu einer Karrierezeile aggregiert werden müssen.
Dazu erstellst du verschachtelte Dictionaries pro Spieler. Die Stats jedes Spielers werden aggregiert und später in ein DataFrame konvertiert.
Erzeuge zunächst ein Dictionary für Spielerstatistiken und eines für gespielte Jahre. Aggregiere die Statistiken aus batting_df in player_stats und die Jahre in years_played:
Iteriere nun durch years_played und füge die Anzahl gespielter Jahre je Spieler in player_stats hinzu:
# Iterate through `years_played` and add the number of years played to `player_stats`for k, v in years_played.items(): player_stats[k]['Years_Played'] = len(list(set(v)))Bereitgestellt von
fielding_df
Als Nächstes kommt fielding_df. Diese Tabelle enthält weitere Spielerstatistiken und ähnelt batting_df. Da du bereits in player_stats aggregierst, fügst du auch die Fielding-Stats hinzu.
Füge dafür beim Iterieren über fielding_df neue Schlüssel in den Spieler-Dictionaries von player_stats hinzu. Lege zuerst eine fielder_list an, um zu markieren, für welche Spieler Fielding-Schlüssel schon angelegt wurden:
# Initialize `fielder_list`fielder_list = []# Add fielding stats to `player_stats` from `fielding_df`for i, row in fielding_df.iterrows(): playerID = row['playerID'] Gf = row['G'] GSf = row['GS'] POf = row['PO'] Af = row['A'] Ef = row['E'] DPf = row['DP'] if playerID in player_stats and playerID in fielder_list: player_stats[playerID]['Gf'] = player_stats[playerID]['Gf'] + Gf player_stats[playerID]['GSf'] = player_stats[playerID]['GSf'] + GSf player_stats[playerID]['POf'] = player_stats[playerID]['POf'] + POf player_stats[playerID]['Af'] = player_stats[playerID]['Af'] + Af player_stats[playerID]['Ef'] = player_stats[playerID]['Ef'] + Ef player_stats[playerID]['DPf'] = player_stats[playerID]['DPf'] + DPf else: fielder_list.append(playerID) player_stats[playerID]['Gf'] = Gf player_stats[playerID]['GSf'] = GSf player_stats[playerID]['POf'] = POf player_stats[playerID]['Af'] = Af player_stats[playerID]['Ef'] = Ef player_stats[playerID]['DPf'] = DPfBereitgestellt von
awards_df
awards_df enthält die Auszeichnungen, die Spieler im Laufe ihrer Karriere erhalten.
Ein guter Einstieg ist, die einzigartigen Auszeichnungen mit unique() anzuzeigen. Oder nutze head(), tail(), info() usw., um die Daten kennenzulernen.
Tipp: Du hast nur die drei Spalten playerID, awardID und yearID eingelesen.
# Print out unique awards from `awards_df`
print(awards_df['awardID'].________)
Wie du siehst, gibt es einige Awards … Kennst du alle?
Wie in Teil I erwähnt, ist Domänenwissen enorm hilfreich. Beispielsweise sind Most Valuable Player, Rookie of the Year, Gold Glove, Silver Slugger und World Series MVP besonders relevant – basierend auf Erfahrung mit MLB.
Man könnte natürlich auch statistisch bestimmen, welche Auszeichnungen am stärksten mit der HoF-Wahl korrelieren – das würde aber deutlich mehr Code erfordern.
Füge nun für jede dieser Auszeichnungen eine Zählung in den Spieler-Dictionaries von player_stats hinzu: Filtere awards_df für jeden Award (fünf Serien), packe sie in awards_list, führe Listen, um hinzugefügte Schlüssel je Award zu tracken, und iteriere dann, um die Zähler zu erhöhen:
# Create DataFrames for each awardmvp = awards_df[awards_df['awardID'] == 'Most Valuable Player']roy = awards_df[awards_df['awardID'] == 'Rookie of the Year']gg = awards_df[awards_df['awardID'] == 'Gold Glove']ss = awards_df[awards_df['awardID'] == 'Silver Slugger']ws_mvp = awards_df[awards_df['awardID'] == 'World Series MVP']# Include each DataFrame in `awards_list`awards_list = [mvp,roy,gg,ss,ws_mvp]# Initialize lists for each of the above DataFramesmvp_list = []roy_list = []gg_list = []ss_list = []ws_mvp_list = []# Include each of the above lists in `lists`lists = [mvp_list,roy_list,gg_list,ss_list,ws_mvp_list]# Add a count for each award for each player in `player_stats`for index, v in enumerate(awards_list): for i, row in v.iterrows(): playerID = row['playerID'] award = row['awardID'] if playerID in player_stats and playerID in lists[index]: player_stats[playerID][award] += 1 else: lists[index].append(playerID) player_stats[playerID][award] = 1Bereitgestellt von
allstar_df
allstar_df enthält, welche Spieler im All-Star-Game aufgetreten sind. Das All-Star-Game ist ein jährliches Showmatch zur Saisonmitte. MLB besteht aus American League und National League. Jeweils die Top 25 vertreten ihre Liga.
Iteriere wie zuvor über allstar_df und zähle All-Star-Einsätze pro Spieler in player_stats.
# Initialize `allstar_list`allstar_list = []# Add a count for each Allstar game appearance for each player in `player_stats`for i, row in allstar_df.iterrows(): playerID = row['playerID'] if playerID in player_stats and playerID in allstar_list: player_stats[playerID]['AS_games'] += 1 else: allstar_list.append(playerID) player_stats[playerID]['AS_games'] = 1Bereitgestellt von
hof_df
hof_df enthält, welche Spieler, Manager und Executives nominiert oder aufgenommen wurden – und auf welchem Weg.
Diese Info ist wertvoll für player_stats: Filtere hof_df auf aufgenommene Spieler, iteriere und markiere in player_stats, wer aufgenommen wurde samt votedBy:
# filter `hof_df` to include only instances where a player was inducted into the Hall of Famehof_df = hof_df[(hof_df['inducted'] == 'Y') & (hof_df['category'] == 'Player')]# Indicate which players in `player_stats` were inducted into the Hall of Famefor i, row in hof_df.iterrows(): playerID = row['playerID'] if playerID in player_stats: player_stats[playerID]['HoF'] = 1 player_stats[playerID]['votedBy'] = row['votedBy']Bereitgestellt von
player_stats
Du hast nun Daten aus batting_df, fielding_df, awards_df, allstar_df und hof_df in player_stats gesammelt. Bevor du appearances_df nutzt, wandelst du player_stats in ein DataFrame um.
Nutze pandasfrom_dict(), um stats_df zu erzeugen:
# Convert `player_stats` into a DataFramestats_df = pd.DataFrame.from_dict(player_stats, orient='index')Bereitgestellt von
stats_df nutzt die Player-IDs als Index. Füge eine Spalte playerID aus dem Index hinzu und führe dann einen Inner Join mit master_df aus.
Merke: Ein Inner Join behält nur Zeilen, die in beiden Tabellen vorkommen – genau das wollen wir hier.
# Add a column for playerID from the `stats_df` index
stats_df['playerID'] = stats_df._____
# Join `stats_df` and `master_df`
master_df = master_df.join(________,on='playerID',how='inner', rsuffix='mstr')
# Inspect first rows of `master_df`
master_df.______
appearances_df
Das letzte DataFrame vor dem Feature Engineering ist appearances_df. Es enthält, wie oft ein Spieler pro Jahr auf welcher Position eingesetzt wurde.
Gib die ersten Zeilen mit head() aus:
print(appearances_df.______)
Tipp: Nutze im IPython-Console weitere Funktionen wie info(), tail() oder die Attribute columns und index. appearances_df hat 21 Spalten – einige sind selbsterklärend (IDs), andere kryptischer wie G_3b, G_dh usw.
Es steckt also viel Information in appearances_df, die aggregiert werden muss – sowohl Einsätze je Position als auch je Ära der MLB.
Wie im ersten Teil beschrieben, gab es Epochen mit deutlich mehr oder weniger Runs pro Spiel. Das beeinflusst Karrierestatistiken – und HoF-Wählende berücksichtigen das. Dein Modell sollte diese Info ebenfalls enthalten.
Erstelle ein Dictionary pos_dict. Iteriere über appearances_df, lege pro Spieler ein Dictionary an und aggregiere Einsätze je Position sowie Spiele je Ära (als Schlüssel).
# Initialize a dictionarypos_dict = {}# Iterate through `appearances_df`# Add a count for the number of appearances for each player at each position# Also add a count for the number of games played for each player in each era.for i, row in appearances_df.iterrows(): ID = row['playerID'] year = row['yearID'] if ID in pos_dict: pos_dict[ID]['G_all'] = pos_dict[ID]['G_all'] + row['G_all'] pos_dict[ID]['G_p'] = pos_dict[ID]['G_p'] + row['G_p'] pos_dict[ID]['G_c'] = pos_dict[ID]['G_c'] + row['G_c'] pos_dict[ID]['G_1b'] = pos_dict[ID]['G_1b'] + row['G_1b'] pos_dict[ID]['G_2b'] = pos_dict[ID]['G_2b'] + row['G_2b'] pos_dict[ID]['G_3b'] = pos_dict[ID]['G_3b'] + row['G_3b'] pos_dict[ID]['G_ss'] = pos_dict[ID]['G_ss'] + row['G_ss'] pos_dict[ID]['G_lf'] = pos_dict[ID]['G_lf'] + row['G_lf'] pos_dict[ID]['G_cf'] = pos_dict[ID]['G_cf'] + row['G_cf'] pos_dict[ID]['G_rf'] = pos_dict[ID]['G_rf'] + row['G_rf'] pos_dict[ID]['G_of'] = pos_dict[ID]['G_of'] + row['G_of'] pos_dict[ID]['G_dh'] = pos_dict[ID]['G_dh'] + row['G_dh'] if year < 1920: pos_dict[ID]['pre1920'] = pos_dict[ID]['pre1920'] + row['G_all'] elif year >= 1920 and year <= 1941: pos_dict[ID]['1920-41'] = pos_dict[ID]['1920-41'] + row['G_all'] elif year >= 1942 and year <= 1945: pos_dict[ID]['1942-45'] = pos_dict[ID]['1942-45'] + row['G_all'] elif year >= 1946 and year <= 1962: pos_dict[ID]['1946-62'] = pos_dict[ID]['1946-62'] + row['G_all'] elif year >= 1963 and year <= 1976: pos_dict[ID]['1963-76'] = pos_dict[ID]['1963-76'] + row['G_all'] elif year >= 1977 and year <= 1992: pos_dict[ID]['1977-92'] = pos_dict[ID]['1977-92'] + row['G_all'] elif year >= 1993 and year <= 2009: pos_dict[ID]['1993-2009'] = pos_dict[ID]['1993-2009'] + row['G_all'] elif year > 2009: pos_dict[ID]['post2009'] = pos_dict[ID]['post2009'] + row['G_all'] else: pos_dict[ID] = {} pos_dict[ID]['G_all'] = row['G_all'] pos_dict[ID]['G_p'] = row['G_p'] pos_dict[ID]['G_c'] = row['G_c'] pos_dict[ID]['G_1b'] = row['G_1b'] pos_dict[ID]['G_2b'] = row['G_2b'] pos_dict[ID]['G_3b'] = row['G_3b'] pos_dict[ID]['G_ss'] = row['G_ss'] pos_dict[ID]['G_lf'] = row['G_lf'] pos_dict[ID]['G_cf'] = row['G_cf'] pos_dict[ID]['G_rf'] = row['G_rf'] pos_dict[ID]['G_of'] = row['G_of'] pos_dict[ID]['G_dh'] = row['G_dh'] pos_dict[ID]['pre1920'] = 0 pos_dict[ID]['1920-41'] = 0 pos_dict[ID]['1942-45'] = 0 pos_dict[ID]['1946-62'] = 0 pos_dict[ID]['1963-76'] = 0 pos_dict[ID]['1977-92'] = 0 pos_dict[ID]['1993-2009'] = 0 pos_dict[ID]['post2009'] = 0 if year < 1920: pos_dict[ID]['pre1920'] = row['G_all'] elif year >= 1920 and year <= 1941: pos_dict[ID]['1920-41'] = row['G_all'] elif year >= 1942 and year <= 1945: pos_dict[ID]['1942-45'] = row['G_all'] elif year >= 1946 and year <= 1962: pos_dict[ID]['1946-62'] = row['G_all'] elif year >= 1963 and year <= 1976: pos_dict[ID]['1963-76'] = row['G_all'] elif year >= 1977 and year <= 1992: pos_dict[ID]['1977-92'] = row['G_all'] elif year >= 1993 and year <= 2009: pos_dict[ID]['1993-2009'] = row['G_all'] elif year > 2009: pos_dict[ID]['post2009'] = row['G_all']Bereitgestellt von
Wandle pos_dict nun per from_dict() in pos_df um:
# Convert the `pos_dict` to a DataFramepos_df = pd.DataFrame.from_dict(pos_dict, orient='index')Bereitgestellt von
Gib die Spalten aus und inspiziere weiter:
# Print the columns
print(pos_df._______)
# Print the first rows
print(pos_df.______)
Bestimme nun den Prozentanteil der Einsätze je Position und je Ära.
Erstelle eine Liste pos_col_list aus den Spalten von pos_df und entferne den String „G_all“. Lege dann für jede Position/Ära eine Prozentspalte an, indem du durch pos_col_list iterierst und durch die Gesamtspiele teilst. Gib abschließend die ersten Zeilen aus:
# Create a list from the columns of `pos_df`
pos_col_list = pos_df.columns.________
# Remove the string 'G_all'
pos_col_list.remove('G_all')
# Loop through the list and divide each column by the players total games played
for col in pos_col_list:
column = col + '_percent'
pos_df[column] = pos_df[col] / pos_df['G_all']
# Print out the first rows of `pos_df`
print(pos_df._______)
Dieses Projekt fokussiert Infielders und Outfielders, da Positionen unterschiedlich bewertet werden. Pitcher und Catcher werden primär nach Defense-Stats beurteilt – das würde hier den Rahmen sprengen.
Da früher viele Spieler mehrere Positionen spielten, filtere Pitcher und Catcher heraus, indem du Spieler entfernst, die mehr als 10% ihrer Spiele auf diesen Positionen absolviert haben.
# Filter `pos_df` to eliminate players who played 10% or more of their games as Pitchers or Catchers
pos_df = pos_df[(______['G_p_percent'] < 0.1) & (pos_df['G_c_percent'] < 0.1)]
# Get info on `pos_df`
pos_df.______
master_df
Du hast zuvor einen Inner Join zwischen master_df und stats_df durchgeführt, um Spielerstammdaten (Namen, Geburtstag, Biografie) mit aggregierten Statistiken zusammenzuführen.
Jetzt willst du das vereinheitlichte master_df mit pos_df verbinden. Achtung: Nutze einen Right Join, denn du willst nur Spieler behalten, die in pos_df enthalten sind:
# Join `pos_df` and `master_df`
master_df = master_df.join(pos_df,on='playerID',how='right')
# Print out the first rows of `master_df`
print(master_df.______)
Filtere master_df nun auf Spieler, die in die Hall of Fame gewählt wurden oder gar nicht gewählt wurden.
Spieler, die über das Veterans Committee oder ein Sonderkomitee aufgenommen wurden, lassen wir weg – dort zählen oft andere Gründe als reine Statistiken.
Die Spalten bats und throws müssen in numerische Werte umgewandelt werden: Ersetze R durch 1 und L durch 0. Nutze apply(), um bats_R und throws_R zu erstellen:
Die Spalten debut und finalGame sind Strings. Du brauchst die Jahre: Importiere datetime, konvertiere die Spalten mit pd.to_datetime(), extrahiere die Jahre mit dt.strftime('%Y') und wandle sie mit pd.to_numeric() um.
# Import datetime
from datetime import datetime
# Convert the `debut` column to datetime
master_df['debut'] = pd.___________(master_df['debut'])
# Convert the `finalGame` column to datetime
master_df['finalGame'] = pd.to_datetime(master_df['finalGame'])
# Create new columns for debutYear and finalYear
master_df['debutYear'] = pd.to_numeric(master_df['debut'].dt.strftime('%Y'), errors='coerce')
master_df['finalYear'] = _____________(master_df['finalGame'].dt.strftime('%Y'), errors='coerce')
# Return the first rows of `master_df`
print(master_df.head())
In master_df gibt es unnötige Spalten. Nutze drop() und erstelle ein neues DataFrame df. Gib die Spalten aus und zeige die Anzahl fehlender Werte je Spalte.
In Teil I dieses Tutorials stand die Vorhersage der Anzahl der Siege eines MLB-Teams in einer Saison im Fokus – auf Basis von Teamstatistiken und weiteren Variablen aus dieser Saison.
Im zweiten Teil testest du ein logistisches Regressionsmodell und ein Random-Forest-Modell aus Scikit-Learn (
sklearn), um vorherzusagen, welche Spieler in die Hall of Fame gewählt werden – basierend auf Karrierestatistiken und Auszeichnungen. Jede Zeile steht für eine Spielerkarriere. Im Baseball gibt es vier Hauptpositionsgruppen: Infield, Outfield, Pitcher und Catcher. Wir konzentrieren uns hier auf Infielders und Outfielders.Die National Baseball Hall of Fame and Museum befindet sich in Cooperstown, New York, und wurde 1939 eröffnet. Ein Spieler kann unter folgenden Bedingungen gewählt werden:
Spieler, die nicht gewählt werden, können später durch das Veterans Committee oder ein Sonderkomitee aufgenommen werden. In diesem Projekt betrachten wir jedoch nur Spieler, die durch die Wahl aufgenommen wurden. Im Kern willst du wissen:
„Kannst du ein Machine-Learning-Modell bauen, das zuverlässig vorhersagt, ob ein MLB-Spieler in die Hall of Fame gewählt wird?“
Im ersten Teil hast du Daten aus einer SQLite-Datenbank geladen. Diesmal lädst du sie aus CSV-Dateien. Sean Lahman hat die Daten auf seiner Website zusammengetragen.
Datenimport
Lies die Daten aus folgenden CSV-Dateien in
pandas-DataFrames:Master.csvmit Spielernamen, Geburtsdatum (DOB) und Bio-Daten;Fielding.csvmit Fielding-Statistiken undBatting.csvmit Batting-Statistiken;AwardsPlayers.csvmit den Preisen der Spieler;AllstarFull.csvmit allen All-Star-Einsätzen;HallOfFame.csv; undAppearances.csvmit Positions-Einsätzen der Spieler.Keine Sorge, wenn noch nicht alles klar ist – die Details folgen Schritt für Schritt!
Lade zuerst die CSV-Dateien, indem du hier klickst. Lege sie idealerweise in einem Projektordner ab. Öffne dann dein Terminal oder starte Jupyter Notebook – und los geht’s!
Lade
pandasalspdund lies die CSV-Dateien ein. Du wählst nur bestimmte Spalten – die verfügbaren Spalten findest du hier.Hinweis: Für dieses Tutorial werden die Daten für dich geladen!
Datenbereinigung und -vorbereitung
Jetzt kannst du bereinigen und vorverarbeiten. Da du mit sieben CSV-Dateien arbeitest, gehst du sie nacheinander durch:
batting_df,fielding_df,awards_df,allstar_df,hof_df,appearances_dfundmaster_df.batting_dfStarte mit
batting_df. Gib mithead()die ersten Zeilen aus:Tipp: Da du alle Spalten eingelesen hast, nutze das Attribut
columns, um dir die Spalten vonbatting_dfanzeigen zu lassen. Nutze gern weitere Pandas-Funktionen, um die Daten gründlich zu inspizieren!Beim Inspizieren fallen drei Dinge auf:
playerIDfür den Spieler-IdentifikatoryearIDfür das JahrteamIDfür das TeamlgIDfür die LigaGAnzahl Spiele,ABAt Bats (Schlagversuche),RRuns,HHits,HRHome Runs,RBIRuns Batted In,SOStrikeouts.Dazu erstellst du verschachtelte Dictionaries pro Spieler. Die Stats jedes Spielers werden aggregiert und später in ein DataFrame konvertiert.
Erzeuge zunächst ein Dictionary für Spielerstatistiken und eines für gespielte Jahre. Aggregiere die Statistiken aus
batting_dfinplayer_statsund die Jahre inyears_played:Iteriere nun durch
years_playedund füge die Anzahl gespielter Jahre je Spieler inplayer_statshinzu:fielding_dfAls Nächstes kommt
fielding_df. Diese Tabelle enthält weitere Spielerstatistiken und ähneltbatting_df. Da du bereits inplayer_statsaggregierst, fügst du auch die Fielding-Stats hinzu.Füge dafür beim Iterieren über
fielding_dfneue Schlüssel in den Spieler-Dictionaries vonplayer_statshinzu. Lege zuerst einefielder_listan, um zu markieren, für welche Spieler Fielding-Schlüssel schon angelegt wurden:awards_dfawards_dfenthält die Auszeichnungen, die Spieler im Laufe ihrer Karriere erhalten.Ein guter Einstieg ist, die einzigartigen Auszeichnungen mit
unique()anzuzeigen. Oder nutzehead(),tail(),info()usw., um die Daten kennenzulernen.Tipp: Du hast nur die drei Spalten
playerID,awardIDundyearIDeingelesen.Wie du siehst, gibt es einige Awards … Kennst du alle?
Wie in Teil I erwähnt, ist Domänenwissen enorm hilfreich. Beispielsweise sind Most Valuable Player, Rookie of the Year, Gold Glove, Silver Slugger und World Series MVP besonders relevant – basierend auf Erfahrung mit MLB.
Man könnte natürlich auch statistisch bestimmen, welche Auszeichnungen am stärksten mit der HoF-Wahl korrelieren – das würde aber deutlich mehr Code erfordern.
Füge nun für jede dieser Auszeichnungen eine Zählung in den Spieler-Dictionaries von
player_statshinzu: Filtereawards_dffür jeden Award (fünf Serien), packe sie inawards_list, führe Listen, um hinzugefügte Schlüssel je Award zu tracken, und iteriere dann, um die Zähler zu erhöhen:allstar_dfallstar_dfenthält, welche Spieler im All-Star-Game aufgetreten sind. Das All-Star-Game ist ein jährliches Showmatch zur Saisonmitte. MLB besteht aus American League und National League. Jeweils die Top 25 vertreten ihre Liga.Iteriere wie zuvor über
allstar_dfund zähle All-Star-Einsätze pro Spieler inplayer_stats.hof_dfhof_dfenthält, welche Spieler, Manager und Executives nominiert oder aufgenommen wurden – und auf welchem Weg.Diese Info ist wertvoll für
player_stats: Filterehof_dfauf aufgenommene Spieler, iteriere und markiere inplayer_stats, wer aufgenommen wurde samtvotedBy:player_statsDu hast nun Daten aus
batting_df,fielding_df,awards_df,allstar_dfundhof_dfinplayer_statsgesammelt. Bevor duappearances_dfnutzt, wandelst duplayer_statsin ein DataFrame um.Nutze
pandasfrom_dict(), umstats_dfzu erzeugen:stats_dfnutzt die Player-IDs als Index. Füge eine SpalteplayerIDaus dem Index hinzu und führe dann einen Inner Join mitmaster_dfaus.Merke: Ein Inner Join behält nur Zeilen, die in beiden Tabellen vorkommen – genau das wollen wir hier.
appearances_dfDas letzte DataFrame vor dem Feature Engineering ist
appearances_df. Es enthält, wie oft ein Spieler pro Jahr auf welcher Position eingesetzt wurde.Gib die ersten Zeilen mit
head()aus:Tipp: Nutze im IPython-Console weitere Funktionen wie
info(),tail()oder die Attributecolumnsundindex.appearances_dfhat 21 Spalten – einige sind selbsterklärend (IDs), andere kryptischer wieG_3b,G_dhusw.Ein Blick in die README-Seite hilft:
G_allGesamtspieleGSSpiele gestartetG_battingSpiele mit BattingG_defenseSpiele in der DefenseG_pals PitcherG_cals CatcherG_1bals First BasemanG_2bals Second BasemanG_3bals Third BasemanG_ssals ShortstopG_lfals Left FielderG_cfals Center FielderG_rfals Right FielderG_ofals OutfielderG_dhals Designated HitterG_phals Pinch HitterG_prals Pinch RunnerEs steckt also viel Information in
appearances_df, die aggregiert werden muss – sowohl Einsätze je Position als auch je Ära der MLB.Wie im ersten Teil beschrieben, gab es Epochen mit deutlich mehr oder weniger Runs pro Spiel. Das beeinflusst Karrierestatistiken – und HoF-Wählende berücksichtigen das. Dein Modell sollte diese Info ebenfalls enthalten.
Erstelle ein Dictionary
pos_dict. Iteriere überappearances_df, lege pro Spieler ein Dictionary an und aggregiere Einsätze je Position sowie Spiele je Ära (als Schlüssel).Wandle
pos_dictnun perfrom_dict()inpos_dfum:Gib die Spalten aus und inspiziere weiter:
Bestimme nun den Prozentanteil der Einsätze je Position und je Ära.
Erstelle eine Liste
pos_col_listaus den Spalten vonpos_dfund entferne den String „G_all“. Lege dann für jede Position/Ära eine Prozentspalte an, indem du durchpos_col_listiterierst und durch die Gesamtspiele teilst. Gib abschließend die ersten Zeilen aus:Dieses Projekt fokussiert Infielders und Outfielders, da Positionen unterschiedlich bewertet werden. Pitcher und Catcher werden primär nach Defense-Stats beurteilt – das würde hier den Rahmen sprengen.
Da früher viele Spieler mehrere Positionen spielten, filtere Pitcher und Catcher heraus, indem du Spieler entfernst, die mehr als 10% ihrer Spiele auf diesen Positionen absolviert haben.
master_dfDu hast zuvor einen Inner Join zwischen
master_dfundstats_dfdurchgeführt, um Spielerstammdaten (Namen, Geburtstag, Biografie) mit aggregierten Statistiken zusammenzuführen.Jetzt willst du das vereinheitlichte
master_dfmitpos_dfverbinden. Achtung: Nutze einen Right Join, denn du willst nur Spieler behalten, die inpos_dfenthalten sind:Filtere
master_dfnun auf Spieler, die in die Hall of Fame gewählt wurden oder gar nicht gewählt wurden.Spieler, die über das Veterans Committee oder ein Sonderkomitee aufgenommen wurden, lassen wir weg – dort zählen oft andere Gründe als reine Statistiken.
Die Spalten
batsundthrowsmüssen in numerische Werte umgewandelt werden: ErsetzeRdurch 1 undLdurch 0. Nutzeapply(), umbats_Rundthrows_Rzu erstellen:Die Spalten
debutundfinalGamesind Strings. Du brauchst die Jahre: Importieredatetime, konvertiere die Spalten mitpd.to_datetime(), extrahiere die Jahre mitdt.strftime('%Y')und wandle sie mitpd.to_numeric()um.In
master_dfgibt es unnötige Spalten. Nutzedrop()und erstelle ein neues DataFramedf. Gib die Spalten aus und zeige die Anzahl fehlender Werte je Spalte.