]> git.sesse.net Git - wloh/blob - www/rating.pl
Train one model (with its own aux parms) per locale.
[wloh] / www / rating.pl
1 #! /usr/bin/perl
2 use strict;
3 use warnings;
4 no warnings qw(once);
5 use CGI;
6 use CGI::Carp qw( fatalsToBrowser );
7 use DBI;
8 use Encode;
9 use POSIX;
10 use HTML::Entities;
11 use utf8;
12 use locale;
13 require '../config.pm';
14 require '../common.pm';
15
16 my $dbh = DBI->connect($config::local_connstr, $config::local_username, $config::local_password)
17         or die "connect: " . $DBI::errstr;
18 $dbh->{AutoCommit} = 0;
19 $dbh->{RaiseError} = 1;
20
21 binmode STDOUT, ':utf8';
22
23 my $cgi = CGI->new;
24 my $locale = wloh_common::get_locale($cgi);
25
26 my $aux_parms = wloh_common::get_auxillary_parameters($dbh, $locale);
27 my $match_stddev = $aux_parms->{'score_stddev'} * sqrt(2.0);
28
29 print CGI->header(-type=>'text/html; charset=utf-8', -expires=>'+5m');
30 POSIX::setlocale(&POSIX::LC_ALL, 'nb_NO.UTF-8');
31
32 printf <<"EOF", $aux_parms->{'rating_prior_stddev'}, $match_stddev;
33 <?xml version="1.0" encoding="UTF-8" ?>
34 <!DOCTYPE
35   html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
36   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
37 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="no">
38   <head>
39     <title>WLoH-rating</title>
40     <link rel="stylesheet" href="style" type="text/css" />
41   </head>
42   <body>
43     <h1>WLoH-rating</h1>
44
45     <p><em>Dette er et hobbyprosjekt fra tredjepart, og ikke en offisiell del av
46       <a href="http://wordfeud.aasmul.net/">Wordfeud Leage of Honour</a>.</em></p>
47
48     <p>Ratingen er dog basert på spilledata fra WLoH (takk til Lobotommy
49       for tilgang!), og oppdateres
50       hver hele time. Den er fullstendig uoffisiell, og har ingen innflytelse
51       på WLoH, men brukes for å estimere vinnersannsynligheter i
52       <a href="index">sannsynlighetsberegningen</a>.</p>
53
54     <p>Modellen kan endre seg når som helst når jeg føler for det :-)
55       Ikke ta ratingen alt for alvorlig, selv om den er basert på
56       relativt fornuftige matematiske modeller. Husk at all statistikk
57       sier mer om fortiden enn om framtiden.</p>
58
59     <h2>Modellparametre</h2>
60
61     <p>For de som vet litt om slikt. Det finnes også en lengre, mer detaljert
62       <a href="ratings-explained">forklaring</a> beregnet på ikke-matematikere.</p>
63
64     <ul>
65       <li>MLE-basert modell med én skalar (styrke) per spiller og to globale skalarer (begge standardavvik, se under), løst med syklisk MM (minorization-maximization). Antall iterasjoner før konvergens: $aux_parms->{num_iterations}.</li>
66       <li>Rimelighetfunksjon, prior: Normalfordeling med µ=500, &sigma;=%.1f (est.)</li>
67       <li>Rimelighetfunksjon, per kamp: Normalfordeling med µ=(score1 - score2), &sigma;=%.1f (est.)</li>
68       <li>Vekting: Inneværende sesong samt de tre siste vektes fullt ut
69         (likt med prior). Deretter eksponentielt synkende vekting, med
70         halveringstid på tre sesonger. Spill som er registrert med
71         0-0, 150-0, 0-150 eller 150-150 ignoreres.</li>
72     </ul>
73
74     <h2>Divisjonsoversikt</h2>
75
76     <table>
77       <tr>
78         <th>Div.</th>
79         <th>Snitt</th>
80         <th>Std.avvik</th>
81       </tr>
82 EOF
83
84 my $season = wloh_common::get_max_season($dbh, $locale);
85
86 # Pick up all the subdivisions' ratings.
87 my %subdivision_ratings = ();
88 my $q = $dbh->prepare('SELECT divisjon, avdeling, serie_id, AVG(rating) AS avg_rating FROM ratings NATURAL JOIN siste_divisjon WHERE sesong=? GROUP BY divisjon, avdeling, serie_id ORDER BY divisjon, avdeling');
89 $q->execute($season);
90
91 while (my $ref = $q->fetchrow_hashref) {
92         my $division = $ref->{'divisjon'};
93         my $rating = $ref->{'avg_rating'};
94         my $id = $ref->{'serie_id'};
95
96         push @{$subdivision_ratings{$division}}, [ $id, $rating ];
97 }
98
99 $q = $dbh->prepare('SELECT divisjon,AVG(rating) AS avg_rating,STDDEV(rating) AS stddev_rating FROM ratings NATURAL JOIN siste_divisjon WHERE sesong=? GROUP BY divisjon ORDER BY divisjon');
100 $q->execute($season);
101
102 my $i = 0;
103 while (my $ref = $q->fetchrow_hashref) {
104         if (++$i % 2 == 0) {
105                 print "      <tr class=\"odd\">\n";
106         } else {
107                 print "      <tr class=\"even\">\n";
108         }
109         printf "        <th>%d.</th>\n", $ref->{'divisjon'};
110         printf "        <td class=\"num\">%.1f</td>\n", $ref->{'avg_rating'};
111         printf "        <td class=\"num\">%.1f</td>\n", $ref->{'stddev_rating'};
112
113         for my $arr (@{$subdivision_ratings{$ref->{'divisjon'}}}) {
114                 my ($id, $rating) = @$arr;
115                 printf "        <td class=\"num\"><a href=\"http://wordfeud.aasmul.net/serie-%d\">%.1f</a></td>\n", $id, $rating;
116         }
117         print "      </tr>\n";
118 }
119
120 print <<"EOF";
121     </table>
122
123   <h2>Rankingliste</h2>
124
125   <table>
126     <tr>
127       <th></th>
128       <th>Nick</th>
129       <th>Rating</th>
130       <th>Std.avvik</th>
131       <th>Sist sett</th>
132     </tr>
133 EOF
134
135 $q = $dbh->prepare('
136 SELECT *
137 FROM ratings
138   NATURAL JOIN kanonisk_navn
139   NATURAL JOIN siste_divisjon
140   NATURAL JOIN spiller_kultur
141 WHERE kultur=?
142 ORDER BY rating DESC');
143 $q->execute($locale);
144
145 $i = 0;
146 while (my $ref = $q->fetchrow_hashref) {
147         if (++$i % 2 == 0) {
148                 print "    <tr class=\"odd\">\n";
149         } else {
150                 print "    <tr class=\"even\">\n";
151         }
152         printf "      <th>%d.</th>\n", $i;
153         printf "      <td><a href=\"http://wordfeud.aasmul.net/bruker-%d\">%s</a></td>\n", $ref->{'id'}, HTML::Entities::encode_entities(Encode::decode_utf8($ref->{'navn'}));
154         printf "      <td class=\"num\">%.1f</td>\n", $ref->{'rating'};
155         printf "      <td class=\"num\">%.1f</td>\n", $ref->{'rating_stddev'};
156         printf "      <td><a href=\"http://wordfeud.aasmul.net/serie-%d\">%s</a></td>\n", $ref->{'serie_id'}, $ref->{'serie_navn'};
157         print "    </tr>\n";
158 }
159 print "    </table>\n";
160
161 wloh_common::output_last_sync($dbh);
162
163 print <<"EOF";
164   </body>
165 </html>
166 EOF
167
168 $dbh->rollback;