Técnicas de aprendizado de máquina para estimar a idade dos usuários com base nos sites do Facebook que eles gostam

25

Eu tenho um banco de dados do meu aplicativo do Facebook e estou tentando usar o aprendizado de máquina para estimar a idade dos usuários com base nos sites que eles gostam no Facebook.

Existem três características cruciais do meu banco de dados:

  • a distribuição etária no meu conjunto de treinamento (12k de usuários no total) é inclinada para usuários mais jovens (ou seja, eu tenho 1157 usuários com 27 anos e 23 usuários com 65 anos);

  • muitos sites não têm mais que 5 pessoas (filtramos os sites do FB com menos de 5 pessoas).

  • há muito mais recursos do que amostras.

Então, minhas perguntas são: que estratégia você sugeriria para preparar os dados para uma análise mais aprofundada? Devo executar algum tipo de redução de dimensionalidade? Qual método de ML seria mais apropriado usar neste caso?

Eu uso principalmente o Python, portanto, dicas específicas do Python serão muito apreciadas.

Wojciech Walczak
fonte
11
Quando você diz "muito mais recursos do que amostras", presumo que você queira dizer que o número único de sites curtidos é >> em um número de usuários. Esse também é o caso do domínio raiz dos sites? ou seja, são vários URLs do youtube.com ou cnn.com nos sites ou eles já se originaram no domínio? Estou inclinado a reduzir a dimensionalidade, recolhendo URLs para raízes de domínio, em vez de páginas específicas, se possível.
Cwharland 17/05
Obrigado pela resposta. O número de recursos (sites exclusivos curtidos) é 32k, enquanto o número de amostras (usuários) é 12k. Os recursos são páginas do Facebook, portanto, não há necessidade de conter os URLs. Um usuário pode gostar de facebook.com/cnn ou não. Eu gosto da idéia de tentar estimar a idade dos usuários com base nos links que compartilham, embora :)
Wojciech Walczak
Ahhh, eu li mal a descrição dos sites curtidos. Obrigado pelo esclarecimento.
Cwharland 17/05

Respostas:

16

Uma coisa para começar seria o k-NN. A idéia aqui é que você tenha uma matriz de usuário / item e, para alguns usuários, tenha uma idade relatada. A idade de uma pessoa na matriz de itens do usuário pode ser bem determinada por algo como a idade média ou mediana de alguns vizinhos mais próximos no espaço de itens.

Para que você exprima cada usuário como um vetor no espaço de itens, encontre os k vizinhos mais próximos e atribua ao vetor em questão uma estatística resumida das idades dos vizinhos mais próximos. Você pode escolher k em um corte de distância ou mais realisticamente, atribuindo idades a um trem de maneira iterativa e escolhendo k que minimiza o erro nessa atribuição.

Se a dimensionalidade for um problema, você poderá executar facilmente a redução nessa configuração decompondo um valor único, escolhendo os m vetores que capturam a maior variação no grupo.

Em todos os casos, já que cada recurso é binário, parece que a semelhança de cosseno seria sua métrica de distância.

Preciso pensar um pouco mais sobre outras abordagens (regressão, rf, etc ...), considerando o foco restrito do seu espaço de recurso (todas as variantes da mesma ação, gostando). Acho que a abordagem de usuário / item pode ser a melhor.

Uma nota de cautela, se as idades que você tiver para treinar forem relatadas, talvez seja necessário corrigir algumas delas. As pessoas no facebook tendem a relatar idades na década em que nasceram. Faça um histograma das datas de nascimento (derivadas das idades) e veja se você tem picos em décadas como 70, 80, 90.

cwharland
fonte
Olá, sua resposta é bastante semelhante à minha estratégia real. Eu usei sklearn.neighbors.KNeighborsRegressorcom métrica de cosseno no espaço reduzido de SVD (após aplicar SVD, o erro médio de estimativa caiu de ~ 6 anos para ~ 4). Os usuários do meu banco de dados têm entre 18 e 65 anos de idade (os usuários mais antigos foram filtrados), portanto há 48 classes possíveis. Gostaria de saber se não há muitas classes para o kNN e se devo tratá-lo como regressão ou um problema de classificação (acho que ambas são aplicáveis).
Wojciech Walczak
Posso dizer, anedoticamente, que usei por classe Florestas Aleatórias para ajustar-se a várias classes individualmente e depois combinei os resultados de cada um desses modelos de várias maneiras. Nesse caso, você pode até pensar em atribuir probabilidades anteriores à idade de cada usuário com o kNN, percorrer cada modelo baseado em classe, usar essas pontuações para atualizar as probabilidades anteriores de cada classe e escolher a classe mais provável dessas posteriores. Parece complicar um pouco demais, mas na pior das hipóteses você teria a precisão do kNN.
Cwharland # 22/14
7

