Techniques d'apprentissage automatique pour estimer l'âge des utilisateurs en fonction des sites Facebook qu'ils aiment

25

J'ai une base de données de mon application Facebook et j'essaie d'utiliser l'apprentissage automatique pour estimer l'âge des utilisateurs en fonction des sites Facebook qu'ils aiment.

Il y a trois caractéristiques cruciales de ma base de données:

  • la répartition par âge dans mon ensemble de formation (12k d'utilisateurs en somme) est biaisée vers les utilisateurs plus jeunes (c'est-à-dire que j'ai 1157 utilisateurs âgés de 27 ans et 23 utilisateurs âgés de 65 ans);

  • de nombreux sites n'ont pas plus de 5 likers (j'ai filtré les sites FB avec moins de 5 likers).

  • il y a beaucoup plus de fonctionnalités que d'échantillons.

Alors, mes questions sont: quelle stratégie proposeriez-vous pour préparer les données pour une analyse plus approfondie? Dois-je effectuer une sorte de réduction de la dimensionnalité? Quelle méthode ML serait la plus appropriée à utiliser dans ce cas?

J'utilise principalement Python, donc des conseils spécifiques à Python seraient grandement appréciés.

Wojciech Walczak
la source
1
Lorsque vous dites "beaucoup plus de fonctionnalités que d'échantillons", je suppose que vous voulez dire que le nombre unique de sites aimés est >> nombre d'utilisateurs. Est-ce également le cas pour le domaine racine des sites? autrement dit, y a-t-il un certain nombre d'URL youtube.com ou cnn.com dans les sites ou sont-elles déjà liées au domaine? Je penche vers la réduction de la dimensionnalité en réduisant les URL aux racines de domaine plutôt que des pages spécifiques si c'est possible.
cwharland
Merci de répondre. Le nombre de fonctionnalités (sites uniques aimés) est de 32k, tandis que le nombre d'échantillons (utilisateurs) est de 12k. Les fonctionnalités sont des pages Facebook, il n'est donc pas nécessaire d'endiguer les URL. Un utilisateur peut aimer facebook.com/cnn ou non. J'aime l'idée d'essayer d'estimer l'âge des utilisateurs en fonction des liens qu'ils partagent, cependant :)
Wojciech Walczak
Ahhh, j'ai mal lu la description des sites aimés. Merci pour la clarification.
cwharland

Réponses:

16

Une chose pour commencer serait k-NN. L'idée ici est que vous avez une matrice utilisateur / article et pour certains des utilisateurs, vous avez un âge déclaré. L'âge d'une personne dans la matrice d'élément utilisateur peut être bien déterminé par quelque chose comme l'âge moyen ou médian de certains voisins les plus proches dans l'espace d'élément.

Vous avez donc chaque utilisateur exprimé sous forme de vecteur dans l'espace des objets, trouvez les k voisins les plus proches et attribuez au vecteur en question une statistique récapitulative des âges des voisins les plus proches. Vous pouvez choisir k sur une coupure de distance ou de manière plus réaliste en affectant de manière itérative des âges à un train retenu et en choisissant le k qui minimise l'erreur dans cette affectation.

Si la dimensionnalité est un problème, vous pouvez facilement réduire cette configuration en décomposant une seule valeur en choisissant les m vecteurs qui captent le plus de variance dans le groupe.

Dans tous les cas, puisque chaque fonctionnalité est binaire, il semble que la similitude en cosinus serait votre mesure de distance.

J'ai besoin de réfléchir un peu plus aux autres approches (régression, rf, etc ...) étant donné la focalisation étroite de votre espace de fonctionnalités (toutes les variantes de la même action, j'aime), je pense que l'approche utilisateur / élément pourrait être la meilleure.

Une note de prudence, si les âges que vous avez pour le train sont auto-déclarés, vous devrez peut-être en corriger certains. Les gens sur Facebook ont ​​tendance à déclarer l'âge dans la décennie où ils sont nés. Tracez un histogramme des dates de naissance (dérivées des âges) et voyez si vous avez des pointes à des décennies comme les années 70, 80, 90.

cwharland
la source
Salut, votre réponse est assez similaire à ma stratégie actuelle. J'ai utilisé sklearn.neighbors.KNeighborsRegressorla métrique cosinus sur un espace réduit en SVD (après application de SVD, l'erreur d'estimation moyenne est passée de ~ 6 ans à ~ 4). Les utilisateurs de ma base de données sont âgés de 18 à 65 ans (les utilisateurs plus âgés ont été exclus), il y a donc 48 classes possibles. Je me demande si ce n'est pas trop de classes pour kNN, et si je dois le traiter comme une régression ou un problème de classification (je pense que les deux sont applicables).
Wojciech Walczak
Je peux dire, de façon anecdotique, que j'ai utilisé par classe Random Forests pour adapter un certain nombre de classes individuellement, puis j'ai combiné les résultats de chacun de ces modèles de diverses manières. Dans ce cas, vous pourriez même penser à attribuer des probabilités antérieures à l'âge de chaque utilisateur avec le kNN, puis parcourir chaque modèle basé sur une classe, utiliser ces scores pour mettre à jour les probabilités antérieures pour chaque classe et choisir la classe la plus probable parmi ces postérieurs. Cela semble un peu compliquer un peu, mais au pire, vous auriez la précision kNN.
cwharland
7

