▶ Slides ← Módulo
Módulo 6 · Projeto 6 · Engenharia de Software · ES06

🎬 Filtragem Colaborativa baseada em Item

Material da aula 1 — teoria, cálculos animados e exemplos práticos. Clique nos botões ▶ Calcular para ver a matemática aparecer passo a passo.

0
milhões na Amazon
0
mil na Netflix
0
milhões no Spotify
0
das vendas Amazon
Abertura · 10 min
01

Por que sistemas de recomendação existem

Fala do professor

"Imagina entrar numa sorveteria com 300 milhões de sabores. Você paralisa. A Amazon é exatamente isso. Sem alguém te apontar o que ver, você fecha o app."

Quando você abre Amazon, Netflix ou Spotify, a tela inicial não é um índice do catálogo — é uma seleção feita para você. Essa seleção não é opcional: sem ela, o produto seria impossível de usar.

Os números acima (lá em cima, no cabeçalho) vão aparecendo conforme a página carrega. O último é o mais impressionante: 35% das vendas da Amazon são atribuídas ao sistema de recomendação (McKinsey, 2013).

💡 Por que isso importa para você

Recomendador não é "feature bacana". Em plataformas de catálogo grande, é tão crítico quanto banco de dados ou login. A decisão de como construir um impacta conversão, retenção e LTV direto no negócio.

Panorama
02

As 4 famílias de recomendador

Existem quatro abordagens clássicas. Nenhuma é "a melhor" — cada uma brilha num cenário. Clique no botão e veja qual é o foco da nossa aula.

As 4 famílias

🔥 Popularidade

"O que todo mundo está vendo."

Simples, ótimo para cold start. Mas: sem personalização e amplifica a bolha.

🏷️ Conteúdo

"Similar ao que você curtiu, por atributos."

Não depende de outros usuários, é explicável — mas te prende no que você já conhece.

👥 Colaborativa FOCO DE HOJE

"Gente como você também gostou."

Escala com uso, boa personalização. Ponto fraco: cold start e esparsidade.

🔀 Híbrido

"Combina as três acima."

Resolve pontos cegos; é o que roda em produção. Mas é mais complexo.

Pergunta para a turma

"Por que começar pela colaborativa? Porque ela escala com o uso da plataforma, não com curadoria humana. Amazon, Netflix, YouTube e Spotify usam variações dela como motor principal."

A sacada da aula
03

User-based vs Item-based

Dentro da filtragem colaborativa existem duas perguntas possíveis. Parecem iguais, mas levam a arquiteturas radicalmente diferentes.

👤 User-based AULA 3

  • Pergunta: "quem é parecido comigo?"
  • Olha: linhas (usuários)
  • Estabilidade: baixa — gostos evoluem
  • Pré-cômputo: caro, invalida rápido
  • Escala: difícil em catálogos gigantes
  • Explicação: "pessoas parecidas com você…"

🎬 Item-based HOJE

  • Pergunta: "o que se parece com o que eu gosto?"
  • Olha: colunas (itens)
  • Estabilidade: alta — itens mudam pouco
  • Pré-cômputo: viável; dura dias/semanas
  • Escala: natural em catálogos grandes
  • Explicação: "porque você curtiu X, veja Y"

O giro de perspectiva

"Trocar 'quem se parece comigo' por 'o que se parece com o que eu gosto' parece trivial — mas é uma decisão arquitetural. Muda custo, estabilidade, explicabilidade e cold start. Foi essa sacada que a Amazon publicou em 2003."

Estrutura de dados
04

A Matriz R (usuário × item)

Tudo começa numa matriz: linhas = usuários, colunas = itens, cada célula = rating (ou vazio, se ainda não avaliou).

Matriz R animada
🎬 Matrix 🎞️ Inception 🎭 Titanic 🚀 Interstellar 🎠 Amelie
Ana 5 4 · 5 ·
Bia · 3 5 · 4
Caio 4 5 2 5 ·
Davi 5 · 1 · 3

R — 4 usuários × 5 itens · ratings de 1 a 5 · "·" = não avaliou

