Skip to content

Instantly share code, notes, and snippets.

@infoslack
Created December 12, 2011 15:02
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save infoslack/1467688 to your computer and use it in GitHub Desktop.
(Testinho número 2) Quem o Luca deve convidar para dividir uma pizza que tenha um gosto mais parecido com o dele?
# encoding: utf-8
DEBUG = 1
@people = {'Renato'=> {'Marguerita'=> 4, 'Quatro queijos'=> 5,
'Escarola'=> 4, 'Portuguesa'=> 5, 'Frango + Catupiry'=> 4,
'Napolitana'=> 3},
'Marcelo'=> {'Marguerita'=> 2, 'Quatro queijos'=> 2,
'Escarola'=> 1, 'Portuguesa'=> 3, 'Frango + Catupiry'=> 5,
'Napolitana'=> 2},
'Lenon'=> {'Marguerita'=> 4, 'Quatro queijos'=> 5,
'Escarola'=> 2, 'Portuguesa'=> 1, 'Frango + Catupiry'=> 1,
'Napolitana'=> 3},
'Renata'=> {'Marguerita'=> 4, 'Quatro queijos'=> 5,
'Escarola'=> 1, 'Portuguesa'=> 1, 'Frango + Catupiry'=> 3,
'Napolitana'=> 4},
'Washington'=> {'Marguerita'=> 1, 'Quatro queijos'=> 1,
'Escarola'=> 2, 'Portuguesa'=> 3, 'Frango + Catupiry'=> 4,
'Napolitana'=> 3},
'Tino'=> {'Marguerita'=> 1, 'Quatro queijos'=> 5,
'Escarola'=> 1, 'Portuguesa'=> 4, 'Frango + Catupiry'=> 3,
'Napolitana'=> 2},
'Luca'=> {'Marguerita'=> 5, 'Quatro queijos'=> 4,
'Escarola'=> 3, 'Portuguesa'=> 4, 'Frango + Catupiry'=> 3,
'Napolitana'=> 2}}
def new_example; puts "\n" + "-" * 80; end
# ESCALA DE CORRELAÇÃO DE PEARSON
# RETORNA O COEFICIENTE DA CORRELAÇÃO DE PEARSON PARA P1 E P2
# VALORES DE CORRELAÇÃO MAIS PRÓXIMOS DE 1 SIGNIFICA MAIOR
def pearson(people, p1, p2)
sum1 = sum2 = sum1_sq = sum2_sq = length = 0
people[p2][people[p1].to_a.first.first]
sum_of_products = people[p1].inject(0) do |product_sum, rating|
if people[p2][rating.first]
sum1 += people[p1][rating.first]
sum2 += people[p2][rating.first]
sum1_sq += people[p1][rating.first] ** 2
sum2_sq += people[p2][rating.first] ** 2
length += 1
product_sum + people[p1][rating.first] * people[p2][rating.first]
else
product_sum
end
end
num = sum_of_products - (sum1 * sum2 / length)
den = Math.sqrt((sum1_sq - (sum1 ** 2) / length) * (sum2_sq - (sum2 ** 2) / length))
return "den == 0" if den == 0
num/den
end
# CLASSIFICAÇÃO DAS NOTAS DAS PIZZAS
# RETORNA OS MELHORES RESULTADOS PARA DESCOBRIR QUEM TEM O GOSTO PARECIDO COM O DE LUCA
def top_matches(people, person, n=7)
scores = people.map do |critic, items|
unless person == critic
[(block_given? ? yield(people, person, critic) : pearson(people, person, critic)), critic]
end
end
scores.compact.sort.reverse[0..n]
end
if DEBUG > 0
new_example
test = top_matches(@people, 'Luca', 2) { |people, person, critic| pearson(people, person, critic) }
puts "#{test.join(", ")} should equal #{[[0.7071067811865476, 'Renato'],[0.3273268353539886, 'Lenon'],[0.1091089451179962, 'Tino']]}"
end
# OBTEM RECOMENDAÇÃO PARA O LUCA USANDO A MÉDIA PONDERADA
# COMPARANDO A SIMILARIDADE TOTAL DO GOSTO MAIS PARECIDO COM O DO LUCA
def recommendations(people, person)
totals = Hash.new(0.0)
sim_sums = Hash.new(0.0)
people.each do |critic, items|
next if critic == person
sim = block_given? ? yield(people, person, critic) : pearson(people, person, critic)
next if sim <= 0
people[critic].each do |item, rating|
next if people[person][item]
totals[item] += people[critic][item] * sim
sim_sums[item] += sim
end
end
rankings = totals.map {|item, total| [total/sim_sums[item], item] }
rankings.sort.reverse
end
def transform_hash(people)
h = Hash.new {|hash, key| hash[key] = {}}
people.each do |person, ratings|
ratings.each {|item, rating| h[item][person] = rating }
end
h
end
if DEBUG > 0
new_example
items = transform_hash(@people)
test = top_matches(items, 'Marguerita')
puts "#{test.join(", ")}"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment