2章 その5

これまでで自分と似た趣向を持つ人を探したが、人ではなく商品をrecommendしたい。
趣向の相関係数を商品のスコアにかけ算する事で、似た趣向を持つ人の意見を重視して商品推薦を行う。



全員のスコアに相関係数をかけてからアイテムの平均スコアを求める
p.17より、getRecommendations関数を実装した
http://www.bitbucket.org/shokai/collective-intelligence-study/src/9af948109f04/recommendations.rb

  # その人(person)以外の全ユーザの評点で重み付けした平均を使い、personへの推薦を算出する
  def getRecommendations(prefs, person, similarity=:sim_pearson)
    totals = { }
    simSums = { }

    prefs.keys.each{ |other|
      next if other == person # 自分自身とは比較しない
      
      sim = self.method(similarity).call(prefs, person, other)
      
      next if sim <= 0 # 0以下のスコアは無視する
      
      prefs[other].keys.each{ |item|
        # まだ見ていない映画の得点のみ算出
        if !prefs[person].key?(item) or prefs[person][item] == 0
          # 類似度計算
          totals[item] = 0 if totals[item] == nil
          totals[item] += prefs[other][item] * sim
          # 類似度を合計
          simSums[item] = 0 if simSums[item] == nil
          simSums[item] +=  sim
        end
      }
    }      
    # 正規化したリストを作る
    rankings = { }
    totals.keys.each{|item|
      total = totals[item]
      rankings[total/simSums[item]] = item
    }

    # スコアが高い順に並べ替える
    result = Array.new
    rankings.keys.sort.reverse.each{ |score|
      result.push( {score => rankings[score]} )
    }
    
    return result
  end

指定しない場合ピアソン相関を使う
irb -r recommendations.rb

>> c.getRecommendations(c.users, 'Toby')
=> [{3.3477895267131=>"The Night Listener"}, {2.83254991826416=>"Lady in the Water"}, {2.53098070376556=>"Just My Luck"}]


ユークリッド距離による相関を使った場合の結果

>> c.getRecommendations(c.users, 'Toby', :sim_distance)
=> [{3.50024784014159=>"The Night Listener"}, {2.75612429399594=>"Lady in the Water"}, {2.46198848607437=>"Just My Luck"}]
>> 

どっちも同じような結果が返ってくるけど、アイテム数が増えたら変わってくるのかな