Jリーグのチームの本当の強さをベイズモデリングで分析してみた


はじめに

今年もJリーグが開幕しましたね!
で、このサッカーというスポーツはホームアドバンテージがかなり強く出るスポーツだと思っています。
CLなどのトーナメントでは、アウェイの点数は2倍にするなどそれを前提としたルールもあります。

私はどちらかというと野球(DeNA)ファンなのですが、野球はスタジアムの好みはあるものの、ホームアドバンテージが必ずしも有利になるということはないように思えます。
Deの守護神、山崎康晃は一時期ホーム以外は防御率0.00、だけどホームでは防御率6点以上ということにもなっていました(まあ狭いからという理由もありますけどね)

というわけでJリーグの各チームのうちホームアドバンテージを抜いても本当に強いチームはどこか? また逆にホームの利を生かしているチームはどこか?というのをベイズモデリングをつかって分析したいと思います。

ちなみに今回の記事は以下のBlogを参考にさせていただいています。
当Blogコードをそのまま流用している箇所については、今回載せませんので合わせてご覧ください

ベイズモデリングで男子プロテニスの強さを分析してみた

データ収集

さて分析するためには、まずデータが必要です。
そのためにはスクレイピングだ!!!・・・となるところですが、JリーグにはJ. League Data Siteというデータ提供サイトがあります。
さすがJリーグです、素晴らしい

そこでスクレイピングなどせずに、日程結果CSVをそのままDLします。
今回は2016-2018, J1/J2/ルヴァンカップに絞って利用します。
なおCSVには取得件数制限がありますので、何回かに分けて取得しています。

データとしてはこんな感じです。
欲しいホームアウェイ含めいろいろありますね。

前処理

今回分析はホームアドバンテージを考慮した強さの分析にあります。
そこで今回はホームアウェイどちらが勝ったかを加えます。
また引き分けは除外データとして削除します。

以下がコードです。色々余計なものもありますが、見なかったことにしてください。。。

df['score_arr'] = df['スコア'].str.split('-')

def func_cate(x):
    if  x[0] < x[1] :
        return 'A'
    elif x[0] > x[1] :
        return 'H'
    else:
        return 'D'

df['winner'] = df['score_arr'].apply(func_cate)
df.loc[df['winner'] == 'H', 'win_team'] = df['ホーム']
df.loc[df['winner'] == 'A', 'win_team'] = df['アウェイ']
df.loc[df['winner'] == 'D', 'win_team'] = 'DRAW'

df.loc[df['winner'] == 'H', 'lose_team'] = df['アウェイ']
df.loc[df['winner'] == 'A', 'lose_team'] = df['ホーム']
df.loc[df['winner'] == 'D', 'lose_team'] = 'DRAW'

df.drop(df.index[df['win_team'] == 'DRAW'], inplace=True)

結果がこちらです
後ろに追加カラムがありますね

分析モデル

このデータをベイズモデリングに投入し、分析していこうと思います。
今回はPyStanを使用しています。モデル式は以下の通りです。

model = """
    data {
        int N;
        int G;
        int<lower=1, upper=N> LW[G, 3];
    }
    parameters {
        ordered[2] performance[G];
        vector<lower=0>[N] mu;
        vector<lower=0>[N] home;
        real<lower=0> s_mu; 
        real<lower=0> h_mu; 
        vector<lower=0>[N] s_pf;
    }
    model {
        for (g in 1:G)
            for (i in 1:2)
                if ((i == 1 && LW[g, 3] == 1) || (i == 2 && LW[g, 3] == 2))
                    performance[g, i] ~ normal(mu[LW[g, i]] + home[LW[g, i]], s_pf[LW[g, i]]);
                else
                    performance[g, i] ~ normal(mu[LW[g, i]], s_pf[LW[g, i]]);

        mu ~ normal(0, s_mu);
        home ~ normal(0, h_mu);
        s_pf ~ gamma(10, 10);
    }
"""

参考サイトのモデルを回収し、以下のように変更しています。

ホームの場合には、μにアドバンテージとなる値を追加し、平均を右に移動しています。
またホームアドバンテージは必ずプラスになると仮定しているため宣言部はvector[N] home;とlower=0の制限をつけています。

あとはこれに投入しStanを回すだけですね。

結果

まずこちらがホームアドバンテージのない純粋なチームの強さになります。
文字化けしているのはApple Gothicのせいなので脳内変換してください

割と上位のチームが上に出ている中、松本山雅が強く出ていますね。
今年からJ1にあがった松本山雅ですが今シーズン要注目かもしれません。

そしてこちらがホームアドバンテージの強さです

こちらは割と幅が広いですね。
(全体的に0にかかっているので真面目に検定すると全部無効になってしまいそうですが、、)

平均値で高いのは札幌でしょうか。
日ハムといい北海道のスポーツ熱は強いのでしょう。
吉原宏太がいたような時代から熱狂的な印象があり、かつ札幌というちょっと遠目のロケーションが有利に働いているのかもしれませんね。

さいごに

今回は趣味として楽しく分析しただけのものですが、なかなか面白かったです
ベイズモデリングは自分でモデリングするため色々なことに適用できます
(Mー1で本当に面白かったのは誰?みたいなことをやっている方もいましたね)

今回のように色々な分析に使えるのでちょっとでも興味が湧きましたらぜひアヒル本あたりから勉強はしてはいかがでしょうか