Les sentiments à Tahiti : un point d’étape.

Arrivée du Windstar Wind Spirit sur le quai d’Uturoa

Tous les voyages ne sont pas ratés comme ceux qu’étudie Jean-Didier Urbain, et celui que je viens de vivre, sans prétendre au succès, est une étape accomplie. Un double voyage, physique d’abord, car rejoindre ce bout de France antipodique demande l’effort de se perdre dans le temps et dans l’espace, la Polynésie s’apprécie d’abord en regardant les cartes et en lisant l’histoire, séparant les cartes postales et les clichés, pour décrypter dans un continent océanique, le flux et le reflux des cultures, et un voyage mental ensuite quand on peut observer l’objet des observations qu’on veut analyser : les commentaires des internautes, le discours des touristes. Trianguler en quelque sorte et découvrir après leurs mots, l’objet de leur expériences et ceux qui en sont absents ( par exemple le mot pirogue, qui est le sport national, est quasi absent du corpus).

Le but de ce voyage était de faire un point d’étape sur un projet engagé au sein du Centre d’Etudes du Tourisme en Océanie-Pacifique, dont le but pragmatique conduit cependant à de nombreuses questions. Le but est simple : comment analyser les données produites par des dispositifs de crowdsourcing, les commentaires produits par les touristes sur des plateformes telles que TripAdvisor, Twitter, Booking, Airbnb, Expedia, Facebook ou Instagram, et quels enseignements en tirer. Il s’inscrit dans la perspective de l’étude de la satisfaction des consommateurs, l’analyse automatique et massive du texte permettant de construire des indicateurs de sentiments, d’émotion et de sujets de discussion, susceptibles de compléter voir de suppléer aux enquêtes par questionnaires traditionnelles, pour informer en continu les responsables d’activités économiques et sociales liées au tourisme qui représentent 11% de l’économie polynésienne.

A cette étape du projet les questions sont surtout méthodologiques. Comment extraire les données, comment constituer les corpus, comment analyser ce texte.

Pour la première question c’était l’occasion de rencontrer le groupe d’étudiants de licence dirigé par Sébastien Chabrier qui ont réfléchi et développé un programme de scrapping en php. Au-delà de la technique de collecte se pose naturellement des questions légales et éthiques : si ces données présentent peu de caractères personnels et ont une finalité de lecture publique, des problèmes de droit d’exploitation à fin de recherche peuvent se poser. L’éclairage des juristes sera nécessaire.

Pour celle de la constitution des corpus, on découvre peu à peu qu’une seule source n’est pas suffisante. Sur TripAdvisor les consommateurs se conforment à l’injonction et évaluent les hôtels uniquement, on y trouvera peu d’éléments pour apprécier leur expérience subjective du voyage, ils s’en tiennent à des aspects matériels et fonctionnels liés aux conditions d’hébergement. Les réseaux sociaux sont une source plus pertinente pour cet aspect, mais le suivi de certains acteurs – par exemple les commentaires sur les excursionnistes – pourrait être bien utiles. Un outil de collecte, outre son aspect technique et informatique (API et scrapping), doit suivre un plan raisonné de constitution d’un corpus à partir de plusieurs sources.

