0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

NPBのボールは「飛ばない時代」に突入したのか?Pythonでデータ分析してみた

Posted at

目次

はじめに

こんにちは、こんばんは。
皆さん野球見てますか?日本プロ野球は大詰めを迎えています。贔屓チームの順位が決まっているチームもあれば、まだまだ優勝争いやCS争いをしているチームもあるでしょう。

本題です。最近野球見ていたり、SNSを見ているとよく思うことがあります。ボール飛ばない気がするです。なのでpythonを使って調べてみました。

調査の設計

まず、「飛ばなくなっている」をどう定義するかを決めます。
候補は以下の通りです。

候補 要素 データ収取のしやすさ 詳細
No1 本塁打数(1試合平均のHR数の推移) NPB公式サイトの「年度別成績」やWikipediaの「年度別本塁打数一覧」から入手可能
No2 OPSや長打率の推移 チーム・個人年度別成績はNPB公式や各種野球データサイトにある。OPSは「出塁率+長打率」なので自分で計算することも可能。
No3 打球速度・飛距離データ NPBでは公式に公開されていない。パ・リーグTVや一部の解析記事に断片的に出る程度。
No4 フライボール割合、HR/FB比率 × NPB公式は打球結果の詳細(ゴロ/フライ/ライナー)を公開していない。

「年度ごとの1試合平均HR数」と「OPS/SLG推移」を軸にすれば、Pythonで分析しやすく、信頼できるデータを集めやすいと考えました。

用語解説
OPSとは出塁率長打率を足し合わせた打撃指標です。
SLGとは長打率の略称で打者で1打数あたりに獲得する平均塁打数を表す指標です。

データ収集

次にデータ収集を行う。以下の項目データ収集を行った。

項目 詳細
球団 NPB球団12球団を対象(Giants,Tigers,BayStars,Carp,Swallows,Dragons,Hawks,Fighters,Marines,Buffaloes,Eagles,Lions)
年度 2024年度~2020年度
本塁打数 各12球団の年間シーズン打撃成績を参考に
試合数 2024~2021年度は143試合、2020年度は新型コロナウィルスの影響で短縮シーズン(120試合)
長打率 野球で打者の「1打数あたりの平均塁打数」を示す指標
出塁率 打者が打数、四球、死球、犠飛の合計数に対し、安打、四球、死球で出塁する割合を示す野球の指標

セントラル・リーグ(6球団)

年度 対象データ
2024年度 https://npb.jp/bis/2024/stats/tmb_c.html
2023年度 https://npb.jp/bis/2023/stats/tmb_c.html
2022年度 https://npb.jp/bis/2022/stats/tmb_c.html
2021年度 https://npb.jp/bis/2021/stats/tmb_c.html
2020年度 https://npb.jp/bis/2020/stats/tmb_c.html

パシフィック・リーグ(6球団)

年度 対象データ
2024年度 https://npb.jp/bis/2024/stats/tmb_p.html
2023年度 https://npb.jp/bis/2023/stats/tmb_p.html
2022年度 https://npb.jp/bis/2022/stats/tmb_p.html
2021年度 https://npb.jp/bis/2021/stats/tmb_p.html
2020年度 https://npb.jp/bis/2020/stats/tmb_p.html

収集したデータ

収集したデータは以下の画像の通りです。

image.png

データ整形

以下のようにデータ整形を行います。

年度ごとのチーム成績を結合し、リーグ全体の平均を算出

コード

import pandas as pd

# データ読み込み
df = pd.read_csv("/content/drive/MyDrive/Colab Notebooks/studying_for_research/baseball/npb_2020_2024_hr.csv")

# OPSを追加
df["OPS"] = df["出塁率"] + df["長打率"]

# 年度ごとに集計
yearly = df.groupby("年度").agg({
    "本塁打数": "sum",
    "試合数": "sum",
    "長打率": "mean",
    "出塁率": "mean",
    "OPS": "mean"
}).reset_index()

# 1試合平均HR数を計算
yearly["HR_per_game"] = yearly["本塁打数"] / yearly["試合数"]

# 結果を確認
display(yearly)

# CSVに保存
yearly.to_csv("npb_2020_2024_summary.csv", index=False)

出力結果

年度	本塁打数	試合数	長打率	出塁率	OPS	HR_per_game
0	2020	1288	1440	0.383750	0.324500	0.708250	0.894444
1	2021	1449	1716	0.375083	0.315000	0.690083	0.844406
2	2022	1304	1716	0.364417	0.308417	0.672833	0.759907
3	2023	1250	1716	0.358167	0.307417	0.665583	0.728438
4	2024	975	1716	0.343583	0.303333	0.646917	0.568182

出力結果からわかること

