変更履歴
recommendations.py → recommendations.rb
映画評論家データ 今まで評価した映画の名前と評価値
# critics == 批評家, 鑑定家, 批判者, 評論家 critics = { '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 Listener' => 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, 'The Night Listener' => 3.0, 'You, Me and Dupree' => 3.5 }, 'Michael Phillips' => { 'Lady in the Water' => 2.5, 'Snakes on a Plane' => 3.0, 'Superman Returns' => 3.5, 'The Night Listener' => 4.0 }, 'Claudia Puig' => { 'Snakes on a Plane' => 3.5, 'Just My Luck' => 3.0, 'The Night Listener' => 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 Listener' => 3.0, 'You, Me and Dupree' => 2.0 }, 'Jack Matthews' => { 'Lady in the Water' => 3.0, 'Snakes on a Plane' => 4.0, 'The Night Listener' => 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 } }
2者間の距離ベース類似度スコアを返す
# Returns a distance-based similarity score for person1 and person2 def sim_distance prefs, person1, person2 # Get the list of shared_items si = prefs[person1].keys & prefs[person2].keys # if they have no ratings in common, return 0 return 0 if si.empty? # Add up the squares of all the differences sum_of_squares = si.inject(0){ |sos, item| sos += ((prefs[person1][item] - prefs[person2][item]) ** 2) } 1 / (1 + sum_of_squares) end
2者間のピアソンの積率相関係数を返す
# Returns the Pearson correlation coefficient for person1 and person2 def sim_pearson prefs, person1, person2 # Get the list of mutually rated items si = prefs[person1].keys & prefs[person2].keys # if they are no ratings in common, return 0 return 0 if si.empty? # Sum calculations n = si.size # Sums of all the preferences sum1, sum2 = 0, 0 si.each do |key| sum1 += prefs[person1][key] sum2 += prefs[person2][key] end # Sums of the squares sum1Sq, sum2Sq = 0, 0 si.each do |key| sum1Sq += prefs[person1][key] ** 2 sum2Sq += prefs[person2][key] ** 2 end # Sum of the products pSum = si.inject(0) { |sum,key| sum += prefs[person1][key] * prefs[person2][key] } # Calculate r (Pearson score) num = pSum - (sum1 * sum2 / n) den = Math.sqrt((sum1Sq - (sum1 ** 2) / n) * (sum2Sq - (sum2 ** 2) / n)) return 0 if den == 0 num / den end
# Returns the best matches for person from the prefs dictionary. # Number of results and similarity function are optional params. def topMatches prefs, person, n=5, similarity='sim_pearson' scores = [] prefs.keys.each do |other| if person != other scores << [method(similarity).call(prefs, person, other), other] end end scores.sort.reverse[0,n] end
# Gets recommendations for a person by using a weighted average # of every other user's rankings def getRecommendations prefs, person, similarity='sim_pearson' totals = {} simSums = {} prefs.keys.each do |other| # don't compare me to myself next if person == other sim = method(similarity).call(prefs, person, other) next if sim <= 0 prefs[other].each do |item,score| if (prefs[person][item] || 0) == 0 # Similarity * Score totals[item] ||= 0 totals[item] += prefs[other][item] * sim # Sum of similarities simSums[item] ||= 0 simSums[item] += sim end end end # Create the normalized list rankings = totals.map do |item, total| [total / simSums[item], item] end # Return the sorted list rankings.sort.reverse end