Sur le plan de l’analyse des données, le principal résultat obtenu est que pour assurer un traitement des données correct, le pré-traitement est une étape cruciale. La solution que nous avons adopté consiste à lemmatiser les mots, à identifier leur formes morphosyntaxiques et les dépendances syntaxiques qui les unissent. On réalise cette étape avec les ressources de CleanNLP et du “Part Of Speech”. Elle permet de nettoyer le texte et d’obtenir des solutions lisibles d’analyse de topics par la méthode LDA et d’approfondir les détails sémantiques (par exemple identifier les qualificatifs de certains objets et concept : hôtel, chambre, alimentation, environnement… Un développement important sera, par la nature des données, de compléter par une meilleure annotation des entités nommées (noms des iles, des établissements, des personnes). Plus généralement l’amélioration de cette étape passe par le développement d’index et de lexiques spécifiques et sans doute d’exploiter d’autres ressources telles que le remarquable Atlas Linguistique de la Polynésie Française.

En confrontant les acteurs aux données, nous avons eu le plaisir d’être accueillis par les représentants du Conseil des Professionnels de l’Hôtellerie et de leur présenter des premiers résultats en phase avec l’expérience vécue des managers et de rencontrer Stéphane Renard, conseiller au Ministère du Tourisme. Ce fût l’occasion de mieux comprendre la problématique économique et touristique : une croissance de 7% du nombre de voyageurs obtenue par l’ouverture de nouvelles lignes ( Frenchbee, United) créant de nouveaux flux de touristes dont une meilleure connaissance est clairement un enjeu. Les hôtels les plus importants n’en capturent que 2 ou 3%, au profit certainement d’autres formes d’hébergement : les pensions de famille qui connaitraient un épisode spéculatif et une professionnalisation qui pourrait les éloigner d’un modèle plus authentique et Airbnb qui semble gagner du terrain dans un contexte où le coût de la vie est très élevé, même pour des touristes aisés. On se verra aussi confirmer la prépondérance de Bora Bora et des motifs de lune de miel. D’autres rencontres avec des acteurs de terrain (Pensions et petits hôtels) nous aura appris l’importance des plateformes (50% de réservation via Booking pour l’un d’eux), le rôle des excursionnistes pour compléter l’expérience de séjour, mais aussi la gestion des approvisionnements. La toile de fond reste la durabilité, l’eau n’est pas partout disponible, la densité de tourisme fait question dans certaines iles, la question de la rencontre avec les populations est cruciale. La spécificité de la Polynésie en dépit de ses apparences de jardin et de son immensité (vaste comme l’Europe), réside dans la rareté de la terre, de petites populations et l’hétérogénéité des infrastructures.

La grande question réside dans la connaissance de ce qui détermine la production de ce type de contenu: quels effets des plateformes et de leur design sur le sentiment et les thématiques? On aura ainsi noté une chute de la production sur TripAdvisor et nous nous interrogeons sur les mécanismes de filtrages et de détection des faux avis. Quels effets des contributeurs qui diffèrent par leurs compétences langagières et leurs expériences de voyage? Un des résultats provisoires de nos analyse s montre ainsi des relations intéressantes entre le sentiment exprimé et le style d’écriture : les commentaires positifs sont plus courts et plus expressifs, les négatifs plus détaillés et plus neutre. Est-ce le résultat d’un biais d’approbation sociale? Quels effets enfin exercent les objets d’évaluation : activités, restaurants, les hôtels, excursions, rencontres, spectacles, couchers de soleils, le lagon, des jardins de corail, les baleines, la vie du Motu. Différentes facettes de l’expérience polynésienne, sans doute façonnées par les mythes, celui du paradis sur terre aux archipels chimériques, celui de la pieuvre qui réunit de ses bras les archipels du triangle polynésien.

La prochaine étape du projet va être une première généralisation. Avec Pierre Ghewy à l’UPF, et Hiriata Brotherson au Cetop, et l’aide des étudiants de la licence informatique, et de Jean-Baptiste Agostin à Paris, il s’agit d’abord de finaliser un premier corpus opérationnel (Tripadvisor+ Twitter+Airbnb), ensuite de tester sur ces données nos modèles et certaines de nos hypothèses en comparant deux sous-ensembles de commentaires : ceux relatifs à l’expérience de Bora-bora et ceux relatifs à celle de Tahiti, en contrôlant par la nature des hébergements.

Rendez-vous en septembre pour présenter les résultats et la méthode (On en a présenté les principes et des éléments de code aux étudiants de l’Ecole Doctorale de l’UPF). On les déposera progressivement sur notre compte Github. (quelques éléments préliminaires sont cependant disponibles sur r.benavent.fr ), le voyage ne fait que débuter.

Annexe : UPF conférence pour tous : ” Les commentaires des internautes, nouvelle source de connaissance des consommateurs. On y présente des premiers résultats et les grandes questions qui traversent la recherche. et une interview dans TahitiInfo.

Les sentiments de Tahiti

onou 2015

Les voyages sont faits pour être vécus mais ce qui en reste ce sont des mots. Des livres de voyageurs, le journal de bord des marins, et aujourd’hui le commentaire des expériences de consommation. A l’heure du post-exotisme ( pas celui-ci), quand le touriste pense rencontrer une culture authentique mais bien souvent façonnée par son propre regard, ce qui compte est moins ce que l’on a vécu que ce que l’on en garde : des selfies et le commentaire des lieux de séjours. C’est certainement moins poétique que Cook et Gauguin, mais plus profitable pour l’industrie du tourisme.

Et c’est à l’occasion d’un de ces voyages, avec l’aide des collègues du Cetop,  des étudiants du master de marketing de l’UPF, et l’écoute du team de Tahiti tourisme, que nous nous sommes lancés dans l’analyse des sentiments exprimés par les touristes à propos de leur séjour  avec une petite incursion dans les packages de text mining de r. Il n’y avait pas de meilleure place pour apprécier la critiques des auberges du paradis.

Pour la méthode, il s’agit d’abord de scrapper, avec les ressources du package rvest, le site de TripAdvisor. La Polynésie est isolée, trouvant ses clients dans trois grands bassins à plus de 10h de vol : l’Asie , les EU et la France. Il y a environ 150 hôtels et 300 pensions. Les résultats donnés dans cette note, sont établis sur la base d’une première extraction centrée sur Tahiti et portant sur 7700 commentaires. On généralisera plus tard sur les 77000 commentaires sur l’ensemble des archipels.

Ce corpus fait l’objet de deux types d’analyses comme on commence à le faire systématiquement dans ce type d’exercice : mesurer la tonalité positive ou négative (le sentiment) et les sujets évoqués ( topic analysis). Pour la première, on emploie tidytext, pour la seconde le modèle LDA du package Topicmodels.

Voici la présentation de travail (demo), avec quelques éléments de code, rendez-vous au piurn 2018 pour une présentation plus complète.

#IA à la moulinette du #ML

Printable up to 18″x18″

Ces dernières années les progrès du text mining renouvellent largement l’étude des contenus textuels.

Un saut a été franchi depuis les techniques classiques d’analyse factorielles des correspondances. Les outils récents inspirés du ML peuvent remplacer ou au moins compléter les bonnes vieilles techniques de l’analyse lexicale.

Alors plutôt que de faire des Sudoku pendant les vacances, autant se balader dans les packages de r et d’appliquer ces techniques à un cas pratique. Pourquoi ne pas explorer justement ce que l’on dit de ces techniques sur les réseaux sociaux. Que dit-on de l’intelligence artificielle et du machine learning ? Quels en sont les sujets de conversation?

Commençons par le début. Il nous faut un corpus. Autant le prendre là où il est facile à capturer, c’est à dire dans Twitter.

La première étape consiste à créer un compte sur l’API (REST), pour pouvoir extraire ce que l’on souhaite ( avec des limites imposées par twitter). Et lLa seconde étape consiste simplement à se connecter à l’API, via r, et à lancer une requête. Ce qui se fait de manière simple avec le code suivant :


 #accès  à l api de twitter
 consumerKey<-"Xq..."
 consumerSecret<-"30l..."
 access_token<-"27A..."
 access_secret<-"zA7..."
 setup_twitter_oauth(consumerKey, consumerSecret, access_token,access_secret)

Pour rechercher les tweets, on échantillonne sur plusieurs variantes de hashtag, en préférant la méthode des twits les plus récents (une alternative proposée par Twitter est de choisir les plus populaires, une troisième méthode mixant les deux approches). Il suffit ensuite de fusionner les fichiers, puis de dédupliquer les enregistrements identiques.


 #recherche des twits avec plusieur requetes 
tweets1 <- searchTwitter("#IA", n = 2000, lang = "fr", resultType = "recent", since = "2017-08-01") 
tweets2 <- searchTwitter("#ML", n = 2000, lang = "fr", resultType = "mixed", since = "2017-08-01") 
tweets3 <- searchTwitter("#AI", n = 2000, lang = "fr", resultType = "recent", since = "2017-08-01") 
tweets4 <- searchTwitter("#MachineLearning", n = 2000, lang = "fr", resultType = "recent", since = "2017-08-01") 
tweets5 <- searchTwitter("#Deeplearning", n = 2000, lang = "fr", resultType = "recent", since = "2017-08-01") 
#transformer en data frame 
tweets_df1 <- twListToDF(tweets1) 
tweets_df2 <- twListToDF(tweets2) 
tweets_df3 <- twListToDF(tweets3) 
tweets_df4 <- twListToDF(tweets4) 
tweets_df5 <- twListToDF(tweets5) 
tweets_df <- rbind(tweets_df1,tweets_df2,tweets_df3,tweets_df4,tweets_df5)

Le décompte se faisant tout les quarts d’heure, on peut répéter l’opération pour récupérer quelques dizaines de milliers de tweets en quelques heures. Et si l’on a un peu de budget on changera d’Api pour streamer en temps réel ce que l’on souhaite.

On dispose donc d’un corpus d’environ 6000 tweets, dont il va falloir nettoyer le contenu. C’est l’opération la plus difficile, elle demande de l’astuce et une bonne compréhension des contenus. Dans notre cas, différentes opérations vont être menées et elles constituent l’étape essentielle où l’astuce de l’analyste est la clé de l’analyse.

  • Il faut aussi éliminer les liens URL, mais aussi les mentions
  • De même les nombres, la ponctuation, mettre en minuscule
  • Certains termes risque de n’apporter aucune information, les mots de liaisons, les articles,  et naturellement les termes qui ont permis la sélection ( #IA par exemple)
  • et enfin réduire les termes à leurs racines pour éviter une trop grande fréquences de termes équivalents mais distincts ( poisson, poissonier) c’est l’opération de stemming qui identifie la racine du lexique constitué.
 
#recherche des twits avec plusieur requetes 
# creation du corpus et nettoyage du texte

tweets_corpus <- Corpus(VectorSource(tweets_text))

removeURL <- function(x) gsub("http[[:alnum:][:punct:]]*", "", x) #enlever les liens
tweets_corpus <- tm_map(tweets_corpus, content_transformer(removeURL)) #enlever les liens
removeACC <- function(x) gsub("@\\w+", "", tweets_corpus) #enlever les comptes
tweets_corpus <- tm_map(tweets_corpus, content_transformer(removeACC)) #enlever les comptes
tweets_corpus <- tm_map(tweets_corpus, removeNumbers) #enlever les nombre
tweets_corpus <- tm_map(tweets_corpus, removePunctuation) # ici cela va supprimer automatiquement tous les caractères de ponctuation
tweets_corpus <- tm_map(tweets_corpus, content_transformer(tolower)) #mettre en minuscule
tweets_corpus <- tm_map(tweets_corpus, removeWords, stopwords("french")) #supprimer automatiquement une bonne partie des mots français "basiques"
tweets_corpus <- tm_map(tweets_corpus, stripWhitespace) # ici cela va supprimer automatiquement tous les espaces vides
tweets_corpus <- tm_map(tweets_corpus, stemDocument, language = "french") #on cherche les radicaux des termes
tweets_corpus <- tm_map(tweets_corpus, removeWords,c("ai", "machinelearning","ia","ml", "deeplearning","rt")) #enlever le terme commun
tdm <- TermDocumentMatrix(tweets_corpus, control=list(wordLengths=c(5, 30))) #creation de la matrice termsXdocuments

On conduit cette opération avec les ressources du package tm qui est le véritable moteur du text mining. C’est une opération très empirique, la procédure se construit de manière itérative, en prenant soin de bien séquencer les différentes actions. Et il sera particulièrement utile de regarder ce que font les autres data-scientists, leurs astuces et les élégances de langage qu’ils emploient. C’est l’étape la plus difficile, d’un point de vue technique  mais aussi pragmatique.

La première commande transforme le fichier de données dans un format particulier qui est celui qui décrit le corpus. Chaque enregistrement est codé sous la forme d’un triplet : le terme ( un mot racine), le document ( un tweet) et la fréquence d’apparition du terme dans le document. Pour l’utilisateur d’un logiciel statistique classique, SPSS, c’est l’élément le plus troublant, r ne fonctionne pas simplement avec des tableaux individusXvariables, ses objets sont beaucoup plus subtils, complexes mais pratiques. Les commandes précedentes effectuent les transformations requises du corpus. La dernière crée la matrice termes document que nous voulons étudier.

Comme à l’ordinaire, débutons par le plus simple : quels sont les termes les plus fréquents? A cette fin, deux technique peuvent être employées. La première est simplement la représentation ordonnée par la fréquence des termes, la seconde, très visuelle est de produire une représentation très populaire, celle des nuages de mots. En fonction de ces résultats on pourra réitérer les opérations précédentes et ajuster le jeu de données et sélectionner les termes que l’on veut analyser. En voici le code et les résultats.


dim(tdm)
nTerms(tdm)
m <- as.matrix(tdm)
v <- sort(rowSums(m), decreasing = TRUE)
d <- data.frame(word = names(v),freq = v)

head(d, 350)
barplot(d[1:70,]$freq, las = 2, names.arg = d[1:70,]$word,
col ="lightblue", main ="Mots les plus fréquents dans les tweets #IA",
ylab = "Fréquences", horiz=TRUE, cex.names = .7)
x11() #pour ne pas ecraser le chart precedent
set.seed(123456)
wordcloud(tweets_corpus, max.words = 100, colors = brewer.pal(8, "Dark2"))

Les choses sérieuses viennent maintenant avec l’utilisation d’une méthode de modélisation des topics. On emploie ici le package ModelTopics et la méthode LDA ( Latent Dirichlet Allocation) , qui cherche à calculer la probabilités qu’un terme appartienne à un Topic, et qu’un topic appartiennent à un document, en ne connaissant que l’appartenance des termes aux document. L’idée est de prendre en compte que chaque document est un mélange de topic, et que chaque topic est un mélange de mots. On en trouvera une excellente présentation ici dont nous avons repris des éléments de code, pour une présentation plus technique la page Wikipedia est un bon début.


#topic modeling

r.dtm <- DocumentTermMatrix(tweets_corpus, control = list(minWordLength =0))
lda <- LDA(r.dtm,k =16, control = list(alpha = 0.01))
(term <- terms(lda, 16)) # first 6 terms of every topic

ap_topics <- tidy(lda, matrix = "beta")
ap_topics

ap_top_terms <- ap_topics %>%
group_by(topic) %>%
top_n(20, beta) %>%
ungroup() %>%
arrange(topic, -beta)

ap_top_terms %>%
mutate(term = reorder(term, beta)) %>%
ggplot(aes(term, beta, fill = factor(topic))) +
geom_col(show.legend = FALSE) +
facet_wrap(~ topic, scales = "free") +
coord_flip()

#library(LDAvis)

Le résultat principal est constitué par le diagramme suivant qui représente pour chaque topic ( on a choisit d’en identifier 9 de manière avouons le arbitraire – la question de la détermination du nombre optimum n’est pas encore résolue). Les valeurs sont les probabilités ( beta) que les termes soient associés aux topics. C’est une sorte de spectre lexical. Le topic 5, par exemple semble être relatifs aux chatbots, à l’IoT et à ses applications en marketing et dans les fintech.

Avouons- le l’interprétation n’est pas évidente. Nous avons besoin d’un nettoyage plus poussé et sans doute de jouer encore plus sur les paramètres du modèle qui consistent d’abord dans le nombre de sujets (topics) qui mérite sans doute d’être plus élevés, et dans un paramètre Alpha qui ajuste le nombre de mots associés aux sujets. Encore mieux, il serait bon d’implémenter le package Ldavis qui produit une visualisation remarquable.

On pourrait aller encore plus loin en considérant ce premier modèle comme un modèle d’entrainement, puis en l’utilisant pour classifier de nouveaux documents. Ainsi, imaginons d’extraire chaque jour un nouveau jeu de données, on peut imaginer construire un outils qui donne l’évolution des thématiques dans la conversation des réseaux-sociaux.  Il nous suffira de la commande suivante :

test.topics <- posterior(train.lda,test)

Une autre approche est celle de la méthode Tsne, fournit par le package Rtsne. C’est finalement une sorte d’analyse des similarités, à la manière du MDS ( Multi Dimensionnal Scaling) mais qui mets en jeu des calculs de distances très particulier, dont la vertu principal est de rendre compte de niveaux d’échelles différents. Ce qui est très proche sera plus ou moins éloignés, ce qui est loin est plus ou moins rapprochés. On échappe au phénomène de dégénérescence du vieux MDS, et à une meilleure représentation quand les objets sont éloignés. On contrôle ceci par un paramètre de perplexité, qui reflète sommes toute le nombre de voisins pris en compte dans les calculs. On lira ceci pour mieux en comprendre les effets.


#tsne
library(Rtsne)
tdmdata<- as.matrix(tdm)
# run Rtsne with default parameters
tsne_out <- Rtsne(tdmdata, dims=2, initial_dims = 80, check_duplicates = FALSE, verbose=TRUE, perplexity = 20, theta=0.8,  max_iter = 1000)
plot(tsne_out$Y, t='n')
text(tsne_out$Y, labels=rownames(tdmdata),cex = 0.7)

En voici les résultats pour plusieurs degrés de perplexité. La représentation est illisible ( il y a environ 4000 termes) mais des groupes de mots bien distincts apparaissent. Elle va nous servir de base pour une meilleure visualisation de cet espace.

Un modèle avec une perplexité de 20 et à 2 dimensions est choisi comme base d’une meilleure visualisation. On va se concentrer sur les termes les plus fréquents et l’on applique une méthode de classification (méthode de ward) dans l’espace définit par tsne, et avec un peu de code supplémentaire, on produit un dendogramme radial produit par le package Ape, dans lequel la taille relative des termes est proportionnelle à leur fréquence et les couleurs correspondent à un découpage en 7 classes.


X1<-tsne_out$Y[,1]
X2<-tsne_out$Y[,2]
Fq<-rowSums (tdmdata, na.rm = FALSE, dims = 1)
Rtsne<-data.frame(Fq,X1, X2)
Rtsne2 <- subset(Rtsne, subset=Fq>30, select=c(X1,X2))

#clustering
m2 <- as.matrix(Rtsne2)
distMatrix <- dist(scale(m2))
fit <- hclust(distMatrix, method = "ward.D2")
p<-plot(fit)
rect.hclust(fit, k = 7) # cut tree into 7 clusters

library(ape)
plot(as.phylo(fit), type = "unrooted")
plot(as.phylo(fit), type = "fan")

# vector of colors
mypal = c("#556270", "#4ECDC4", "#1B676B", "#FF6B6B", "#C44D58")
# cutting dendrogram in 7 clusters
clus = cutree(fit, 7)
# plot
op = par(bg = "#E8DDCB")
# Size reflects frequency
plot(as.phylo(fit), type = "fan", tip.color = mypal[clus], label.offset = 1, cex = log(Rtsne$Fq, 10), col = "red")

Voici le trail! On y lit plus clairement les sujet : on peut commençant en descendant à droite par un premier thème sur les chatbots et de Facebook naturellement qui se poursuit sur une thématique marketing et bancaire, les applications. Le troisième thème, en rouge est plus centré sur l’entreprise et l’organisation, l’impact sur les conseillers. Les thèmes du fantasme et du changement nécessaire s’enchaîne assez logiquement, un sixième thème se centre sur la résolution de problème, le dernier est relatif aux questions entrepreuneuriales et aux start-up.
On aura condensé ainsi un contenu brut de 7000 tweets et 4000 mots en une image.

Crédit Photo : Eugenia Loli – immaculate