從零開始學習分析棒球之路 (2): Pandas DataFrame 基礎操作與查詢

處理數據的流程中我們會需要選取特定範圍或依照篩選條件取得對應資料,以下介紹一些資料選取及篩選的方法。

本文流程:


1. 查看資料:

本次使用的 CSV 資料,為各隊球員的打擊紀錄及防守紀錄:

Player,Team,Games_Played,Home_Runs,Batting_Average,Position,Chances,Errors,Double_Plays
Mike Trout,Los Angeles Angels,135.0,39.0,0.303,CF,342,2,0
Mookie Betts,Los Angeles Dodgers,145.0,0.0,0.290,RF,368,1,0
Aaron Judge,New York Yankees,120.0,31.0,0.285,RF,311,3,0
Freddie Freeman,Atlanta Braves,150.0,38.0,0.305,1B,1336,8,148
Nolan Arenado,St. Louis Cardinals,125.0,32.0,0.275,3B,370,4,78
Christian Yelich,Milwaukee Brewers,125.0,0.0,0.290,LF,286,2,0
Juan Soto,Washington Nationals,130.0,35.0,0.295,LF,310,6,0
Cody Bellinger,Los Angeles Dodgers,140.0,40.0,0.310,1B,320,7,150
Trea Turner,Washington Nationals,130.0,20.0,0.280,SS,300,5,100
Ronald Acuna Jr.,Atlanta Braves,140.0,37.0,0.300,CF,330,9,120
Anthony Rendon,Los Angeles Angels,130.0,32.0,0.290,3B,280,6,80
Gleyber Torres,New York Yankees,125.0,25.0,0.275,2B,275,8,90
Xander Bogaerts,Boston Red Sox,140.0,28.0,0.280,SS,290,7,110
Bryce Harper,Philadelphia Phillies,135.0,34.0,0.295,RF,295,5,100
Javier Baez,Chicago Cubs,125.0,27.0,0.285,SS,310,6,90
Eloy Jimenez,Chicago White Sox,130.0,33.0,0.290,LF,280,4,0
Kris Bryant,San Francisco Giants,135.0,30.0,0.280,3B,300,5,120
Paul Goldschmidt,St. Louis Cardinals,140.0,36.0,0.295,1B,330,6,140
Jose Altuve,Houston Astros,125.0,22.0,0.275,2B,290,7,80
Marcus Semien,Toronto Blue Jays,135.0,29.0,0.285,SS,295,8,100

上面資料中可分為共通欄位, 進攻數據欄位, 防守數據欄位

共通欄位 (不屬於進攻或防守的資料):

  • Player: 球員的名字。
  • Team: 球員所屬的球隊。

進攻/打擊數據欄位:

  • Games_Played: 球員參加的比賽場次。
  • Home_Runs: 球員擊出的全壘打數量。
  • Batting_Average: 球員的平均打擊率。

防守數據欄位:

  • Position: 球員在球場上的位置,例如投手(P)、捕手(C)、游擊手(SS)、外野手(OF)等。
  • Chances: 球員在防守中面臨的機會數,包括接球、扔球等。
  • Errors: 球員在防守中犯的錯誤次數。
  • Double_Plays: 球員在防守中完成的雙殺次數,即在一次守備中完成兩次出局。

讀取所有資料並顯示:

import pandas as pd

player_all_df = pd.read_csv("player_stats.csv")
player_all_df

2. 選取特定欄位:

我們可以透過 loc() 及 iloc() 選取特定欄位。

通過 loc() 選取部分資料,loc() 的使用方法為 loc[row_labels, col_labels] (冒號 “:” 代表全選的意思):

# player_all_df.loc[row_labels, col_labels]
player_defence_df = player_all_df.loc[:, ["Player", "Team", "Position", "Chances", "Errors", "Double_Plays"]]

# to_csv() is used to export the data as csv
player_defence_df.to_csv("player_defence.csv")
player_defence_df

通過 iloc() 選取部分資料,iloc() 的使用方法為df.iloc[row_index, column_index] (0:5 的意思為 column index 0~4,不包含 column index 5):

player_offense_df = player_all_df.iloc[:, 0:5]
player_offense_df

3. 條件式篩選資料:

有時候我們想透過條件的方式查詢符合條件的資料,例如我們可以透過條件的方式找出失誤超過 5 次的球員:

# 條件式篩選的語法為 df[條件]
filtered_df = player_defence_df[player_defence_df["Errors"]>5]
filtered_df

如果讀者很好奇條件代表的意思,我們可以顯示條件運算的結果。

條件運算的結果會回傳每個 row 是否符合條件:

# 以 player_defence_df["Errors"]>5 為例,會選出 Errors 欄位 > 5 的位置
filtered_condition = player_defence_df["Errors"]>5
filtered_condition

我們也可以給定多個條件進行篩選,例如我們想找出出賽場數少但全壘打多的選手。

我們篩選出賽場數不足 130 場,全壘打大於等於 30 支的選手。

filtered_df = player_offense_df[(player_offense_df['Games_Played'] < 130) & (player_offense_df['Home_Runs'] >= 30)]
filtered_df  

4. 新增欄位:

有時候我們會需要計算並將結果儲存於新的欄位中。

例如我們想計算每個球員的失誤率,其中失誤率 (Error_rate) 的定義為失誤數(Errors) 除以防守機會 (Chances):

player_defence_df["Error_rate"] = player_defence_df["Errors"]/ player_defence_df["Chances"]
player_defence_df

這時候讀者們會發現 Error_rate 小數太多造成閱讀不易,我們可以重新定義一個欄位為每 100 場的失誤率為 Error_rate_100。

player_defence_df["Error_rate_100"] = player_defence_df["Error_rate"] * 100

# 刪除 col
player_defence_df.drop(["Error_rate"], axis=1, inplace=True)

player_defence_df

這樣我們比較容易觀察出每 100 次防守中,發生超出兩次以上失誤的人:

filtered_df = player_defence_df[player_defence_df["Error_rate_100"]>2]
filtered_df

但這樣的文字其實還是很難分析,未來我們會用可視化的方式將資料轉換成圖表讓大家分析時可以更容易看出資料涵蓋的意義

留言

熱門文章