-
Notifications
You must be signed in to change notification settings - Fork 2
/
glicko.clj
88 lines (73 loc) · 2.91 KB
/
glicko.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
(ns ranking-algorithms.glicko
(:require [clojure.math.numeric-tower :as math]))
(defn as-glicko-opposition
[{ goals-for :for goals-against :against ranking :points rd :rd}]
{:opponent-ranking ranking
:opponent-ranking-rd rd
:score (cond (> goals-for goals-against) 1 (< goals-for goals-against) 0 :else 0.5)})
(defn initial-rankings [teams]
(apply array-map (mapcat (fn [x] [x {:points 1500.00 :rd 350.00}]) teams)))
(defn tidy [team]
(if (= "Rànger's" team) "Rangers" team))
(def q
(/ (java.lang.Math/log 10) 400))
(defn g [rd]
(/ 1
(java.lang.Math/sqrt (+ 1
(/ (* 3 (math/expt q 2) (math/expt rd 2))
(math/expt ( . Math PI) 2))))))
(defn e [rating opponent-rating opponent-rd]
(/ 1
(+ 1
(math/expt 10 (/ (* (- (g opponent-rd))
(- rating opponent-rating))
400)))))
(defn process-opponent [total opponent]
(let [{:keys [g e]} opponent]
(+ total
(* (math/expt g 2) e (- 1 e)))))
(defn d2 [opponents]
(/ 1 (* (math/expt q 2)
(reduce process-opponent 0 opponents))))
(defn update-ranking [ranking-delta opponent]
(let [{:keys [ranking opponent-ranking opponent-ranking-rd score]} opponent]
(+ ranking-delta
(* (g opponent-ranking-rd)
(- score (e ranking opponent-ranking opponent-ranking-rd))))))
(defn g-and-e
[ranking {o-rd :opponent-ranking-rd o-ranking :opponent-ranking}]
{:g (g o-rd) :e (e ranking o-ranking o-rd)})
(defn ranking-after-round
[{ ranking :ranking rd :ranking-rd opponents :opponents}]
(+ ranking
(* (/ q
(+ (/ 1 (math/expt rd 2))
(/ 1 (d2 (map (partial g-and-e ranking)
opponents)))))
(reduce update-ranking
0
(map #(assoc-in % [:ranking] ranking)
opponents)))))
(defn rd-after-round
[{ ranking :ranking rd :ranking-rd opponents :opponents}]
(java.lang.Math/sqrt (/ 1
(+ (/ 1 (math/expt rd 2))
(/ 1
(d2 (map (partial g-and-e ranking)
opponents)))))))
(defn c [rd t]
(java.lang.Math/sqrt (/ (- (math/expt 350 2)
(math/expt rd 2))
t)))
(defn updated-rd [old-rd c t]
(min (java.lang.Math/sqrt (+ (math/expt old-rd 2)
(* (math/expt c 2) t)))
350.00))
(defn process-match [ts match]
(let [{:keys [home away home_score away_score]} match]
(-> ts
(update-in [home :points]
#(ranking-after-round {:ranking %
:ranking-rd (:rd (get ts home))
:opponent-ranking (:points (get ts away))
:opponent-ranking-td (:rd (get ts away))})))))