2021年NPBの7割前後終了時点で、シーズンをイロレーティングとモンテカルロシミュレーションで予想してみる

#最初に

イロレーティングでシーズン後にレーティングを出しているのを見ていて、あれ？
シーズン途中でレーティングを出して、それからモンテカルロシミュレーションで順位を予想することができるじゃないかと思いやってみました。

レーティングでは、**疑似的に勝率**を出すことができるため、それをモンテカルロシミュレーションを使えば順位を確率の形で表現は可能です。

#レーティングとシミュレーションに関して

[イロレーティング](https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%AD%E3%83%AC%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0)の計算方法や[モンテカルロシミュレーション](https://ja.wikipedia.org/wiki/%E3%83%A2%E3%83%B3%E3%83%86%E3%82%AB%E3%83%AB%E3%83%AD%E6%B3%95)は、wikipedia等をご参照ください。


ここでイロレーティングは簡易方式を採用しました。

```
R'a = Ra+ 32xWba
R'b = Rb- 32xWba
Wba=(Rb-Ra)/800 + 0.5
```

Wbaは、BがAに勝つ勝率を意味するため、モンテカルロシミュレーションであるさいころが振ることで、試合の勝ち・負けを計算できます。

また、シーズンスタート時のレーティングですが、1,500でスタートしています。

2021年は交流戦もあったため、セパ同時にレーティングを出しています。交流戦以外に使われることないのですが、もしかすると日本シリーズでこのレーティングが活用できるかもしれません。

これらの計算からすでに終了済みの試合からレーティングを出し、その値をからまだ行われていない試合をレーティングから勝利を確率的に出し、シーズンの勝ち星を予想します。当然の予想の中の勝敗でレーティングも変更していきます。

これを3,000回繰り返して、シーズン順位の確率を求めるのがモンテカルロシミュレーションになります。

:::note info
3,000回は統計上有意義な数字です。これを増やせば精度が上がると考えないほうがいいと思います。
:::


#実行

##実行条件

python3が実行できる環境でき、インターネットを使うことができる環境ならば
実行可能です。

##ソース

ソースは、2つです。githubに上げています。

[npb2021_rating_monte](https://github.com/rakichiki/npb2021_rating_monte.git)

ここにある2つのソース(download_np.py,monte.py)をダウンロードしてください。

##注意点

実行するうえで3つほど注意を。

1つ目は、beautifulsoup4のインストールです。以下の手順で行いました。

```
 python3 -m venv myenv
 source ./myenv/bin/activate

 python3 -m pip install black

 which black

 pip install beautifulsoup4
```

beautifulsoup4を使っていますが、正直、構造化されていないhtmlはbeautifulsoup4だけで必要な情報を取得できず、
力技でデータを取得しました。泣きそう...


2つ目は、windows 10のwsl2のubuntuでやったのですが、以下の設定が必要でした。
sslのエラーが出たらこの設定してみてください(NPBさん、頑張りませんか？)。

[https://designetwork.daichi703n.com/entry/2020/10/03/openssl-seclevel-ubuntu-focal](https://designetwork.daichi703n.com/entry/2020/10/03/openssl-seclevel-ubuntu-focal)

3つ目として、このツール類は、シーズン中に実行することを前提に組まれています。
シーズン後にこのサイトを見て、実行した場合には、どうなるかわかりません。

実行時にNPBから現時点のデータをとってきているので、残り試合とか計算しています。
このため、シーズン後はどうなっているのか皆目見当がつきません。外部のデータをよりどころにしているのためですが（試験用のデータとかあったほうがいいのでしょうけど）。


##使い方

pythonが動くターミナルから以下を実行してください。

```
# python download_np.p
```

NPBのサイトから勝敗の情報と残り試合を取得し、取得時のレーティングと成績を求めています。

終了後、3つのファイル（now_rating.json,result_team.json,yotei.json）を作成します。また、データ取得時のレーティングなども飾らず表示しています。

ここで問題が生じます。

```
登録試合数
{'ヤデ': 24, 'ヤ巨': 25, 'ヤ中': 25, 'ヤ広': 24, 'ヤ神': 25, 'デ巨': 25, 'デ中': 25, 'デ広': 25, 'デ神': 25, '巨中': 25, '巨広': 25, '巨神': 25, '中広': 25, '中神': 25, '広神': 25, 'ロ楽': 25, ' ロ日': 21, 'ロ西': 25, 'ロオ': 25, 'ロソ': 25, '楽日': 25, '楽西': 25, '楽オ': 24, '楽ソ': 24, '日西': 24, '日オ': 25, '日ソ': 25, '西オ': 25, '西ソ': 25, 'オソ': 25}

成績
{'ヤ': {'win': 48, 'lost': 38, 'even': 12}, 'デ': {'win': 39, 'lost': 52, 'even': 13}, '巨': {'win': 52, 'lost': 39, 'even': 13}, '中': {'win': 39, 'lost': 51, 'even': 14}, '広': {'win': 39, 'lost': 52, 'even': 10}, '神': {'win': 58, 'lost': 42, 'even': 3}, 'ロ': {'win': 47, 'lost': 39, 'even': 15}, '楽': {'win': 47, 'lost': 44, 'even': 13}, '日': {'win': 35, 'lost': 48, 'even': 15}, '西': {'win': 39, 'lost': 48, 'even': 17}, 'オ': {'win': 50, 'lost': 40, 'even': 14}, 'ソ': {'win': 44, 'lost': 44, 'even': 17}}

レーティング
{'ヤ': 1530, 'デ': 1507, '巨': 1524, '中': 1444, '広': 1493, '神': 1496, 'ロ': 1578, '楽': 1472, '日': 1496, '西': 1440, 'オ': 1539, 'ソ': 1481}
```

現在NPBに記載されている予定試合の箇所は、まだ雨天中止時の開催日が登録されているものがあります。

このため、登録試合（これは試合終了した試合数と予定試合数を足したもの）が２５になっていない組み合わせがまだＮＰＢのサイトに記載が不足している試合になります。

上の表記は、2021/9/5時点のため変動があると思います。
この差分を入れるために、monte.pyに

```monte.y
yotei.append({"date": "20211025", "shiai": [{"team1": "ヤ", "team2": "デ"}, {"team1": "ロ", "team2": "日"}, {"team1": "楽", "team2": "オ"}]})
yotei.append({"date": "20211026", "shiai": [{"team1": "ヤ", "team2": "広"}, {"team1": "ロ", "team2": "日"}, {"team1": "楽", "team2": "ソ"}]})
yotei.append({"date": "20211027", "shiai": [{"team1": "ロ", "team2": "日"}]})
yotei.append({"date": "20211028", "shiai": [{"team1": "ロ", "team2": "日"}]})
yotei.append({"date": "20211029", "shiai": [{"team1": "日", "team2": "西"}]})
```

不足分を強引に入れています。

このため、もし、2021/9/5以降で過不足ある場合は、上記を修正してください。team1/2はどっちに入れてもかまいません（ホーム・ビジターの概念がないので、どっちでもいい）。


データ取得時のレーティングと残り試合の組み合わせが取れましたので、レーティングの勝率の出し方とモンテカルロシミュレーションで勝敗決めて、順位予想をしてみます。

```
# python monte.py
```

実行すると、以下のように表示されます（数字はランダム要素を含んでいるので毎回微妙に違います）。

数字は、各順位になる確率で%になります。並びは、期待順位が高い順に並べています(うまく表示できなかった)。

```
セリーグ順位予想
team  1       2       3       4       5       6
巨    33.7    32.6    22.8    8.3    2.0    0.6
神    32.2    32.8    25.3    7.9    1.7    0.1
ヤ    32.1    27.3    24.2    10.1    4.7    1.6
デ    0.8    3.2    11.1    28.5    31.2    25.2
広    0.8    3.0    10.5    27.0    30.5    28.3
中    0.3    1.1    6.1    18.2    29.9    44.3

パリーグ順位予想
team  1       2       3       4        5       6
ロ    49.3    28.3    11.9    6.4    3.2    0.8
オ    36.1    34.1    16.7    8.8    3.4    0.8
楽    6.5    15.8    27.9    26.0    16.6    7.2
ソ    5.7    13.9    23.9    25.7    21.0    9.7
日    1.7    4.9    10.8    18.2    28.2    36.2
西    0.7    3.0    8.7    14.8    27.5    45.3
```

整形した以下になります。

セリーグ順位予想

|team  |1       |2       |3       |4       |5       |6|
|:----:|:------:|:------:|:------:|:------:|:------:|:------:|
|巨    |33.7    |32.6    |22.8    | 8.3    | 2.0    | 0.6|
|神    |32.2    |32.8    |25.3    | 7.9    | 1.7    | 0.1|
|ヤ    |32.1    |27.3    |24.2    |10.1    | 4.7    | 1.6|
|デ    | 0.8    | 3.2    |11.1    |28.5    |31.2    |25.2|
|広    | 0.8    | 3.0    |10.5    |27.0    |30.5    |28.3|
|中    | 0.3    | 1.1    | 6.1    |18.2    |29.9    |44.3|


パリーグ順位予想

|team  |1       |2       |3       |4       | 5      | 6  |
|:----:|:------:|:------:|:------:|:------:|:------:|:------:|
|ロ    |49.3    |28.3    |11.9    | 6.4    | 3.2    | 0.8|
|オ    |36.1    |34.1    |16.7    | 8.8    | 3.4    | 0.8|
|楽    | 6.5    |15.8    |27.9    |26.0    |16.6    | 7.2|
|ソ    | 5.7    |13.9    |23.9    |25.7    |21.0    | 9.7|
|日    | 1.7    | 4.9    |10.8    |18.2    |28.2    |36.2|
|西    | 0.7    | 3.0    | 8.7    |14.8    |27.5    |45.3|



なんかそれっぽいと思うか、それとも、なんか微妙に違うな的に見えるかもしれません。これがあっているどうかは、2021/10末ぐらいにわかります。外れても、すいません、これっぽちも保障することはありません。

ついでに、これを書いているの中の人は、ちなロでも、ちな巨でもありません。

ループ数は3,000回していますが、お好みで変更してみてください（統計上これっぽちも推奨しません。それは誤差という概念があるので、繰り返し数を増やしても意味はありません。だって、1mmの単位のものさしで、nmは測れませんよ）。

また、勝利数の分布などを出してみるのもいいかもしれませんね（気が向いたら）。

#問題

イロレーティングとモンテカルロシミュレーションでNPBのシーズン予想をしてみましたが、いくつか問題があるのではないかと思っています。

##問題１：引き分け問題

イロレーティングは勝ち負けしか評価できないので、引き分けをシミュレーションできません。2021年シーズンは特殊で9回終了します。このため、　例年以上に引き分けが発生しています。2021年シーズは、だいたい１００試合で１２試合前後引き分けになっています（たった1チームは異常に少ないですが）

残り４０試合前後のため、5試合前後引き分けが出てくると想定されます。その考慮は少し難しいのではないかと考えています。

##問題２：野球というリーグ戦の問題

野球は、イロレーティングを評価しづらい問題があります。それは、野球は常に全力で戦えないところです。

野球はどうしても投手に偏った成績が出やすいですが、その投手は全試合出れるわけではありません。スターターは、せいぜい6試合に1回しか出れませんし、勝ちパも2試合に1回も出れば、監督もしくは投手コーチの運用方針を疑うレベルです。

このため、常に全力で試合ができないため、どうしてイロレーティングでは野球は評価が難しいスポーツの1つです。

ただし、調子の上下や覚醒などは、他のスポーツでもあるため、確率論でしか議論できないイロレーティングやモンテカルロ法では誤差の範囲でしょうから、それは考慮不要だと考えています。

##問題３：新型コロナ等の不測発生時の問題

2021年前後特有の問題である新型コロナによる選手の大幅隔離の可能性があることです。

2021年、数チームが新型コロナのため大幅に選手離脱しています。そこで一気に成績を下げたチームもあります（そうでないチームもありましたが）。

少数のメンバーの怪我や調子悪化等は、チームスポーツや確率論で成績を求めるイロレーティングならば誤差の範囲のうちでしょう。ですが、主力が４，５人欠けるほどの大幅離脱はさすがにイロレーティングの計算（減算）の範囲を超えると思います。

選手の方々はワクチン接種＋2週間経過していると思われるため、後半は陽性になる可能性は大幅に減少している思いますが（り患も確率論に過ぎないので...）、

それでも何があるかわかりません。もし、新型コロナで陽性になりチームが大幅に戦力減少になった場合は、予想するのも難しい状況になるでしょう。

##問題４：イロレーティングを野球リーグ適応の問題

イロレーティングを導入しているKに32を使いましたが、競技によっては任意のようです。これは、競技の性質によって関係しているのだと思います。Kの値が大きいほど、レイティングがアクティブに、低いほど非活発に動きます。

ＮＰＢのチームの勝率が6割前後から4割前後です。この差が小さいと見るか、大きいと見るかは、人によります。

ですが、テニス星人が席巻しているテニス界や、新しい将棋星人を迎えた将棋界のような非常に強力なプレイヤーとか弱い地球人（界隈外から見れば化け物ですが）を比較しないといけないイロレーティングで、実力差がそこまでないチーム戦とはそのまま使うには整合性があわないのかもしれません。

もう少し野球に見合ったＫの値（私の感覚ではもう少し小さい値）を使えば実情に合うのではないかと思います。

##問題５：スタート時のレーティング

これはシーズンスタート時に皆レーティングを1,500でスタートしています。選手の入れ替えなどされているため、シーズン開始時に1,500で足並みを揃えるのはそれほど悪い方式だと思えません。

ですが、このため、レーティングが安定するまである程度の試合数を経過しないといけません。それが、30試合なのか、それともそうではないのかわかりません。サッカー等の代表の評価は、年をまたいで変わるかわけではありませんので、もう少し前年から引き継いだほうがいいのかもしれません。

ただし、NPBは前年最下位から優勝するケースは、たまに発生する事象のため、前年の成績はそれほど重要視する必要性はないのかもしれません。

#今後

今後、これが受けたら、2つのことをしてもいいかと思っています。

1. 過去のシーズンを途中で予想して、どの時点ぐらいでレーティング＆モンテカルロシミュレーションで予想確率が上げられるのか調べる。
2. Kの値が32固定ではなく、柔軟に変更して、レーティングとその予想にどの程度変わるか、適切か調べる。