このデータからは、2020年から2024年にかけてNPBの打撃成績が継続的に低下していることが分かります。特に2024年は、ホームラン数、長打率、出塁率、OPSが過去5年間で最も低い水準に達しました。これは、単にホームランが減っているだけでなく、リーグ全体として「投高打低」の傾向が強まっていることを示しています。急激な変化は、ボールの反発係数など、何らかの外部要因が影響している可能性が高いと推測されます。

可視化

次にデータの可視化を行います。

  • 年度ごとの 1試合平均HR数 の推移グラフを作成
  • 年度ごとの SLG推移グラフ を作成
  • 3年移動平均を加え、トレンドを平滑化

年度ごとの 1試合平均HR数 の推移グラフを作成

コード

import matplotlib.pyplot as plt
import pandas as pd

# 整形済みデータを読み込み
yearly = pd.read_csv("npb_2020_2024_summary.csv")

# HR_per_game の推移
plt.plot(yearly["年度"], yearly["HR_per_game"], marker="o", color="red", label="HR per game")
plt.title("NPB Annual Average Home Runs Per Game")
plt.xlabel("fiscal year")
plt.ylabel("HR per game")
plt.legend()
plt.grid(True)
plt.show()

出力結果

image.png

縦軸はHR_per_game(1試合あたりHR数)を示す。横軸ではfiscal year(年度)を示す。

出力結果からわかること

このグラフは、2020年から2024年のNPBにおける1試合あたりのホームラン数が、継続的に減少していることを示しています。特に2024年は急激な落ち込みを見せ、過去5年間で最も少ない水準となりました。この急激な減少は、単なる選手個々の傾向ではなく、ボールの反発係数など、何らかの外部要因が影響している可能性が高いと考えられます。このことから、NPBではパワーヒッターよりも、確実なミートや走塁技術が重要視される「投高打低」の傾向が強まっていると分析できます。

年度ごとのSLG推移グラフを作成

コード

import matplotlib.pyplot as plt
import pandas as pd
import matplotlib as mpl

mpl.rcParams['font.family'] = 'DejaVu Sans' 

# 整形済みデータを読み込み
yearly = pd.read_csv("npb_2020_2024_summary.csv")

# 長打率 (SLG) の推移
plt.plot(yearly["年度"], yearly["長打率"], marker="o", color="green", label="SLG") 
plt.title("NPB Slugging Percentage (SLG) by Year") 
plt.xlabel("fiscal year")
plt.ylabel("SLG") 
plt.legend()
plt.grid(True)
plt.show()

出力結果

image.png

縦軸はSLG(長打率)を示す。横軸ではfiscal year(年度)を示す。

出力結果からわかること

日本のプロ野球におけるSLGは2020年から2024年にかけて一貫して下降傾向にあることがわかります。最も高かった2020年の値(0.385)から、2024年には最も低い値(0.344)まで、毎年着実に低下しており、この期間において打者の長打力が全体的に減少していることを示唆しています。

3年移動平均を加え、トレンドを平滑化

コード

import matplotlib.pyplot as plt

# 年度ごとに平均SLGを計算
slg_trend = df.groupby("年度")["長打率"].mean()

# 移動平均(3年)
slg_trend_ma = slg_trend.rolling(window=3, center=True).mean()

# グラフ描画
plt.figure(figsize=(8,5))
plt.plot(slg_trend.index, slg_trend.values, marker="o", label="平均SLG")
plt.plot(slg_trend_ma.index, slg_trend_ma.values, color="red", linewidth=2, label="移動平均(3年)")

plt.title("Annual Average SLG Trend (with Moving Average)")
plt.xlabel("Year")
plt.ylabel("Average SLG")
plt.legend()
plt.grid(True)
plt.show()

出力結果

image.png

縦軸はAverage SLG(平均長打率)を示す。横軸ではyear(年度)を示す。

出力結果からわかること

日本のプロ野球におけるSLGの年間平均値と、それを平滑化した3年移動平均の推移を示しています。元のSLG値は2020年から2024年にかけて継続して下降しているのに対し、3年移動平均線も同様に下降傾向を示しており、SLGの低下が短期的な変動ではなく、より長期的なトレンドであることを裏付けています。特に、3年移動平均線は、元のデータに見られる年ごとのわずかな変動を吸収し、全体として安定したSLGの減少トレンドを明確に示しています。

統計的分析

次に統計的分析を行います。

ANOVA(分散分析)

コード

import pandas as pd
from scipy import stats

# Load the yearly summarized data which contains the 'HR_per_game' column
yearly = pd.read_csv("npb_2020_2024_summary.csv")

# Group by year
groups = [yearly[yearly["年度"] == year]["HR_per_game"] for year in sorted(yearly["年度"].unique())]

# Perform one-way ANOVA
f_stat, p_val = stats.f_oneway(*groups)

