集合知プログラミング 2.4をperl化してみた(レコメンデーション)

Tobyにおすすめを紹介。
pythonでかかれてたのでperlで以下どぎゃーん

#!/usr/bin/perl -w

use warnings;
use strict;
use Dumpvalue;

require 'pearson.pl';
require 'euclid.pl';

my %prefs = (
  'Lisa Rose' => {
    'Lady in the Water'  => 2.5,
    'Snakes on a Plane'  => 3.5,
    'Just My Luck'       => 3.0,
    'Superman Returns'   => 3.5,
    'You, Me and Dupree' => 2.5,
    'The Night Listner'  => 3.0,
  },
  'Gene Seymour' => {
    'Lady in the Water'  => 3.0,
    'Snakes on a Plane'  => 3.5,
    'Just My Luck'       => 1.5,
    'Superman Returns'   => 5.0,
    'You, Me and Dupree' => 3.5,
    'The Night Listner'  => 3.0,
  },
  'Michael Pillips' => {
    'Lady in the Water'  => 2.5,
    'Snakes on a Plane'  => 3.0,
    'Superman Returns'   => 3.5,
    'The Night Listner'  => 4.0,
  },
  'Claudia Puig' => {
    'Snakes on a Plane'  => 3.5,
    'Just My Luck'       => 3.0,
    'The Night Listner'  => 4.5,
    'Superman Returns'   => 4.0,
    'You, Me and Dupree' => 2.5,
  },
  'Mick LaSalle' => {
    'Lady in the Water'  => 3.0,
    'Snakes on a Plane'  => 4.0,
    'Just My Luck'       => 2.0,
    'Superman Returns'   => 3.0,
    'The Night Listner'  => 3.0,
    'You, Me and Dupree' => 2.0,
  },
  'Jack Matthew' => {
    'Lady in the Water'  => 3.0,
    'Snakes on a Plane'  => 4.0,
    'The Night Listner'  => 3.0,
    'Superman Returns'   => 5.0,
    'You, Me and Dupree' => 3.5,
  },
  'Toby' => {
    'Snakes on a Plane'  => 4.5,
    'You, Me and Dupree' => 1.0,
    'Superman Returns'   => 4.0,
  },
);

# person以外の全ユーザーの評点重み付き平均を使い、personへの推薦を算出する
sub getRecommendations {
  my($person, $simirarity) = @_;
  my(%totals,%simSums);
  
  foreach my $other(keys(%prefs)) {
    if ($other ne $person) {
      # $personと$otherの類似度算出
      my $sim = $simirarity->($person, $other);
      # スコアが低いのは無視
      if ($sim <= 0) {
        next;
      }
      
      foreach my $key(keys(%{$prefs{$other}})) {
        # 見た事がない映画のみをオススメする
        if (!$prefs{$person}{$key}) {
          # 類似性 * スコア
          $totals{$key} += $prefs{$other}{$key} * $sim;
          # 類似度を合計
          $simSums{$key} += $sim;
        }
      }
    }
  }
  
  # 正規化したリストを作る
  my @rankings = ();
  while (my($key,$val) = each(%totals)) {
    push(@rankings, [$val / $simSums{$key}, $key]);
  }
  # スコアが高い順にソート
  @rankings = sort { $b->[0] <=> $a->[0] } @rankings;
  
  return \@rankings;
}

# 評価者をランキング
Dumpvalue->new->dumpValue(getRecommendations('Toby', \&sim_pearson));

1;

# sql query for make hash
#SELECT * FROM user_mst;
#SELECT * FROM user_footprint WHERE user_id = ?

これだよこれ、これやりたかったの。
来週は三章をやろう。


・出力結果

yuki@sorauta corrective]$ perl getRecommendations.pl
0.1481481481481480  ARRAY(0x14298b80)
   0  3.3477895267131
   1  'The Night Listner'
1  ARRAY(0x14298c30)
   0  2.83254991826416
   1  'Lady in the Water'
2  ARRAY(0x14298a60)
   0  2.53098070376556
   1  'Just My Luck'