J'ai récemment fait un projet similaire en Python (prédire les opinions en utilisant des données FB) et j'ai obtenu de bons résultats avec le processus de base suivant:

  1. Lisez l'ensemble de formation (n = N) en itérant ligne par ligne sur des enregistrements délimités par des virgules et utilisez un compteur pour identifier les pages les plus populaires.
  2. Pour chacune des K pages les plus populaires (j'en ai utilisé environ 5000, mais vous pouvez jouer avec différentes valeurs), utilisez pandas.DataFrame.isin pour tester si chaque individu de l'ensemble de formation aime chaque page, puis créez un cadre de données N x K des résultats (je l'appellerai xdata_train)
  3. Créez une série (je l'appellerai ydata_train) contenant toutes les variables de résultat (dans mon cas, les opinions, à votre âge) avec le même indice que xdata_train
  4. Configurer un classificateur de forêt aléatoire via scikit-learn pour prédire ydata_train en fonction de xdata_train
  5. Utilisez les tests de validation croisée de scikit-learn pour ajuster les paramètres et affiner la précision (ajustement du nombre de pages populaires, du nombre d'arbres, de la taille minimale des feuilles, etc.)
  6. Sortez le classificateur de forêt aléatoire et la liste des pages les plus populaires avec cornichon (ou gardez en mémoire si vous faites tout en même temps)
  7. Chargez le reste de vos données, chargez la liste des pages populaires (si nécessaire) et répétez l'étape 2 pour produire xdata_new
  8. Chargez le classificateur de forêt aléatoire (si nécessaire) et utilisez-le pour prédire les valeurs des données xdata_new
  9. Exportez les scores prévus vers un nouveau CSV ou un autre format de sortie de votre choix

Dans votre cas, vous devrez remplacer le classifieur par un régresseur (alors voir ici: http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html ) mais sinon le même processus devrait fonctionner sans trop de problèmes.

En outre, vous devez être conscient de la caractéristique la plus étonnante des forêts aléatoires en Python: la parallélisation instantanée! Ceux d'entre nous qui ont commencé à faire cela dans R et qui sont ensuite passés sont toujours étonnés, surtout lorsque vous travaillez sur une machine avec quelques dizaines de cœurs (voir ici: http://blog.yhathq.com/posts/comparing- forêts-aléatoires-en-python-et-r.html ).

Enfin, notez que ce serait une application parfaite pour l'analyse de réseau si vous disposez des données sur les amis ainsi que sur les individus eux-mêmes. Si vous pouvez analyser l'âge des amis d'un utilisateur, l'âge de l'utilisateur sera presque certainement dans un an ou deux de la médiane de ses amis, en particulier si les utilisateurs sont assez jeunes pour avoir construit leurs réseaux d'amis tout en étant l'école (puisque la plupart seront des camarades de classe). Cette prédiction l'emporterait probablement sur tout ce que vous obtiendriez de la modélisation --- c'est un exemple classique d'un problème où les bonnes données> le bon modèle à chaque fois.

Bonne chance!

Therriault
la source
2
Un aspect intéressant de l'utilisation des 5000 meilleurs sites est le fait qu'ils peuvent ne pas être bons pour segmenter les utilisateurs en fonction de leur âge. Les meilleurs sites, par construction, sont ceux que tout le monde visite. Ils ne sont donc pas très bons pour segmenter vos utilisateurs car toutes les classifications (âges) possibles se sont engagées avec ces sites. Il s'agit d'une notion similaire à la partie idf de tf-idf. idf permet de filtrer le bruit «tout le monde a cette fonctionnalité». Comment les sites les plus visités se classent-ils en tant que caractéristiques dans vos tracés d'importance variable avec votre RF?
cwharland
1
Bon point. Une solution simple pour cela serait de stratifier l'ensemble de données de formation en J tranches d'âge (par exemple, 13-16, 17-20, 21-24, etc.) et de prendre les pages supérieures (K / J) pour chaque groupe. Cela garantirait une représentation significative de chaque groupe. Il y aura certainement un certain chevauchement entre les groupes, donc si vous êtes vraiment difficile, vous voudrez peut-être prendre les pages uniques (K / J) pour chaque groupe, mais je pense que cela pourrait être exagéré.
Therriault
5

Une autre suggestion est de tester la régression logistique . En prime, les poids (coefficients) du modèle vous donneront une idée des sites qui ne sont pas liés à l'âge.

Sklearn propose le package sklearn.linear_model.LogisticRegression qui est également conçu pour gérer des données éparses.

Comme mentionné dans les commentaires, dans le cas présent, avec plus de variables d'entrée que d'échantillons, vous devez régulariser le modèle (avec sklearn.linear_model.LogisticRegression utiliser l' penalty='l1'argument).

damienfrancois
la source
1
Avec LR, je pense qu'il faudrait faire plusieurs modèles de bacs à âge. Comment comparer deux modèles pour des tranches d'âge différentes qui prédisent le même problème d'inclusion pour un utilisateur?
cwharland
1
Notez que LR échoue lorsqu'il y a plus de variables que d'observations et fonctionne mal si les hypothèses du modèle ne sont pas remplies. Pour l'utiliser, la réduction de dimensionnalité doit être une première étape.
Christopher Louden
1
@cwharland, vous ne devez pas considérer la variable de réponse comme catégorique car elle est continue par nature et discrétisée par la définition du problème. Le considérer comme catégorique signifierait dire à l'algorithme que prédire l'âge de 16 ans alors qu'il a 17 ans est aussi une erreur grave que prédire 30 ans quand il a réellement 17 ans. Le considérer comme continu garantit que les petites erreurs (16 vs 17) sont considérées comme des erreurs petites et grandes ( 30 vs 17) sont considérés comme importants. La régression logistique est utilisée dans ce cas pour prédire la valeur continue et non pour estimer les probabilités postérieures.
damienfrancois
@ChristopherLouden Vous avez raison de dire que la version vanille de la régression logistique ne convient pas au cas du «grand p petit n», j'aurais dû mentionner que la régularisation est importante dans le cas présent. Je mets à jour ma réponse. Mais le LR régularisé en L1 est une sorte de sélection de fonctionnalités, donc je ne considère pas la nécessité d'une étape FS préliminaire.
damienfrancois
@damienfrancois: Je suis définitivement d'accord. Je suis juste un peu inquiet que dans ce cas, LR pénalisera trop sévèrement les valeurs intermédiaires. Il ne semble pas y avoir de motivation à mapper sur une courbe de type sigmoïde étant donné que vous n'êtes pas particulièrement intéressé par les valeurs d'âge extrêmes. Peut-être que j'interprète mal l'utilisation.
cwharland
4

Certaines recherches de D. Nguyen et al. essayez de prédire l'âge des utilisateurs de twitter en fonction de leurs tweets. Vous les trouvez peut-être utiles. Ils utilisent une régression logistique et linéaire.

lgylym
la source
3

Outre les méthodes plus sophistiquées, vous pouvez essayer la formule Bayes

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

P (I | p1 ... pn) est la probabilité qu'un utilisateur appartienne au groupe d'âge I s'il a aimé p1, .., pn

P (i) est la probabilité qu'un utilisateur appartienne au groupe d'âge i

P (p1 .. pn | i) est la probabilité qu'un utilisateur aime p1, .., pn s'il appartient au groupe d'âge i.

  • Vous disposez déjà des estimations de P (i) à partir de vos données: il s'agit simplement de la proportion d'utilisateurs dans le groupe d'âge I.
  • Pour estimer P (p1 ... pn | i), pour chaque tranche d'âge i estimer la probabilité (fréquence) p_ij d'aimer une page j. Pour avoir p_ij non nul pour tout j, vous pouvez mélanger la fréquence pour l'ensemble de la population avec un petit poids.

  • Ensuite, log P (p1 ... pn | i) = sum (log p_ij, i = p1, .., pn), la somme sur toutes les pages qu'un nouvel utilisateur aime. Cette formule serait approximativement vraie en supposant qu'un utilisateur aime les pages de son groupe d'âge indépendamment.

  • Théoriquement, vous devez également ajouter log (1-p_ij) pour tout ce qu'il n'a pas aimé, mais dans la pratique, vous devriez constater que la somme de log (1-p_ij) sera peu importante, donc vous n'en aurez pas besoin trop beaucoup de mémoire.

Si vous ou quelqu'un d'autre avez essayé, veuillez commenter le résultat.

Valentas
la source
2

C'est un problème très intéressant.

J'ai fait face à un problème similaire en analysant les photos que les utilisateurs téléchargent sur le réseau social. J'ai fait l'approche suivante:

  • Plutôt que d'associer des données à des âges (15 ans, 27 ans, ...), ce que j'ai fait, c'est d'établir différents groupes d'âge: moins de 18 ans, de 18 à 30 ans et plus de 30 ans (cela est dû au problème spécifique que nous avons rencontré). face, mais vous pouvez choisir les intervalles que vous voulez). Cette division aide beaucoup à résoudre le problème.
  • Par la suite, j'ai créé un clustering hiérarchique (diviseur ou agrégatif). Ensuite, je choisis les branches où j'avais des utilisateurs avec des âges connus (ou des âges de groupe), puis pour cette branche, j'ai étendu le même âge à ce groupe.

Cette approche est un apprentissage semi-supervisé et je l'ai recommandé au cas où vous n'auriez que quelques données étiquetées.

Veuillez noter que sur un réseau social, les gens mentent généralement sur l'âge (juste pour le plaisir, ou parfois parce qu'ils veulent se camoufler sur le réseau social).

adesantos
la source