#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

La voix des bots ouvre les marchés

hal-mortDans 2001 Odyssée de l’espace, la conversation finale entre l’homme et Hal,  l’intelligence artificielle, ne passe pas par un écran, des diodes, un visuel plan souvent et rarement holographique, mais par la voix fût-elle synthétique.

Si depuis les années 80, en  débutant l’histoire avec le PC – même si  l’écran de cinéma et le petit écran de la télévision ont converti les masses depuis bien plus longtemps – l’écran se décline dans toutes les tailles et des épaisseurs de plus en plus fines, s’équipant d’une sensibilité tactile et par conséquence ouvre les voix de l’intelligence. Cet écran favorise l’image, unique ou fragmenté, ainsi que le texte, l’écrit. La conversation demeure épistolaire. Les textos sont des télégrammes.

L’avenir de la conversation avec les machines risque de quitter l’écran pour rejoindre le régime de conversation le plus universel et le plus fondamental : la vocalise. Le premier des médias, avec la lumière, c’est une onde qui parcourt l’air. Une vague qui s’élance des lèvres pour faire vibrer l’oreille interne puis être convertie en crépitement électrique dans les réseaux du cortex. Babiller. Parler.  Il faut à un humain guère plus de 2 ou 3 ans pour s’y mettre. Et encore, l’art des vagues peut ne rien dire et se concentrer sur la forme même de l’onde, c’est la musique et ses langues.

De manière plus prosaïque, les technologies nouvelles du #deeplearning en permette de nouveaux développement, à l’instar de la technologie Wavenet proposé par une des filiales d’Alphabet – DeepMinds ( et on recommande de lire tout le post et même la publication).

L’application la plus évidente est naturellement celles des livres parlants, de l’audio description pour aider les mal-voyants. Le vaste marché des centres d’appel et de relation client est concerné au premier titre, car automatiser une grande partie de la tâche par des agents conversationnel (incarnés dans une voix plutôt qu’une image) promet des gains de productivités considérable. On peut l’élargir sans hésiter à l’ensemble des ATM et autres bornes interactives. Ces technologies concerne aussi les médias où l’on imagine des bulletins de nouvelles et de météo générés par des intelligences virtuelles et lues à la radio par des speakers synthétiques. Mais surtout, il y a deux vastes marchés potentiels où l’interface fondamentale est liée au son et la voix. Il s’agit de manière évidente celui des autos et autres véhicules  autonomes. C’est le moyen de donner au passager un moyen de contrôle de l’ IA qui le conduit, ne serait-ce que lui ordonner de s’arrêter – bref un safeword. L’autre est plus proche de nous , c’est celui- des interfaces telles que Echo d »Amazon , Siri de Apple, ou son analogue Everywhere chez Google. Parler est souvent le moyen le plus simple de commander. Ce type d’ interface a vocation à s’enrichir, ne serait-ce que par la coordination des objets connectés au domicile ( ordonner par son intermédiation la température souhaitée de la pièce). Il y a encore bien d’autres marchés, c’est une question d’imagination. Le point essentiel c’est de comprendre que les interfaces audios représentent un espace encore inexploré : pour demander qu’on nous passe le sel, on ne s’envoie pas de texto, on vocalise. L’informatique d’hier fonctionne au doigt et à l’oeil, celle du futur proche aura des lèvres et des oreilles.

PS : cette petite note a été suscitée par des questions d’Atlantico à propos de WaveNet. Elle rejoint d’autres interviews dans le même titre et des sujets similaires :