Recentemente, eu fiz um projeto semelhante em Python (prevendo opiniões usando dados semelhantes ao FB) e tive bons resultados com o seguinte processo básico:

  1. Leia no conjunto de treinamento (n = N) iterando sobre registros delimitados por vírgula, linha por linha, e use um contador para identificar as páginas mais populares
  2. Para cada uma das K páginas mais populares (usei cerca de 5000, mas você pode brincar com valores diferentes), use pandas.DataFrame.isin para testar se cada indivíduo no conjunto de treinamento gosta de cada página e faça um dataframe N x K dos resultados (vou chamá-lo de xdata_train)
  3. Crie uma série (eu vou chamá-la de ydata_train) contendo todas as variáveis ​​de resultado (na minha opinião de caso, na sua idade) com o mesmo índice que xdata_train
  4. Configure um classificador de floresta aleatório através do scikit-learn para prever ydata_train com base em xdata_train
  5. Use o teste de validação cruzada do scikit-learn para ajustar os parâmetros e refinar a precisão (ajustar o número de páginas populares, o número de árvores, o tamanho mínimo das folhas etc.)
  6. Classificador de floresta aleatório de saída e lista de páginas mais populares com pickle (ou mantenha na memória se você estiver fazendo tudo de uma vez)
  7. Carregue o restante dos dados, carregue a lista de páginas populares (se necessário) e repita a etapa 2 para produzir xdata_new
  8. Carregue o classificador de floresta aleatório (se necessário) e use-o para prever valores para os dados xdata_new
  9. Envie as pontuações previstas para um novo formato CSV ou outro formato de saída de sua escolha

No seu caso, você precisaria trocar o classificador por um regressor (consulte aqui: http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html ), caso contrário, o mesmo processo deve funcionar sem muitos problemas.

