2章 その11

その10で、ある映画に似ている映画とその類似度を取れるようになった。
自分がこれまで評価した映画に付けたスコアと、まだ見ていない映画との類似度を使って、まだ見ていない映画に何点をつけるかを予測する。


p.26~27より
recommendations.rb にgetRecommendedItems関数を追加
http://www.bitbucket.org/shokai/collective-intelligence-study/src/36aef661a53f/recommendations.rb

  def getRecommendedItems(prefs, itemMatch, user)
    userRatings = prefs[user]
    scores = Hash.new
    totalSim = Hash.new
    
    #このユーザに評価されたアイテムをループする
    userRatings.each{ |item, rating|

      # このアイテムに似ているアイテムたちをループする
      itemMatch[item].each{ |i|
        i.each{ |similarity, item2|

          # このアイテムに対してユーザがすでに評価を行っていれば無視する
          next if userRatings.key?(item2)
          
          # 評点と類似度を掛け合わせたものの合計で重みづけする
          scores[item2] = 0 if !scores.key?(item2)
          scores[item2] += similarity * rating
          
          # すべての類似度の合計
          totalSim[item2] = 0 if !totalSim.key?(item2)
          totalSim[item2] += similarity
        }
      }
    }
    
    # 正規化のため、それぞれの重み付けしたスコアを類似度の合計で割る
    rankings = Hash.new
    scores.each{ |item, score|
      rankings[ score/totalSim[item] ] = item
    }
    
    # 降順に並べて配列に入れたランキングを返す
    result = Array.new
    rankings.keys.sort.reverse.each{ |score|
      result.push( {score => rankings[score] } )
    }
    return result
  end


p.27より、Tobyにオススメする映画リストを計算

>> pp c.getRecommendedItems(c.users, itemsim, 'Toby')
[{3.18263473053892=>"The Night Listener"},
 {2.59833187006146=>"Just My Luck"},
 {2.47308781869688=>"Lady in the Water"}]
=> nil

アイテム同士の類似度は先に計算されているので、毎回呼び出さなくてすんでいる