Zum Hauptinhalt springen

Scikit-Learn Tutorial: Baseball Analytics Teil 2

A Scikit-Learn tutorial to using logistic regression and random forest models to predict which baseball players will be voted into the Hall of Fame
· 15 Min. lesen

Entdecke KI

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.

baseball

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')

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:

  1. 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
  1. Viele Spielstatistiken – zum Beispiel:
  • G Anzahl Spiele,
  • AB At Bats (Schlagversuche),
  • R Runs,
  • H Hits,
  • HR Home Runs,
  • RBI Runs Batted In,
  • SO Strikeouts.
  1. 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:

# Initialize dictionaries for player stats and years playedplayer_stats = {}years_played = {}# Create dictionaries for player stats and years played from `batting_df`for i, row in batting_df.iterrows():    playerID = row['playerID']    if playerID in player_stats:        player_stats[playerID]['G'] = player_stats[playerID]['G'] + row['G']        player_stats[playerID]['AB'] = player_stats[playerID]['AB'] + row['AB']        player_stats[playerID]['R'] = player_stats[playerID]['R'] + row['R']        player_stats[playerID]['H'] = player_stats[playerID]['H'] + row['H']        player_stats[playerID]['2B'] = player_stats[playerID]['2B'] + row['2B']        player_stats[playerID]['3B'] = player_stats[playerID]['3B'] + row['3B']        player_stats[playerID]['HR'] = player_stats[playerID]['HR'] + row['HR']        player_stats[playerID]['RBI'] = player_stats[playerID]['RBI'] + row['RBI']        player_stats[playerID]['SB'] = player_stats[playerID]['SB'] + row['SB']        player_stats[playerID]['BB'] = player_stats[playerID]['BB'] + row['BB']        player_stats[playerID]['SO'] = player_stats[playerID]['SO'] + row['SO']        player_stats[playerID]['IBB'] = player_stats[playerID]['IBB'] + row['IBB']        player_stats[playerID]['HBP'] = player_stats[playerID]['HBP'] + row['HBP']        player_stats[playerID]['SH'] = player_stats[playerID]['SH'] + row['SH']        player_stats[playerID]['SF'] = player_stats[playerID]['SF'] + row['SF']        years_played[playerID].append(row['yearID'])    else:        player_stats[playerID] = {}        player_stats[playerID]['G'] = row['G']        player_stats[playerID]['AB'] = row['AB']        player_stats[playerID]['R'] = row['R']        player_stats[playerID]['H'] = row['H']        player_stats[playerID]['2B'] = row['2B']        player_stats[playerID]['3B'] = row['3B']        player_stats[playerID]['HR'] = row['HR']        player_stats[playerID]['RBI'] = row['RBI']        player_stats[playerID]['SB'] = row['SB']        player_stats[playerID]['BB'] = row['BB']        player_stats[playerID]['SO'] = row['SO']        player_stats[playerID]['IBB'] = row['IBB']        player_stats[playerID]['HBP'] = row['HBP']        player_stats[playerID]['SH'] = row['SH']        player_stats[playerID]['SF'] = row['SF']        years_played[playerID] = []        years_played[playerID].append(row['yearID'])

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)))

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'] = DPf

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] = 1

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'] = 1

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']

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 pandas from_dict(), um stats_df zu erzeugen:

# Convert `player_stats` into a DataFramestats_df = pd.DataFrame.from_dict(player_stats, orient='index')

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.

Ein Blick in die README-Seite hilft:

  • G_all Gesamtspiele
  • GS Spiele gestartet
  • G_batting Spiele mit Batting
  • G_defense Spiele in der Defense
  • G_p als Pitcher
  • G_c als Catcher
  • G_1b als First Baseman
  • G_2b als Second Baseman
  • G_3b als Third Baseman
  • G_ss als Shortstop
  • G_lf als Left Fielder
  • G_cf als Center Fielder
  • G_rf als Right Fielder
  • G_of als Outfielder
  • G_dh als Designated Hitter
  • G_ph als Pinch Hitter
  • G_pr als Pinch Runner

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']

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')

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.

Themen