]> git.sesse.net Git - wloh/blobdiff - train.pl
Load the covariance table before doing anything else, since that process can happen...
[wloh] / train.pl
index 119b738dd4cddf322fee45107db587cb4df1dd47..084f84b91c14f60029fe98f0b3e9dfcdb845f92f 100755 (executable)
--- a/train.pl
+++ b/train.pl
@@ -6,17 +6,16 @@ no warnings qw(once);
 use POSIX;
 require './config.pm';
 
-my $dbh = DBI->connect($config::local_connstr, $config::local_username, $config::local_password)
-       or die "connect: " . $DBI::errstr;
-$dbh->{AutoCommit} = 0;
-$dbh->{RaiseError} = 1;
-
 # Find last completely done season 
-my $ref = $dbh->selectrow_hashref('SELECT sesong FROM fotballserier GROUP BY sesong HAVING COUNT(*)=COUNT(avgjort=1 OR NULL) ORDER BY sesong DESC LIMIT 1');
-my $last_season = $ref->{'sesong'};
+sub find_last_season {
+       my $dbh = shift;
+       my $ref = $dbh->selectrow_hashref('SELECT sesong FROM fotballserier GROUP BY sesong HAVING COUNT(*)=COUNT(avgjort=1 OR NULL) ORDER BY sesong DESC LIMIT 1');
+       return $ref->{'sesong'};
+}
 
-# Fetch games
-my $q = $dbh->prepare('
+sub fetch_games {
+       my ($dbh, $last_season, $games, $ids) = @_;
+       my $q = $dbh->prepare('
 SELECT
   deltager1.id as p1, deltager2.id as p2, maalfor, maalmot, least(pow(2.0, (sesong - ? + 3) / 3.0), 1.0) AS vekt
 FROM
@@ -25,44 +24,94 @@ FROM
   JOIN Fotballdeltagere deltager2 ON resultater.Motstander=deltager2.Nr AND resultater.Serie=deltager2.Serie
   JOIN Fotballserier serier on resultater.Serie=serier.Nr
 WHERE deltager1.Nr > deltager2.nr
-');
-$q->execute($last_season);
-
-my @games = ();
-my %ids = ();
+       ');
+       $q->execute($last_season);
 
-while (my $ref = $q->fetchrow_hashref) {
-       next if ($ref->{'maalfor'} == 150 && $ref->{'maalmot'} == 0);
-       next if ($ref->{'maalfor'} == 0 && $ref->{'maalmot'} == 150);
-       next if ($ref->{'maalfor'} == 150 && $ref->{'maalmot'} == 150);
-       push @games, { %$ref };
-       $ids{$ref->{'p1'}} = 1;
-       $ids{$ref->{'p2'}} = 1;
+       while (my $ref = $q->fetchrow_hashref) {
+               next if ($ref->{'maalfor'} == 150 && $ref->{'maalmot'} == 0);
+               next if ($ref->{'maalfor'} == 0 && $ref->{'maalmot'} == 150);
+               next if ($ref->{'maalfor'} == 150 && $ref->{'maalmot'} == 150);
+               next if ($ref->{'maalfor'} == 0 && $ref->{'maalmot'} == 0);
+               push @$games, { %$ref };
+               $ids->{$ref->{'p1'}} = 1;
+               $ids->{$ref->{'p2'}} = 1;
+       }
 }
 
-# Output to file
-my $tmpnam = POSIX::tmpnam();
-open DATA, ">", $tmpnam
-       or die "$tmpnam: $!";
+sub output_to_file {
+       my ($games, $ids) = @_;
 
-printf DATA "%d\n", scalar keys %ids;
-for my $id (keys %ids) {
-       printf DATA "%d\n", $id;
-}
-for my $ref (@games) {
-       printf DATA "%d %d %d %d %f\n", $ref->{'p1'}, $ref->{'p2'}, $ref->{'maalfor'}, $ref->{'maalmot'}, $ref->{'vekt'};
+       my $tmpnam = POSIX::tmpnam();
+       open DATA, ">", $tmpnam
+               or die "$tmpnam: $!";
+
+       printf DATA "%d\n", scalar keys %$ids;
+       for my $id (keys %$ids) {
+               printf DATA "%d\n", $id;
+       }
+       for my $ref (@$games) {
+               printf DATA "%d %d %d %d %f\n", $ref->{'p1'}, $ref->{'p2'}, $ref->{'maalfor'}, $ref->{'maalmot'}, $ref->{'vekt'};
+       }
+       close DATA;
+
+       return $tmpnam;
 }
-close DATA;
 
-$dbh->do('DELETE FROM ratings');
-my $iq = $dbh->prepare('INSERT INTO ratings ( id, rating, rating_stddev ) VALUES (?, ?, ?)');
+sub train_model {
+       my ($filename, $ratings, $covariances, $aux_params) = @_;
+
+       open RATINGS, "$config::base_dir/bayeswf < $filename |"
+               or die "bayeswf: $!";
+       while (<RATINGS>) {
+               chomp;
+               my @x = split;
+               if ($x[0] eq 'covariance') {
+                       push @$covariances, (join("\t", @x[1..3]));
+               } elsif ($x[0] eq 'aux_param') {
+                       push @$aux_params, ("nb-NO" .  "\t" . $x[1] . "\t" . $x[2]);
+               } else {
+                       push @$ratings, ($x[2] . "\t" . $x[0] . "\t" . $x[1]);
+               }
+       }
 
-open RATINGS, "$config::base_dir/bayeswf < $tmpnam |"
-       or die "bayeswf: $!";
-while (<RATINGS>) {
-       /(.*) (.*) (.*)/ or next;
-       $iq->execute($3, $1, $2);
+       close RATINGS;
 }
 
-$dbh->commit;
+my $dbh = DBI->connect($config::local_connstr, $config::local_username, $config::local_password)
+       or die "connect: " . $DBI::errstr;
+$dbh->{AutoCommit} = 0;
+$dbh->{RaiseError} = 1;
+
+$dbh->do('SET client_min_messages TO WARNING');
+
+my $last_season = find_last_season($dbh);
+my @games = ();
+my %ids = ();
+fetch_games($dbh, $last_season, \@games, \%ids);
+my $tmpnam = output_to_file(\@games, \%ids);
+
+my @ratings = ();
+my @covariances = ();
+my @aux_params = ();
+train_model($tmpnam, \@ratings, \@covariances, \@aux_params);
 unlink($tmpnam);
+
+$dbh->do('CREATE TABLE new_covariance ( player1 smallint NOT NULL, player2 smallint NOT NULL, cov float NOT NULL )');
+$dbh->do('COPY new_covariance ( player1, player2, cov ) FROM STDIN');
+$dbh->pg_putcopydata(join("\n", @covariances));
+$dbh->pg_putcopyend();
+$dbh->do('ALTER TABLE new_covariance ADD PRIMARY KEY ( player1, player2 );');
+$dbh->do('DROP TABLE IF EXISTS covariance');
+$dbh->do('ALTER TABLE new_covariance RENAME TO covariance');
+
+$dbh->do('TRUNCATE aux_params');
+$dbh->do('COPY aux_params ( kultur, id, value ) FROM STDIN');
+$dbh->pg_putcopydata(join("\n", @aux_params));
+$dbh->pg_putcopyend();
+
+$dbh->do('TRUNCATE ratings');
+$dbh->do('COPY ratings ( id, rating, rating_stddev ) FROM STDIN');
+$dbh->pg_putcopydata(join("\n", @ratings));
+$dbh->pg_putcopyend();
+
+$dbh->commit;