Além disso, você deve estar ciente do recurso mais surpreendente de florestas aleatórias em Python: paralelização instantânea! Aqueles de nós que começaram a fazer isso no R e depois se mudaram sempre ficam impressionados, especialmente quando você começa a trabalhar em uma máquina com algumas dezenas de núcleos (veja aqui: http://blog.yhathq.com/posts/comparing- florestas-aleatórias-em-python-e-r.html ).

Por fim, observe que esse seria um aplicativo perfeito para análise de rede se você tiver os dados dos amigos e dos próprios indivíduos. Se você puder analisar a idade dos amigos de um usuário, a idade do usuário quase certamente estará dentro de um ano ou dois da mediana entre seus amigos, principalmente se os usuários forem jovens o suficiente para criar suas redes de amigos enquanto ainda estão na rede. escola (já que a maioria será de colegas de classe). Essa previsão provavelmente superaria qualquer uma que você obtivesse com a modelagem - este é um exemplo de problema em que os dados certos> sempre são o modelo certo.

Boa sorte!

Therriault
fonte
2
Um aspecto interessante do uso dos 5000 principais sites é o fato de que eles podem não ser bons em segmentar usuários com idade. Os principais sites, por construção, são aqueles que todo mundo visita. Portanto, eles não são muito bons em segmentar seus usuários, pois todas as classificações possíveis (idades) se envolveram com esses sites. Esta é uma noção semelhante à parte idf do tf-idf. O idf ajuda a filtrar o ruído "todo mundo tem esse recurso". Como os sites mais visitados são classificados como recursos em seus gráficos de importância variável com o seu RF?
Cwharland
11
Bom ponto. Uma solução fácil para isso seria estratificar o conjunto de dados de treinamento em caixas de idade (por exemplo, 13-16, 17-20, 21-24 etc.) e acessar as páginas principais (K / J) de cada grupo. Isso garantiria que você tenha uma representação significativa para cada grupo. Certamente haverá alguma sobreposição entre os grupos; portanto, se você for realmente exigente, poderá escolher as páginas principais (K / J) de cada grupo, mas acho que isso pode ser um exagero.
Therriault
5

Outra sugestão é testar a regressão logística . Como um bônus adicional, os pesos (coeficientes) do modelo fornecerão uma idéia de quais sites são discriminatórios por idade.

O Sklearn oferece o pacote sklearn.linear_model.LogisticRegression , projetado para lidar com dados esparsos também.

Conforme mencionado nos comentários, no presente caso, com mais variáveis ​​de entrada que amostras, você precisa regularizar o modelo (com sklearn.linear_model.LogisticRegression use o penalty='l1'argumento).

damienfrancois
fonte
11
Com o LR, você teria que criar vários modelos para as caixas de idade, eu acho. Como comparar dois modelos para diferentes faixas etárias que prevêem o mesmo problema de inclusão para um usuário?
Cwharland
11
Observe que o LR falha quando há mais variáveis ​​do que observações e apresenta um desempenho ruim se as suposições do modelo não forem atendidas. Para usá-lo, a redução de dimensionalidade deve ser o primeiro passo.
Christopher Louden
11
@cwharland, você não deve considerar a variável de resposta como categórica, pois é contínua por natureza e discretizada pela definição do problema. Considerá-lo categórico significaria dizer ao algoritmo que prever 16 anos de idade quando realmente tem 17 anos é um erro grave como prever 30 quando realmente tem 17 anos. O fato de ser contínuo garante que pequenos erros (16 vs 17) sejam considerados pequenos e grandes erros ( 30 vs 17) são considerados grandes. A regressão logística é usada neste caso para prever o valor contínuo e não estimar probabilidades posteriores.
Damienfrancois
@ChristopherLouden Você está certo que a versão baunilha da regressão logística não é adequada para o caso 'large p small n', eu deveria ter mencionado que a regularização é importante no presente caso. Eu atualizo minha resposta. Mas a LR regularizada por L1 é uma espécie de seleção de recursos, por isso não considero necessário um passo preliminar da FS.
Damienfrancois
@damienfrancois: Eu definitivamente concordo. Estou um pouco preocupado com o fato de que, neste caso, o LR penalize os valores intermediários de maneira muito severa. Parece não haver motivação para mapear para uma curva sigmoidal, uma vez que você não está particularmente interessado em valores extremos de idade. Talvez eu esteja interpretando mal o uso.
Cwharland 22/05
4

Algumas pesquisas de D. Nguyen et al. tente prever a idade do usuário do twitter com base em seus tweets. Talvez você os ache úteis. Eles usam regressão logística e linear.

lgylym
fonte
3

Além dos métodos mais sofisticados, você pode experimentar a fórmula de Bayes

P (I | p1 ... pn) = P (p1 ... pn | I) P (I) / soma_i (P (p1 ... pn | i) P (i))

P (I | p1 ... pn) é a probabilidade de um usuário pertencer à faixa etária I se ele gostou de p1, .., pn

P (i) é a probabilidade de um usuário pertencer à faixa etária i

P (p1 .. pn | i) é a probabilidade de um usuário gostar de p1, .., pn se pertencer à faixa etária i.

  • Você já tem as estimativas para P (i) a partir de seus dados: essa é apenas a proporção de usuários na faixa etária I.
  • Para estimar P (p1 ... pn | i), para cada faixa etária, estimo a probabilidade (frequência) p_ij para gostar de uma página j. Para ter p_ij diferente de zero para todos os j, você pode misturar a frequência para toda a população com um pequeno peso.

  • Em seguida, registre P (p1 ... pn | i) = soma (log p_ij, i = p1, .., pn), a soma de todas as páginas de que um novo usuário gosta. Essa fórmula seria aproximadamente verdadeira, supondo que um usuário goste das páginas de sua faixa etária de forma independente.

  • Teoricamente, você também deve adicionar log (1-p_ij) para tudo o que ele não gostou, mas na prática você deve achar que a soma do log (1-p_ij) será irrelevantemente pequena, para que você não precise muito muita memória.

Se você ou alguém já tentou isso, comente o resultado.

Valentas
fonte
2

Este é um problema muito interessante.

Enfrentei um semelhante analisando as imagens que os usuários carregam na rede social. Eu fiz a seguinte abordagem:

  • Em vez de associar dados a idades (15, 27, ...), o que fiz foi estabelecer diferentes grupos de idades: menos de 18, de 18 a 30 e maior que 30 (isso se deve ao problema específico em que estávamos de frente, mas você pode escolher os intervalos que quiser). Essa divisão ajuda muito a resolver o problema.
  • Depois, criei um cluster hierárquico (divisivo ou agregativo). Depois, escolhi os ramos em que tinha usuários com idades conhecidas (ou idades em grupo) e, em seguida, para esse ramo, estendi a mesma idade para esse grupo.

Essa abordagem é um aprendizado semi-supervisionado e eu a recomendo caso você tenha apenas alguns dados rotulados.

Por favor, observe que em uma rede social, as pessoas geralmente mentem sobre a idade (apenas por diversão, ou às vezes porque querem se camuflar na rede social).

adesantos
fonte