1. はじめに
前回の記事社会人野球 Eloレーティング(2021〜2025)を複数年で算出し、チーム名統一+バーチャートレースで可視化してみたでは、過去5年間のJABA大会や都市対抗野球などの結果データをもとに、社会人野球チームの単年のEloレーティングを算出することに挑戦してみました。
今回の記事ではその続編として、以下の2点を中心に拡張しました。
1️⃣ 対象を過去10年(2015〜2025)の試合結果に拡大
2️⃣ 休部・廃部に対応できる機能の追加
こちらが作成したバーチャートレースです
そして、社会人野球ファンとしては大変残念なことにパナソニック野球部が2026年シーズン限りで休部することが先月発表されました。休部に至った背景にはさまざまな要因があると考えられますが、報道ではその一因として、報道では近年の成績不振ということが挙げられています。そこで本記事では、この記事の主題であるレーティングの観点から見て、本当に成績不振だったのかも検証してみます。
2. 対象とした大会と期間
- 対象期間:2015年〜2025年
- 対象大会
- JABA 日本選手権対象大会(各地区大会)
- 都市対抗野球大会(予選および本戦)
- 社会人野球日本選手権(予選および本戦)
なお、結果は一球速報の社会人野球のページを見て一つ一つcsvにまとめていったのと
以下のJABAの旧HPから各種大会結果のPDFを参照してこれも一つ一つcsvにまとめていきました。
3. 入力データ(CSV形式)
1試合を1行として記録します。最低限必要なのは以下の5列です。
列名 内容 例
date 試合日 (YYYY-MM-DD) 2024-07-18
team_a チームA Honda
team_b チームB JR東日本
score_a チームAの得点 5
score_b チームBの得点 1
任意で以下の列も追加できるようにしました。
- tournament → 大会名(都市対抗、日本選手権など)
- stage → 本戦/予選/練習試合など(重み付けに利用)
また、重み付けとしてJABA 日本選手権対象大会や都市対抗予選は1.0、都市対抗本戦は1.5、練習試合は0.5(今回は入力データに含んでいません)としました。
サンプルCSVは以下の通りです。
2025/3/8,Honda鈴鹿,鷺宮製作所,4,5,第79回JABA東京スポニチ大会,regional
2025/3/8,NTT西日本,JR東日本,3,1,第79回JABA東京スポニチ大会,regional
2025/3/8,Honda熊本,JFE東日本,5,6,第79回JABA東京スポニチ大会,regional
2025/8/29,東芝,JR東日本,8,9,第96回都市対抗野球大会(1回戦),main
2025/8/30,TDK,鷺宮製作所,4,5,第96回都市対抗野球大会(1回戦),main
2025/8/30,JR東日本東北,トヨタ自動車,5,3,第96回都市対抗野球大会(1回戦),main
4. チーム名統一の考え方と休部・廃部の考えかた
社会人野球では、以下のような企業再編・チーム名変更などが頻繁に発生します。
- 「A社硬式野球部」 → 「Aホールディングス」
- 「B工業」 → 「Bテック」
このような変更を正しく扱うため、
旧名 → 統一名 の対応マップ(辞書)をコード内に定義しました。
これにより、同一チームのレーティング履歴が年度をまたいで一貫するようにしました。
また社会人野球では、チーム名変更だけでなく、休部・廃部 も少なからず発生します。
この点を考慮しないと、すでに活動していないチームがランキング上位に残り続けてしまい、
現実の勢力図と乖離したレーティングになってしまいます。
そこで本コードでは、
- 「この日付をもって休部・廃部した」
- それ以降の試合・ランキングには登場しない
という情報を、コードに明示的に定義するようにしました。
この設定により、
-
指定日 以前 の試合
→ 通常どおりレーティング計算に参加 -
指定日 以降 の試合
→ レーティング計算・ランキング集計から除外
という挙動にしています。
5. レーティング計算の前提
複数年をまたいで Elo レーティングを算出する場合、初年度のレートの初期値をどう扱うかについて考えましたが、この記事では
- 2015年を起点年とし、すべてのチームを初期レート 1500 でスタート
- 2016年以降は前年の最終レートを引き継ぎ、累積的に更新
という形にしています。また、2015年中に登場しなかった新規チームは、登場時点で自動的にレーティング1500で参入するようにしました。
6. Eloレーティング算出プログラム全文(複数年・チーム名統一対応/休部・廃部対応)
# -*- coding: utf-8 -*-
"""
社会人野球 Elo レーティング計算(複数CSV対応・累積・日単位履歴対応)
- 休部・廃部チームは指定日以降は計算・ランキングから除外
"""
import math
import pandas as pd
from datetime import datetime
# ===== 入力CSV =====
INPUT_FILES = [
"shakaijin_yakyu_2015.csv",
"shakaijin_yakyu_2016.csv",
"shakaijin_yakyu_2017.csv",
"shakaijin_yakyu_2018.csv",
"shakaijin_yakyu_2019.csv",
"shakaijin_yakyu_2020.csv",
"shakaijin_yakyu_2021.csv",
"shakaijin_yakyu_2022.csv",
"shakaijin_yakyu_2023.csv",
"shakaijin_yakyu_2024.csv",
"shakaijin_yakyu_2025.csv",
]
OUTPUT_PREFIX = "shakaijin_elo"
# ===== 基本設定 =====
INITIAL_RATING = 1500.0
BASE_K = 20.0
ELO_SCALE = 400.0
STAGE_K_WEIGHT = {
"main": 1.5, "regional": 1.0, "friendly": 0.5,
"本戦": 1.5, "予選": 1.0, "練習試合": 0.5,
}
# ===== チーム名統一マップ =====
TEAM_NAME_MAP = {
"かずさマジック": "日本製鉄かずさマジック",
"新日鐵住金かずさマジック": "日本製鉄かずさマジック",
"新日鐵住金鹿島": "日本製鉄鹿島",
"JR北海道硬式野球クラブ": "JR北海道",
"室蘭シャークス": "日本製鉄室蘭シャークス",
"新日鐵住金東海REX":"日本製鉄東海REX",
"新日鐵住金東海R E X":"日本製鉄東海REX",
"新日鐵住金広畑":"新日鐵住金広畑",
"三菱日立パワーシステムズ横浜":"三菱重工East",
"三菱日立パワーシステムズ":"三菱重工East",
"三菱パワー":"三菱重工East",
"MHPS横浜":"三菱重工East",
"三菱重工神戸・高砂":"三菱重工West",
"富士重工業":"SUBARU",
"HONDA":"Honda",
"ホンダ":"Honda",
"Honda":"Honda",
"Honda(埼玉)":"Honda",
"ホンダ鈴鹿":"Honda鈴鹿",
"HONDA鈴鹿":"Honda鈴鹿",
"ホンダ熊本":"Honda熊本",
"HONDA熊本":"Honda熊本",
"日本製鉄広畑": "日本製鉄瀬戸内",
"新日鐵住金広畑":"日本製鉄瀬戸内",
"三菱自動車倉敷": "三菱自動車倉敷オーシャンズ",
"九州三菱自動車":"KMGホールディングス",
"KMG":"KMGホールディングス",
"光シーガルズ":"日本製鉄山口",
"光シーガールズ":"日本製鉄山口",
"鮮ど市場ゴールデンラークス":"熊本ゴールデンラークス",
"熊本GL":"熊本ゴールデンラークス",
"鮮ど市場硬式野球部":"熊本ゴールデンラークス",
"JX-ENEOS":"ENEOS",
"新日鐵住金大分":"日本製鉄九州大分",
"日本製鉄九州":"日本製鉄九州大分",
"大福ロジ":"大福ロジスティクス",
"永和商事ウィング":"永和商事ウイング",
"FedEx":"フェデックス",
"JR東日本(東京)":"JR東日本",
}
# ===== 休部・廃部情報(※統一後の名前で記述)=====
INACTIVE_TEAMS = {
"きらやか銀行": "2022-12-31",
"永和商事ウイング": "2020-12-31",
"三菱重工長崎":"2016-12-31",
"三菱重工広島":"2020-12-31",
"三菱重工名古屋":"2020-12-31",
"大福ロジスティクス":"2024-12-31",
"JPアセット証券":"2024-12-31",
}
INACTIVE_TEAMS = {
k: pd.to_datetime(v) for k, v in INACTIVE_TEAMS.items()
}
# ===== 関数 =====
def margin_of_victory_multiplier(score_diff: int, rating_diff: float) -> float:
return math.log(abs(score_diff) + 1.0) * 2.2 / ((abs(rating_diff) * 0.001) + 2.2)
def expected_score(ra: float, rb: float) -> float:
return 1.0 / (1.0 + 10.0 ** ((rb - ra) / ELO_SCALE))
def normalize_name(name: str) -> str:
name = str(name).strip()
return TEAM_NAME_MAP.get(name, name)
def is_active(team: str, date: pd.Timestamp) -> bool:
"""指定日時点で活動中か"""
inactive_date = INACTIVE_TEAMS.get(team)
if inactive_date is None:
return True
return date <= inactive_date
def load_games(files):
frames = []
rename_map = {
"Date": "date",
"Team A": "team_a",
"Team B": "team_b",
"Socre A": "score_a",
"Score A": "score_a",
"Score B": "score_b",
"tournament": "tournament",
"Tournament": "tournament",
"stage": "stage",
"Stage": "stage",
}
for f in files:
df = pd.read_csv(f)
df = df.rename(columns={k: v for k, v in rename_map.items() if k in df.columns})
frames.append(df)
games = pd.concat(frames, ignore_index=True)
games["date"] = pd.to_datetime(games["date"], errors="coerce")
games["team_a"] = games["team_a"].astype(str).apply(normalize_name)
games["team_b"] = games["team_b"].astype(str).apply(normalize_name)
games["score_a"] = pd.to_numeric(games["score_a"], errors="coerce").astype("Int64")
games["score_b"] = pd.to_numeric(games["score_b"], errors="coerce").astype("Int64")
games = games.dropna(subset=["date", "team_a", "team_b", "score_a", "score_b"])
games = games.sort_values("date").reset_index(drop=True)
return games
def snapshot_year_df(year: int, rating_dict: dict) -> pd.DataFrame:
rows = []
snapshot_date = pd.Timestamp(f"{year}-12-31")
for team, rating in rating_dict.items():
# その年の年末時点で活動中か?
if not is_active(team, snapshot_date):
continue
rows.append({"team": team, "rating": rating})
if not rows:
return pd.DataFrame()
df = pd.DataFrame(rows)
df = df.sort_values("rating", ascending=False, ignore_index=True)
df.insert(0, "year", year)
return df
# ===== メイン処理 =====
def main():
df = load_games(INPUT_FILES)
rating = {}
history_rows = []
per_year_tables = []
for idx, row in df.iterrows():
date = row["date"]
a, b = row["team_a"], row["team_b"]
# どちらかが休部・廃部後なら試合ごとスキップ
if not (is_active(a, date) and is_active(b, date)):
continue
sa, sb = int(row["score_a"]), int(row["score_b"])
stage = row.get("stage", None)
year = int(date.year)
rating.setdefault(a, INITIAL_RATING)
rating.setdefault(b, INITIAL_RATING)
ra, rb = rating[a], rating[b]
ea = expected_score(ra, rb)
score_a = 1.0 if sa > sb else 0.0 if sa < sb else 0.5
k = BASE_K * STAGE_K_WEIGHT.get(stage, 1.0)
if sa != sb:
diff = abs(sa - sb)
rdiff = (ra - rb) if sa > sb else (rb - ra)
mov = margin_of_victory_multiplier(diff, rdiff)
else:
mov = 1.0
delta = k * mov * (score_a - ea)
rating[a] += delta
rating[b] -= delta
date_str = date.strftime("%Y-%m-%d")
history_rows.extend([
{
"date": date_str,
"team": a,
"opponent": b,
"score_for": sa,
"score_against": sb,
"rating": rating[a],
"stage": stage,
},
{
"date": date_str,
"team": b,
"opponent": a,
"score_for": sb,
"score_against": sa,
"rating": rating[b],
"stage": stage,
},
])
next_year = (
idx == len(df) - 1
or int(df.iloc[idx + 1]["date"].year) != year
)
if next_year:
snap = snapshot_year_df(year, rating)
if not snap.empty:
per_year_tables.append(snap)
final_year = int(df.iloc[-1]["date"].year)
final_table = snapshot_year_df(final_year, rating).drop(columns=["year"])
history = pd.DataFrame(history_rows)
final_table.to_csv(f"{OUTPUT_PREFIX}_final_ratings.csv", index=False)
history.to_csv(f"{OUTPUT_PREFIX}_rating_history.csv", index=False, encoding="utf-8-sig")
if per_year_tables:
all_years = pd.concat(per_year_tables, ignore_index=True)
all_years.to_csv(f"{OUTPUT_PREFIX}_yearly_snapshots.csv", index=False)
print("[DONE]")
if __name__ == "__main__":
main()
実行後の出力
- shakaijin_elo_final_ratings.csv ⇒ 最新(最終日)の Elo レーティング順位表
- shakaijin_elo_rating_history.csv⇒ 1試合ごと・1チームごとに「その試合後のレーティング」を記録した履歴データ
- shakaijin_elo_yearly_snapshots.csv⇒ その年の最後の試合終了時点のレーティング
7. 結果(レーティングの推移 TOP20)
なお、社会人野球チームは名称がここ10年間で変わっているチームもありますが、2025年時点の名称で統一しています。
| 順位 | 2015年 | 2016年 | 2017年 | 2018年 | 2019年 | 2020年 | 2021年 | 2022年 | 2023年 | 2024年 | 2025年 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 日本生命 (1775.03) | トヨタ自動車 (1762.44) | トヨタ自動車 (1805.83) | NTT東日本 (1828.84) | 大阪ガス (1820.02) | Honda (1845.91) | 大阪ガス (1848.78) | ENEOS (1909.65) | トヨタ自動車 (1973.25) | トヨタ自動車 (1994.94) | トヨタ自動車 (1983.49) |
| 2 | NTT西日本 (1671.76) | NTT東日本 (1726.08) | NTT東日本 (1802.43) | トヨタ自動車 (1785.83) | NTT東日本 (1802.58) | NTT東日本 (1830.83) | NTT東日本 (1816.67) | トヨタ自動車 (1907.72) | ENEOS (1891.80) | 三菱重工East (1906.73) | ヤマハ (1966.95) |
| 3 | Honda (1670.71) | ヤマハ (1704.62) | 日本通運 (1748.67) | 大阪ガス (1771.56) | 日本通運 (1801.44) | 日本通運 (1787.78) | ヤマハ (1810.99) | 東京ガス (1869.65) | 日本通運 (1876.87) | Honda (1886.44) | Honda (1881.43) |
| 4 | 大阪ガス (1654.44) | 日本生命 (1697.12) | 日本生命 (1721.59) | 日本通運 (1751.47) | 日本生命 (1798.78) | トヨタ自動車 (1784.61) | Honda (1805.07) | NTT東日本 (1849.09) | 東京ガス (1853.60) | 日本通運 (1870.71) | ENEOS (1865.31) |
| 5 | トヨタ自動車 (1620.14) | 日立製作所 (1687.58) | 三菱重工East (1707.12) | Honda (1739.01) | 東芝 (1795.64) | 日本生命 (1777.04) | 三菱重工East (1795.73) | 三菱重工East (1817.62) | ヤマハ (1841.96) | ENEOS (1853.19) | 三菱重工East (1846.54) |
| 6 | NTT東日本 (1603.62) | 王子 (1686.50) | Honda (1706.64) | 日本生命 (1736.37) | トヨタ自動車 (1770.79) | NTT西日本 (1760.20) | 日本通運 (1792.71) | 日本通運 (1807.84) | Honda熊本 (1836.48) | ヤマハ (1842.14) | NTT東日本 (1843.54) |
| 7 | ヤマハ (1598.77) | Honda (1679.91) | ヤマハ (1685.42) | 三菱重工名古屋 (1711.88) | 日本製鉄鹿島 (1749.71) | ヤマハ (1757.55) | トヨタ自動車 (1786.32) | 東芝 (1799.94) | 三菱重工East (1831.56) | NTT東日本 (1828.55) | 日本通運 (1838.95) |
| 8 | 日本製鉄かずさマジック (1592.88) | 日本通運 (1677.29) | 日本新薬 (1682.80) | 日本製鉄鹿島 (1711.01) | Honda (1737.87) | 東芝 (1757.38) | 日立製作所 (1781.29) | Honda熊本 (1794.55) | Honda (1814.31) | 東京ガス (1823.56) | 王子 (1837.29) |
| 9 | 三菱重工長崎 (1592.16) | ENEOS (1668.52) | パナソニック (1680.47) | 東芝 (1705.83) | 三菱重工East (1731.87) | ENEOS (1752.43) | 東京ガス (1779.87) | Honda (1787.55) | JR東日本 (1792.92) | 東芝 (1796.95) | NTT西日本 (1827.57) |
| 10 | SUBARU (1589.15) | 日本新薬 (1644.27) | 王子 (1679.39) | 三菱重工East (1697.91) | JFE東日本 (1729.35) | 大阪ガス (1745.67) | ENEOS (1766.68) | 日立製作所 (1776.46) | 東芝 (1790.69) | 西部ガス (1782.51) | 日本生命 (1821.38) |
| 11 | 東芝 (1588.28) | NTT西日本 (1642.89) | 東芝 (1661.66) | JFE西日本 (1694.37) | JFE西日本 (1724.37) | 日本製鉄鹿島 (1732.65) | セガサミー (1741.07) | 大阪ガス (1769.24) | NTT東日本 (1777.41) | 三菱重工West (1777.20) | Honda熊本 (1811.24) |
| 12 | 三菱重工広島 (1587.02) | 東芝 (1637.81) | 三菱重工広島 (1655.31) | 王子 (1687.99) | ヤマハ (1724.01) | 三菱重工East (1723.62) | 東芝 (1735.28) | ヤマハ (1760.01) | 三菱重工West (1752.67) | Honda熊本 (1772.05) | 東芝 (1794.79) |
| 13 | 王子 (1580.35) | 三菱重工広島 (1635.05) | 東京ガス (1654.19) | 日本新薬 (1685.04) | 王子 (1721.84) | 日本新薬 (1712.10) | 王子 (1720.21) | JR東日本 (1749.79) | 王子 (1739.25) | JR東日本 (1759.02) | 東京ガス (1785.02) |
| 14 | 日立製作所 (1579.36) | パナソニック (1634.65) | 日立製作所 (1652.22) | パナソニック (1675.03) | 日立製作所 (1715.07) | JR東日本 (1708.84) | JFE東日本 (1719.50) | セガサミー (1748.15) | 三菱自動車岡崎 (1733.21) | JFE西日本 (1756.22) | SUBARU (1784.80) |
| 15 | 伯和ビクトリーズ (1569.92) | 三菱重工East (1621.22) | 大阪ガス (1647.38) | 東京ガス (1672.18) | ENEOS (1703.37) | 日立製作所 (1708.83) | 東邦ガス (1719.01) | 日本新薬 (1734.13) | 日本新薬 (1729.80) | JR東日本東北 (1751.90) | JFE西日本 (1773.11) |
| 16 | 三菱重工East (1568.67) | JR九州 (1620.49) | 三菱重工名古屋 (1646.12) | 日立製作所 (1671.93) | 鷺宮製作所 (1700.88) | JFE東日本 (1704.09) | Honda熊本 (1716.73) | 日本生命 (1733.60) | 西部ガス (1729.59) | 日本製鉄鹿島 (1742.29) | 三菱重工West (1768.75) |
| 17 | ENEOS (1565.13) | 三菱重工長崎 (1620.45) | JR西日本 (1644.99) | Honda鈴鹿 (1666.29) | 三菱自動車岡崎 (1699.14) | 王子 (1696.13) | 日本製鉄鹿島 (1710.22) | 日本製鉄鹿島 (1722.22) | 大阪ガス (1729.10) | 王子 (1735.51) | 西部ガス (1767.68) |
| 18 | 日本通運 (1564.42) | 大阪ガス (1615.15) | ENEOS (1637.31) | ENEOS (1664.97) | NTT西日本 (1686.96) | Honda鈴鹿 (1694.78) | NTT西日本 (1706.82) | 三菱重工West (1714.14) | 日立製作所 (1727.58) | 日本生命 (1733.28) | 三菱自動車岡崎 (1753.04) |
| 19 | 信越硬式野球クラブ (1563.78) | JR西日本 (1607.05) | NTT西日本 (1637.22) | 三菱重工広島 (1664.87) | JR九州 (1680.45) | JR九州 (1680.45) | JR東日本 (1702.50) | 鷺宮製作所 (1713.46) | パナソニック (1721.14) | NTT西日本 (1729.95) | JR東日本 (1749.39) |
| 20 | JFE西日本 (1558.65) | JR東日本 (1599.92) | JR東日本 (1628.54) | 西濃運輸 (1644.82) | Honda鈴鹿 (1679.51) | JFE西日本 (1676.69) | 日本生命 (1699.15) | TDK (1691.22) | SUBARU (1710.33) | 日立製作所 (1729.71) | JR東日本東北 (1745.67) |
8. バーチャートレースで可視化
複数年分のEloレーティング推移を、日ごとのアニメーションとして表現しました。
使用ライブラリは以下です。
pip install bar_chart_race matplotlib pandas
バーチャートレース化するプログラムは以下になります。JABAの大会にはプロの2軍も参加することがあるので、それは含めないようにしています。
# -*- coding: utf-8 -*-
"""
社会人野球 Eloレーティング履歴CSVから日ごとのバーチャートレース動画を生成(x軸固定・日本語対応)
"""
import pandas as pd
import bar_chart_race as bcr
import matplotlib.pyplot as plt
# ===== 設定 =====
INPUT_CSV = "shakaijin_elo_rating_history.csv"
OUTPUT_VIDEO = "elo_barchart_race_daily_2015-2025.mp4"
TOP_N = 10
FPS = 15
TITLE = "社会人野球 Eloレーティング推移(日別)"
# ===== 除外したいチーム(方法①)=====
EXCLUDE_TEAMS = [
"中日ドラゴンズ"
]
# ===== 日本語フォント設定 =====
plt.rcParams['font.family'] = ['Meiryo'] # Windows用
plt.rcParams['axes.unicode_minus'] = False
# ===== データ読み込み =====
df = pd.read_csv(INPUT_CSV, encoding="utf-8")
# ===== 特定チームを除外 =====
df = df[~df["team"].isin(EXCLUDE_TEAMS)]
required = {"date", "team", "rating"}
if not required.issubset(df.columns):
raise ValueError(f"CSVに必要な列がありません: {required - set(df.columns)}")
df["date"] = pd.to_datetime(df["date"], errors="coerce")
df = df.dropna(subset=["date", "team", "rating"])
# ===== 日ごとの平均レーティング =====
daily = df.groupby(["date", "team"])["rating"].mean().unstack(fill_value=None)
# ===== 初期レーティング補完 =====
first_day = daily.index.min()
daily.loc[first_day] = daily.loc[first_day].fillna(1500)
daily = daily.sort_index()
daily = daily.ffill()
# レーティング変動のないチームを除外(任意)
daily = daily.loc[:, daily.std() > 0]
# ===== X軸の範囲を決める =====
x_min = 1400
x_max = daily.max().max() + 40
# ===== xlimを固定したFigureを作成 =====
fig, ax = plt.subplots(figsize=(7, 4.5))
ax.set_xlim(x_min, x_max)
ax.tick_params(axis='x', labelsize=8)
ax.tick_params(axis='y', labelsize=8)
# ===== バーチャートレース生成(x軸固定)=====
bcr.bar_chart_race(
df=daily,
filename=OUTPUT_VIDEO,
n_bars=TOP_N,
sort='desc',
title=TITLE,
fixed_order=False,
fixed_max=True,
interpolate_period=False,
steps_per_period=40,
period_length=3000 / FPS,
cmap='dark12',
bar_size=0.95,
period_fmt='%Y-%m-%d',
period_label={'x': 0.92, 'y': 0.1, 'ha': 'right', 'va': 'center'},
dpi=300,
fig=fig
)
print(f"[DONE] バーチャートレース動画を出力しました: {OUTPUT_VIDEO}")
# ===== 最終日の静止グラフをPNGで保存 =====
last_date = daily.index.max()
last_values = daily.loc[last_date].sort_values(ascending=True).tail(TOP_N)
fig2, ax2 = plt.subplots(figsize=(7, 4.5))
ax2.barh(last_values.index, last_values.values,
color=plt.cm.Dark2.colors[:TOP_N])
ax2.set_xlim(x_min, x_max)
ax2.set_xlabel("Eloレーティング")
ax2.set_title(
f"{TITLE}\n({last_date.strftime('%Y-%m-%d')} 時点)",
fontsize=12
)
ax2.tick_params(axis='x', labelsize=8)
ax2.tick_params(axis='y', labelsize=8)
# PNG出力
OUTPUT_PNG = "elo_barchart_lastframe.png"
plt.tight_layout()
plt.savefig(OUTPUT_PNG, dpi=300)
plt.close(fig2)
print(f"[DONE] バーチャートレース動画を出力しました: {OUTPUT_VIDEO}")
print(f"[DONE] 最終フレームのPNGを保存しました: {OUTPUT_PNG}")
実行後の出力
- elo_barchart_race_daily_2015-2025.mp4 → 日付ごとのレーティング推移アニメーション(1章で示した動画です)
9. パナソニック野球部のレーティングの推移について
パナソニック硬式野球部の過去10年のレーティングと順位は以下になります
| 年 | レーティング | 順位 |
|---|---|---|
| 2015 | 1551.45 | 24 |
| 2016 | 1634.65 | 14 |
| 2017 | 1680.47 | 9 |
| 2018 | 1675.03 | 14 |
| 2019 | 1641.36 | 24 |
| 2020 | 1660.75 | 25 |
| 2021 | 1678.99 | 23 |
| 2022 | 1686.73 | 24 |
| 2023 | 1721.14 | 19 |
| 2024 | 1647.14 | 36 |
| 2025 | 1622.89 | 42 |
図は以下です。
確かに直近2年間は成績が低下しているように見えます。しかし、2023年には過去最高のレーティングを記録しており、「著しく悪化している」と言えるほどではないようにも感じられます。
10. まとめ
今回は以下の件を対応し、社会人野球チームのランキングをバーチャートレースで示すことができました。
1️⃣ 対象を過去10年(2015〜2025)の試合結果に拡大
2️⃣ 休部・廃部に対応できる機能の追加
最後に、パナソニック野球部の皆さんには、休部なんて吹き飛ばすくらい、来年こそ大きく頑張ってほしいです!
都市対抗本戦に出場されたら、ぜひ応援に行かせていただきます!!