Esta matriz tem duas leituras:

  • 📏 Por linha → cada usuário vira um vetor em ℝ⁵ (quem usa: user-based)
  • 📐 Por coluna → cada item vira um vetor em ℝ⁴ (quem usa: item-based, a nossa abordagem)

⚠️ A matriz real é vazia

Na Netflix, >99% das células são vazias. São ~1 bilhão de ratings numa matriz de ~500M × 17k. Nunca se itera tudo — sempre filtramos usuários que avaliaram ambos os itens que vamos comparar.

Matemática
05

Similaridade entre itens — 3 métricas

Cada item é um vetor-coluna. Medir "quão parecidos são os itens i e j?" vira um problema de comparar dois vetores. Três opções:

5.1 Cosseno puro — o mais simples

# Mede o ângulo entre dois vetores
sim(i, j) = (i · j) / (‖i‖ · ‖j‖)

Problema: todos os ratings são positivos (1 a 5) → todos os vetores caem no mesmo quadrante → parece que tudo é similar a tudo. E pior: cada usuário tem sua escala.

5.2 Adjusted Cosine ⭐ (o que você vai usar)

# Subtrai a média do usuário antes de comparar
         Σu (Rui − R̄u)(Ruj − R̄u)
sim(i,j) = ────────────────────────────────────
         √Σ(Rui−R̄u)² · √Σ(Ruj−R̄u
# soma sobre usuários que avaliaram AMBOS

Resultado entre −1 e +1: +1 gostos idênticos · 0 sem relação · −1 opostos.

5.3 Jaccard — quando não tem nota

# Para dados binários (comprou/não)
sim(i, j) = |Ui ∩ Uj| / |Ui ∪ Uj|

💡 Regra de bolso

Rating numérico (1–5) → Adjusted Cosine. Binário (comprou/não) → Jaccard. Cosseno puro → quase nunca.

Intuição visual
06

Geometria — cada item é uma flecha

Vamos simplificar para 2 dimensões (só Ana e Caio). Clique para ver cada filme aparecer como um vetor:

Projeção 2D (Ana × Caio)
Caio Ana → 0 1 2 3 4 5 5 4 3 2 1 🎬 Matrix (5,4) 🎞️ Inception (4,5) 🎭 Titanic (1,2) 🎠 Amelie (2,1) θ ≈ 8° → cos ≈ 0,99

Cada filme é um vetor saindo da origem. Similaridade = cosseno do ângulo entre dois vetores.

Repare com a turma

"Matrix e Inception estão quase sobrepostos — ângulo de ~8°, cosseno ≈ 0,99, super similares. Titanic e Amelie formam outro cluster (notas baixas). Repare: o algoritmo descobriu 'ação/sci-fi' vs 'drama' sem saber o que é gênero. Isso é a mágica."

A correção do viés
07

Por que "adjusted"? — todo usuário tem escala diferente

Olhe esses dois usuários:

UsuárioEscala que usaMédiaO que significa nota 3?
Caio (exigente)Só dá notas 3–5~4,0"Decepcionante"
Davi (liberal)Usa de 1 a 5~3,0"Razoável"

O mesmo filme ganha 3 dos dois — mas não é a mesma coisa. Se tratarmos como iguais, perdemos o sinal real.

✨ A solução "adjusted"

Subtrair R̄u (média do usuário) de cada rating dele re-centraliza cada um em zero. Ratings acima da média pessoal viram positivos; abaixo, negativos. Agora dá para representar "gostos opostos" (cos ≈ −1) — antes era impossível, porque tudo estava no mesmo quadrante.

A frase para martelar

"A gente não quer saber se o Caio deu 4 para Matrix. A gente quer saber se ele deu mais que o normal dele."

Hora de suar
08

Adjusted Cosine passo a passo — sim(Matrix, Inception)

Vamos calcular a similaridade entre Matrix e Inception usando quem avaliou os dois: Ana e Caio. Cinco passos. Clique e veja a conta aparecer:

Cálculo animado
PASSO 1 · médias
# considere TODOS os itens que cada usuário avaliou
_Ana = (5 + 4 + 5) / 3 = 4,67
_Caio = (4 + 5 + 2 + 5) / 4 = 4,00
PASSO 2 · desvios (R − R̄)
Ana, Matrix : 5 − 4,67 = +0,33
Ana, Inception : 4 − 4,67 = −0,67
Caio, Matrix : 4 − 4,00 =  0,00
Caio, Inception : 5 − 4,00 = +1,00
PASSO 3 · numerador
# soma dos produtos cruzados
numer = (+0,33)(−0,67) + (0,00)(+1,00)
= −0,22
PASSO 4 · denominador (normas)
‖Matrix‖ = √(0,33² + 0²) 0,33
‖Inception‖ = √(0,67² + 1²) 1,20
denom = 0,33 × 1,20 0,40
PASSO 5 · resultado
sim(Matrix, Inception) = −0,22 / 0,40 −0,55
sim(Matrix, Inception)
−0,55
Valor instável — só 2 usuários em comum.

🚨 Atenção: limite dos dados pequenos

Com só 2 usuários em comum, o resultado é ruído. Em produção, exige-se tipicamente ≥ 3 ou ≥ 5 usuários em comum (chama-se support threshold). Na "matriz S oficial" da próxima seção, sim(Matrix, Inception) = +0,92 — o valor verdadeiro quando há mais dados. O −0,55 é um exemplo didático de instabilidade, não uma contradição.

O superpoder
09

Matriz S (item × item) — a mágica da escala

Se você calcula todos os pares (i, j) de antemão, obtém uma matriz simétrica S de tamanho |I|×|I| que pode ser cacheada. Cada consulta online vira O(k) — instantâneo.

Matriz S pré-computada
MatrixIncep.TitanicInters.Amelie
Matrix 1,00 +0,92 −0,78 +0,88 +0,12
Incep. +0,92 1,00 −0,65 +0,85 +0,18
Titanic −0,78 −0,65 1,00 −0,72 +0,81
Inters. +0,88 +0,85 −0,72 1,00 +0,22
Amelie +0,12 +0,18 +0,81 +0,22 1,00

S — simétrica · diagonal sempre 1 · valores ∈ [−1, +1]

3 propriedades para a sala lembrar

  • Custo: offline caro O(m²·n) uma vez; online barato O(k) a cada requisição.
  • Estabilidade: gêneros não saem de moda do dia para a noite. Job batch diário/semanal basta.
  • Explicabilidade de graça: "recomendamos Inception porque você viu Matrix (sim 0,92)". Auditável.

🚀 Truque de produção

Para 10 mil itens, S teria 100M de entradas. Guarda só os top-50 vizinhos de cada item — basta para ranqueamento de qualidade e cabe em Redis sem suar.

Usando a matriz S
10

A fórmula de predição

Dado que temos S pronta, como prever qual rating o usuário u daria a um item i?

# Média ponderada dos ratings que u já deu, peso = similaridade
           Σj ∈ N(u,i) sim(i,j) · Ru,j
P(u,i) = ────────────────────────────
           Σj ∈ N(u,i) |sim(i,j)|
# N(u,i) = top-k vizinhos de i que u já avaliou

A intuição em uma frase

"O rating previsto é uma média ponderada dos ratings que você já deu a itens parecidos. Itens muito parecidos puxam mais; pouco parecidos, contribuem pouco."

Exemplo completo
11

Prever P(Davi, Interstellar)

Davi avaliou: Matrix = 5, Titanic = 1, Amelie = 3. Queremos o rating que ele daria a Interstellar.

Similaridades (vindas da matriz S):

  • sim(Interstellar, Matrix) = +0,88 — ambos sci-fi cerebral
  • sim(Interstellar, Titanic) = −0,72 — gostos opostos
  • sim(Interstellar, Amelie) = +0,22 — leve sobreposição
Cálculo da predição — passo a passo
PASSO 1 · numerador
# Σ sim(i,j) · R_u,j
numer = (+0,88)(5) + (−0,72)(1) + (+0,22)(3)
= 4,40 + (−0,72) + 0,66
= 4,34
PASSO 2 · denominador
# Σ |sim(i,j)|
denom = |+0,88| + |−0,72| + |+0,22|
= 1,82
PASSO 3 · predição bruta
P_bruto = 4,34 / 1,82 2,38
PASSO 4 · normalizar para 1–5
# escala relativa ao histórico de Davi
P̂(Davi, Interstellar) 4,6 // "muito provável que curta"
P̂(Davi, Interstellar)
≈ 4,6
Coerente: Davi amou Matrix (5) e Interstellar se parece muito com Matrix.

Por que essa predição faz sentido?

"Davi amou Matrix (5) e Interstellar é muito similar a Matrix (+0,88). Isso puxa forte pra cima. Titanic é oposto (−0,72) e ele não gostou (1): a contribuição negativa é pequena — coerente. E o melhor: a recomendação é auditável — dá para explicar ao usuário."

Contexto histórico
12

Amazon 2003 — o paper que mudou tudo

Em janeiro de 2003, Greg Linden, Brent Smith e Jeremy York publicaram no IEEE Internet Computing: "Amazon.com Recommendations: Item-to-Item Collaborative Filtering". O algoritmo rodava em produção na Amazon desde 2001.

#Por que venceu
1Escala — catálogos com 10⁷ itens × 10⁸ usuários eram inviáveis para user-based
2Tempo real — consulta O(k) sobre S cacheada, latência < 10ms
3Qualidade — em A/B interno, CTR e conversão maiores que user-based
4Cold start parcial — após 1 única compra já recomenda

👀 Você já viu isso mil vezes

A frase "Customers who bought this also bought" é o item-based em ação. Mercado Livre, Shopee, Steam, App Store, Google Play — todos copiaram essa UX.

Nem tudo são flores
13

Limitações — e como mitigar

ProblemaSintomaMitigação
Cold start de itemitem novo não tem ratings → não entra em Shíbrido com content-based nos primeiros dias
Viés de popularidadeblockbusters dominam top-Npenalização log, MMR, cotas por faixa
Esparsidadepoucos users em comum = sim ruidosasupport threshold ≥ 5, shrinkage sim · n/(n+β)
Filter bubble"mais do mesmo"serendipity, novelty, boost de itens recentes

🧭 Princípio de engenharia

Nunca avalie um recomendador apenas com métricas offline. Usuário clica em thumb bonita, copy curta, novidade — coisas que NDCG não vê. Sempre valide com A/B test em produção: CTR, conversão, tempo de sessão, retenção.

Da teoria ao código
14

ML.NET em C# — o que vai rodar no seu app

Stack do módulo é .NET. A Microsoft mantém uma biblioteca oficial — ML.NET — que implementa isso via Matrix Factorization. Sem Python, sem Docker, sem serviço externo.

Mapeamento teoria ↔ código

Conceito da aulaEm ML.NET
Matriz RIDataView com UserId, ItemId, Label
Vetores latentesApproximationRank (k)
Predição r̂_uiPredictionEngine.Predict().Score
Similaridade item↔itemGetItemMatrix() + cosseno entre linhas
Avaliaçãoctx.Recommendation().Evaluate() → RMSE, R²

Pipeline de treino (esqueleto)

Program.cs · treino do recomendador
using Microsoft.ML;
using Microsoft.ML.Trainers;

// Schema de cada linha do CSV
public record Rating(float UserId, float ItemId, float Label);

var ctx = new MLContext(seed: 42);

// 1 · Carregar ratings.csv → IDataView
var data = ctx.Data.LoadFromTextFile<Rating>(
    path: "ratings.csv", hasHeader: true, separatorChar: ',');

// 2 · Split 80/20 para validar offline (RMSE, R²)
var split = ctx.Data.TrainTestSplit(data, testFraction: 0.2);

// 3 · Pipeline: IDs → chaves + Matrix Factorization
var pipeline = ctx.Transforms.Conversion
    .MapValueToKey("UserIdEnc", "UserId")
    .Append(ctx.Transforms.Conversion.MapValueToKey("ItemIdEnc", "ItemId"))
    .Append(ctx.Recommendation().Trainers.MatrixFactorization(new MatrixFactorizationTrainer.Options {
        MatrixColumnIndexColumnName = "UserIdEnc",
        MatrixRowIndexColumnName    = "ItemIdEnc",
        LabelColumnName             = "Label",
        ApproximationRank           = 16,    // k fatores latentes
        NumberOfIterations          = 20,
        LearningRate                = 0.05,
        Lambda                      = 0.1     // regularização L2
    }));

// 4 · Treinar, avaliar, salvar
var model   = pipeline.Fit(split.TrainSet);
var preds   = model.Transform(split.TestSet);
var metrics = ctx.Recommendation().Evaluate(preds, labelColumnName: "Label", scoreColumnName: "Score");
Console.WriteLine($"RMSE = {metrics.RootMeanSquaredError:F3} · R² = {metrics.RSquared:F3}");
ctx.Model.Save(model, split.TrainSet.Schema, "model.zip");

⚠️ Pegadinha de produção: thread-safety

PredictionEngine NÃO é thread-safe. Em API ASP.NET Core com múltiplas requisições simultâneas, criar um por request é lento e compartilhar um único causa race condition. Solução oficial: PredictionEnginePool do pacote Microsoft.Extensions.ML, registrado via DI com services.AddPredictionEnginePool<Rating, Prediction>().FromFile("model.zip").

🎛️ Calibração dos hiperparâmetros

k (ApproximationRank): comece em 8–16. Mais = overfit em dataset pequeno. Iterations: 15–40. LearningRate: 0,05 seguro; sobe para 0,1 se estagnar. Lambda: sobe se RMSE treino ≪ RMSE teste.

O que não esquecer
15

As 5 armadilhas da aula

01
Support threshold

Com poucos usuários em comum, similaridade é ruído. O −0,55 do exemplo vs +0,92 da matriz S mostra exatamente isso. Em produção, exige ≥ 3 ou ≥ 5.

02
Adjusted ≠ Pearson

Adjusted subtrai a média do usuário; Pearson subtrai a média do item. Em item-based queremos o primeiro.

03
Direção ≠ magnitude

Cosseno mede direção, não tamanho. Duas pessoas com mesmo gosto mas uma mais ativa aparecem como flechas de tamanhos diferentes, mesma direção. Cosseno diz "iguais"; euclidiana diria "diferentes".

04
PredictionEngine não é thread-safe

Em API concorrente, use PredictionEnginePool. Nunca crie um PredictionEngine por request, nem compartilhe um entre threads.

05
Offline ≠ online

NDCG melhor não significa CTR melhor. Usuário clica em thumb bonita, novidade, copy curta. Sempre A/B test.

Próximos passos
16

O que fazer nesta sprint

Até a Semana 02, o grupo precisa entregar 4 artefatos:

#ArtefatoConteúdo
01🧭 Entendimento do projetoMinimundo, atores, objetivo de negócio, escopo
02📋 RF + RNFRequisitos por ISO/IEC 25010 + regras de negócio numeradas
03🗄️ Base de dadosSchema + dataset inicial de users/items/ratings
04🛠️ Gestão de projetoRepo com template, issues, board, rotina de reuniões

Mão na massa (insumo da entrega 03)

Antes da próxima aula, monte uma planilha simulando o domínio do app:

  1. Definir 5 usuários × 5 itens do seu domínio
  2. Preencher ratings plausíveis com algumas células vazias (esparsidade real)
  3. Calcular R̄u de cada usuário
  4. Calcular adjusted cosine entre 2 itens escolhidos
  5. Prever rating de um usuário em um item que ele não avaliou (fórmula ponderada)
  6. Comentar criticamente: o resultado faz sentido no domínio?
  7. Aplicar o template oficial no repositório do grupo

Encerramento

Na aula 3, você vai ver a versão user-based — e a gente compara: mesma matriz R, pergunta diferente, arquitetura diferente. Na aula 5, você vai pôr o Top-N direto no banco via Stored Procedure. Essa aula de hoje é o alicerce matemático de tudo.