print("ANOVA結果")
print("F値:", f_stat)
print("p値:", p_val)

出力結果

ANOVA結果 
F値: 5.936972139783051 
p値: 0.00048035907501589093

出力結果からわかること

ANOVA(分散分析)を実施した結果、F値は 5.94、p値は 0.00048 となりました。一般的に、p値が 0.05 未満であれば、帰無仮説(この場合は「年度間に差がない」)が棄却され、統計的に有意な差があると判断されます。今回の分析では、p値が 0.00048 と非常に小さいため、この基準を満たしています。この結果は、NPBの1試合平均本塁打数が、年度によって偶然ではない明らかな変動があったことを意味します。これは、SLG(長打率)の低下トレンドと同様に、「飛ばないボール」疑惑を裏付ける根拠の一つとなり得ます。

Tukey検定

コード

import pandas as pd
import statsmodels.api as sm
from statsmodels.stats.multicomp import pairwise_tukeyhsd

# Tukey HSD 検定
tukey = pairwise_tukeyhsd(endog=df["HR_per_game"], groups=df["年度"], alpha=0.05)

print(tukey)

# 結果を表形式で表示
tukey_result = pd.DataFrame(data=tukey.summary().data[1:], columns=tukey.summary().data[0])
print(tukey_result)

出力結果

Multiple Comparison of Means - Tukey HSD, FWER=0.05 
====================================================
group1 group2 meandiff p-adj   lower   upper  reject
----------------------------------------------------
  2020   2021    -0.05 0.9585 -0.2554  0.1554  False
  2020   2022  -0.1345 0.3578 -0.3399  0.0709  False
  2020   2023   -0.166 0.1672 -0.3714  0.0394  False
  2020   2024  -0.3263 0.0004 -0.5317 -0.1209   True
  2021   2022  -0.0845 0.7736 -0.2899  0.1209  False
  2021   2023   -0.116 0.5086 -0.3214  0.0894  False
  2021   2024  -0.2762 0.0033 -0.4816 -0.0708   True
  2022   2023  -0.0315 0.9925 -0.2369  0.1739  False
  2022   2024  -0.1917 0.0783 -0.3971  0.0137  False
  2023   2024  -0.1603 0.1949 -0.3657  0.0452  False
----------------------------------------------------
   group1  group2  meandiff   p-adj   lower   upper  reject
0    2020    2021   -0.0500  0.9585 -0.2554  0.1554   False
1    2020    2022   -0.1345  0.3578 -0.3399  0.0709   False
2    2020    2023   -0.1660  0.1672 -0.3714  0.0394   False
3    2020    2024   -0.3263  0.0004 -0.5317 -0.1209    True
4    2021    2022   -0.0845  0.7736 -0.2899  0.1209   False
5    2021    2023   -0.1160  0.5086 -0.3214  0.0894   False
6    2021    2024   -0.2762  0.0033 -0.4816 -0.0708    True
7    2022    2023   -0.0315  0.9925 -0.2369  0.1739   False
8    2022    2024   -0.1917  0.0783 -0.3971  0.0137   False
9    2023    2024   -0.1603  0.1949 -0.3657  0.0452   False

出力結果からわかること

この検定結果によると、2020年対2024年および2021年対2024年の比較において、統計的に有意な差が確認されました。具体的には、2020年と2024年の比較ではp値が0.0004、2021年と2024年の比較ではp値が0.0033となり、いずれも有意水準0.05を下回っています。これは、2024年の1試合あたりの平均本塁打数が、2020年と2021年と比較して統計的に有意に減少していることを意味します。

一方で、2020年から2023年までの期間においては、どの年のペアを比較しても有意な差は見られませんでした。また、2022年と2024年、2023年と2024年の比較では、わずかにp値が0.05を超えているため、厳密な有意差は認められませんでした。

回帰分析

コード

import statsmodels.api as sm
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib as mpl

try:
    mpl.rcParams['font.family'] = 'IPAexGothic'
except:
    print("IPAexGothic font not found. Using default font.")
    mpl.rcParams['font.family'] = 'DejaVu Sans'


# 年度を数値に変換(カテゴリではなく数値でトレンドを見る)
df['year_num'] = df['年度'] - df['年度'].min()

# 回帰モデル作成
X = sm.add_constant(df['year_num'])  # 切片を追加
y = df['HR_per_game']
model = sm.OLS(y, X).fit()

# 回帰結果の概要
print(model.summary())

# 可視化
plt.figure(figsize=(8,5))
sns.scatterplot(x='year_num', y='HR_per_game', data=df, s=80)
sns.regplot(x='year_num', y='HR_per_game', data=df, scatter=False, ci=None, color='red')
plt.xlabel("年度")
plt.ylabel("HR per Game")
plt.title("Trend of HR per Game (2020-2024)")
plt.show()

