Rubyで書くアイテムの推薦

前回は評者の相関まで計算しました.
そこで,この値を使って映画の推薦をしてしまおう,という魂胆です.

推薦値の計算

正直,ちょっと長いです.
もっとすっきり書きたかったんですが,何やってるか分かるでしょうか...

module My
  class Recommender
    #
    # 評価者相関と映画評価の積で一番の映画を推薦する
    #
    def get_recommendations(critics, me, user_options = {})
      options = {
        :similarity => 'get_pearson_correlation',
      }.merge(user_options)

      # 最初に値を参照した際に、nilで返さないように0で初期化する
      recommendations = Hash.new(0)
      similarities = Hash.new(0)
      (others = critics.keys).delete(me)

      # other(自分以外)ごとの推薦値を算出する
      others.each do |other|
        similarity = send(options[:similarity], critics, me, other)
        # 逆相関の評価者は推薦に使わない
        next if similarity <= 0

        # 映画の評価値と相関値を掛ける
        critics[other].each do |movie, critic|
          recommendations[movie] += (critic * similarity)
          similarities[movie] += similarity
        end
      end

      # 自分が批評済のものは無駄なので削除
      # ただし、評価を0点にしていたものは残す
      recommendations.delete_if { |movie, critic|
        critics[me].keys.include?(movie) and critics[me][movie] != 0.0
      }.map { |movie, critic|
        # 相関値の総和で正規化する
        [movie, critic.quo(similarities[movie])]
      }.sort_by { |movie, recommendation|
        recommendation
      }.reverse
    end
  end
end

実行結果

以下のように呼び出す部分を足して,実行してみます.

recommender = My::Recommender.new
puts recommender.get_recommendations(critics, 'Toby')
puts '----------'
puts recommender.get_recommendations(critics, 'Toby', { :similarity => 'get_euclidean_similarity' })

いざ,実行!

% ./recommender.rb
The Night Listener
3.3477895267131
Lady in the Water
2.83254991826416
Just My Luck
2.53098070376556
----------
The Night Listener
3.50024784014159
Lady in the Water
2.75612429399594
Just My Luck
2.46198848607437

本文のp.17と同じ結果が得られました.