Estou um pouco confuso com o modo como o SVD é usado na filtragem colaborativa. Suponha que eu tenha um gráfico social e construa uma matriz de adjacência a partir das bordas e faça um SVD (vamos esquecer a regularização, as taxas de aprendizado, as otimizações de escassez etc.), como uso esse SVD para melhorar minhas recomendações?
Suponha que meu gráfico social corresponda ao instagram e fui encarregado de recomendar usuários no serviço, com base apenas no gráfico social. Primeiro, eu construí uma matriz de adjacência , pega o SVD, , escolhe os primeiros autovalores, e daí?
Presumivelmente, eu criaria um novo conjunto de matrizes: então o que se faz?
Eu olhei na Web, e a maioria dos links se concentra no cálculo do SVD, mas ninguém lhe diz o que fazer com ele. Então, o que eu deveria fazer?
fonte
Respostas:
No entanto: com SVD puro de baunilha, você pode ter problemas para recriar a matriz original, e muito menos prever valores para itens ausentes. A regra prática nesta área é calcular a classificação média por filme e subtrair essa média para cada combinação de usuário / filme, ou seja, subtrair o viés do filme de cada usuário. Em seguida, é recomendável que você executar SVD, e, claro, você teria que gravar esses valores viés em algum lugar, a fim de classificações de recriar ou prever para valores desconhecidos. Eu li o post de Simon Funk no SVD para recomendações - ele inventou uma abordagem incremental de SVD durante a competição da Netflix.
http://sifter.org/~simon/journal/20061211.html
Eu acho que a matriz degradante A antes do SVD faz sentido, já que o primo próximo do SVD, PCA, também funciona de maneira semelhante. Em termos de computação incremental, Funk me disse que, se você não rebaixar, a primeira direção do gradiente domina o restante da computação. Eu já vi isso em primeira mão, basicamente sem coisas humilhantes não funcionam.
fonte
Eu gostaria de oferecer uma opinião divergente:
Bordas ausentes como valores ausentes
Em um problema de filtragem colaborativa, as conexões que não existem (o usuário não avaliou o item , a pessoa não fez amizade com a pessoa ) geralmente são tratadas como valores ausentes a serem previstos, e não como zeros. Ou seja, se o usuário não avaliado item de , queremos adivinhar o que ele pode avaliá-lo se ele tinha classificado como ele. Se pessoa não friended , queremos adivinhar como provável é que ele quer para um amigo dele. As recomendações são baseadas nos valores reconstruídos.j x y i j x yEu j x y Eu j x y
Quando você pega o SVD do gráfico social (por exemplo, conecte-o
svd()
), basicamente está imputando zeros em todos os pontos ausentes. Que isso é problemático é mais óbvio na configuração de classificação de itens do usuário para filtragem colaborativa. Se eu tivesse uma maneira de preencher com segurança as entradas ausentes, não precisaria usar o SVD. Eu apenas daria recomendações com base nas entradas preenchidas. Se eu não tiver uma maneira de fazer isso, não os preencherei antes de fazer o SVD. *SVD com valores ausentes
Obviamente, a
svd()
função não sabe lidar com valores ausentes. Então, o que exatamente você deveria fazer? Bem, há uma maneira de reformular o problema comoEsse é realmente o problema que você está tentando resolver e não vai usar
svd()
para resolvê-lo. Uma maneira que funcionou para mim (nos dados do prêmio Netflix) foi:Tentar encaixar as entradas com um modelo simples, por . Isso realmente faz um bom trabalho.X^i , j= μ + αEu+ βj
Use algum algoritmo para encontrar os vetores que minimizam a distância da matriz original. Por exemplo, use este documento
Boa sorte!
*: O que Tenali está recomendando são basicamente os vizinhos mais próximos. Você tenta encontrar usuários semelhantes e faz recomendações sobre isso. Infelizmente, o problema da escarsidade (~ 99% da matriz está faltando valores) dificulta a localização de vizinhos mais próximos usando distância de cosseno ou similaridade de jaccard ou qualquer outra coisa. Portanto, ele recomenda fazer um SVD da matriz (com zeros imputados nos valores ausentes) para compactar primeiro os usuários em um espaço menor de recursos e, em seguida, fazer comparações lá. Fazer SVD com os vizinhos mais próximos é bom, mas eu ainda recomendaria fazer o SVD da maneira certa (quero dizer ... do meu jeito). Não há necessidade de imputar valores sem sentido!
fonte
A razão pela qual ninguém lhe diz o que fazer com isso é porque, se você sabe o que o SVD faz, é um pouco óbvio o que fazer com ele :-).
Como suas linhas e colunas são o mesmo conjunto, explicarei isso por meio de uma matriz diferente A. Permita que a matriz A seja tal que as linhas sejam os usuários e as colunas sejam os itens de que o usuário gosta. Observe que essa matriz não precisa ser simétrica, mas no seu caso, acho que acaba sendo simétrica. Uma maneira de pensar em SVD é a seguinte: O SVD encontra um espaço de recurso oculto onde os usuários e itens de que eles gostam têm vetores de recursos que estão alinhados.
Agora, se eu der dois vetores do mesmo espaço de recurso e pedir para você descobrir se eles são semelhantes, qual é a coisa mais simples que você pode pensar para fazer isso? Produto de ponto.
fonte
Isso é para tentar responder à parte "como fazer" da pergunta para quem deseja implementar praticamente recomendações de SVD esparsas ou inspecionar o código-fonte para obter detalhes. Você pode usar um software FOSS pronto para uso para modelar SVD esparso. Por exemplo,
vowpal wabbit
,libFM
, ouredsvd
.vowpal wabbit
possui 3 implementações de algoritmos "do tipo SVD" (cada uma selecionável por uma das 3 opções de linha de comando). Estritamente falando, eles devem ser chamados de "fatoração matricial aproximada, iterativa", em vez de puro "SVD" clássico, mas estão intimamente relacionados ao SVD.Você pode pensar neles como uma fatoração SVD aproximada muito computacionalmente eficiente de uma dispersão (principalmente zeros) matriz.Aqui está uma receita completa e prática para fazer recomendações de filmes no estilo Netflix com
vowpal wabbit
e sua--lrq
opção "quadrática de classificação baixa" ( ) que parece funcionar melhor para mim:Arquivo de formato do conjunto de dados
ratings.vw
(cada classificação em uma linha por usuário e filme):Onde o 1º número é a classificação (de 1 a 5 estrelas), seguida pelo ID do usuário que avaliou e o ID do filme que foi classificado.
Os dados de teste estão no mesmo formato, mas podem (opcionalmente) omitir a coluna de classificações:
opcionalmente porque para avaliar / testar previsões precisamos de classificações para comparar as previsões. Se omitirmos as classificações,
vowpal wabbit
ainda assim as preveremos, mas não será possível estimar o erro de previsão (valores previstos x valores reais nos dados).Para treinar, solicitamos
vowpal wabbit
encontrar um conjunto deN
fatores de interação latente entre usuários e filmes de que eles gostam (ou não). Você pode pensar nisso como encontrar temas comuns em que usuários semelhantes classificam um subconjunto de filmes de maneira semelhante e usar esses temas comuns para prever como um usuário classificaria um filme que ainda não classificou.vw
opções e argumentos que precisamos usar:--lrq <x><y><N>
encontra fatores latentes "quadráticos de classificação baixa".<x><y>
: "um" significa cruzar os espaços de nomes dos [es] e dos [ovi] no conjunto de dados. Observe que apenas a 1ª letra em cada espaço de nome é usada com a--lrq
opção<N>
:N=14
abaixo está o número de fatores latentes que queremos encontrar-f model_filename
: escreva o modelo final emmodel_filename
Portanto, um simples comando de treinamento completo seria:
Depois de termos o
ratings.model
arquivo de modelo, podemos usá-lo para prever classificações adicionais em um novo conjunto de dadosmore_ratings.vw
:As previsões serão gravadas no arquivo
more_ratings.predicted
.Usando
demo/movielens
avowpalwabbit
árvore de origem, recebo ~ 0,693 MAE (erro absoluto médio) após o treinamento em 1 milhão de classificações de usuário / filmeml-1m.ratings.train.vw
com 14 fatores latentes (o que significa que a matriz do meio SVD é uma matriz de 14 x 14 linhas x colunas) e teste no independente conjunto de testeml-1m.ratings.test.vw
. Quão bom é 0,69 MAE? Para o intervalo completo de previsões possíveis, incluindo o caso não classificado (0) [0 a 5], um erro de 0,69 é de ~ 13,8% (0,69 / 5,0) do intervalo completo, ou seja, cerca de 86,2% de precisão (1 - 0,138).Você pode encontrar exemplos e uma demonstração completa de um conjunto de dados semelhante (movielens) com documentação na
vowpal wabbit
árvore de fontes no github:--rank
opção--lrq
opçãoNotas:
movielens
demonstração usa várias opções I omitido (para simplificar) do meu exemplo: em particular--loss_function quantile
,--adaptive
e--invariant
--lrq
implementaçãovw
é muito mais rápida do que--rank
, em particular, ao armazenar e carregar os modelos.Créditos:
--rank
opção vw foi implementada por Jake Hofman--lrq
A opção vw (com abandono opcional) foi implementada por Paul Minerofonte
Eu diria que o nome
SVD
é enganador. De fato, oSVD
método no sistema de recomendação não usa diretamente a fatoração SVD. Em vez disso, ele usa descida de gradiente estocástico para treinar os vieses e vetores de fatores.Os detalhes
SVD
e osSVD++
algoritmos do sistema de recomendação podem ser encontrados nas Seções5.3.1
e5.3.2
no livroFrancesco Ricci, Lior Rokach, Bracha Shapira, and Paul B. Kantor. Recommender Systems Handbook. 1st edition, 2010
.No Python, há um pacote bem estabelecido implementado por esses algoritmos nomeados
surprise
. Na documentação , eles também mencionam os detalhes desses algoritmos.fonte