M1

TD n°3 - Exercice 2

clients = [
  [4,   7,   nil, 4, 8,   2,   nil, nil, 2,   3  ],
  [3,   nil, 5,   4, nil, 5,   nil, 4,   1,   nil],
  [nil, 6,   4,   6, 2,   nil, 1,   3,   1,   nil],
  [nil, nil, 7,   5, 3,   nil, nil, nil, 2,   nil],
  [6,   2,   5,   9, 1,   9,   3,   nil, nil, 8  ],
  [3,   7,   4,   5, 7,   1,   1,   2,   3,   2  ],
  [nil, nil, 4,   4, nil, 3,   5,   5,   5,   4  ],
  [5,   1,   5,   8, nil, 7,   nil, 5,   nil, 7  ],
  [3,   2,   4,   9, 2,   nil, 1,   4,   nil, 7  ],
  [2,   8,   5,   4, nil, 2,   nil, 3,   1,   nil]
]

# Calcul des moyennes par client
moyennes = clients.collect(&:compact).map do |notes|
  notes.sum / notes.size.to_f
end

# Calcul du coefficient de Pearson
coeffs = clients.map.with_index do |xnotes, nx|
  rx = moyennes[nx]

  clients.map.with_index do |ynotes, ny|
    ry = moyennes[ny]

    numerateur   = 0
    denominateur = 0

    ynotes.each.with_index do |note, index|
      numerateur   += (xnotes[index].to_i - rx) * (note.to_i - ry)
      denominateur += (xnotes[index].to_i - rx)**2 * (note.to_i - ry)**2
    end

    (numerateur.to_f / Math.sqrt(denominateur)).abs
  end
end

# == Debug
# puts
# print "      |"
# puts 1.upto(clients.size).to_a.map { |i| sprintf("  c%-2d  |", i) }.join("")
#
# coeffs.each_with_index do |line, index|
#   printf " c%-2d  |", index+1
#
#   line.each_with_index do |value, lindex|
#     printf (lindex == index) ? "       |" : " % 2.2f |", value
#   end
#
#   puts
# end
#
# puts
# == Debug

# En partant du principe qu'on se place du point de vue
# du premier client, on conserve que les w supérieur à 1
# car d'après la consigne, x et y sont corrélés si w(x, y) > 1
c1coeffs = coeffs[0][1..-1].map do |w|
  w > 1 ? w : nil
end

somme, nb_client = 0, 0

c1coeffs.each.with_index do |coeff, nclient|
  # Si les deux clients ne sont pas corrélés, on passe
  # au suivant.
  next unless coeff

  # On regarde si le client corrélé a lu le livre numéro 3
  if note = clients[nclient][2]
    somme += note
    nb_client += 1
  end
end

# Finalement, si on a une moyenne supérieure ou égale à 4
# en prenant les notes des clients proches du premier, on
# peut proposer le livre, sinon, non.
if (moyenne = somme / nb_client.to_f) >= 4
  puts "Intéressant de proposer le livre"
else
  puts "Pas intéressant de proposer le livre"
end