NLP : CorEx, le topic modeling non supervisé et semi-supervisé
Détecter automatiquement les sujets d’un corpus, c’est possible avec le CorEx (Correlation Explanation) !
Un compromis entre le topic modeling non supervisé et la classification supervisée, qui suppose une labellisation préalable : le topic modeling semi-supervisé.
Le topic modeling semi-supervisé permet aux data scientists d’ajouter leur compréhension, leurs connaissances des données, et d’aiguiller l’algorithme de reconnaissance de sujets avec des mots-clés.
A la différence des LDA et NMF, connus, CorEx permet l’ajout d’ “anchor words” qui représentent des sujets particuliers. Il est possible de donner un poids à ces anchors, poids qui dépend de notre certitude à trouver ces sujets dans notre corpus.
Il n’y a pas de nombre idéal de sujets. CorEx pourra trouver des sujets peu mentionnés dans l’ensemble du corpus mais prépondérants dans quelques articles. Illustration ci-dessous ; mon corpus contenait de nombreux articles scientifiques, je souhaitais que le CorEx identifie le sujet “Physic” ; il a détecté ce sujet :
Topic 4 :
star, galaxy, stellar, number, planet, telescope, observation, galactic, redshift, solar
Fonctionnement général du CorEx
Contrairement au LDA, le CorEx ne suppose pas de modèle génératif des données, c’est-à-dire que le CorEx ne s’intéresse pas aux mécanismes habituels d’écriture d’un document.
La logique d’un modèle génératif est la suivante : la probabilité qu’un sujet soit mentionné dans un document dépend du vocabulaire présent dans ce document. Ainsi le modèle cherchera à décrire la probabilité conditionnelle P(X|Y) et la probabilité P(Y) pour calculer P(Y|X) qui représente la probabilité que le sujet Y soit présent, connaissant les variables X.
Sans supposer de modèle génératif, le CorEx peut déceler des sujets latents, c’est-à-dire des sujets non explicitement mentionnés mais pourtant présents. Si par exemple plusieurs articles parlent de football, handball et tennis, CorEx va détecter le sujet latent “sport” et capter l’information partagée entre football, handball et tennis. Dans sa quête de sujets, CorEx s’intéresse aux sujets qui contiennent le maximum d’information.
Le CorEx apprend à partir des sujets informatifs plutôt que des sujets génératifs.
C’est la corrélation totale qui va évaluer l’information d’un sujet ; cette corrélation totale (TC) est calculée de cette façon :
H représente l’entropie d’une variable aléatoire. En théorie de l’information, l’entropie correspond à la quantité d’information contenue par une source d’information. Conceptuellement, la TC (Total Correlation) est une mesure de la dépendance totale. Si TC = 0, alors il n’y a aucune information partagée entre les variables ; elles sont indépendantes. Si, au contraire TC est élevé, il y a de l’information partagée entre les variables, donc la présence d’un sujet.
Données et pré-processing
Pour l’application du CorEx dans le cadre de cet article, nous allons nous intéresser aux données d’Airbnb accessibles gratuitement sur leur site http://insideairbnb.com/get-the-data.html. J’ai sélectionné les reviews des hôtes d’Oslo (super ville !).
J’ai rapidement nettoyé ces données pour qu’elles soient utilisables par le CorEx en suivant cette méthode.
Une fois les données privées de ponctuation, accents, stopwords, j’ai extrait les caractéristiques en utilisant le CountVectorizer de Sklearn introduit dans cet article.
Après pré-traitement, mon jeu de données ressemble à cela :
Une fois nettoyé, mon jeu de données est composé de 18 902 commentaires.
Exploration
Pour la partie exploratoire, nous allons nous intéresser à la colonne comments_cleaned, regarder la taille des textes et le vocabulaire prépondérant.
La moitié des messages nettoyés a une longueur supérieure à 125. C’est largement suffisant pour aborder plusieurs sujets (le multi-label topic modeling est nécessaire). Par exemple, le commentaire “A perfect apartment in Oslo! Great location, very clean and cosy!” mentionne la qualité de l’appartement et sa localisation.
Affichons maintenant les unigrams et bigrams prépondérants :
from wordcloud import WordClouddef create_wordcloud(words):
long_string = ','.join(str(v) for v in list(words.values))
long_string = long_string.replace("[","").replace("]","").replace("'","")
wordcloud = WordCloud(background_color="white", width=1000, height=500, max_words=350, contour_width=3, contour_color='steelblue')
wordcloud.generate(long_string)
return wordcloud.to_image()create_wordcloud(data.comments_cleaned)
Il semblerait que “location” (localisation) soit beaucoup utilisé, mais ce Wordcloud n’apporte pas assez d’informations pour reconnaître les sujets abordés.
Une première itération du CorEx va nous aider.
Application du CorEx
Non-supervisé
Dans un premier temps, il est toujours intéressant de lancer l’algorithme sans l’orienter (application non supervisée). Ensuite, nous l’orienterons en lui proposant des ancres, c’est-à-dire des propositions de sujets pertinents.
from corextopic import corextopic as ctmodel = ct.Corex(
n_hidden = 10 #Nombre de topics à détecter
)vocab = vectorizer.get_feature_names() #Ensemble des mots uniques
model = model.fit(X, words = vocab)### Affichage
for i, topic_ngrams in enumerate(model.get_topics(n_words=10)):
topic_ngrams = [ngram[0] for ngram in topic_ngrams if ngram[1] > 0]
print("\nTopic %d :"%i)
print(', '.join(topic_ngrams))
Résultats :
Topic 0 :
understand, bnb, forget, air bnb, make home, ji, hope return, ingrid, easy understand, little hard
Topic 1 :
shopping mall, simple, finish, keep contact, size number, fireplace, visitor, mall, strong, nice shop
Topic 2 :
walk, station, bus, number, minute, number minute, tram, restaurant, min, number min
Topic 3 :
decorated, state, joseph, city day, popular, available stay, snezana, fairly, improve, floor heat
Topic 4 :
kitchen, bathroom, bed, floor, room, within, bedroom, distance, within walk, living
Topic 5 :
oslo, give, get, also, stay, tip, around, time, provide, lot
Topic 6 :
feel, make, home, even, like, make feel, arrive, welcome, feel like, late
Topic 7 :
drop, karl, son, gate, karl johans, rather, life, johans, fang, henTopic 8 :
question, respond, answer, quick, quickly, quick respond, answer question, always, reply, response
Topic 9 :
recommend, highly, highly recommend, definitely recommend, recommend place, recommend stay, anyone, definitely, recommend apartment, recommend anyone
Appliquer l’algorithme en mode non supervisé donne déjà des résultats intéressants. Il semblerait y avoir un sujet sur la compréhension générale, un sujet sur les points d’intérêts proches de la location, un sur l’intérieur de l’appartement, un sur les questions & réponses de l’hôte et enfin un sujet sur la recommandation de l’endroit.
C’est dans cette situation que l’on constate les qualités de l’algorithme CorEx. Sans aucune labellisation, le CorEx a déjà identifié des sujets pertinents.
Semi-supervisé
Pour bénéficier au maximum des avantages des ancres et des possibilités du semi-supervisé, il est important de lire quelques textes pour identifier soi-même les différents sujets mentionnés.
Au vu du Word Cloud et de la lecture de quelques articles, j’ai identifié les sujets suivants : localisation, propreté, check-in, restaurants & bars, accessibilité.
En réfléchissant à des mots propres à ces catégories, nous pouvons créer les ancres suivantes et relancer l’algorithme :
anchors = [
["easy understand", "little hard","understand"],
["question", "respond", "answer", "answer question", "reply"],
["location", "locate"],
["bed","bedroom", "kitchen","bathroom"],
["restaurant", "bar", "facilities"],
["feel", "feeling", "make feel"],
["clean"],
["checkin", "check", "key"],
["transport", "bus", "train", "station", "metro"]
]
anchors = [
[a for a in topic if a in vocab]
for topic in anchors
]model_anchored = ct.Corex(
n_hidden = 10
)vocab = vectorizer.get_feature_names()model_anchored = model_anchored.fit(
X,
words = vocab,
anchors=anchors,
anchor_strength=3)
Résultats :
Topic 0 :
understand, easy understand, little hard, speak, real, throw, entire, stone, stone throw, read
Topic 1 :
question, respond, answer, answer question, reply, quickly, quick respond, quick, message, respond quickly
Topic 2 :
location, locate, apartment location, well locate, location close, place location, apartment locate, central location, location easy, centrally locate
Topic 3 :
bed, kitchen, bathroom, bedroom, room, floor, living, living room, shower, sleep
Topic 4 :
restaurant, bar, shop, cafe, store, grocery, restaurant bar, park, bar restaurant, shop restaurant
Topic 5 :
feel, make feel, home, make, feel like, feel home, feel welcome, like, like home, welcome
Topic 6 :
clean, apartment clean, nice clean, place clean, clean well, clean apartment, clean tidy, super clean, room clean, everything clean
Topic 7 :
check, key, late, get, even, arrive, easy, meet, check check, arrival
Topic 8 :
station, bus, train, metro, number, walk, minute, number minute, min, number min
Topic 9 :
oslo, stay, give, time, tip, visit, back, come, recommend, definitely
Pour savoir quels messages parlent de la localisation, nous pourrions simplement faire une recherche sur les mots “location” et “locate”, nous aurions de très bons résultats. Mais pour certains sujets, le vocabulaire est plus varié. Le CorEx va identifier les mots clés pertinents. Pour le sujet lié aux moyens de transport par exemple, le mot “number” faisant référence à un nombre (cf. Nettoyage) semble très informatif.
Nous pouvons connaître la corrélation totale (dont j’ai parlé précédemment) calculée par l’algorithme :
print("TC ",model_anchored.tc)
print("TCS ",model_anchored.tcs)TC 31.066487840057956
TCS [4.0358849 3.9741712 1.92337717 3.71262071 3.19055892 3.51461774 2.40463319 2.51898384 3.72829293 2.06334723]
Cela nous indique quels sujets ont une forte corrélation. La corrélation totale vaut 31, ce qui est assez élevé.
Now what?
Le modèle CorEx permet de s’intéresser spécifiquement à chaque document et de savoir à quel(s) sujet(s) il est lié. Avec quelques manipulations, nous créons le jeu de données suivant :
Il devient alors facile de requêter sur ce tableau pour n’avoir que les commentaires liés à un sujet. Par exemple, voilà les commentaires liés au sujet “transport” :
14900
Very cosy appartment in walking distance to the train station. We would book again!
13450 We felt at home every moment we stayed with Ivar and Siri. There was plenty of space to spread out and relax. Getting back and forth to the center of Oslo was a breeze because we were just a hop, skip and a jump from the train.
10241 Terje is very nice. The traffic information he provided is very helpful when we first arrived. The decorations in the room is special. There are plenty of plants and a lovely cat . Traffic is convenient since the location is in the city center and next to the central railway (Website hidden by Airbnb) is definitely a good place to stay in Oslo.
Prise de recul
En quelques minutes, nous pouvons avoir une classification de chaque article/commentaire/message présents dans notre corpus. C’est déjà très beau mais le CorEx n’est pas parfait. Je ne le recommande pas pour un travail qui demande de la grande précision (évaluation de tendances, calcul du nombre de commentaires liés à une catégorie en particulier).
Du fait des données non labellisées, nous ne pouvons pas évaluer précisément les performances du CorEx. Mais quelques lectures suffisent pour voir que le CorEx a une labellisation “facile”, c’est-à-dire qu’il suffit de peu de mots pour qu’un message soit assigné à un sujet.
Un message comme “A nice and cosy place, perfect for a weekend or a short trip to Oslo!” sera labellisé dans la catégorie “feeling” car les mots “nice”, “cozy”, “perfect” sont fortement associés aux “feel home”, “feel welcome”, bien que le message ne mentionne pas de “feeling”.
Ainsi, CorEx est très pertinent à utiliser avec des sujets vraiment distincts comme une classification d’articles journalistiques (entre sport et finance par exemple). Mais l’algorithme aura de piètres résultats s’il doit faire la différence entre des articles de handball ou de football.