2章 その10
これまで、あるユーザに似たユーザリストを計算してから、似たユーザの持つリンクや映画をレコメンドしてきた。これをユーザベースの協調フィルタリング呼ぶらしい。
それに対して、あるアイテムがあり、それに似ているかどうか重み付けされたスコアを持つアイテムのリストを使う方法を、アイテムベースの協調フィルタリングと呼ぶ。
大規模な商業サイトの場合、ユーザもアイテムも数が多いので動的に全て計算していると間に合わなくなる。そこでアイテムベースの協調フィルタリングを使って計算数を減らしたい。アイテム間の関係性はユーザ間の関係性より変化が少ないから、適当な間隔(例えば数時間とか?)で計算しておけば良い。
というわけであるアイテムと似たアイテムリストを作る。
p.25より
recommendations.rbに calculateSimilarItems関数を追加
http://www.bitbucket.org/shokai/collective-intelligence-study/src/6ab36a2a5d95/recommendations.rb
# アイテムをキーとして持ち、それぞれのアイテムに似ている # アイテムのリストを値として持つディクショナリを作る def calculateSimilarItems(prefs, n=10) result = Hash.new # 嗜好の行列をアイテム中心な形に反転させる itemPrefs = transformPrefs(prefs) c = 0 itemPrefs.keys.each{ |item| # 巨大なデータセットを処理している時、100件毎に進行状況を表示 c += 1 puts c.to_s + '/' + itemPrefs.length.to_s if c % 100 == 0 # このアイテムにもっとも似ているアイテムたちを探す scores = topMatches(itemPrefs, item, n, :sim_distance) # ユークリッド距離で計算 result[item] = scores } return result end
その1で作った映画のスコアを使って、あるアイテムと似たアイテムリストを類似度付きで作成
irb
>> require 'recommendations.rb' => true >> require 'pp' => true >> c = Critics.new => #<Critics:0x66ebbc @users={"Jack Matthews"=>{"The Night Listener"=>3.0, "Superman Returns"=>5.0, "Lady in the Water"=>3.0, "Snake on a Plane"=>4.0, "You, Me and Dupree"=>3.5}, "Gene Seymour"=>{"The Night Listener"=>3.0, "Superman Returns"=>5.0, "Lady in the Water"=>3.0, "Snake on a Plane"=>3.5, "You, Me and Dupree"=>3.5, "Just My Luck"=>1.5}, "Mick LaSalle"=>{"The Night Listener"=>3.0, "Superman Returns"=>3.0, "Lady in the Water"=>3.0, "Snake on a Plane"=>4.0, "You, Me and Dupree"=>2.0, "Just My Luck"=>2.0}, "Toby"=>{"Superman Returns"=>4.0, "Snake on a Plane"=>4.5, "You, Me and Dupree"=>1.0}, "Claudia Puig"=>{"The Night Listener"=>4.5, "Superman Returns"=>4.0, "Snake on a Plane"=>3.5, "You, Me and Dupree"=>2.5, "Just My Luck"=>3.0}, "Lisa Rose"=>{"The Night Listener"=>3.0, "Superman Returns"=>3.5, "Lady in the Water"=>2.5, "Snake on a Plane"=>3.5, "You, Me and Dupree"=>2.5, "Just My Luck"=>3.0}, "Michael Phillips"=>{"The Night Listener"=>4.0, "Superman Returns"=>3.5, "Lady in the Water"=>2.5, "Snake on a Plane"=>3.0}}> >> pp itemsim = c.calculateSimilarItems(c.users) {"The Night Listener"=> [{0.285714285714286=>"Lady in the Water"}, {0.181818181818182=>"Snake on a Plane"}, {0.153846153846154=>"Just My Luck"}, {0.148148148148148=>"You, Me and Dupree"}, {0.102564102564103=>"Superman Returns"}], "Superman Returns"=> [{0.166666666666667=>"Snake on a Plane"}, {0.102564102564103=>"The Night Listener"}, {0.0909090909090909=>"Lady in the Water"}, {0.0645161290322581=>"Just My Luck"}, {0.0533333333333333=>"You, Me and Dupree"}], "Lady in the Water"=> [{0.4=>"You, Me and Dupree"}, {0.285714285714286=>"The Night Listener"}, {0.222222222222222=>"Just My Luck"}, {0.0909090909090909=>"Superman Returns"}], "Snake on a Plane"=> [{0.222222222222222=>"Lady in the Water"}, {0.181818181818182=>"The Night Listener"}, {0.166666666666667=>"Superman Returns"}, {0.105263157894737=>"Just My Luck"}, {0.0512820512820513=>"You, Me and Dupree"}], "You, Me and Dupree"=> [{0.4=>"Lady in the Water"}, {0.181818181818182=>"Just My Luck"}, {0.148148148148148=>"The Night Listener"}, {0.0533333333333333=>"Superman Returns"}, {0.0512820512820513=>"Snake on a Plane"}], "Just My Luck"=> [{0.222222222222222=>"Lady in the Water"}, {0.181818181818182=>"You, Me and Dupree"}, {0.153846153846154=>"The Night Listener"}, {0.105263157894737=>"Snake on a Plane"}, {0.0645161290322581=>"Superman Returns"}]} => nil