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

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

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

# OD手法
今回参考にしたのは以下の本です。
[レイティング・ランキングの数理 ―No.1は誰か？―](http://www.amazon.co.jp/dp/4320123905)

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

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

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

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

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

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

 - Jリーグ2015年セカンドステージの第1~16戦までの結果を利用([Jリーグ公式](http://www.jleague.jp/stats/SFMS01.html)より拝借)
 - 実行環境は R 3.1.3

```rconsole: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](https://qiita-image-store.s3.amazonaws.com/0/105203/2888f3a2-94fe-02d9-78ef-d00075c9d99f.png)

OD手法では

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

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

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

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

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

- 対戦データは[こちら](http://blog.livedoor.jp/taguchi_sumo/archives/1044513528.html)からお借りしました
- 得点の概念がないので、勝ち星をそのまま得点と見立てています

![OD_SUMO.png](https://qiita-image-store.s3.amazonaws.com/0/105203/b7056532-8854-0a2f-0aa0-86121539c484.png)

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