なんちゃってレーティング計算
例えば、A〜Dの4人の勝率マトリクスが以下のようになっていたときに、
A | B | C | D | |
---|---|---|---|---|
AのB,C,Dへの勝率 | 0.50 | 0.10 | 0.90 | 0.99 |
B | 0.90 | 0.50 | 0.80 | 0.99 |
C | 0.10 | 0.20 | 0.50 | 0.99 |
D | 0.01 | 0.01 | 0.01 | 0.50 |
このようなレーティングを計算するコードです(A=2150で固定とします)
A=2150
B=2429
C=1872
D=1204
レーティングの理論は本当は難しいのだろうけど、
次のように簡単な最小二乗法で求めてみました。
間違っていたらすいません。
まず、目的関数を勝率y[i][j]とレーティング関数p(x)との二乗差で定義します。
D=sum_ij(y[i][j] - p(x[i] - x[j]))^2
レーティング関数p(x)はx=150のときに0.7になるようなシグモイド関数を選びました。
次に、初期値x[i]を適当に設定して、上式の勾配、
∂D/∂x[i] = sum_j(y[i][j] - p(x[i] - x[j]))*p'(x[i] - x[j])
で更新します。これをなんどか繰り返せば、そのうち収束します。
#include <stdio.h> #include <stdlib.h> #include <math.h> // 勝率7割がR=150点差となるようなシグモイド関数p(x) double sig(double x) { return (exp(x/150.0)) / (1.0 + exp(x/150.0)); } double dsig(double x) { double a = (1.0 + exp(x/150.0)); return (exp(x/150.0)) / (a*a); } // // A,B,C,Dの4人のrartingを最急降下により求める。 // ただし、Aのratingは2150に固定。 // int main() { // 勝率マトリクス double y[16][16] = { // A B C D {0.50, 0.10, 0.90, 0.99}, // A のB, C, Dへの勝率 {0.90, 0.50, 0.80, 0.99}, {0.10, 0.20, 0.50, 0.99}, {0.01, 0.01, 0.01, 0.50} }; double x[16], dx[16]; int i, j, N, it; N = 4; // 人数 // 初期化 for(i = 0;i < N;i++) x[i] = 2150; // 適当に反復計算 for(it = 0;it < 10000;it++) { double err = 0.0; double max_dx = -100000; printf("x = [%d ", (int)x[0]); // 微分値初期化 for(i = 0;i < N;i++) { dx[i] = 0.0; } // 微分値を求める for(i = 1;i < N;i++) { for(j = 0;j < N;j++) { double d = x[i] - x[j]; double dv = (y[i][j] - sig(d)); dx[i] = dx[i] + dv * dsig(d); // 誤差もついでに計算 err += dv * dv; } // 微分値の最大値を保存 // 最大の更新量が1となるようにするため if(max_dx < fabs(dx[i])) max_dx = fabs(dx[i]); } // 更新実行 for(i = 1;i < N;i++) { x[i] = x[i] + 1.0 * dx[i] / max_dx; printf("%d ", (int)x[i]); } printf("] err = %.4f\n", err); } }