JFLの試合結果から順位表を作成


はじめに

日本フットボールリーグオフィシャルWebサイトの日程・結果から試合結果をスクレイピング

スクレイピング

import requests
from bs4 import BeautifulSoup

url = "http://www.jfl.or.jp/jfl-pc/view/s.php?a=1542&f=2020A001_spc.html"

r = requests.get(url)
r.raise_for_status()

soup = BeautifulSoup(r.content, "html.parser")

data = []

for table in soup.find_all("table", class_="table-data"):

    trs = table.find_all("tr")

    th = int(trs[0].th.get_text(strip=True).strip("第節"))

    for i, tr in enumerate(trs[1:], 1):

        tds = [td.get_text(strip=True) for td in tr.find_all("td")]

        data.append([th, i] + tds)

データラングリング

import pandas as pd

df = pd.DataFrame(
    data, columns=["節", "番号", "日にち", "時間", "ホーム", "スコア", "アウェイ", "スタジアム", "備考"]
)

df.set_index(["節", "番号"], inplace=True)

df

df_score = (
    df["スコア"].str.split("-", expand=True).rename(columns={0: "ホーム得点", 1: "アウェイ得点"})
)

df_score["ホーム得点"] = pd.to_numeric(df_score["ホーム得点"], errors="coerce").astype("Int64")
df_score["アウェイ得点"] = pd.to_numeric(df_score["アウェイ得点"], errors="coerce").astype("Int64")

df1 = pd.concat([df, df_score], axis=1).dropna(subset=["ホーム得点", "アウェイ得点"])

# ホームの結果のみ
df_home = df1.loc[:, ["ホーム", "ホーム得点", "アウェイ得点"]].copy()
df_home.rename(columns={"ホーム": "チーム名", "ホーム得点": "得点", "アウェイ得点": "失点"}, inplace=True)
df_home["戦"] = "ホーム"
df_home.head()

# アウェイの結果のみ
df_away = df1.loc[:, ["アウェイ", "アウェイ得点", "ホーム得点"]].copy()
df_away.rename(columns={"アウェイ": "チーム名", "アウェイ得点": "得点", "ホーム得点": "失点"}, inplace=True)
df_away["戦"] = "アウェイ"
df_away.head()

# ホームとアウェイを結合
df_total = pd.concat([df_home, df_away])

# 得失点を計算
df_total["得失点"] = df_total["得点"] - df_total["失点"]


# 勝点追加
df_total["勝点"] = df_total["得失点"].apply(lambda x: 1 if x == 0 else 0 if x < 0 else 3)
df_total["勝敗"] = df_total["勝点"].replace({0: "敗戦", 1: "引分", 3: "勝利"})

df_total.head()

# 得点・失点・得失点・勝点 集計
pv_score = df_total.pivot_table(
    index="チーム名", values=["得点", "失点", "得失点", "勝点"], aggfunc=sum
)

pv_score

# 勝敗集計
pv_wl = pd.crosstab(df_total["チーム名"], [df_total["戦"], df_total["勝敗"]])
pv_wl

# 列名変更
# pv_wl.columns = ["勝利A", "引分A", "敗戦A", "勝利H", "引分H", "敗戦H"]

pv_wl.rename(columns={"アウェイ": "A", "ホーム": "H"}, inplace=True)
pv_wl.columns = pv_wl.columns.swaplevel(0, 1)
pv_wl.columns = ["".join(col).strip() for col in pv_wl.columns.values]

# 合計追加
pv_wl["勝利"] = pv_wl["勝利H"] + pv_wl["勝利A"]
pv_wl["引分"] = pv_wl["引分H"] + pv_wl["引分A"]
pv_wl["敗戦"] = pv_wl["敗戦H"] + pv_wl["敗戦A"]

# 試合数追加
pv_wl["試合数"] = pv_wl["勝利"] + pv_wl["引分"] + pv_wl["敗戦"]

# 確認
pv_wl

df2 = df_total.copy()

# 評価値を作成
df2["評価値"] = ((df2["勝点"]) * 10000) + (df2["得失点"] * 100) + df2["得点"]
df2

# 評価値集計
df3 = df2.pivot_table(
    values="評価値", index="チーム名", columns="節", aggfunc=sum, fill_value=0
)
df3

# 評価値の累計和
df_eval = df3.apply(lambda d: d.cumsum(), axis=1)
df_eval

# 評価値から順位作成
df_chart = df_eval.rank(ascending=False, method="min").astype(int)
df_chart.sort_values(by=df_chart.columns[-1], inplace=True)
df_chart

# 最終順位取得
s1 = df_chart.iloc[:, -1]
s1.name = "順位"

df_diff = df_chart.diff(axis=1).fillna(0).astype(int)
df_diff

#  前節差分
s2 = df_diff.iloc[:, -1].apply(lambda x: "-" if x == 0 else "▼" if x < 0 else "▲")
s2.name = "前節"
s2

# 全部を結合
df4 = pd.concat([pv_score, pv_wl], axis=1).join([s1, s2])

# 順位で昇順
df4.sort_values(["順位"], inplace=True)

df_rank = df4.reset_index().loc[
    :,
    [
        "前節",
        "順位",
        "チーム名",
        "勝点",
        "試合数",
        "勝利",
        "勝利H",
        "勝利A",
        "引分",
        "引分H",
        "引分A",
        "敗戦",
        "敗戦H",
        "敗戦A",
        "得失点",
        "得点",
        "失点",
    ],
]

df_rank

print(df_rank.to_markdown(index=False))

順位表

2020/10/07現在

前節 順位 チーム名 勝点 試合数 勝利 勝利H 勝利A 引分 引分H 引分A 敗戦 敗戦H 敗戦A 得失点 得点 失点
1 Honda FC 18 8 5 2 3 3 2 1 0 0 0 11 15 4
2 ヴェルスパ大分 15 7 5 2 3 0 0 0 2 2 0 5 14 9
3 テゲバジャーロ宮崎 14 7 4 1 3 2 1 1 1 1 0 6 11 5
4 MIOびわこ滋賀 13 8 4 2 2 1 1 0 3 1 2 4 17 13
5 いわきFC 13 8 4 3 1 1 0 1 3 1 2 0 14 14
6 ソニー仙台FC 13 8 4 1 3 1 1 0 3 1 2 0 13 13
7 松江シティFC 12 9 4 3 1 0 0 0 5 1 4 -5 10 15
8 FC大阪 11 8 3 2 1 2 2 0 3 1 2 3 12 9
9 奈良クラブ 11 8 3 1 2 2 1 1 3 2 1 2 10 8
10 鈴鹿ポイントゲッターズ 11 8 3 2 1 2 0 2 3 3 0 0 9 9
11 ホンダロックSC 10 8 3 0 3 1 0 1 4 4 0 -7 8 15
12 東京武蔵野シティFC 8 6 2 2 0 2 0 2 2 1 1 1 7 6
13 ヴィアティン三重 8 8 2 1 1 2 1 1 4 2 2 -3 8 11
14 ラインメール青森 8 7 2 1 1 2 1 1 3 1 2 -5 7 12
15 FCマルヤス岡崎 5 8 1 0 1 2 1 1 5 3 2 -5 7 12
16 高知ユナイテッドSC 3 8 0 0 0 3 2 1 5 2 3 -7 9 16

つづき