前回はデータが少なくt検定が微妙な感じになりましたので、データ数を増やしてみました。
データの確保
コードを改善して、「一般社団法人日本野球機構」の公式サイトに格納されている2005年以降のセ・パ両リーグのデータを取得しました。
# 必要なライブラリを読み込み
from bs4 import BeautifulSoup
import requests
import csv
import pandas as pd
import time
# 指定したURLからデータを取得(セリーグ)
for year1 in range(2021, 2004, -1):
time.sleep(1)
res = requests.get("https://npb.jp/bis/"+str(year1)+"/stats/bat_c.html")
# 取得したデータをsoup変数に代入
soup = BeautifulSoup(res.content,"html.parser")
# 取得したデータから目的の「表」を検索
table = soup.select("#stdivmaintbl")
table = soup.find("table")
# 表中の行を検索
rows = table.find_all("tr")
# 表のヘッダ行を探して、データフレームの列名とする。
if year1 == 2021:
columns = [v.text.replace(" ","") for v in rows[1].find_all("th")]
columns.insert(2,"所属")
df = pd.DataFrame(columns=columns)
# ヘッダ行以外の行からデータを取り出して、データフレームに追加していく。
for i in range(len(rows)-2):
tds = rows[i + 2].find_all("td")
if len(tds) == len(columns):
values = [td.text.replace(" ","") for td in tds]
df = df.append(pd.Series(values, index=columns),ignore_index= True)
# 指定したURLからデータを取得(パリーグ)
for year2 in range(2021, 2004, -1):
time.sleep(1)
res = requests.get("https://npb.jp/bis/"+str(year2)+"/stats/bat_p.html")
# 取得したデータをsoup変数に代入
soup = BeautifulSoup(res.content,"html.parser")
# 取得したデータから目的の「表」を検索
table = soup.select("#stdivmaintbl")
table = soup.find("table")
# 表中の行を検索
rows = table.find_all("tr")
# ヘッダ行以外の行からデータを取り出して、データフレームに追加していく。
for i in range(len(rows)-2):
tds = rows[i + 2].find_all("td")
if len(tds) == len(columns):
values = [td.text.replace(" ","") for td in tds]
df = df.append(pd.Series(values, index=columns),ignore_index= True)
# 作成したデータフレームをcsvファイルとして出力する。
df.to_csv("2005-2021_batter_all.csv",encoding="utf-8")
データ分析
データ数が当初「32個」から「990個」まで増加しました。
[再掲]今回の仮説
「本塁打」を20本以上打った選手と20本未満の選手では、「打率」に差がある。
コードの実装
import pandas as pd
from scipy import stats
# データの読み込み
df = pd.read_csv("2005-2021_batter_all.csv")
# 本塁打が20本以上の選手を抜き出す
df_over20 = df[df["本塁打"] >= 20]
print("本塁打が20本以上の選手は"+str(len(df_over20))+"人")
# 本塁打が20本未満の選手を抜き出す
df_under20 = df[df["本塁打"] < 20]
print("本塁打が20本未満の選手は"+str(len(df_under20))+"人")
# 本塁打が20本以上の選手の平均打率
print("本塁打が20本以上の選手の平均打率は"+str(round(df_over20["打率"].mean(),3)))
# 本塁打が20本未満の選手の平均打率
print("本塁打が20本未満の選手の平均打率は"+str(round(df_under20["打率"].mean(),3)))
# t検定を行う
print(stats.ttest_ind(df_over20["打率"], df_under20["打率"], equal_var= False))
なお、t検定の結果求められるp値の有意水準は一般的な値である5%(0.05)とします。
実行結果・考察
実行結果
本塁打が20本以上の選手は294人
本塁打が20本未満の選手は696人
本塁打が20本以上の選手の平均打率は0.285
本塁打が20本未満の選手の平均打率は0.279
Ttest_indResult(statistic=2.706732834687604, pvalue=0.007025196323910355)
考察
数字上は本塁打が20本以上の選手と20本未満の選手の平均打率の差は6厘に縮まりましたが、pvalue(=p値)が0.05より小さい値になっていますので、この差は「有意な差である」と言えます。
まとめ
データ数を増やすことで前回立てた仮説が正しいことが証明されました。