LoginSignup
11
10

More than 5 years have passed since last update.

得失点データを使ってサッカーJ1のランキングを考える

Posted at

ランキングを考える

J1の勝ち点の表を見ていて「上位チームに勝つのも下位チームに勝つのも、同じ勝ち点3って何だかなぁ」とふと思いました。リーグ内のチーム/競技者数が多い対戦スポーツほど(たとえば相撲)、こういった格差というものを感じます。

お仕事の関係で読み進めていた本で、強さを考慮したランキングの考え方が紹介されていたので、J1の結果を使ってチームの強さを考えてみました。

OD手法

今回参考にしたのは以下の本です。
レイティング・ランキングの数理 ―No.1は誰か?―

難しい証明は流し読みしてしまえば、アルゴリズム系の書籍としては読みやすい部類です。
惜しむらくは、ランキングの例として多用されているのがNFL等のデータで、「ラッシングヤード数が~」等と書かれてもいまいちイメージがつかないところ。

この本では色々なランキングの考え方・手法が紹介されていますが、今回考えたいJリーグのランキングに一番ハマりそうな手法として「OD手法」というものを選んでみました。

OD手法では、チームのランキングを攻撃力(Offensive rating)と守備力(Defensive rating)を定義して評価するのですが、

(第7章 攻撃力・守備力レイティング手法 より)
攻撃力と守備力の間には循環的な関係があり、攻撃力と守備力を個別にレイティングしようとする場合、各々は他を考慮に入れなければならないのである。

という辺りをどう解決するか、が第7章に書かれています。

Rで実装(というほどのものでもない...)

OD手法の細かい説明は書籍に譲るとして、実際のデータに当てはめてRで実行してみます。
適当に書いているので汚いコードで恐縮ですが、とてもシンプルな方法というのは分かってもらえるかと思います。

  • Jリーグ2015年セカンドステージの第1~16戦までの結果を利用(Jリーグ公式より拝借)
  • 実行環境は R 3.1.3
od.R
# 得失点のマトリックスを作る
a <- matrix(
  c(
    0, 2, 3, 0, 1, 1, 0, 1, 1, 1, 3, 3, 1, 3, 0, 0, 1, 0,
    1, 0, 2, 2, 0, 2, 0, 2, 1, 1, 2, 2, 1, 3, 3, 1, 3, 2,
    4, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 0, 4, 3, 1, 1, 1, 1,
    1, 2, 4, 0, 0, 2, 1, 0, 0, 1, 1, 2, 1, 3, 1, 2, 0, 3,
    0, 2, 2, 2, 0, 2, 3, 0, 6, 0, 2, 4, 5, 4, 2, 0, 0, 5,
    0, 1, 1, 0, 0, 0, 1, 0, 0, 2, 0, 1, 0, 0, 1, 1, 2, 2,
    0, 0, 0, 1, 1, 0, 0, 0, 2, 1, 1, 1, 1, 1, 0, 1, 0, 0,
    2, 1, 1, 2, 1, 1, 3, 0, 0, 1, 3, 2, 0, 3, 3, 3, 3, 0,
    0, 1, 1, 0, 0, 1, 2, 2, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0,
    2, 0, 0, 1, 0, 0, 0, 2, 1, 0, 2, 1, 2, 1, 2, 1, 3, 2,
    1, 2, 1, 1, 0, 0, 3, 2, 2, 0, 0, 2, 1, 1, 1, 1, 0, 2,
    0, 1, 0, 1, 0, 0, 3, 0, 2, 1, 1, 0, 5, 2, 2, 7, 0, 0,
    1, 0, 1, 2, 1, 0, 2, 0, 0, 1, 1, 0, 0, 0, 2, 0, 0, 2,
    1, 1, 1, 1, 3, 0, 1, 2, 3, 1, 0, 1, 1, 0, 0, 0, 0, 1,
    2, 5, 1, 0, 1, 3, 0, 1, 3, 1, 2, 0, 3, 0, 0, 1, 0, 6,
    0, 1, 1, 1, 0, 0, 3, 0, 2, 1, 0, 1, 0, 1, 1, 0, 3, 0,
    0, 1, 0, 1, 3, 2, 0, 2, 2, 0, 0, 2, 3, 1, 1, 2, 0, 3,
    0, 3, 2, 0, 2, 4, 3, 0, 1, 1, 4, 2, 2, 0, 1, 0, 1, 0
  ), 18, 18
)

a_label <- c("Tokyo", "Osaka", "Urawa", "Yokohama", "Hiroshima", "Ko-fu", "Yamagata", "Kashima", "Matsumoto", 
             "Sho-nan", "Niigata", "Ko-be", "Shimizu", "Sendai", "Kawasaki", "Tosu", "Kashiwa", "Nagoya")

# 初期ベクトル
d1 <- as.vector(rep(1:1, length = 18))
d2 <- as.vector(rep(0:0, length = 18))

# 交互精緻化プロセス
iterate_func <- function(a_mat, d_cur) {
  d_next <- a_mat %*% (1/(t(a_mat) %*% (1/d_cur)))
  return(d_next)
}

i <- 0
repeat{
  d2 <- iterate_func(a, d1)
  i <- i + 1
  if( as.double(sqrt(as.vector(d1-d2) %*% as.vector(d1-d2))) >= 0.000001 ) d1 <- d2
  else break
}

o <- t(a) %*% (1/d2)
plot(d2, o, type="n")
text(d2, o, a_label)

結果

こんな感じになりました(四角内の数字は16節時点での実際の順位)。
OD_J1.png

OD手法では

  • Offensive ratingが高い = 攻撃力が高い
  • Defensive ratingが低い = 防御力が高い

となるので、上図で言うと以下のように評価出来ます。

  • 左上 = 攻撃力・守備力共に高い(広島、鹿島など)
  • 左下 = 攻撃力は低いが、守備力が高い(FC東京、甲府など)
  • 右上 = 攻撃力は高いが、守備力が低い(名古屋、大阪など)
  • 右下 = 攻撃力・守備力共に低い(山形・清水など)

勝ち点や得失点だけが並んだ殺風景な順位表よりは、直感的な視覚化になりました(多分)。
勝ち点ベースで評価される実際の順位とも、それほど違和感がない感じになりました。やっぱり広島強いですね…。
個別チームについて細かくコメントするとJリーグ大好きな知人に刺されそうなので、どう評価するかは皆さんにお任せです。

おまけ

J1がそこそこ面白い結果だったので、相撲でも同じことが出来ないかと考えてやってみました。

  • 対戦データはこちらからお借りしました
  • 得点の概念がないので、勝ち星をそのまま得点と見立てています

OD_SUMO.png

白鵬の異常な強さが良くわかる結果になりました。
が、勝ち星を得点と見立てた都合上、比較的新顔の力士は負け数も少ない = 防御力が高いと判定されています。
うーん。一工夫必要な感じ。

11
10
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
11
10