集合知プログラミング

chapter2

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
programming_collective_intelligence.txt · 最終更新: 2009/08/26 02:06 by fistfvck