出力結果

                            OLS Regression Results                            
==============================================================================
Dep. Variable:            HR_per_game   R-squared:                       0.283
Model:                            OLS   Adj. R-squared:                  0.270
Method:                 Least Squares   F-statistic:                     22.87
Date:                Sat, 20 Sep 2025   Prob (F-statistic):           1.23e-05
Time:                        11:59:45   Log-Likelihood:                 20.100
No. Observations:                  60   AIC:                            -36.20
Df Residuals:                      58   BIC:                            -32.01
Df Model:                           1                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const          0.9128      0.039     23.187      0.000       0.834       0.992
year_num      -0.0768      0.016     -4.782      0.000      -0.109      -0.045
==============================================================================
Omnibus:                        3.859   Durbin-Watson:                   2.704
Prob(Omnibus):                  0.145   Jarque-Bera (JB):                2.891
Skew:                           0.463   Prob(JB):                        0.236
Kurtosis:                       3.548   Cond. No.                         4.74
==============================================================================

image.png

出力結果からわかること

この回帰分析は、2020年から2024年にかけてNPBの平均本塁打数が一貫して減少していることを統計的に裏付けるものです。これは、以前から議論されている「飛ばないボール疑惑」を支持する有力な材料の一つとなり得ます。ただし、モデルの説明力が約28%であることから、本塁打数の減少は年度だけが原因ではなく、他の様々な要因が複合的に作用している可能性も示唆されます

縦軸はHR_per_game(1試合あたりHR数)を示す。横軸ではfiscal year(年度)を示す。

OPS/SLGとHR_per_gameの相関

コード

import pandas as pd

# OPSを計算(まだ列がない場合)
df["OPS"] = df["出塁率"] + df["長打率"]

# 相関係数の確認
corr = df[["HR_per_game", "OPS", "長打率", "出塁率"]].corr()
print(corr)

出力結果

             HR_per_game       OPS       長打率       出塁率
HR_per_game     1.000000  0.854791  0.920500  0.550620
OPS             0.854791  1.000000  0.966285  0.861930
長打率             0.920500  0.966285  1.000000  0.702323
出塁率             0.550620  0.861930  0.702323  1.000000

出力結果からわかること

この相関行列を見ると、1試合あたりの本塁打数(HR_per_game)は、長打率(SLG)と0.92という非常に強い正の相関を示しています。これは、長打率が高くなると本塁打数も増加する傾向が非常に強いことを意味します。次に、OPSとは0.85の強い正の相関があり、OPSが上昇すれば本塁打数も増えることがわかります。一方、出塁率(OBP)との相関は0.55と中程度にとどまっています。

考察

今回の分析から、2020年から2024年にかけてNPBの打撃成績は明確に下降傾向を示していることが分かりました。特に2024年は本塁打数、長打率、OPSいずれの指標も過去5年間で最低水準となり、リーグ全体として「投高打低」の傾向が強まっています。

統計的検定の結果からも、2024年の本塁打数は2020年および2021年と比べて有意に低いことが確認されました。これは単なる偶然ではなく、リーグ全体に共通する外部要因が作用している可能性を示唆しています。

背景要因としては、以下の可能性が考えられます。

背景原因 詳細
ボールの反発係数の変化 過去に統一球や加藤球など「飛ぶボール」「飛ばないボール」の議論があり、今回の急激な指標低下も同様のケースである可能性がある
投手レベルの向上 投手の平均球速上昇、分業化(中継ぎ・抑えの強化)などにより、打者が長打を放ちにくくなっている可能性がある
戦略面の変化 セイバーメトリクス普及により、打撃戦よりも投手戦を前提としたチーム編成・戦略が浸透している可能性がある

ただし、本分析は年度ごとの「打撃成績平均値」に基づいており、個人の打球速度や飛距離データ、球場ごとの環境要因(球場サイズ、風、ドーム・屋外差など)までは考慮できていません。より詳細に検証するためには、Statcastのような打球データや球場別成績の活用が必要です。

結論
2024年シーズンに見られる「打撃成績の急激な低下」は統計的にも裏付けられ、ボールや環境要因の変化が疑われる現象だと考えられます。今後も継続的にデータを収集し、2025年以降のトレンドが反発するのか、あるいは「飛ばない時代」が定着するのかを検証していきたいと思います。

まとめ

今回はpythonを用いて、日本プロ野球のボールが飛ばなくなっているのかpythonで分析してみました。2025シーズンのプロ野球成績がでたらまた分析していきたいと思います。ちなみに体感ですが、球宴以降ボールが飛んでいるような気がします。機能性かもしれませんが....

githubのリポジトリです。参考にしてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?