(Testinho número 2) Quem o Luca deve convidar para dividir uma pizza que tenha um gosto mais parecido com o dele?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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