la seconde partie du cours sur la social data avec trois chapitres:
-l'approche bag of words avec tidytext,
-le sentiment analysis avec r
-le nlp avec clean nlp et udpipe
2. Introduction g´en´erale du cours
Ce cours permet aux ´etudiants de se familiariser avec les donn´ees capturant la
mani`ere dont les individus interagissent sur les r´eseaux sociaux.
Les techniques utilisent le logiciel r et diff´erentes de ses librairies. Chaque ´etudiant devra
installer sur sa machine r, l’environnement de travail Rstudio
(https://www.rstudio.com/) et les biblioth`eques n´ecessaires.
Le cours est construit sur 6 s´eances. Id´ealement, chaque s´eance sera d´ecoup´e de la
sorte:
matin: pr´esentation et d´emonstration du code r
apr`es-midi: mise en application des ´el´ements
A la fin du cours, chaque ´etudiant devra pr´esenter une analyse autour de social data de
son choix.
April 23, 2018 2 / 241
3. plan du cours
le contenu du cours est le suivant:
S´eance 1: social data et extraction de la social data avec r
S´eance 2: manipuler les donn´ees dans r
S´eance 3: repr´esenter les donn´ees dans r
S´eance 4: les basiques du text mining dans r
S´eance 5: l’analyse de sentiment avec r
S´eance 6: le nlp avec r
April 23, 2018 3 / 241
4. ressources
Le cours est bas´e sur plusieurs ouvrages r´ecents et consultables en ligne:
R for Data Science, Wickham & Grolemund, O’Reilly, 2017, disponible en ligne:
http://r4ds.had.co.nz/
Advanced R, Wickham, CRC Press, 2014, disponible en ligne:
https://adv-r.hadley.nz/
Data Visualization for Social Science, Healy, forthcoming, Princeton University
Press, disponible en ligne: http://socviz.co/
Cookbook for R, Chang, O’Reilly, 2013, seconde ´edition, disponible en ligne:
http://www.cookbook-r.com/
Text Mining with R, Silge & Robinson, O’Reilly, 2017, disponible en ligne:
https://www.tidytextmining.com/
Introduction `a la programmation en R, Goulet, 2016, cinqui`eme ´edition:
https://cran.r-project.org/doc/contrib/Goulet introduction programmation R.pdf
The Art of R Programming, Matloff, 2011, no starch press,
http://www.freetechbooks.com/the-art-of-r-programming-t1087.html
Speech and Language Processing, Jurafsky et Martin, 2017,
https://web.stanford.edu/ jurafsky/slp3/
April 23, 2018 4 / 241
5. ressources hors ouvrages
En dehors de ces ouvrages, diff´erentes ressources peuvent ˆetre int´eressantes:
la documentation sur la suite tidyverse: https://www.tidyverse.org/
les cheatsheets `a t´el´echarger sur le site de rstudio:
https://www.rstudio.com/resources/cheatsheets/
le site de Hadley Wickham: http://hadley.nz/
le blog de thinkR: https://thinkr.fr/le-blog/
le m´eta blog r-bloggers.com: https://www.r-bloggers.com/
le blog de David Robinson: http://varianceexplained.org/
le blog de Julia Silge: https://juliasilge.com/blog/
le blog Rstudio: https://blog.rstudio.com
sur twitter le hastag #rstats
April 23, 2018 5 / 241
6. ressources th´eoriques
Mis `a part quelques incursions, le cours n’est pas un cours de datascience. Pour les
´etudiants d´esireux d’acqu´erir les techniques de base de la datascience, deux ouvrages de
base pourront ˆetre consult´es:
The Elements of Statistical Learning, Hastie, Tibshirani & Friedman , Springer,
seconde edition 2008 : https://web.stanford.edu/ hastie/Papers/ESLII.pdf
An Introduction to Statistical Learning with Applications in R, James, Witten,
Hastie & Tibshirani, Springer, sixi`eme edition 2013 :
http://www-bcf.usc.edu/ gareth/ISL/
Concernant le deep learning et R, ce blog (https://tensorflow.rstudio.com/blog.html)
est une source int´eressante en lien avec cet ouvrage r´ecent:
https://www.manning.com/books/deep-learning-with-r.
April 23, 2018 6 / 241
8. S´eance 4: le package tidytext
April 23, 2018 8 / 241
9. L’approche ’bag of word”
Tr`es tr`es globalement, on peut distinguer deux approches en terme de text mining:
les approches de type ”bag of word”:
les approches de type ”syntactic parsing”
L’approche bag of word approche un texte comme une suite non organis´ee de mots. Dans ce cours, nous verrons le package
tidytext qui permet de d´ecouper un text en ngrams et poser les premi`eres briques du topic modeling
Figure: l’approche bag of word, tir´e de Speech and Language Processing. Jurafsky et Martin (2017)
April 23, 2018 9 / 241
10. L’approche ”syntactic parsing”
L’approche ”syntactic parsing” appr´ehende un document comme un vecteur de V dimensions o`u V est la taille du vocabulaire
utilis´e. Cette repr´esentation permet de prendre en compte la structure d’organisation des mots.
Figure: l’approche ”syntactic parsing”, Kwartler (2017)
Concernant l’approche ”syntactic parsing”, nous utiliserons diff´erents packages d´evelopp´es r´ecemment autour du NLP comme
openNLP ou word2vec. Mais avant de voir ces packages, il nous faut nous plonger dans les techniques de nettoyage du texte.
April 23, 2018 10 / 241
11. le nettoyage du texte
Apr`es les phases de collecte et de pr´etraitement des donn´ees vient la phase de nettoyage. Cette
phase est un passage oblig´e qui va permettre notamment:
d’uniformiser la mise en forme du texte (ponctuations, majuscule, termes sp´eciaux),
de supprimer les mots communs ou stopword,
de supprimer certains mots via un dictionnaire sp´ecifique,
de supprimer ou non certains ´el´ements (urls, ´emojis, etc...)
substituer des chaines de caract`ere
Un certain nombre d’outils et de techniques permettent dans r de r´ealiser ces tˆaches:
les regex ou expressions r´eguli`eres qui fournissent des m´ethodes normalis´ees pour
rechercher, supprimer et substituer des chaˆınes de caract`eres,
des packages sp´ecifiques comme stringr ou stringi (il y a en a d’autres) qui permettent
de traiter les chaˆınes de caract`eres,
des fonctions sp´ecifiques de package de text mining comme lsa ou tm qui permettent de
nettoyer le texte
April 23, 2018 11 / 241
12. le nettoyage du texte: un processus pragmatique et
progressif
Avec le text-mining il faudra souvent coder soi-mˆeme certaines proc´edures adhoc `a l’aide de ces
´el´ements:
en ´ecrivant des fonctions qui permettent d’effectuer en groupe des traitements,
en recombinant certaines proc´edures existants
en adaptant la documentation existante (stackoverflow, ....)
Dans tous les cas, la phase de nettoyage soit ˆetre:
pragmatique: `a chaque texte, `a chaque ´etude son traitement et ses phases de nettoyage,
progressive: `a chaque phase, on risque d’endommager le corpus de mani`ere permanente
(ex: supprimer du texte ou des expressions non voulues)
maˆıtris´ee: certains traitements sur les matrices de texte sont extrˆemement gourmands en
m´emoire active. Or r est ´egalement tr`es gourmand (c’est l’un de ses d´efauts...), il faudra
parfois faire des arbitrages entre les proc´edures.
April 23, 2018 12 / 241
13. les fonctions de base pour travailler avec les chaˆınes de
caract`ere
De base r poss`ede des fonctions pour travailler avec les chaˆınes de caract`ere:
https://stat.ethz.ch/R-manual/R-devel/library/base/html/grep.html
Example
# 1 d´etecter si le pattern est pr´esent dans ma cha^ıne de caract`ere ==>bool´een
grepl(mon pattern, ma cha^ıne)
# 2 obtenir l’index des ´el´ements d’une liste matchant le pattern ==>numeric
grep(mon pattern, ma cha^ıne)
# 3 substituer un pattern `a un autre
sub(ma_cha^ıne, mon pattern, mon pattern de remplacement, ma cha^ıne) ***
# 4 indique `a quelle place un pattern appara^ıt ==>matrice
gsub(ma_cha^ıne, mon pattern, mon pattern de remplacement, ma cha^ıne, ignore.case=T)
# 5 localise un pattern dans une cha^ıne de caract`ere
regexpr(’’a’’, message)
April 23, 2018 13 / 241
14. les fonctions de base pour travailler avec les chaˆınes de
caract`ere (2)
Quelques fonctions suppl´ementaires
Example
# 1 strsplit: segmenter une cha^ıne de caract`ere si matching d’un pattern ==>cha^ıne
strsplit(x, ma cha^ıne, pattern)
# 2 nchar: obtenir le nombre de caract`ere d’une cha^ıne: ==>numeric
nchar(ma cha^ıne)
# 3 paste: concat`ene un objet r en une cha^ıne de caract`ere avec s´eparation
paste(mon_objet, sep = " ", collapse = NULL)
# 4 agrep: matching imparfait (notion de distance)
agrep(pattern, ma cha^ıne ignore.case=FALSE, max= integer)
April 23, 2018 14 / 241
15. le package stringr
Le package stringr permet de manipuler les chaˆınes de caract`ere sans transformation pr´ealable
du texte (`a la diff´erence du package tm qui n´ecessite de transformer le texte en un corpus).
Int´egr´e dans tidyverse, il est possible de l’utiliser par exemple pour traiter l’ensemble des lignes
d’une colonne d’un dataframe comprenant du texte. Il permet d’effectuer les pr´etraitements en
amont de l’utilisation du package tidytext.
Le package offre de nombreuses options et possibilit´es pour manipuler les chaˆınes de caract`ere.
Dans les phases les plus communes de text mining nous utiliserons tr`es souvent trois op´erations:
je veux d´etecter si une phrase contient un pattern particulier (mot, expression) pour
compter le nombre d’occurrence, connaˆıtre la position du pattern dans la chaˆıne de
caract`ere
je veux extraire un pattern particulier
je veux substituer un pattern particulier `a un autre
je veux filter mes donn´ees en fonction de l’existence un pattern particulier dans ma
chaˆıne de caract`ere
April 23, 2018 15 / 241
16. d´etecter des patterns avec le package stringr
Example
# 1 d´etecter si le pattern est pr´esent dans ma cha^ıne de caract`ere ==>bool´een
str_detect(ma_cha^ıne, mon pattern)
# 2 obtenir l’index des ´el´ements d’une liste matchant le pattern ==>numeric
str_which(ma_cha^ıne, mon pattern)
# 3 compter le nombre de fois o`u le pattern appara^ıt ==>numeric
str_count(ma_cha^ıne, mon pattern)
# 4 indique `a quelle place un pattern appara^ıt ==>matrice
str_locate(ma_cha^ıne, mon pattern)
April 23, 2018 16 / 241
17. les r´esultats
Example
gateau<-c("eclair", "mousse", "baba")
# 1 d´etecter si le pattern est pr´esent dans ma cha^ıne de caract`ere
str_detect(gateau, "a")
[1] TRUE FALSE TRUE
# 2 d´etecter l’index
str_which(gateau, "a")
[1] 1 3
# 3 compter le nombre de fois o`u le pattern appara^ıt
str_count(gateau, "a")
[1] 1 0 2
# 4 d´etecte `a quelle place un pattern appara^ıt
str_locate(gateau, "a")
start end
[1,] 4 4
[2,] NA NA
[3,] 2 2
April 23, 2018 17 / 241
18. extraire et identifier des patterns avec le package stringr
Example
# 1 extraction d’un pattern ==>cha^ıne caract`ere
str_sub(ma_cha^ıne, d´ebut de l’extraction av, fin de l’extraction apr`es)
str_sub(message, 2,4)
# 2 extract des ´el´ements d’une liste contenant le pattern ==>cha^ıne
str_subset(ma_cha^ıne, mon pattern)
str_subset(message, "z")
# 3 extraction du pattern `a chaque matching ==>vecteur caract`ere
str_extract(ma_cha^ıne, mon pattern)
str_extract(message, "z’’)
str_extract_all(message, "z")
# 4
str_match(ma_cha^ıne, mon pattern)
str_match(message, "z’’) matrice
str_match_all(message, "z") matrice
April 23, 2018 18 / 241
19. les r´esultats
Example
# 1 str_sub(gateau, 2,4)
[1] "cla" "ous" "aba"
# 2 str_subset(gateau, "a")
[1] "eclair" "baba"
# 3 str_extract_all(gateau, "a")
[1] "a" NA "a"
# 4 str_extract_all(gateau, "a")
[[1]]
[1] "a"
[[2]]
character(0)
[[3]]
[1] "a" "a"
# 5 str_match(gateau, "a")
[,1]
[1,] "a"
[2,] NA
[3,] "a"
April 23, 2018 19 / 241
20. substituer des patterns avec le package stringr (***)
Example
# 1
str_sub()<-value
# 2
str_replace(ma_cha^ıne, mon pattern, mon pattern de remplacement)
# 3
str_replace_all(ma_cha^ıne, mon pattern, mon pattern de remplacement)
# 4
str_to_lower(ma_cha^ıne)
str_to_upper(ma_cha^ıne)
str_to_title(ma_cha^ıne)
April 23, 2018 20 / 241
21. autres fonctions int´eressantes de stringr
Example
# 1
str_length (ma_cha^ıne) extraction de la longueur d’une cha^ıne de caract`ere =>numeric
str_length(gateau)
[1] 6 6 4
# 2
str_pad(ma_cha^ıne, nbcar_av, nbcar_ap) place espace avant apr`es (str_trim())
[1] "eclair" "mousse" "baba"
# 3
str_dup(ma_cha^ıne, numeric)
str_dup(gateau,3)
[1] "eclaireclaireclair" "moussemoussemousse" "babababababa"
April 23, 2018 21 / 241
22. un compl´ement `a stringr: stringi
stringi permet de manipuler les chaˆınes de caract`ere sans transformation pr´ealable du texte. La
documentation (https://cran.r-project.org/web/packages/stringi/stringi.pdf) de 136 pages (!!!)
donne l’aper¸cu des possibilit´es. Comme stringr le package permet de substituer, extraire,
compter, trier les chaˆınes de caract`ere via des proc´edures de matching. Voici une liste des
fonctions souvent utilis´ees:
stri detect()
stri count()
stri dup()
stri extract all()
stri length()
stri replace all()
stri split()
stri sub()
stri subset()
stri reverse()
stri pad both()
stri match all()
stri replace na()
stri trim both()
2
April 23, 2018 22 / 241
23. Comparaison entre les packages de gestion des chaˆınes de
caract`ere
Objet Base r Stringr Stringi forme
extraction d’un pattern regmatches() str extract() stri extract all chaine
extraction selon position regmatches() str sub() stri sub() chaine
extraction des x pattern regmatches() str extract all() stri extract all chaine
localisation des pattern regexpr() str locale() stri locale() numeric
localisation des x patterns gegexpr() str locale all() stri locale all() numeric
substitution des pattern sub() str replace() stri replace() chaine
substitution x fois des pattern gsub() str replace all() stri replace all() chaine
d´etection d’un pattern grepl() str detect() stri detect() bool´een
d´ecoupe selon un pattern strsplit() str split() stri split() chaine
concat`ene selon un pattern paste(), paste0() str c() stri c et stri paste chaine
donne la longueur d’une chaˆıne nchar str length() stri length numeric
Table: Comparaison entre les packages de gestion des chaˆınes de caract`ere adapt´e de ”automated data collection with r”,
Munzert & al.
April 23, 2018 23 / 241
24. exemple d’utilisation de str detect
Je veux identifier les posts facebook qui contiennent des termes
particuliers afin de cr´eer une cat´egorie.
Example
# 1 je cr´ee une liste, mon dictionnaire de mots cl´es
jeux <- c("jeu", "concours", "CONCOURS","Concours", "Jeux", "Gagnez",
"Jouer", "tirage","tir´e","Tirage", "jouer")
# 2 je cr´ee une colonne suppl´ementaire dans mon extract que je nomme concours
mes_donnees$concours[is.na(mes_donnees$concours)] <- "autre"
# 3 je cr´ee ma r`egle: si je d´etecte un des mots dans le titre du post
alors ce le post sera class´e ’’jeu’’ sinon ’’autre’’
mes_donnees<-mes_donnees%>%
mutate(concours=ifelse(str_detect(message, paste(jeux, collapse="|")),
"concours", "autre"))
April 23, 2018 24 / 241
25. exemple d’utilisation de string detect
Quel r´esultat?
Example
graphique_eng_concours<-numi_neomas%>%
mutate(annee = format(created_time, "%Y"))%>%
group_by(type,concours,from_name, annee)%>%
filter(annee>="2017")%>%
filter(concours !=’NA’)%>%
summarise(total = sum(total_engagement))%>%
ggplot(aes(x= reorder(from_name, -total),y=total,fill=from_name))+
geom_bar(stat = "identity")+coord_flip()+
facet_grid(concours~type)+
scale_y_continuous(labels = comma)+labs(x = "page",
y = "volume de l’engagement",
title = "volume d’engagement g´en´er´e
par les posts en 2017",
subtitle = "hors dark posts")
April 23, 2018 25 / 241
27. exemple d’utilisation de str remplace
Je travaille sur un dataset twitter et je veux supprimer `a la fois les RT et
les urls des messages
Example
# 1 je cr´ee une cha^ıne de caract`ere (une expression r´eguli`ere)
remplace_regex <- "https://[A-Za-zd]+
|http://[A-Za-zd]+|&|<|>|RT|https"
# 2 je passe ma regex avec la fonction str_replace_all
clean_text <- mes_datas %>%
filter(!str_detect(text, "^RT")) %>%
mutate(text_clean = stringr::str_replace_all(text, remplace_regex,’’’’ )
# 3 autre ´ecriture
clean_text <- mes_datas %>%
filter(!str_detect(text, "^RT")) %>%
mutate(text_clean = stringr::str_replace_all(text, "https://t.co/[A-Za-zd]+
|http://[A-Za-zd]+|&|<|>|RT|https",’’’’ )
April 23, 2018 27 / 241
28. application de la proc´edure
Example
tmls <- rtweets::get_timelines(c("hadleywickham", "drob", "juliasilge"), n = 3200)
==>colonne du dataset est tmls$text
#je cree une nouvelle colonne
tmls %>%
filter(!str_detect(text, "^RT")) %>%
mutate(text_clean = stringr::str_replace_all(text, remplace_regex,’’’’ )
#je cree un nouveau dataset avec une nouvelle colonne
clean_text <- tmls %>%
filter(!str_detect(text, "^RT")) %>%
mutate(text_clean = stringr::str_replace_all(text, remplace_regex,’’’’ )
April 23, 2018 28 / 241
29. autres formules int´eressantes
Example
#je veux extraire les urls d’une chaine de caract`ere
library(stringr)
url_pattern <- "http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*(),]|(?:%[0-9a-fA-F][0
mes_urls <- str_extract(tmls, url_pattern)
mes_urls <- unlist(mes_urls)
mes_urls<-na.omit(mes_urls)
mes_urls<-as.data.frame(mes_urls)
mon_data_frame$mes_hastags <- str_extract_all(mon_data_frame$mon_text, "#S+")
hs_pattern<-"#S+"
mon_data_frame$mes_hastags <- str_extract_all(mon_data_frame$mon_text, hs_pattern)
mon_data_frame$mes_id <- str_extract_all(mon_data_frame$mon_text, "@S+"
id_pattern<-"@S+"
mon_data_frame$mes_hastags <- str_extract_all(mon_data_frame$mon_text, id_pattern)
April 23, 2018 29 / 241
30. travail sur les hashtags
Example
tmls$mes_hastags <- str_extract_all(tmls$text, "#S+")
hs_pattern<-"#S+"
tmls$mes_hastags <- str_extract_all(tmls$text, hs_pattern)
hashtags <- unlist(tmls$mes_hastags)
hashtags<-as.data.frame(hashtags)
hashtags$hashtags<-substring(hashtags$hashtags, 2)
nb_hashtags<-table(hashtags)
sort(nb_hashtags, decreasing = TRUE)[1:30]
#ok m^eme traitement possible pour les mentions (sauf l’extraction du @)
April 23, 2018 30 / 241
31. l’aide m´emoire sur le package stringr
Figure: `a t´el´echarger ici: https://www.rstudio.com/resources/cheatsheets
April 23, 2018 31 / 241
32. Le package tidytext
Le package tidytext est un package r´ecent permettant de faire du text mining. Comme indiqu´e
au d´ebut du cours les deux auteurs de tidytext ont mis en ligne l’ouvrage qu’ils ont consacr´e `a
ce package: https://www.tidytextmining.com/
Par ailleurs, les blogs des deux auteurs rendent compte des derni`eres ´evolutions du package:
http://varianceexplained.org/ (david robinson)
https://juliasilge.com/ (julia silge)
Combinant l’approche de text mining ”bag of words” et l’approche de stockage des donn´ees
”tidy” ce package permet d’effectuer rapidement des traitements de text mining.
Techniquement, le package permet de d´ecouper la chaˆıne de caract`ere en n-grams:
n grams=1 alors je d´ecoupe mot `a mot ma chaˆıne de caract`ere
n grams=2 alors je d´ecoupe ma chaˆıne de caract`ere par bloc de deux mots
n grams=3 alors je d´ecoupe ma chaˆıne de caract`ere par bloc de trois mots
April 23, 2018 32 / 241
33. les ramifications de tidytext
Ce package tidytext permet `a la fois de calculer les m´etriques traditionnelles en text mining
comme le td-idf ou le coefficient de gini, d’effectuer des analyses de sentiment, de produire aussi
bien des analyses de type topic modeling ou encore de type word embedding. Du fait de la
structure ”tidy”’ des donn´ees, il est compatible avec les packages comme dplyr, purr, stringr ou
encore ggplot.
April 23, 2018 33 / 241
34. le principe de base de tidytext: la fonction unnest ou
tokenization
Example
library(tidytext) #je load la librairie
mon_tidy_dataframe<-mon_dataframe %>%
unnest_tokens(word, le_texte_de_mon_dataframe)
April 23, 2018 34 / 241
35. mon dataset de travail
Pour travailler sur ce package, nous avons constitu´e un nouveau dataset qui contient les 3000
derniers posts pour cinq pages facebook: le figaro, le monde, lib´eration et france inter.
Example
library(Rfacebook)
library(lubridate)
library(tidyverse)
library(tidytext)
#j’extrait les donn´ees
lemonde <-getPage(page="lemonde.fr", token=fb_oauth, n = 3000)
franceinter<-getPage(page="franceinter", token=fb_oauth, n = 3000)
liberation<-getPage(page="Liberation", token=fb_oauth, n = 3000)
lefigaro<-getPage(page="lefigaro", token=fb_oauth, n = 3000)
lacroix<-getPage(page="lacroix.journal", token=fb_oauth, n = 3000)
# je combine les extracts en un dataset (ok==>dataframe)
presse<-rbind(lemonde, franceinter, liberation, lefigaro,lacroix)
April 23, 2018 35 / 241
36. les donn´ees de d´epart
Je dispose au d´epart d’un extract Facebook avec les titres des posts dans la colonne
mes donnees$Message. Je souhaite analyser le texte de ces messages (connaˆıtre les
th´ematiques, les associations de mots, les mots les plus fr´equents, etc...)
April 23, 2018 36 / 241
37. le traitement de base effectuer par tidytext
En une ligne, j’ai d´ecoup´e chaque message en bloc de 1 mot (option propos´ee par le package par
d´efaut). Au d´epart, chaque post est stock´ee sur une ligne de mon dataframe. Apr`es le
d´ecoupage du texte du message, j’aurai autant de lignes que la longueur du message. A mon
dataframe de d´epart est venue s’ajouter une nouvelle colonne: mes donnees$word
April 23, 2018 37 / 241
38. les mots les plus pr´esents....
J’obtiens un tibble de deux colonnes avec le mot et son classement. Quels sont les mots les
pr´esents dans le classement: macron, politique, donald, ...?
Example
tidy_presses<-presse%>%
unnest_tokens(word,message)%>%
dplyr::count(word, sort=TRUE)
Il va falloir nettoyer....
April 23, 2018 38 / 241
39. code pour visualiser les mots pr´esents plus de 600 fois
Example
tidy_presses_graph<-presse%>%
unnest_tokens(word,message)%>%
dplyr::count(word, sort=TRUE)%>%
mutate(word=reorder(word,-n))%>%
filter(n>600)%>%
ggplot(aes(x=word,y=n))+
geom_bar(stat="identity")+theme_minimal()+
theme(axis.text=element_text(size=6),
axis.title=element_text(size=6,face="bold"))+
theme(axis.text.x = element_text(size=8,angle = 90, hjust = 1))
April 23, 2018 39 / 241
41. code pour supprimer les mots communs
Example
Afin de supprimer les mots communs, nous allons utiliser la commande filter de dplyr, les
dictionnaires de mots communs de tidytext et d’autres dictionnaires issus de package si besoin
est.
# utlisation du dictionnaire int´egr´e dans tidytext
tidy_presses_graph<-presse%>%
unnest_tokens(word,message)%>%
anti_join(stop_words) %>% #pas de fran¸cais
anti_join(get_stopwords(language = "fr"))%>% #nouveau add-on
dplyr::count(word, sort=TRUE)%>%
mutate(word=reorder(word,-n))%>%
filter(n>600)%>%
ggplot(aes(x=word,y=n))+
geom_bar(stat="identity",fill = "#FF6666")+theme_minimal()+
theme(axis.text=element_text(size=8),
axis.title=element_text(size=8))+
theme(axis.text.x = element_text(size=8,face="bold",angle = 90, hjust = 1))+
labs(x = "mots",
y = "nombre d’occurence",
title = "liste des mots apparaissant plus de 600 fois dans les tokens")
April 23, 2018 41 / 241
43. utiliser diff´erents packages pour supprimer les mots
communs
Parfois il faut combiner plusieurs dictionnaires de diff´erents package pour supprimer les mots
cl´es. On utilise la syntaxe suivante: nom package::fonction du package)
Example
tidy_presses_graph<-presse%>%
unnest_tokens(word,message)%>%
anti_join(stop_words) %>% #pas de fran¸cais
anti_join(get_stopwords(language = "fr"))%>% #nouveau add-on
filter(!word %in% tm::stopwords(’en’))%>% # dictionnaire tm ==> load(tm)
filter(!word %in% lsa::stopwords_en)%>%# dictionnaire lsa==> load(lsa)
filter(!word %in% tm::stopwords(’fr’))%>%
filter(!word %in% lsa::stopwords_fr)%>%
dplyr::count(word, sort=TRUE)%>%
mutate(word=reorder(word,-n))%>%
filter(n>600)%>%
ggplot(aes(x=word,y=n))+
geom_bar(stat="identity",fill = "#FF6666")+theme_minimal()+
theme(axis.text=element_text(size=8), axis.title=element_text(size=8))+
theme(axis.text.x = element_text(size=8,face="bold",angle = 90, hjust = 1))+
labs(x = "mots",y = "nombre d’occurence",
title = "liste des mots apparaissant plus de 600 fois dans les tokens")
April 23, 2018 43 / 241
49. r´esultat graphique
il reste encore du bruit (lib´eration, lib´e, figaro, france, les mots commen¸cant par www., etc...)
Plus le texte sera bruit´e, plus les r´esultats seront difficiles `a interpr´eter (ex: topic modeling).
Dans le mˆeme temps, plus on applique de filtre, plus on risque de d´etruire le texte (attention
aux regex).
En dernier recours, il est possible de filtrer `a la ”main” le texte en cr´eant une liste de mots et
d’expressions que l’on souhaite exclure.
Example
#je cr´ee une liste de mots que je souhaite exclure:
mystopwords <- data_frame(word=c("lib´eration", "lib´e", "france", "lefigaro.fr",
"appsfacebookcomliberationjournalreaderdate","dun", "dune", "figaro",
"kiosquelefigarofrlefigaroxtoral", "http", "bitly", "liberation.fr",
"www.liberationfr","liberation","lacroix","journalliberation","cc",
"kiosquelefigarofr"))
#j’utilise la syntaxe suivante de dplyr pour passer mon dictionnaire
anti_join(mystopwords, by = "word")
April 23, 2018 49 / 241
51. r´esultat graphique
....le r´esultat non d´efinitif. On pourrait filter les mots le nombre de caract`ere, en utilisant le
matching approximatif (fuzzy matching). Au d´el`a de son r´esultat, ”on” apprend beaucoup du
texte lors de cette phase.
April 23, 2018 51 / 241
52. commen¸cons les calculs: la fr´equence d’occurrence des
mots (1)
Example
# ma proc´edure de nettoyage du texte.
base<-presse%>%
unnest_tokens(word,message)%>%
mutate(word = str_replace_all(word,"https://t.co/[A-Za-zd]+
|http://[A-Za-zd]+
|&|<|>|RT|https|[’‘^~’]|[:digit:]|[:punct:]",""))%>%
mutate(word = str_replace_all(word, "https|//t|http|&|<|>", ""))%>%
filter(str_detect(word, "[a-z]"))%>%
filter(word !="http")%>%
filter(word !="bitly")%>%
filter(nchar(word)>1)%>%
anti_join(stop_words) %>%
anti_join(get_stopwords(language = "fr"))%>%
filter(!word %in% tm::stopwords(’en’))%>%
filter(!word %in% lsa::stopwords_en)%>%
filter(!word %in% tm::stopwords(’fr’))%>%
filter(!word %in% lsa::stopwords_fr)
April 23, 2018 52 / 241
53. commen¸cons les calculs: la fr´equence d’occurrence des
mots (2).
Example
# a partir de ce r´esultat, je calcule le total de fois o`u un mot est pr´esent dans me
en fonction de la page
mots_page<-base%>%
count(from_name, word, sort = TRUE) %>%
ungroup()
April 23, 2018 53 / 241
55. commen¸cons les calculs: la fr´equence d’occurrence des
mots.
Example
# je calcule ensuite la somme des mots par page
(je vais juste un ’’group_by)
total_words <-mots_page%>%
group_by(from_name) %>%
summarize(total = sum(n))
April 23, 2018 55 / 241
56. jointure des deux fichiers
Example
# j’effectue une jointure
page_mots<- left_join(mots_page, total_words)
April 23, 2018 56 / 241
57. le calcul du tf idf
Les calculs que nous venons d’effectuer vont nous permettre de calculer le tf-idf (terme
frequency inverse document frequency).
Cette mesure statistique permet d’´evaluer l’importance d’un terme contenu dans un document
relativement `a une collection de document. Le poids d’un terme va diminuer
proportionnellement au nombre d’occurrences du mot dans l’ensemble des documents (fr´equence
du mot dans l’ensemble du corpus) et accroˆıtre lorsqu’il est tr`es pr´esent dans un document
appartenant au corpus.
Un document a plus de chances d’ˆetre pertinent comme r´eponse `a une recherche d’un terme si
ce document poss`ede une certaine occurrence de ce terme en son sein et que ce terme poss`ede
une raret´e dans d’autres documents reli´es `a ce document.
Dans notre exemple, le document ne sera pas un post compte tenu de sa faible longueur mais
l’ensemble des posts publi´es par une page. Autrement dit, nous avons 5 documents avec chaque
document est compos´e des 5000 posts d’une seule et unique page. En calculant le tf idf entre
les pages, je souhaite mettre en ´evidence les termes les ”plus” sp´ecifique `a une page.
April 23, 2018 57 / 241
58. le calcul du tf idf dans tidytext: la fonction bind tf idf
Example
# j’appelle la fonction
origine_words <- page_mots%>%
bind_tf_idf(word, from_name, n)%>%
arrange(desc(tf_idf))
Les r´esultats laissent effectivement apparaˆıtre les sp´ecificit´es des pages (ex france inter les
chroniqueurs).
April 23, 2018 58 / 241
62. quels sont les mots les plus sp´ecifiques entre les diff´erentes
pages?
April 23, 2018 62 / 241
63. la loi de Zipf’s
Nous venons de voir le calcul du tf-idf avec tidytext. Toujours `a partir des fr´equences
d’occurrence des mots, il est possible de calculer un indicateur qui relie la fr´equence d’utilisation
d’un mot et son rang: la loi de Zipf’s.
La loi de Zipf pr´evoit que dans un texte donn´e, la fr´equence d’occurrence f(x) d’un mot est li´ee
`a son rang rank (x) dans l’ordre des fr´equences par une loi de la forme f ( x ) = K/x o`u K est
une constante.
Par exemple si l’on choisit K=3000 alors le mot le plus courant est cens´e revenir 3 000 fois, le
dixi`eme mot reviendra 300 fois, le centi`eme 30 fois et le milli`eme, 3 fois.
La loi sugg`ere que le plus le rang d’un mot augmente, plus sa fr´equence sera faible.
April 23, 2018 63 / 241
64. quels sont les mots les plus sp´ecifiques entre les diff´erentes
pages?
Example
freq_by_rank <- origine_words %>%
group_by(from_name) %>%
mutate(rank = row_number(),
‘term frequency‘ = n/total)
#filtre que les valeurs extr^emes
rank_subset <- freq_by_rank %>%
filter(rank < 2000)
#calcul de la relation :lm(log10(‘term frequency‘) ~ log10(rank), data =rank_subset)
Coefficients: (Intercept: -1.5978 ) log10(rank: -0.7238 )
#je remplace dans le graphique les coefficients pour tracer la courbe.
freq_by_rank %>%
ggplot(aes(rank, ‘term frequency‘, color = from_name)) +
geom_abline(intercept = -1.6, slope = -0.72, color = "gray50", linetype = 2) +
geom_line(size = 1.1, alpha = 0.8) + theme_minimal()+ theme(legend.position="top")
scale_x_log10()+ scale_y_log10(labels=scales::comma)
April 23, 2018 64 / 241
66. travailler sur les associations de mots avec tidytext
Nous avons travaill´e avec tidytext avec la mˆeme strat´egie: d´ecouper un texte en bloc d’un mot
(n gram=1).
Tidytext permet de d´ecouper le texte en bloc de mots sup´erieur `a un mot (n gram=2, n
gram=3) pour travailler sur des associations de mots. Une fois ces associations identifi´ees, nous
allons ˆetre capable d’appliquer ensuite certains calculs comme le tf idf afin d’identifier les
associations les plus sp´ecifiques. Au niveau de la visualisation, les associations vont nous
permettre d’utiliser les repr´esentations en r´eseau.
April 23, 2018 66 / 241
67. quels sont les couples de mots les plus sp´ecifiques entre les
diff´erentes pages?
Example
# je charge les packages n´ecessaires (nous utiliserons le dataset presse)
library(dplyr)
library(tidytext)
library(stringr)
library(lsa)
library(tm)
library(tidyr)
# a partir du dataset de base, je cr´ee un nouveau dataset
presse_ngram<-dplyr::select(presse, id, message, from_name)
# j’appelle la fonction du package tidytext
j’applique la fonction sur la colonne message avec ngrams=2
presse_bigram <-presse_ngram%>%
tidytext::unnest_tokens(ngram, message, token = "ngrams", n = 2)
April 23, 2018 67 / 241
69. quelques manipulations interm´ediaires...
Example
# j’effectue des manipulations
# je compte le nombre de couple
presse_bigram%>%
count(ngram,sort=TRUE)
# je s´epare les mots ==>deux colonnes
library(tidyr)
presse_bigram_separated <- presse_bigram%>%
tidyr::separate(ngram, c("word1", "word2"), sep = " ")
April 23, 2018 69 / 241
70. le r´esultat sous forme de dataframe
Il va falloir nettoyer le corpus (encodage.....)
April 23, 2018 70 / 241
71. premi`ere ´etape du nettoyage
Example
# je supprime les mots communs (j’applique les r´egles pour
chaque mot cf. word1 et word2)
bigram_filtered <- presse_bigram_separated %>%
dplyr::filter(!word1 %in% stop_words$word) %>%
dplyr::filter(!word1 %in% mystopwords$word) %>%
dplyr::filter(!word1 %in% lsa::stopwords_en)%>%
dplyr::filter(!word1 %in% lsa::stopwords_fr)%>%
dplyr::filter(!word2 %in% stop_words$word) %>%
dplyr::filter(!word2 %in% mystopwords$word) %>%
dplyr::filter(!word2 %in% lsa::stopwords_en)%>%
dplyr::filter(!word2 %in% lsa::stopwords_fr)
April 23, 2018 71 / 241
72. seconde ´etape: je supprime les caract`eres sp´eciaux
Example
# je supprime les mots communs
(j’applique les r´egles pour chaque mot cf. word1 et word2)
bigram_filtered$word1<-str_replace_all(bigram_filtered$word1,
"https://t.co/[A-Za-zd]+|http://[A-Za-zd]+|&|<|>|RT|https|[’‘^~’]
|[:digit:]|[:punct:]","")
bigram_filtered$word2<-str_replace_all(bigram_filtered$word2,
"https://t.co/[A-Za-zd]+|http://[A-Za-zd]+|&|<|>|RT|https|[’‘^~’]
|[:digit:]|[:punct:]","")
bigram_filtered$word1<- str_replace_all(bigram_filtered$word1,
"https|//t|http|&|<|>", "")
bigram_filtered$word2<- str_replace_all(bigram_filtered$word2,
"https|//t|http|&|<|>", "")
April 23, 2018 72 / 241
73. une m´ethode (de brut) pour les accents
En sortie j’observe que le mot ´election est devenu ˜a c lections du fait d’un probl`eme d’encodage.
Il est possible de g´erer ce probl`eme en combinant:
Example
une r`egle de ce type:
bigram_filtered$word1<-gsub("l^aTMasile","asile ",bigram_filtered$word1)
une r`egle sur les accents de ce type:
bigram_filtered$word1<-gsub("~A","`a",bigram_filtered$word1)
une r`egle avec une regex:
bigram_filtered$word2<-str_replace_all(bigram_filtered$word2, ".*^aTM","")
#exemples
x <- ’aabb.ccdd’ ==>mon caract`ere de r´ef´erence (.)
xx<-str_replace_all(’.*’, ’’, x) ==>’’
xxx<-str_replace_all(’bb.*’, ’’, x) ==>’aa’
xxxx<-str_replace_all(’.*bb’, ’’, x) ==> ‘.ccdd’
xxxxx<-str_replace_all(’..*’, ’’, x) ==>’aabb’
xxxxx<-str_replace_all(’.*.’, ’’, x) ==>’ccdd’
April 23, 2018 73 / 241
75. le r´esultat des traitements de nettoyage
April 23, 2018 75 / 241
76. les manipulations du dataframe
Une fois le texte un peu plus propre, il est possible d’engager les transformations
Example
#je calcule le nombre d’´el´ements
bigram_counts <- bigram_filtered %>%
count(word1, word2, sort = TRUE)
#je concatene les deux colonnes en une
presse_bigram_united <- bigram_filtered %>%
unite(ngram,word1, word2, sep = " ")
#je calcule le tf-idf sur cette colonne unique
bigram_tf_idf <- presse_bigram_united %>%
count(from_name,ngram) %>%
bind_tf_idf(ngram, from_name, n) %>%
arrange(desc(tf_idf))
April 23, 2018 76 / 241
78. un premier r´esultat graphique de l’association des mots
Example
#je calcule le nombre d’´el´ements
bigram_tf_idf %>%
select(-sum(n))%>%
arrange(desc(tf_idf))
plot_bigram<-bigram_tf_idf%>%
arrange(desc(tf_idf))%>%
mutate(ngram = factor(ngram, levels = rev(unique(ngram))))
#je choisis d’afficher seulement les 60 premiers r´esultats
ggplot(plot_bigram[1:60,], aes(ngram, tf_idf, fill = from_name)) +
geom_bar(stat = "identity") +
labs(x = NULL, y = "tf-idf") +
coord_flip()
April 23, 2018 78 / 241
79. les 60 plus fortes associations de mots en vertu du tf-idf
April 23, 2018 79 / 241
80. les 20 plus fortes associations de mots en vertu du tf-id par
page
Example
#je s´electionne 20 premiers r´esutlats par page
plot_bigram<- plot_bigram%>%
group_by(from_name) %>%
top_n(20) %>%
ungroup
ggplot(plot_bigram, aes(ngram, tf_idf, fill = from_name)) +
geom_bar(stat = "identity", show.legend = FALSE) +
labs(x = NULL, y = "tf-idf") +
facet_wrap(~from_name, ncol = 2, scales = "free") +
coord_flip()
April 23, 2018 80 / 241
82. un r´ecapitulatif interm´ediaire
Tidytext permet donc de d´ecouper le texte en n grams
Example
#je veux d´ecouper mot `a mot mon texte
bigram_counts <- bigram_filtered %>%
count(word1, word2, sort = TRUE)
#je veux d´ecouper mon texte par couple de mots
mes_bigrams <- mes_donnees %>%
unnest_tokens(bigram, text, token = "ngrams", n = 2)
#je veux d´ecouper mon texte par bloc de trois mots
mes_trigrams <- mes_donnees %>%
unnest_tokens(trigram, text, token = "ngrams", n = 3)
Bien ´evidemment, il faut ensuite adapter les phases de traitement au nombre de ngrams. Nous
verrons une application de cette m´ethode lorsque nous nous int´eresserons au sentiment analysis.
April 23, 2018 82 / 241
83. visualiser les associations de mots avec igraph
Robinson et Silge recommandent le package igraph pour visualiser les r´eseaux d’association de
mots. igraph (documentation ici: http://igraph.org/r/ de 431 pages...) permet de repr´esenter
les donn´ees en r´eseaux `a partir d’un dataframe en passant par la fonction ggraph du package
ggraph. A noter que igraph comme ggplot repose ´egalement sur la ”logique” de la grammaire
des graphiques ou grammaire en couches.
Example
library(igraph)
#je filtre sur le nombre de fois o`u est pr´esent le m^eme bigram et
je passe la fonction graph_from_data_frame() du package igraph
bigram_graph <- bigram_counts %>%
filter(n >20) %>%
graph_from_data_frame()
#j’appelle le package ggraph pour passer de la forme dataframe `a une forme
d’organisation des donn´ees comptatible avec la repr´esentation en r´eseau
library(ggraph)
set.seed(2017)
ggraph(bigram_graph,layout = ’kk’) +
geom_edge_link() + geom_node_point() +
geom_node_text(aes(label = name), vjust = 1, hjust = 1)+theme_minimal()
April 23, 2018 83 / 241
84. le r´esultat de la fonction graph from data frame()
April 23, 2018 84 / 241
97. Les logiques de sentiment analysis
L’analyse de sentiment vise `a inf´erer `a partir d’´el´ements textuels (mots, phrases, document) des
´el´ements tels que la tonalit´e ou les sentiments exprim´es par l’auteur du texte ´etudi´e. Si la
version la plus basique vise `a capturer la polarit´e d’un texte, diff´erentes approches ont ´et´e
d´evelopp´es `a partir de choix comme :
la technique utilis´ee: les dictionnaires (approche lexicale), le machine learning (support
machine vector) et la statistique (naive bayes)
la m´ethode de d´ecoupage du texte: le mot, la phrase ou encore le document
la m´etrique de r´esultat: polarit´e, score, mesure adhoc,...
April 23, 2018 97 / 241
98. Les approches lexicales et d’apprentissage
L’approche lexicale comprend diff´erentes phases
phase d’extraction du texte,
phase de tokenisation et nettoyage,
phase de matching vis `a vis d’un r´ef´erentiel,
phase d’encr´ement (incr´ement si matching, pas d’incr´ement si non matching ex: +1/-1
de plus au cumul, 0 si non matching)
phase de r´esultat
L’approche machine learning comprend elle aussi diff´erentes phases
phase d’extraction du texte,
phase de pr´etraitement,
phase d’apprentissage,
phase de classification,
phase de r´esultat
April 23, 2018 98 / 241
99. les packages de sentiment analysis dans r
Plusieurs packages de ”sentiment analysis” ont ´et´e d´evelopp´es dans r.
r permet d’utiliser quasiment l’ensemble des outils et m´ethodologies reli´ees au text mining
(anciens ou r´ecents) y compris le sentiment analysis.
Certains packages de sentiment analysis sont bas´es sur une approche lexicale et fournissent en
sortie d’analyse une d´ecomposition du texte en terme de polarit´e (positif ou n´egatif), de score
(echelle de -5 `a +5) ou encore d’´emotion (joy, sadness, etc..). Par ailleurs, il est ´egalement
possible d’effectuer les analyses mot `a mot, au niveau de la phrase (phase de tokenisation) ou
encore au niveau du texte. A noter que certains packages permettent de se cr´eer ses propres
r´ef´erentiels (ex: je cr´ee un dictionnaire sp´ecifique dans lequel je renseigne la correspondance
entre un mot et son score, son sentiment, etc...
Pour la plupart ces packages sont destin´es `a exploiter/travailler sur des corpus en anglais. si
certains int`egrent des dictionnaires fran¸cais, les dictionnaires utilis´es restent peu ´etoff´es.
Enfin, certains packages de text mining comme tidytext ou quantela int´egrent des fonctions
permettant d’effectuer des analyses de sentiment analysis (r´eutilisation de fonctions existantes
dans d’autres package et/ou cr´eation de fonctions sp´ecifiques).
April 23, 2018 99 / 241
100. les packages de sentiment analysis dans r
Plusieurs packages de ”sentiment analysis” ont ´et´e d´evelopp´es dans r. Voici une liste non
exhaustive des packages de sentiment analysis:
Tidytext avec la fonction get sentiment (bag of words, approche lexicale avec diff´erents
dictionnaires permettant d’obtenir une polarit´e, des sentiments ou un score)
Rsentiment (bag of words, approche lexicale, ´echelle polarit´e),
SentimentAnalysis (bag of words, approche lexicale, ´echelle polarit´e),
sentimentr (bag of words, approche lexicale, sentiment),
proust (bag of words, approche lexicale, sentiment),
meanr, stanset.....
April 23, 2018 100 / 241
101. l’analyse de sentiment avec tidytext: la m´ethode ”afinn”’
Le package tidytext int`egre une fonction permettant de qualifier le text: la fonction
get sentiment. En ajoutant comme param`etre de la fonction diff´erents dictionnaires lexicaux
(3), il est possible d’obtenir diff´erents r´esultats pour un mˆeme texte. A noter que ces m´ethodes
n’int`egre pas de dictionnaire fran¸cais..
Example
tidytext::get_sentiments("afinn")
ranking des mots entre -5 et +5
# A tibble: 2,476 x 2
word score
<chr> <int>
1 abandon -2
2 abandoned -2
3 abandons -2
4 abducted -2
5 abduction -2
6 abductions -2
7 abhor -3
8 abhorred -3
9 abhorrent -3
10 abhors -3
April 23, 2018 101 / 241
102. obtenir la polarit´e des mots: la m´ethode ”bing”
avec la param`etre ”bing” dans la fonction get sentiment, je classe les mots selon l’opposition
positif/n´egatif..
Example
tidytext::get_sentiments("bing")
# A tibble: 6,788 x 2
word sentiment
<chr> <chr>
1 2-faced negative
2 2-faces negative
3 a+ positive
4 abnormal negative
5 abolish negative
6 abominable negative
7 abominably negative
8 abominate negative
9 abomination negative
10 abort negative
# ... with 6,778 more rows
April 23, 2018 102 / 241
103. obtenir une classification par ´emotion: la m´ethode ”nrc”
avec la param`etre ”nrc” dans la fonction get sentiment, je classe chaque mot selon l’´emotion
dominante que ce mot exprime. La liste des ´emotions est la suivante: anger, anticipation,
disgust, fear, joy, sadness, surprise, trust. (cf. doc:
http://saifmohammad.com/WebPages/NRC-Emotion-Lexicon.htm).
Example
tidytext::get_sentiments("nrc")
A tibble: 13,901 x 2
# word sentiment
1 abacus trust
2 abandon fear
3 abandon negative
4 abandon sadness
5 abandoned anger
6 abandoned fear
7 abandoned negative
8 abandoned sadness
9 abandonment anger
10 abandonment fear
# ... with 13,891 more rows
April 23, 2018 103 / 241
104. exemple sur un corpus de post facebook
Example
# Rfacebook+tidytext
base_sentiment_bing<-extract_r_the_economist%>%
tidytext::unnest_tokens(word,message)%>%
filter(str_detect(word, "[a-z]"))%>%
anti_join(stop_words) %>%
filter(!word %in% tm::stopwords(’en’))%>%
filter(!word %in% lsa::stopwords_en)%>%
inner_join(get_sentiments("bing")) %>%
count(sentiment)%>%
arrange(-n)
# sentiment n
1 negative 2404
2 positive 1940
April 23, 2018 104 / 241
105. exemple sur un corpus de post facebook
Example
base_emotion<-extract_r_the_economist%>%
tidytext::unnest_tokens(word,message)%>%
filter(str_detect(word, "[a-z]"))%>%
anti_join(stop_words) %>%
filter(!word %in% tm::stopwords(’en’))%>%
filter(!word %in% lsa::stopwords_en)%>%
inner_join(get_sentiments("nrc"))%>%
group_by(sentiment, word)%>%
count(word, sort = TRUE)
# cr´eation d’un dataframe (fonction table)
tableau<-as.data.frame(table(base_emotion$sentiment))
colnames(tableau)<-c("emotion", "nombre d’occurence")
# emotion nombre
1 anger 349
2 anticipation 331
3 disgust 252
4 fear 424
5 joy 256
6 negative 812
7 positive 816
8 sadness 345 April 23, 2018 105 / 241
106. code graphique
Example
base_emotion_graphique<-extract_r_the_economist%>%
tidytext::unnest_tokens(word,message)%>%
filter(str_detect(word, "[a-z]"))%>%
anti_join(stop_words) %>%
filter(!word %in% tm::stopwords(’en’))%>%
filter(!word %in% lsa::stopwords_en)%>%
inner_join(get_sentiments("nrc"))%>%
group_by(sentiment, word)%>%
count(word, sort = TRUE)%>%
filter(n>20)%>%
ggplot(aes(x= reorder(word,(n)),y=n,fill = sentiment))+
geom_bar(stat="identity")+
coord_flip()+theme_minimal()+
theme(axis.text=element_text(size=6),
axis.title=element_text(size=6,face="bold"))+
labs(x = "mots",
y = "nombre d’occurence",
title = "liste des mots apparaissant plus de 20 fois dans le classement")
April 23, 2018 106 / 241
108. filtre selon l’´emotion: sadness
Example
# Rfacebook+tidytext
base_emotion_sadness<-extract_r_the_economist%>%
tidytext::unnest_tokens(word,message)%>%
filter(str_detect(word, "[a-z]"))%>%
anti_join(stop_words) %>%
filter(!word %in% tm::stopwords(’en’))%>%
filter(!word %in% lsa::stopwords_en)%>%
inner_join(get_sentiments("nrc"))%>%
filter(sentiment == "sadness") %>%
count(word, sort = TRUE)
# word n
1 vote 34
2 revolution 32
3 death 25
4 bad 22
5 illegal 22
6 tax 21
7 die 20
8 leave 20
9 poverty 20
10 income 18
April 23, 2018 108 / 241
109. filtre selon l’´emotion: joy
Example
# Rfacebook+tidytext
base_emotion_joy<-extract_r_the_economist%>%
tidytext::unnest_tokens(word,message)%>%
filter(str_detect(word, "[a-z]"))%>%
anti_join(stop_words) %>%
filter(!word %in% tm::stopwords(’en’))%>%
filter(!word %in% lsa::stopwords_en)%>%
inner_join(get_sentiments("nrc"))%>%
filter(sentiment == "joy") %>%
count(word, sort = TRUE)
# word n
1 food 37
2 save 36
3 money 35
4 vote 34
5 found 31
6 pay 25
7 white 23
8 peace 22
9 deal 20
10 electric 20
# ... with 246 more rows April 23, 2018 109 / 241
110. classer les mots selon une ´echelle de score: la m´ethode
afinn
avec la param`etre ”afinn” dans la fonction get sentiment, je classe chaque mot selon une ´echelle
allant de -5 `a +5..
Example
base_score<-extract_r_the_economist%>%
tidytext::unnest_tokens(word,message)%>%
filter(str_detect(word, "[a-z]"))%>%
anti_join(stop_words) %>%
filter(!word %in% tm::stopwords(’en’))%>%
filter(!word %in% lsa::stopwords_en)%>%
inner_join(get_sentiments("afinn"))%>%
group_by(score, word)%>%
count(word, sort = TRUE)
April 23, 2018 110 / 241
113. une comparaison des trois m´ethodes: afinn, nrc et bing
Example
il est possible de repr´esenter dans un m^eme graphique les trois m´ethodes d’analyse d
-en effectuant par ligne la somme des scores de chaque mot pour la m´ethode afinn
-pas d’op´eration pour la m´ethode bing (positive/n´egatif)
-en sommant les valeurs ’’positives’’ et ’’n´egatives’’ de la m´ethode nrc.
#premi`ere ´etape
afinn_economist <-extract_r_the_economist %>%
tidytext::unnest_tokens(word,message)%>%
inner_join(get_sentiments("afinn")) %>%
group_by(type,time, engagement)%>%
summarise(sentiment = sum(score)) %>%
mutate(method = "AFINN")
April 23, 2018 113 / 241
114. une comparaison des trois m´ethodes: afinn, nrc et bing
Example
#seconde ´etape
bing_and_nrc_economist <- bind_rows(extract_r_the_economist%>%
tidytext::unnest_tokens(word,message)%>%
#dplyr::anti_join(tidytext::stop_words)%>%
#dplyr::filter(!word %in% tm::stopwords(’en’))%>%
#dplyr::filter(!word %in% lsa::stopwords_en)%>%
inner_join(get_sentiments("bing")) %>%
group_by(type, time, engagement)%>%
mutate(method = "Bing et al."),
extract_r_the_economist%>%
tidytext::unnest_tokens(word,message)%>%
#dplyr::anti_join(tidytext::stop_words)%>%
#dplyr::filter(!word %in% tm::stopwords(’en’))%>%
#dplyr::filter(!word %in% lsa::stopwords_en)%>%
group_by(type, time, engagement)%>%
inner_join(get_sentiments("nrc") %>%
filter(sentiment %in% c("positive", "negative"))) %>%
mutate(method = "NRC")) %>%
count(method,type, time,sentiment) %>%
spread(sentiment, n, fill = 0) %>%
mutate(sentiment = positive - negative)
April 23, 2018 114 / 241
120. l’analyse des mots les plus pr´esents en mati`ere de polarit´e:
les bigrams
Example
#rappel de la m´ethode pour extraire des bigrams
library(dplyr)
library(tidytext)
library(tidyr)
eco_bigrams <- extract_r_the_economist%>%
group_by(type, annee)%>%
unnest_tokens(bigram, message, token = "ngrams", n = 2)
eco_bigrams_separated <- eco_bigrams %>%
separate(bigram, c("word1", "word2"), sep = " ")
April 23, 2018 120 / 241
121. l’analyse des mots les plus pr´esents en mati`ere de polarit´e:
les bigrams
Example
#bigrams et sentiment analysis
AFINN <- get_sentiments("afinn")
not_words <- eco_bigrams_separated %>%
filter(word1 == "not") %>% #je filtre
inner_join(AFINN, by = c(word2 = "word")) %>% #jointure avec le dictionnaire
count(word2, score, sort = TRUE) %>%
ungroup()
not_words %>%
mutate(contribution = n * score) %>%
arrange(desc(abs(contribution))) %>%
head(30) %>%
mutate(word2 = reorder(word2, contribution)) %>%
ggplot(aes(word2, n * score, fill = n * score > 0)) +
geom_col(show.legend = FALSE) + theme_minimal()+
labs(x = "mots pr´ec´ed´es par "not"",
y = " contribution: sentiment score * nombre d’occurence du mot",
title = "top 30 des mots ayant la plus forte contribution `a la polarit´e par s
coord_flip()
April 23, 2018 121 / 241
123. les bigrams avec un dictionnaire perso
Example
#bigrams et sentiment analysis
negation_words <- c("not", "no", "never", "without")
eco_negated_words <- eco_bigrams_separated %>%
filter(word1 %in% negation_words) %>%
inner_join(AFINN, by = c(word2 = "word")) %>%
count(word1, word2, score, sort = TRUE) %>%
ungroup()
eco_negated_words%>%
mutate(contribution = n * score) %>%
arrange(desc(abs(contribution))) %>%
#head(50) %>%
mutate(word2 = reorder(word2, contribution)) %>%
ggplot(aes(word2, n * score, fill = n * score > 0)) +
geom_col(show.legend = FALSE) + theme_minimal()+
labs(x = "Words preceded by "not"",
y = " contribution: sentiment score * nombre d’occurrence du mot",
title = "top 50 des mots ayant la plus forte contribution `a la polarit´e par s
coord_flip()
April 23, 2018 123 / 241
125. une conclusion sur tidytext et le sentiment analysis
Le sentiment analysis est une brique importante dans le package tidytext. En jouant sur les
dictionnaires s´emantiques, la longueur des n-grams (simple, bigrams, trigrams), il permet de
g´en´erer des r´esultats tr`es facilement. En outre, si nous avons travaill´e avec des dataframes, le
package permet d’effectuer des analyses de sentiment analysis en prenant en entr´ee des
documents de type document term matrix ou term document matrix (nous verrons ces formes
lorsque nous travaillerons sur le topic modeling).
Bien ´evidemment, le package souffre de diff´erentes faiblesses: une analyse mots `a mots qui ne
capture pas les formes complexes de langage (ex: sarcasme) et la faiblesse des m´ethodes de
dictionnaires lorsque l’on travaille avec des corpus sp´ecifiques (ex: finance).
April 23, 2018 125 / 241
126. les autres packages dans r et le sentiment analysis
Comme nous l’avons indiqu´e en introduction d’autres packages existent sous r en mati`ere de
topic modeling. Non content d’effectuer les mˆemes op´erations par rapport `a tidytext (taggging
avec les m´ethodes afinn, nrc et bing), ces packages apportent d’autres fonctionnalit´es
int´eressantes en terme: :
r´ef´erentiels de tagging: d’autres dictionnaires (finance, multi-langues, etc...)
structure du corpus (analyse au niveau des mots, analyse au niveau de la phrase),
r´esultats graphique (visualisation du texte),
algorithme de classification (stanford nlp),
stanset.....
A noter que certains de ces packages lorsqu’ils appelent des traitements java (stanford nlp)
deviennent gourmands en m´emoire. Dans la partie suivant, nous allons passer en revue les
diff´erents packages en nous focalisant sur leurs sp´ecificit´es.
April 23, 2018 126 / 241
127. le package sentiment analysis
Ce package est un compl´ement `a tidytext et poss`ede de nombreuses fonctions int´eressantes :
la prise en charge de diff´erentes structures d’organisation de la donn´ees (dataframe,
matrix, corpus)
le chargement de diff´erents dictionnaires ”sp´ecifiques”:
Harvard-IV,
Henry’s Financial
Loughran-McDonald Financial
la cr´eation de dictionnaires sp´ecifiques (cr´eation, importation, modification, chargement,
exportation),
l’utilisation de fonction de traitement du texte (stemming, stopword, tokenisation
comptage),
structure du corpus (analyse au niveau des mots, analyse au niveau de la phrase,
comptage),
des ´el´ements graphiques,
la mod´elisation (lasso et ridge)
April 23, 2018 127 / 241
128. la fonction analyse sentiment
Example
#´ecriture de base
sa_eco<-analyzeSentiment(extract_r_the_economist$message,
language = "english",
aggregate = NULL,
removeStopwords = FALSE,
stemming = FALSE)
attention par d´efaut la fonction effectue le stemming, supprimme les mots communs
a noter que certains param`etres ne sont possibles qu’avec une matrice en entree.
April 23, 2018 128 / 241
135. la repr´esentation en histogramme
Example
hist(sa_extract$SentimentGI)
hist(sa_extract$SentimentHE)
hist(sa_extract$SentimentLM)
hist(sa_extract$SentimentQDAP)
April 23, 2018 135 / 241
137. le package syuzhet
Les principales fonctions de ce package sont les suivantes:
l’int´egration de diff´erents dictionnaires (get nrc sentiment) ou
(get sentiment dictionary())
le sentiment par phrase (get sentences)
la mise en compte de diff´erents languages, (get sentiment dictionary())
le tagging avec le framework nlp stanford (get stanford sentiment())
la tokenisation par mot (tiydext like) (get tokens)
des repr´esentations graphiques (simple plot )
April 23, 2018 137 / 241
138. la visualisation des dictionnaires
apr`es avoir charg´e la librairie (library(syuzhet)), il est possible d’afficher les dictionnaires
suivants:
syuzhet::get sentiment dictionary(dictionary = ”syuzhet”, language = ”french”)
syuzhet::get sentiment dictionary(dictionary = ”nrc”, language = ”french”)
syuzhet::get sentiment dictionary(dictionary = ”afinn”, language = ”french”)
syuzhet::get sentiment dictionary(dictionary = ”bing”, language = ”french”)
syuzhet::get sentiment dictionary(dictionary = ”syuzhet”, language = ”english”)
syuzhet::get sentiment dictionary(dictionary = ”nrc”, language = ”english”)
syuzhet::get sentiment dictionary(dictionary = ”afinn”, language = ”english”)
syuzhet::get sentiment dictionary(dictionary = ”bing”, language = ”english”)
syuzhet::get sentiment dictionary(dictionary = ”nrc”, language = ”spanish”)
syuzhet::get sentiment dictionary(dictionary = ”afinn”, language = ”spanish”)
syuzhet::get sentiment dictionary(dictionary = ”bing”, language = ”spanish”)
........
April 23, 2018 138 / 241
139. la visualisation des dictionnaires
Example
appeler les dictionnaires pour effectuer le tagging des mots:
method <- "nrc"
lang <- "english"
my_text_values <- get_sentiment(mon_texte, method=method, language=lang)
April 23, 2018 139 / 241
140. la cr´eation d’un graphique comparatif
Example
#longueur du message ==>graphique
extract_r_the_economist$length<-str_length(extract_r_the_economist$message)
#fonction syuzhet
syuzhet_result_eco<-syuzhet::get_sentiment(extract_r_the_economist$message,
method = "syuzhet", path_to_tagger = NULL,
cl = NULL, language = "english",
lexicon = NULL)
# cr´eation du dataframe +jointure
syuzhet_result_eco<-as.data.frame(syuzhet_result_eco)
extract_r_the_economist<-cbind(extract_r_the_economist,syuzhet_result_eco)
April 23, 2018 140 / 241
141. la cr´eation d’un graphique comparatif
Example
extract_r_the_economist%>%
mutate(annee<-lubridate::year(time))%>%
filter(annee != 2012)%>%
group_by(type, time, length)%>%
summarise(sum = sum(syuzhet_result_eco, na.rm = TRUE))%>%
ggplot(aes(x=time, y=sum,size=length,color=type))+
scale_size_area(max_size = 4, guide = FALSE) +
geom_point(alpha=0.8)+theme_minimal()+
theme(axis.text.x = element_text(size=10, angle=90))+
theme(legend.position="bottom")+
theme(legend.text=element_text(size=5))+
theme(legend.title=element_text(size=5))+geom_jitter()+ facet_grid(type~.)+
theme(strip.text.x = element_text(face="bold",size =10,
colour = "black", angle = 90))+
labs(x = "date",
y = "score",
title = "sentiment par tweet et type",
subtitle = "")
April 23, 2018 141 / 241
144. obtenir un histogramme des sentiments
Example
nrc_data_eco<- get_nrc_sentiment(extract_r_the_economist$message)
barplot(sort(colSums(prop.table(nrc_data_eco[, 1:8]))),
horiz = TRUE,
cex.names = 0.7,
las = 1,
main = "r´epartition des ´emotions dans mon extract twitter", xlab="pourcentage")
April 23, 2018 144 / 241
146. obtenir un graphique rapidement avec la fonction
get sentiment
Example
bis<-get_sentiment(extract_r_the_economist$message)
plot(bis, type = "o", pch = 20, bg = par("bg"), col = "grey", cex = .4,
main = ’sentiment dans le temps’)
April 23, 2018 146 / 241
148. obtenir diff´erentes tendances: la fonction simple plot
Example
bis<-get_sentiment(extract_r_the_economist$message)
simple_plot(bis)
April 23, 2018 148 / 241
150. les autres packages
D’autres packages de sentiment analysis.:
sentimentr (get sentences()) calcul par phrases
stanset (get sentences()) calcul score nlp
R sentiment (calculate score())
meanr (score())
proustr (travail sur les oeuvres de proust)
April 23, 2018 150 / 241
151. le programme
Pour le reste du cours:
faire un extract et tester `a mimima les trois dictionnaires
faire les graphiques corpus anglais
tester un autre package r avec le mˆeme corpus
faire un travail sur le bigrams
travailler sur un corpus fran¸cais
April 23, 2018 151 / 241
153. L’approche ’bag of word”
Tr`es tr`es globalement, on peut distinguer deux approches en terme de text mining:
les approches de type ”bag of word”
les approches de type ”syntactic parsing”
L’approche bag of word approche un texte comme une suite non organis´ee de mots. Typiquement, le package tidytext qui
permet de d´ecouper un text en ngrams et poser les premi`eres briques du topic modeling adopte cette approche.
Figure: l’approche bag of word, tir´e de Speech and Language Processing. Jurafsky et Martin (2017)
April 23, 2018 153 / 241
154. L’approche ”syntactic parsing”
L’approche ”syntactic parsing” appr´ehende un document comme un vecteur de V dimensions o`u V est la taille du vocabulaire
utilis´e.
Figure: l’approche ”syntactic parsing”, Kwartler (2017)
April 23, 2018 154 / 241
155. L’approche ”syntactic parsing” en pratique
L’approche ”syntactic parsing” va d´ecouper le corpus en attribuant `a chaque token un ´el´ement
(part of speech) selon un glossaire plus ou moins standardis´e. La liste ci-dessus donne une id´ee
des r´esultats possibles de cette op´eration de tagging:
ADJ, adjective, ex: new, good, high, special, big, local
ADP, adposition, ex: on, of, at, with, by, into, under
ADV, adverb, ex:really, already, still, early, now
CONJ, conjunction, ex: and, or, but, if, while, although
DET, determiner, article, ex :the, a, some, most, every, no, which
NOUN, noun, ex: year, home, costs, time, Africa
NUM, numeral,ex: twenty-four, fourth, 1991, 14:24
PRT, particle, ex: at, on, out, over per, that, up, with
PRON, pronoun,ex: he, their, her, its, my, I, us
VERB, verb, ex: is, say, told, given, playing, would
. ,punctuation marks,ex: . , ; !
X, other rsatz, esprit, dunno, gr8, univeristy
Une fois cette annotation r´ealis´ee, il devient possible s’effectuer des nombreuses analyses en
combinant le r´esultat du pos-tagging avec d’autres fonctionnalit´es comme la lemmatisation ou le
”dependency parsing”
April 23, 2018 155 / 241
156. un premier exemple avec udpipe
Example
Apr`es avoir annot´e ce texte: mon texte¡-c(”this is my text”) sur le
principe du syntactic parsing nous obtenons le r´esultat suivant (tagging
r´ealis´e avec le package udpipe). En plus du pos-tagging nous obtenons
´egalement la lemmatisation pour chaque token (c’=¿ce, est=¿ˆetre)
April 23, 2018 156 / 241
157. un second exemple avec udpipe
Example
Si l’on veux annoter ce texte: my text¡-c(”c’est mon texte”) en utilisant le
principe du syntactic parsing nous obtenons ce r´esultat suivant (package
udpipe). A noter qu’il faut charger pour chaque langue un dictionnaire
sp´ecifique pour obtenir l’output.
April 23, 2018 157 / 241
158. Le ”syntactic parsing” et r
Diff´erents packages existent dans r autour de l’approche ”syntactic parsing” comme openNLP,
cleanNLP ou Udpipe. Contrairement `a l’approche bag of word, l’approche ”syntactic parsing”
n´ecessite au pr´ealable d’avoir install´e un ou plusieurs backends. Un backend s’apparente `a une
”sous couche logicielle” n´ecessaire pour g´en´erer les op´erations comme par exemple:
le package openNLP n´ecessite d’avoir install´e la librairie stanford NLP+l’environnement
java,
le package udpipe permet d’annotation et ne n´ecessite pas l’installation d’un backend
sp´ecifique (il faut seulement t´el´echarger les diff´erents dictionnaires)
le package spacyr qui est une interface dans r pour acc´eder aux fonctionnalit´es de la
librairie python spacy (n´ecessite d’installer un environnement python, la librairie spacy et
ses librairies),
le package cleanNLP permet d’appeler diff´erents backends (stanford npl+java,
spacy+python, udpipe et tokenizers-ce dernier permet juste de tokenizerle texte)
Compte tenu de sa consommation en m´emoire extrˆemement importante, nous utiliserons dans
cette partie du cours les backends spacy/python et udpipe.
April 23, 2018 158 / 241
159. Installer le package udpipe
Example
# phase d’installation du package et des dictionnaires
installation du package+dictionnaires (extr^emement long....)
devtools::install_github("jwijffels/udpipe.models.ud.2.0")
installation du packaage avec une autre url (+rapide)
install.packages("udpipe.models.ud.2.0",
repos = "http://www.datatailor.be/rcube",
type = "source")
#une fois install´ee, il faut charger dans r le package
et des librairies utilis´ees dans le tuto
# librairie du package
library(udpipe)
# librairie pour manipuler les tables
library(data.table)
#la libraririe pour la creation des graphiques/barchart (alternative `a ggplot)
library("lattice", lib.loc="C:/Program Files/R/R-3.4.2/library")
April 23, 2018 159 / 241
160. tagger un texte: la fonction udpipe annotate du package
udpipe
Example
# mon texte
texte_1<-c("this is my text")
# je charge mon dictionnaire
ud_en<- udpipe_load_model(file =
"C:/Users/jjg/Documents/R/win-library/3.4/udpipe.models.ud.2.0/udpipe-ud-2.0-170801/
# j’annote mon texte avec la fonction udpipe_annotate
# (mon _dictionnaire, mon texte)
my_texte_1_anno<- udpipe_annotate(ud_en, x = texte_1)
# je transforme le r´esultat de ma fonction en un dataframe
my_texte_1_anno<-as.data.frame(my_text_1_anno)
April 23, 2018 160 / 241
162. tagger un texte: la fonction udpipe annotate du package
udpipe
Example
# mon texte de d´epart
texte_2<-c("c’est mon texte")
# je charge mon dictionnaire
ud _fr <- udpipe_load_model(file =
"C:/Users/jjg/Documents/R/win-library/3.4/udpipe.models.ud.2.0/udpipe-ud-2.0-170801/
# j’annote mon texte avec la fonction udpipe_annotate (r´esultat est une liste)
my_texte_2_anno<- udpipe_annotate(object = ud_fr, x =texte_2)
# je transforme le r´esultat de ma fonction en un dataframe
my_texte_2_anno<-as.data.frame(my_texte_2_anno)
April 23, 2018 162 / 241
164. tagger des commentaires: l’exemple des commentaires
airBnb
Example
# appeler le dataset
data(brussels_reviews)
==>les donn´ees sont des donn´ees
d’entrainement pr´esentes dans le package udpipe
# je visualise les donn´ees
(la langue est d´ej`a identifi´ee pour chaque commentaire
==>je peux appliquer le dictionnaire ad´equat
head(brussels_reviews)
# je visualise la r´epartition des commentaires par langue
table(brussels_reviews$language)
es fr nl
500 500 500
April 23, 2018 164 / 241
166. tagger l’ensemble des commentaires
Example
# je d´ecoupe mon dataframe en trois listes sur le crit`ere de la langue
bxl_anno <- split(brussels_reviews, brussels_reviews$language)
==>j’obtiens une nested list (une liste avec trois listes `a l’int´erieur)
# tagging es (tagger les commentaires en espagnol=>dico es)
ud_sp <- udpipe::udpipe_load_model(file=
"C:/Users/jjg/Documents/R/win-library/3.4/udpipe.models.ud.2.0/
udpipe-ud-2.0-170801/spanish-ancora-ud-2.0-170801.udpipe")
bxl_anno$es <- udpipe_annotate(object = ud_sp, x = bxl_anno$es$feedback,
doc_id = bxl_anno$es$id)
# tagging fr
ud_fr <- udpipe_load_model(file =
"C:/Users/jjg/Documents/R/win-library/3.4/udpipe.models.ud.2.0/
udpipe-ud-2.0-170801/french-partut-ud-2.0-170801.udpipe")
bxl_anno$fr <- udpipe_annotate(object = ud_fr, x = bxl_anno$fr$feedback,
doc_id = bxl_anno$fr$id)
# tagging nl
ud_nl <- udpipe_load_model(file =
"C:/Users/jjg/Documents/R/win-library/3.4/udpipe.models.ud.2.0/
udpipe-ud-2.0-170801/dutch-lassysmall-ud-2.0-170801.udpipe") April 23, 2018 166 / 241
167. consolider mes donn´es
Example
# je transforme chacune des listes annot´ees en un dataframe ==>liste de dataframes
brussels_reviews_anno <- lapply(bxl_anno, as.data.frame)
#je cree un dataframe unique `a partir de ma liste de dataframes ==>dataframe unique
brussels_reviews_anno <- data.table::rbindlist(brussels_reviews_anno)
#la commande pour visualiser la structure de mon dataframe global
str(brussels_reviews_anno)
April 23, 2018 167 / 241
169. ajuster ma requˆete
Les op´erations telles que le ”pos-tagging”, le ”dependancy parsing”et la ”lemmatization”
peuvent ˆetre relativement longues lorsque l’on dispose d’un corpus important. La fonction
annotate comprend diff´erents param`etres qui permettent d’ajuster les op´erations en fonction de
ses besoins:
seulement token: x ¡- udpipe annotate(ud fr, x = txt, tagger = ”none”, parser = ”none”)
token+pos tagging+lemmatisation (pas de dependancy parsing): x ¡-
udpipe annotate(ud dutch, x = txt, tagger = ”default”, parser = ”none”)
token+ dependancy parsing: x ¡- udpipe annotate(ud dutch, x = txt, tagger = ”none”,
parser = ”default”)
April 23, 2018 169 / 241
170. afficher la structure d’un corpus d’apr`es le pos tagging
Example
# fonction du package qui permet de calculer les fr´equences par colonne particuli`er
stats <- txt_freq(brussels_reviews_anno$upos)
#je transforme mes fr´equences en facteur
stats$key <- factor(stats$key, levels = rev(stats$key))
#la je trace mon graphique (librairie lattice)
barchart(key ~ freq, data = stats, col = "cadetblue",
main = "UPOS (Universal Parts of Speech) frequency of occurrence",
xlab = "Freq")
April 23, 2018 170 / 241
172. afficher la structure d’un corpus d’apr`es le pos tagging
Example
# je filtre mon dataset avec le tag que je souhaite garder
stats <- subset(brussels_reviews_anno, upos %in% c("NOUN"))
# fonction du package qui permet de calculer les fr´equences
stats <- txt_freq(stats$token)
#je transforme mes fr´equences en facteur
stats$key <- factor(stats$key, levels = rev(stats$key))
#la je trace mon graphique
barchart(key ~ freq, data = head(stats, 20), col = "cadetblue",
main = "Most occurring nouns", xlab = "Freq")
April 23, 2018 172 / 241
174. afficher la structure d’un corpus d’apr`es le pos tagging
Example
stats <- subset(brussels_reviews_anno, upos %in% c("ADJ"))
# l’appelle la fonction du package qui permet de calculer les fr´equences
stats <- txt_freq(stats$token)
#je transforme mes fr´equences en facteur
# ordonner le vecteur
statskey <- factor(stats$key, levels = rev(stats$key))
#la je trace mon graphique
barchart(key ~ freq, data = head(stats, 20), col = "cadetblue",
main = "Most occurring adjectives", xlab = "Freq")
April 23, 2018 174 / 241
176. afficher la structure d’un corpus d’apr`es le pos tagging
Example
# je filtre mon dataset avec le tag que je souhaite garder
stats <- subset(brussels_reviews_anno, upos %in% c("ADV"))
# fonction du package qui permet de calculer les fr´equences
stats <- txt_freq(stats$token)
#je transforme mes fr´equences en facteur
stats$key <- factor(stats$key, levels = rev(stats$key))
#la je trace mon graphique
barchart(key ~ freq, data = head(stats, 20), col = "cadetblue",
main = "Most occurring adverbs", xlab = "Freq")
April 23, 2018 176 / 241
178. afficher la structure d’un corpus d’apr`es le pos tagging
Example
# je filtre mon dataset avec le tag que je souhaite garder
stats <- subset(brussels_reviews_anno, upos %in% c("VERB"))
# fonction du package qui permet de calculer les fr´equences par colonne particuli`er
stats <- txt_freq(stats$token)
#je transforme mes fr´equences en facteur
# ordonner le vecteur
stats$key <- factor(stats$key, levels = rev(stats$key))
#la je trace mon graphique
barchart(key ~ freq, data = head(stats, 20), col = "cadetblue",
main = "Most occurring verbs", xlab = "Freq")
April 23, 2018 178 / 241
180. afficher la structure d’un corpus d’apr`es le pos tagging
Example
# je filtre mon dataset avec le tag que je souhaite garder
stats <- subset(brussels_reviews_anno, upos %in% c("NUM"))
# fonction du package qui permet de calculer les fr´equences
stats <- txt_freq(stats$token)
#je transforme mes fr´equences en facteur
stats$key <- factor(stats$key, levels = rev(stats$key))
#la je trace mon graphique
barchart(key ~ freq, data = head(stats, 20), col = "cadetblue",
main = "Most occurring num", xlab = "Freq")
April 23, 2018 180 / 241
182. les cooccurrences
Le package permet de calculer trois types de cooccurrence:
la cooccurrence entre les termes au niveau d’un mˆeme paragraphe ou texte,
la cooccurrence entre des termes cons´ecutifs,
la cooccurrence entre deux termes s´epar´es `a n skipgrams (`a n mots pr`es),
L’output d’un calcul de cooccurrence est un dataframe qui contient:
une colonne avec le terme 1,
une colonne avec le terme 2,
la cooccurrence soit le nombre de fois o`u les deux mots apparaissent ensemble.
April 23, 2018 182 / 241
183. calculer la cooccurrence
Example
# je filtre mon dataset (fonction subset)
la liste des tags:
https://www.clips.uantwerpen.be/pages/mbsp-tags
data(brussels_reviews_anno)
co_fr <- subset(brussels_reviews_anno,
xpos %in% c("NN", "JJ") & language %in% "fr")
==>ici je veux les noms et les adjectifs en fran¸cais
# j’applique la fonction qui permet de calculer les cooccurrences
co_fr <- cooccurrence(co_fr, group = "doc_id", term = "lemma")
# je visualise le d´ebut de mon dataframe
head(co_fr)
#je transforme mes donn´ees
co_fr<-as.data.frame(co_fr)
co_fr$x<-paste(co_fr$term1, co_fr$term2)
April 23, 2018 183 / 241
185. un peu de ggplot dans tout cela....
Example
library(ggplot2)
library(dplyr)
co_fr%>%
dplyr::mutate(x=reorder(x,cooc))%>%
dplyr::filter(cooc>50)%>%
ggplot2::ggplot(aes(x=x,y=cooc, color=cooc))+
geom_point(stat="identity")+theme_minimal()+
scale_color_distiller(palette = "Spectral")+
theme(axis.text=element_text(size=8),
axis.title=element_text(size=8))+
coord_flip() +
theme(axis.text.x = element_text(size=8,face="bold",angle = 90))+
theme(legend.justification=c(1,0), legend.position=c(1,0))+
abs(x = "mots",
y = "nombre de cooccurence",
title = "coocurrence de terme")
April 23, 2018 185 / 241
187. calculer la cooccurrence
Example
data(brussels_reviews_anno)
# je filtre mon dataset ==>les ´el´ements+langue
la liste des tags:
https://www.clips.uantwerpen.be/pages/mbsp-tags
co_es <- subset(brussels_reviews_anno,
xpos %in% c("NN", "JJ") & language %in% "es")
# j’applique la fonction qui permet de calculer les cooccurrences
co_es <- cooccurrence(co_es, group = "doc_id", term = "lemma")
# je visualise le d´ebut de mon dataframe
head(co_es)
#je transforme mes donn´ee
co_es<-as.data.frame(co_es)
co_es$x<-paste(co_es$term1, co_es$term2)
April 23, 2018 187 / 241
190. d’autres fonctions int´eressantes du package: le topic
modeling
Example
# je cr´ee mon set de donn´ees
x <- subset(brussels_reviews_anno, language == "fr")
x <- subset(x, xpos %in% c("JJ"))
x <- x[, c("doc_id", "lemma")]
#je cr´ee une matrice puis je filtre pour r´eduire la taille de la matrice
x <- document_term_frequencies(x)
dtm <- document_term_matrix(x)
dtm <- dtm_remove_lowfreq(dtm, minfreq = 10)
dtm <- dtm_remove_tfidf(dtm, top = 100)
# j’applique la fonction de topic modeling LDA (param`etres: nombre de topic
et m´ethode ( VEM algorithm ou Gibbs Sampling))
#je charge la librairie topic models
library(topicmodels)
mymodel <- LDA(x = dtm, k = 3, method = "VEM")
April 23, 2018 190 / 241
191. le topic modeling: la mod´elisation
Example
# j’extrais des donn´ees reli´ees `a mod´elisation
terminology <- predict(mymodel, type = "terms",
min_posterior = -1, min_terms = 0)
#min_posterior ==>filtre minimum probabilit´e
ex-post ==>l’ensemble des termes -1
#min_terms ==>max de termes `a faire appara^ıtre
ici ==>max =0
April 23, 2018 191 / 241
197. conclusion sur udpipe
lorsque l’on souhaite effectuer des op´erations telles que le ”pos-tagging”, le ”dependy parsing”et
la ”lemmatization” dans l’environnement r, le package udpipe est aujourd’hui la solution la plus
simple. En effet, ce package ne n´ecessite pas l’installation de backends, op´eration qui peut ˆetre
d´elicate (cf. java). Dans ce cours, nous nous sommes concentr´es sur la fonction
udpipe annotate. Or, le package dispose d’autres fonctionnalit´es int´eressantes comme:
la possibilit´e de cr´eer de matrice de termes
la possibilit´e d’effectuer des transformations sur les matrices (sparse terms, specific terms,
etc...)
d’effectuer du topic modeling
de transformer le texte
d’´evaluer les r´esultats,
de cr´eer, modifier, exporter, importer ses propres dictionnaires,
....
April 23, 2018 197 / 241
198. le package cleanNLP
le package permet de g´erer diff´erents backends pour proc´eder au tagging. La documentation du
package est claire sur les sp´ecificit´es des diff´erents backends (installation, manipulation et
performance):
tokenizers: a fast parser that only requires the stringi package, but produces only
tokenized text
udpipe: a parser with no external dependencies that produces tokens, lemmas, part of
speech tags, and dependency relationships. (the recommended starting point given its
balance between ease of use and functionality. It also supports the widest range of natural
languages).
spacy: based on the Python library, a more feature complete parser that included named
entity recognition and word embeddings. (it does require a working Python installation
and some other set-up. Recommended for users who are familiar with Python or plan to
make heavy use of the package)
corenlp: based on the Java library with the same name. Supports coreferences and other
bleeding-edge annotation tasks. (not recommended for most users given its slow speed
and difficult set-up)
April 23, 2018 198 / 241
199. Initialiser le package
Example
apr`es avoir t´el´echarger le package cleanNLP, il
le charger dans rstudio ainsi que les autres packages
# Initialiser le package cleanNLP
library(cleanNLP) #package cleanNLP
library(reticulate) #interface avec python
library(dplyr) #manipulation des donn´ees
library(magrittr) #fonctions pipe
library(ggplot2) #repr´esentation graphique
April 23, 2018 199 / 241