SlideShare a Scribd company logo
1 of 241
Download to read offline
Extraire, transformer et
repr´esenter la social data avec R
Seconde partie: le text mining
April 23, 2018 1 / 241
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
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
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
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
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
April 23, 2018
April 23, 2018 7 / 241
S´eance 4: le package tidytext
April 23, 2018 8 / 241
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
mon r´esultat
April 23, 2018 26 / 241
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]+|&amp;|&lt;|&gt;|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]+|&amp;|&lt;|&gt;|RT|https",’’’’ )
April 23, 2018 27 / 241
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
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
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
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
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
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
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
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
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
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
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
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
r´esultat graphique
Dans l’´etat, le graphique ne nous apprends rien....
April 23, 2018 40 / 241
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
r´esultat graphique
C’est d´ej`a mieux....
April 23, 2018 42 / 241
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
r´esultat graphique
C’est encore mieux....
April 23, 2018 44 / 241
r´esultat graphique
.... mais ce n’est pas parfait: url, nombre, mots li´es `a l’extract...
April 23, 2018 45 / 241
utiliser des filtres g´en´eraux
Ajoutons quelques filtres...)
Example
tidy_presses_graph<-presse%>%
unnest_tokens(word,message)%>%
filter(str_detect(word, "[a-z]"))%>%
filter(word !="http")%>%
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)%>%
dplyr::count(word, sort=TRUE)%>%
mutate(word=reorder(word,-n))%>%
filter(n>100)%>%
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))+
labs(x = "mots",
y = "nombre d’occurence",
title = "liste des mots apparaissant plus de 100 fois dans les tokens")April 23, 2018 46 / 241
r´esultat graphique
....les urls...
April 23, 2018 47 / 241
traiter les urls
Example
tidy_presses_graph<-presse%>%
unnest_tokens(word,message)%>%
mutate(word = str_replace_all(word,"https://t.co/[A-Za-zd]+
|http://[A-Za-zd]+
|&amp;|&lt;|&gt;|RT|https|[’‘^~’]|[:digit:]|[:punct:]",""))%>%
mutate(word = str_replace_all(word, "https|//t|http|&amp;|&lt;|&gt;", ""))%>%
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)%>%
dplyr::count(word, sort=TRUE)%>%
mutate(word=reorder(word,-n))%>%
filter(n>100)
April 23, 2018 48 / 241
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
notre proc´edure....
Example
tidy_presses_graph<-presse%>%
tidytext::unnest_tokens(word,message)%>%
dplyr::mutate(word = stringr::str_replace_all(word,"https://t.co/[A-Za-zd]+
http://[A-Za-zd]+|&amp;|&lt;|&gt;|RT|https|[’‘^~’]|[:digit:]|[:punct:]",""))%>%
mutate(word = str_replace_all(word, "https|//t|http|&amp;|&lt;|&gt;", ""))%>%
filter(str_detect(word, "[a-z]"))%>%
filter(word !="http")%>%
filter(word !="bitly")%>%
filter(nchar(word)>1)%>%
anti_join(mystopwords, by = "word")%>%
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)%>%
dplyr::count(word, sort=TRUE)%>%
mutate(word=reorder(word,-n))%>%
filter(n>100)%>%
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))
April 23, 2018 50 / 241
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
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]+
|&amp;|&lt;|&gt;|RT|https|[’‘^~’]|[:digit:]|[:punct:]",""))%>%
mutate(word = str_replace_all(word, "https|//t|http|&amp;|&lt;|&gt;", ""))%>%
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
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
r´esultat graphique
April 23, 2018 54 / 241
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
jointure des deux fichiers
Example
# j’effectue une jointure
page_mots<- left_join(mots_page, total_words)
April 23, 2018 56 / 241
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
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
un graphique illustratif
Example
origine_words <- page_mots%>%
bind_tf_idf(word, from_name, n)
origine_words <- origine_words %>%
bind_tf_idf(word, from_name, n)%>%
arrange(desc(tf_idf))
plot_words<-origine_words%>%
arrange(desc(tf_idf))%>%
top_n(50) %>%
mutate(word = factor(word, levels = rev(unique(word))))%>%
ggplot(aes(word, tf_idf, fill = from_name)) +theme_minimal()+
geom_bar(stat = "identity") +
labs(x = NULL, y = "tf-idf") +
coord_flip()
April 23, 2018 59 / 241
top 50 par tf-idf
April 23, 2018 60 / 241
vision par page
Example
origine_words <- page_mots%>%
bind_tf_idf(word, from_name, n)
origine_words <- origine_words %>%
bind_tf_idf(word, from_name, n)%>%
arrange(desc(tf_idf))
plot_plot_words<-origine_words %>%
arrange(desc(tf_idf))%>%
mutate(word = factor(word, levels = rev(unique(word))))
plot_plot_words_plot<-plot_plot_words %>%
group_by(from_name) %>%
top_n(15) %>%
ungroup %>%
ggplot(aes(word, 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 61 / 241
quels sont les mots les plus sp´ecifiques entre les diff´erentes
pages?
April 23, 2018 62 / 241
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
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
une bonne approximation?
April 23, 2018 65 / 241
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
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
la structure du dataframe
April 23, 2018 68 / 241
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
le r´esultat sous forme de dataframe
Il va falloir nettoyer le corpus (encodage.....)
April 23, 2018 70 / 241
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
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]+|&amp;|&lt;|&gt;|RT|https|[’‘^~’]
|[:digit:]|[:punct:]","")
bigram_filtered$word2<-str_replace_all(bigram_filtered$word2,
"https://t.co/[A-Za-zd]+|http://[A-Za-zd]+|&amp;|&lt;|&gt;|RT|https|[’‘^~’]
|[:digit:]|[:punct:]","")
bigram_filtered$word1<- str_replace_all(bigram_filtered$word1,
"https|//t|http|&amp;|&lt;|&gt;", "")
bigram_filtered$word2<- str_replace_all(bigram_filtered$word2,
"https|//t|http|&amp;|&lt;|&gt;", "")
April 23, 2018 72 / 241
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
la multiplication des r`egles de substitution
April 23, 2018 74 / 241
le r´esultat des traitements de nettoyage
April 23, 2018 75 / 241
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
la structure d’organisation des donn´ees interm´ediaires
April 23, 2018 77 / 241
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
les 60 plus fortes associations de mots en vertu du tf-idf
April 23, 2018 79 / 241
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
le graphique
April 23, 2018 81 / 241
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
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
le r´esultat de la fonction graph from data frame()
April 23, 2018 84 / 241
le r´esultat de la fonction ggraph
April 23, 2018 85 / 241
ajoutons une notion d’intensit´e
Example
#je cree un objet suppl´ementaire avec une fl`eche
a <- grid::arrow(type = "closed", length = unit(.10, "inches"))
# je cr´ee un graphe avec le code suivant.
ggraph(bigram_graph,layout = ’kk’) +
geom_edge_link(aes(edge_alpha = n), show.legend = TRUE,
arrow = a, end_cap = circle(.05, ’inches’)) +
geom_node_point(color = "red", size = 1) +
geom_node_text(aes(label = name),color = "blue", size = 3, vjust = 1, hjust = 1)
theme_void()
April 23, 2018 86 / 241
le r´esultat de la fonction ggraph
April 23, 2018 87 / 241
le trigram pour la route
Example
#trigrams n=3
presse_trigram<-presse_ngram%>%
unnest_tokens(trigram, message, token = "ngrams", n = 3)
View(presse_trigram)
presse_trigram%>%
count(trigram,sort=TRUE)
presse_trigram_separated <- presse_trigram%>%
separate(trigram, c("word1", "word2", "word3"), sep = " ")
April 23, 2018 88 / 241
premi`ere phase de nettoyage
Example
trigram_filtered <- presse_trigram_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)%>%
dplyr::filter(!word3 %in% stop_words$word) %>%
dplyr::filter(!word3 %in% mystopwords$word) %>%
dplyr::filter(!word3 %in% lsa::stopwords_en)%>%
dplyr::filter(!word3 %in% lsa::stopwords_fr)
April 23, 2018 89 / 241
seconde phase de nettoyage: je duplique n fois mes r`egles
Example
trigram_filtered$word1<-gsub("l^aTMasile"," ",trigram_filtered$word1)
trigram_filtered$word2<-gsub("l^aTMasile"," ",trigram_filtered$word2)
trigram_filtered$word3<-gsub("l^aTMasile"," ",trigram_filtered$word3)
trigram_filtered$word1<-gsub("~A","`a",trigram_filtered$word1)
trigram_filtered$word2<-gsub("~A","`a",trigram_filtered$word2)
trigram_filtered$word3<-gsub("~A","`a",trigram_filtered$word3)
trigram_filtered$word1<-gsub("~A¡","´a",trigram_filtered$word1)
trigram_filtered$word2<-gsub("~A¡","´a",trigram_filtered$word2)
....................................................................................
trigram_filtered$word1<- str_replace_all(trigram_filtered$word1,
"https|//t|http|&amp;|&lt;|&gt;", "")
trigram_filtered$word2<- str_replace_all(trigram_filtered$word2,
"https|//t|http|&amp;|&lt;|&gt;", "")
trigram_filtered$word3<- str_replace_all(trigram_filtered$word3,
"https|//t|http|&amp;|&lt;|&gt;", "")
April 23, 2018 90 / 241
les manipulations ex-post
Example
presse_trigram_united <- trigram_filtered %>%
unite(trigram, word1, word2, word3,sep = " ")
trigram_tf_idf <- presse_trigram_united %>%
count(from_name,trigram) %>%
bind_tf_idf(trigram, from_name, n) %>%
arrange(desc(tf_idf))
trigram_tf_idf %>%
select(-sum(n))%>%
arrange(desc(tf_idf))
plot_trigram<-trigram_tf_idf%>%
arrange(desc(tf_idf))%>%
mutate(trigram = factor(trigram, levels = rev(unique(trigram))))
ggplot(plot_trigram[1:60,], aes(trigram, tf_idf, fill = from_name)) +
geom_bar(stat = "identity") +
labs(x = NULL, y = "tf-idf") +
coord_flip()
April 23, 2018 91 / 241
a vos claviers..
April 23, 2018 92 / 241
les manipulations ex-post
Example
plot_trigram<- plot_trigram%>%
group_by(from_name) %>%
top_n(20) %>%
ungroup
ggplot(plot_trigram, aes(trigram, 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 93 / 241
le top 20 des trigrams par page
April 23, 2018 94 / 241
la repr´esentation en r´eseau
April 23, 2018 95 / 241
S´eance 5: l’analyse de sentiment avec r
April 23, 2018 96 / 241
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
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
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
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
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
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
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
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
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
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
le r´esultat
April 23, 2018 107 / 241
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
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
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
code graphique
Example
base_score_graphique<-extract_r_the_economist%>%
tidytext::unnest_tokens(word,message)%>%
filter(str_detect(word, "[a-z]"))%>%
anti_join(tidytext::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)%>%
filter(n>10)%>%
ggplot(aes(x= reorder(word,(n)),y=n,fill = score))+
geom_bar(stat="identity")+
scale_fill_continuous(high = "#132B43", low = "#56B1F7")+
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 = "occurence et score")
April 23, 2018 111 / 241
le r´esultat
April 23, 2018 112 / 241
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
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
le r´esultat
April 23, 2018 115 / 241
l’analyse des mots les plus pr´esents en mati`ere de polarit´e
Example
bing_word_counts_eco <-extract_r_the_economist%>%
group_by(type)%>%
tidytext::unnest_tokens(word,message)%>%
dplyr::inner_join(get_sentiments("bing")) %>%
count(word, sentiment, sort = TRUE) %>%
dplyr::ungroup()
bing_word_counts_eco %>%
group_by(sentiment) %>%
top_n(40) %>%
ungroup() %>%
mutate(word = reorder(word, n)) %>%
ggplot(aes(word, n, fill = sentiment)) +
scale_color_manual(values = economist_sentiment, name = "", breaks = c("negatif","
geom_col(show.legend = FALSE) + facet_grid(sentiment~., scales = "free_y") +
theme_minimal()+ labs(y = "Contribution to sentiment", x = NULL) + coord_flip()
April 23, 2018 116 / 241
le r´esultat
April 23, 2018 117 / 241
l’analyse des mots les plus pr´esents en mati`ere de polarit´e
Example
library(wordcloud)
library(reshape2)
extract_r_the_economist%>%
tidytext::unnest_tokens(word,message)%>%
inner_join(get_sentiments("bing")) %>%
count(word, sentiment, sort = TRUE) %>%
reshape2::acast(word ~ sentiment, value.var = "n", fill = 0) %>%
comparison.cloud(colors = c("firebrick4", "chartreuse4"),
max.words = 100)
April 23, 2018 118 / 241
le r´esultat
April 23, 2018 119 / 241
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
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
le r´esultat
April 23, 2018 122 / 241
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
le r´esultat
April 23, 2018 124 / 241
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
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
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
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
le resultat
April 23, 2018 129 / 241
la fonction analyse sentiment
Example
sa_eco<-analyzeSentiment(extract_r_the_economist$message, language = "english",
aggregate = NULL, removeStopwords = FALSE,
stemming = FALSE)
sa_extract<-extract_r_the_economist
sa_extract<-cbind(sa_extract, sa_eco) #recr´ee ma base
sa_extract<-sa_extract%>%
filter(annee!= 2012) #pb extract
ggplot(sa_extract, aes(time)) +
geom_line(aes(y = sa_extract$SentimentGI,colour = "var0"))+
#geom_line(aes(y = sa_extract$SentimentHE,colour = "var1"))+
#geom_line(aes(y = sa_extract$SentimentLM,colour = "var2"))+
#geom_line(aes(y = sa_extract$SentimentQDAP,colour = "var3"))+
theme_minimal()+
labs(x = "date",
y = "score",
title = "calcul du sentiment total",
subtitle = "m´ethode sentiment GI") # a adapter
April 23, 2018 130 / 241
le dictionnaire GI
April 23, 2018 131 / 241
le dictionnaire HE
April 23, 2018 132 / 241
le dictionnaire LM
April 23, 2018 133 / 241
le dictionnaire QDAP
April 23, 2018 134 / 241
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
une comparaison des m´ethodes
April 23, 2018 136 / 241
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
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
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
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
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
la m´ethode afinn
April 23, 2018 142 / 241
la m´ethode syuzhet
April 23, 2018 143 / 241
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
repr´esentation graphique
April 23, 2018 145 / 241
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
repr´esentation graphique
April 23, 2018 147 / 241
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
repr´esentation graphique
April 23, 2018 149 / 241
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
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
S´eance 6: syntactic parsing
April 23, 2018 152 / 241
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
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
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
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
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
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
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
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
visualiser cette premi`ere op´eration
Example
View (my texte 1 anno)
April 23, 2018 161 / 241
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
afficher cette seconde op´eration
Example
April 23, 2018 163 / 241
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
afficher cette seconde op´eration
April 23, 2018 165 / 241
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
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
le r´esultat obtenu
April 23, 2018 168 / 241
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
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
mes donn´ees
April 23, 2018 171 / 241
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
mes donn´ees
April 23, 2018 173 / 241
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
mes donn´ees
April 23, 2018 175 / 241
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
mes donn´ees
April 23, 2018 177 / 241
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
mon r´esultat
April 23, 2018 179 / 241
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
mes donn´ees
April 23, 2018 181 / 241
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
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
mes donn´ees
April 23, 2018 184 / 241
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
mes donn´ees
April 23, 2018 186 / 241
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
un r´esultat graphique
Example
library(ggplot2)
library(dplyr)
co_es%>%
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))+
labs(x = "mots",
y = "nombre de cooccurence",
title = "coocurrence de terme")
April 23, 2018 188 / 241
mes donn´ees
April 23, 2018 189 / 241
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
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
r´esultat: 1 dataframe par topic
April 23, 2018 192 / 241
le topic modeling: afficher l’attribution de chaque
document topic
Example
# j’extrais des donn´ees reli´ees `a mod´elisation
terminology_2 <- predict(mymodel, dtm, type = c("topics", "terms"),
min_posterior = -1, min_terms = 0)
terminology_2
#min_posterior ==>filtre minimum probabilit´e ex-post
==>l’ensemble des termes -1
#min_terms ==>max de termes `a faire appara^ıtre
==>max =0
April 23, 2018 193 / 241
mon r´esultat
April 23, 2018 194 / 241
le topic modeling: la m´ethode ”gibbs”
Example
# autre m´ethode de calcul sample ’’Gibbs’’
mymodel_bis <- LDA(x = dtm, k = 4, method = "Gibbs")
terminology <- predict(mymodel_bis, type = "terms",
min_posterior = 0.05, min_terms = 3)
scores <- predict(mymodel_bis, type = "topics", newdata = dtm)
head(scores)
April 23, 2018 195 / 241
r´esultat: 1 dataframe par topic
April 23, 2018 196 / 241
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
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
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
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining
extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining

More Related Content

What's hot

Développement Web - Module 1 - Introduction
Développement Web - Module 1 - IntroductionDéveloppement Web - Module 1 - Introduction
Développement Web - Module 1 - IntroductionMohammed Amine Mostefai
 
BigData_Chp3: Data Processing
BigData_Chp3: Data ProcessingBigData_Chp3: Data Processing
BigData_Chp3: Data ProcessingLilia Sfaxi
 
Structure du rapport d'etat d'avancement doctorat
Structure du rapport d'etat d'avancement doctoratStructure du rapport d'etat d'avancement doctorat
Structure du rapport d'etat d'avancement doctoratIkram Benabdelouahab
 
Premier pas de web scrapping avec R
Premier pas de  web scrapping avec RPremier pas de  web scrapping avec R
Premier pas de web scrapping avec RCdiscount
 
Analyse de la valeur
Analyse de la valeurAnalyse de la valeur
Analyse de la valeurEric Métais
 
Formation PHP
Formation PHPFormation PHP
Formation PHPkemenaran
 
Presentation Habilitation à Diriger des Recherches
Presentation Habilitation à Diriger des RecherchesPresentation Habilitation à Diriger des Recherches
Presentation Habilitation à Diriger des RecherchesBOUWMANS Thierry
 
La prédiction du churn client dans le domaine du telecom
La prédiction du churn client dans le domaine du telecomLa prédiction du churn client dans le domaine du telecom
La prédiction du churn client dans le domaine du telecomIsmail Sanni
 
BigData_TP4 : Cassandra
BigData_TP4 : CassandraBigData_TP4 : Cassandra
BigData_TP4 : CassandraLilia Sfaxi
 
Grille évaluation diaporama
Grille évaluation diaporama Grille évaluation diaporama
Grille évaluation diaporama cdicondorcet02
 
Rapport exposé eXtreme Programming XP
Rapport exposé eXtreme Programming XPRapport exposé eXtreme Programming XP
Rapport exposé eXtreme Programming XPSarah
 
Recherche qualitative 2020
Recherche qualitative 2020Recherche qualitative 2020
Recherche qualitative 2020Pascal Boulet
 
Cours Big Data Chap3
Cours Big Data Chap3Cours Big Data Chap3
Cours Big Data Chap3Amal Abid
 
Android - Tp1 - installation et démarrage
Android - Tp1 -   installation et démarrageAndroid - Tp1 -   installation et démarrage
Android - Tp1 - installation et démarrageLilia Sfaxi
 
Avancement de mon doctorat (Damien Clauzel, janvier 2009)
Avancement de mon doctorat (Damien Clauzel, janvier 2009)Avancement de mon doctorat (Damien Clauzel, janvier 2009)
Avancement de mon doctorat (Damien Clauzel, janvier 2009)Damien Clauzel
 

What's hot (20)

Développement Web - Module 1 - Introduction
Développement Web - Module 1 - IntroductionDéveloppement Web - Module 1 - Introduction
Développement Web - Module 1 - Introduction
 
Data Science
Data ScienceData Science
Data Science
 
BigData_Chp3: Data Processing
BigData_Chp3: Data ProcessingBigData_Chp3: Data Processing
BigData_Chp3: Data Processing
 
Image Mining
Image MiningImage Mining
Image Mining
 
Structure du rapport d'etat d'avancement doctorat
Structure du rapport d'etat d'avancement doctoratStructure du rapport d'etat d'avancement doctorat
Structure du rapport d'etat d'avancement doctorat
 
Premier pas de web scrapping avec R
Premier pas de  web scrapping avec RPremier pas de  web scrapping avec R
Premier pas de web scrapping avec R
 
Mahout clustering
Mahout clusteringMahout clustering
Mahout clustering
 
Analyse de la valeur
Analyse de la valeurAnalyse de la valeur
Analyse de la valeur
 
Formation PHP
Formation PHPFormation PHP
Formation PHP
 
Presentation Habilitation à Diriger des Recherches
Presentation Habilitation à Diriger des RecherchesPresentation Habilitation à Diriger des Recherches
Presentation Habilitation à Diriger des Recherches
 
La prédiction du churn client dans le domaine du telecom
La prédiction du churn client dans le domaine du telecomLa prédiction du churn client dans le domaine du telecom
La prédiction du churn client dans le domaine du telecom
 
BigData_TP4 : Cassandra
BigData_TP4 : CassandraBigData_TP4 : Cassandra
BigData_TP4 : Cassandra
 
Grille évaluation diaporama
Grille évaluation diaporama Grille évaluation diaporama
Grille évaluation diaporama
 
Mongo DB
Mongo DBMongo DB
Mongo DB
 
Rapport exposé eXtreme Programming XP
Rapport exposé eXtreme Programming XPRapport exposé eXtreme Programming XP
Rapport exposé eXtreme Programming XP
 
Recherche qualitative 2020
Recherche qualitative 2020Recherche qualitative 2020
Recherche qualitative 2020
 
Cours Big Data Chap3
Cours Big Data Chap3Cours Big Data Chap3
Cours Big Data Chap3
 
Android - Tp1 - installation et démarrage
Android - Tp1 -   installation et démarrageAndroid - Tp1 -   installation et démarrage
Android - Tp1 - installation et démarrage
 
Avancement de mon doctorat (Damien Clauzel, janvier 2009)
Avancement de mon doctorat (Damien Clauzel, janvier 2009)Avancement de mon doctorat (Damien Clauzel, janvier 2009)
Avancement de mon doctorat (Damien Clauzel, janvier 2009)
 
Les étapes clés d'un projet web
Les étapes clés d'un projet webLes étapes clés d'un projet web
Les étapes clés d'un projet web
 

Similar to extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining

Apport des thésaurus pour le catalogage et la localisation des données enviro...
Apport des thésaurus pour le catalogage et la localisation des données enviro...Apport des thésaurus pour le catalogage et la localisation des données enviro...
Apport des thésaurus pour le catalogage et la localisation des données enviro...Desconnets Jean-Christophe
 
Histoire des Sciences et des techniques, TIC et Inquiry Based Science Teachin...
Histoire des Sciences et des techniques, TIC et Inquiry Based Science Teachin...Histoire des Sciences et des techniques, TIC et Inquiry Based Science Teachin...
Histoire des Sciences et des techniques, TIC et Inquiry Based Science Teachin...M@rsouin
 
Comment récupérer un projet Web pourri ... et réussir à travailler dessus.
Comment récupérer un projet Web pourri ... et réussir à travailler dessus.Comment récupérer un projet Web pourri ... et réussir à travailler dessus.
Comment récupérer un projet Web pourri ... et réussir à travailler dessus.Guillaume RICHARD
 
Panorama des logiciels de gestion de références bibliographiques
Panorama des logiciels de gestion de références bibliographiquesPanorama des logiciels de gestion de références bibliographiques
Panorama des logiciels de gestion de références bibliographiquesURFIST de Paris
 
03 Web Semantique
03  Web Semantique03  Web Semantique
03 Web Semantiquebadirh
 
Formation Zotero avancée pour doctorants - Isidoct mars 2020 ENS Lyon
Formation Zotero avancée pour doctorants - Isidoct mars 2020 ENS LyonFormation Zotero avancée pour doctorants - Isidoct mars 2020 ENS Lyon
Formation Zotero avancée pour doctorants - Isidoct mars 2020 ENS LyonAlain Marois
 
Création de bases de données
Création de bases de donnéesCréation de bases de données
Création de bases de donnéesRiadh ASSOUAK
 
Exploiter les données issues de Wikipedia
Exploiter les données issues de WikipediaExploiter les données issues de Wikipedia
Exploiter les données issues de WikipediaRobert Viseur
 
Séminaire Inria IST - Référentiels et interoperabilité (2)
Séminaire Inria IST - Référentiels et interoperabilité (2)Séminaire Inria IST - Référentiels et interoperabilité (2)
Séminaire Inria IST - Référentiels et interoperabilité (2)Antoine Isaac
 
Programmation orientee aspect 201401 - Ensim
Programmation orientee aspect 201401 - EnsimProgrammation orientee aspect 201401 - Ensim
Programmation orientee aspect 201401 - EnsimLaurent Broudoux
 
Ecole ESMA : Rapport de projet - Application de gestion d'une bibliotheque
Ecole ESMA : Rapport de projet - Application de gestion d'une bibliothequeEcole ESMA : Rapport de projet - Application de gestion d'une bibliotheque
Ecole ESMA : Rapport de projet - Application de gestion d'une bibliothequeMehdi Hamime
 
Détecter et nettoyer le contenu générique
Détecter et nettoyer le contenu génériqueDétecter et nettoyer le contenu générique
Détecter et nettoyer le contenu génériquebenoit chevillot
 
0 a104g formation-introduction-a-ibm-spss-modeler-text-analytics
0 a104g formation-introduction-a-ibm-spss-modeler-text-analytics0 a104g formation-introduction-a-ibm-spss-modeler-text-analytics
0 a104g formation-introduction-a-ibm-spss-modeler-text-analyticsCERTyou Formation
 
2007 vsst lcd
2007 vsst lcd2007 vsst lcd
2007 vsst lcdSouad Mo
 

Similar to extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining (20)

Apport des thésaurus pour le catalogage et la localisation des données enviro...
Apport des thésaurus pour le catalogage et la localisation des données enviro...Apport des thésaurus pour le catalogage et la localisation des données enviro...
Apport des thésaurus pour le catalogage et la localisation des données enviro...
 
Histoire des Sciences et des techniques, TIC et Inquiry Based Science Teachin...
Histoire des Sciences et des techniques, TIC et Inquiry Based Science Teachin...Histoire des Sciences et des techniques, TIC et Inquiry Based Science Teachin...
Histoire des Sciences et des techniques, TIC et Inquiry Based Science Teachin...
 
Comment récupérer un projet Web pourri ... et réussir à travailler dessus.
Comment récupérer un projet Web pourri ... et réussir à travailler dessus.Comment récupérer un projet Web pourri ... et réussir à travailler dessus.
Comment récupérer un projet Web pourri ... et réussir à travailler dessus.
 
Panorama des logiciels de gestion de références bibliographiques
Panorama des logiciels de gestion de références bibliographiquesPanorama des logiciels de gestion de références bibliographiques
Panorama des logiciels de gestion de références bibliographiques
 
03 Web Semantique
03  Web Semantique03  Web Semantique
03 Web Semantique
 
Formation Zotero avancée pour doctorants - Isidoct mars 2020 ENS Lyon
Formation Zotero avancée pour doctorants - Isidoct mars 2020 ENS LyonFormation Zotero avancée pour doctorants - Isidoct mars 2020 ENS Lyon
Formation Zotero avancée pour doctorants - Isidoct mars 2020 ENS Lyon
 
Création de bases de données
Création de bases de donnéesCréation de bases de données
Création de bases de données
 
Exploiter les données issues de Wikipedia
Exploiter les données issues de WikipediaExploiter les données issues de Wikipedia
Exploiter les données issues de Wikipedia
 
Séminaire Inria IST - Référentiels et interoperabilité (2)
Séminaire Inria IST - Référentiels et interoperabilité (2)Séminaire Inria IST - Référentiels et interoperabilité (2)
Séminaire Inria IST - Référentiels et interoperabilité (2)
 
Cours 01.pptx
Cours 01.pptxCours 01.pptx
Cours 01.pptx
 
Programmation orientee aspect 201401 - Ensim
Programmation orientee aspect 201401 - EnsimProgrammation orientee aspect 201401 - Ensim
Programmation orientee aspect 201401 - Ensim
 
Ecole ESMA : Rapport de projet - Application de gestion d'une bibliotheque
Ecole ESMA : Rapport de projet - Application de gestion d'une bibliothequeEcole ESMA : Rapport de projet - Application de gestion d'une bibliotheque
Ecole ESMA : Rapport de projet - Application de gestion d'une bibliotheque
 
Détecter et nettoyer le contenu générique
Détecter et nettoyer le contenu génériqueDétecter et nettoyer le contenu générique
Détecter et nettoyer le contenu générique
 
Design patterns
Design patternsDesign patterns
Design patterns
 
Design patterns
Design patternsDesign patterns
Design patterns
 
Présentation cice telos
Présentation cice   telosPrésentation cice   telos
Présentation cice telos
 
Usageordi Ciney
Usageordi CineyUsageordi Ciney
Usageordi Ciney
 
0 a104g formation-introduction-a-ibm-spss-modeler-text-analytics
0 a104g formation-introduction-a-ibm-spss-modeler-text-analytics0 a104g formation-introduction-a-ibm-spss-modeler-text-analytics
0 a104g formation-introduction-a-ibm-spss-modeler-text-analytics
 
2007 vsst lcd
2007 vsst lcd2007 vsst lcd
2007 vsst lcd
 
Rapport Tal Master 1
Rapport Tal Master 1Rapport Tal Master 1
Rapport Tal Master 1
 

extraire, représenter et traiter la social data avec r. seconde partie: applicaiton au text mining

  • 1. Extraire, transformer et repr´esenter la social data avec R Seconde partie: le text mining April 23, 2018 1 / 241
  • 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
  • 7. April 23, 2018 April 23, 2018 7 / 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
  • 26. mon r´esultat April 23, 2018 26 / 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]+|&amp;|&lt;|&gt;|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]+|&amp;|&lt;|&gt;|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
  • 40. r´esultat graphique Dans l’´etat, le graphique ne nous apprends rien.... April 23, 2018 40 / 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
  • 42. r´esultat graphique C’est d´ej`a mieux.... April 23, 2018 42 / 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
  • 44. r´esultat graphique C’est encore mieux.... April 23, 2018 44 / 241
  • 45. r´esultat graphique .... mais ce n’est pas parfait: url, nombre, mots li´es `a l’extract... April 23, 2018 45 / 241
  • 46. utiliser des filtres g´en´eraux Ajoutons quelques filtres...) Example tidy_presses_graph<-presse%>% unnest_tokens(word,message)%>% filter(str_detect(word, "[a-z]"))%>% filter(word !="http")%>% 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)%>% dplyr::count(word, sort=TRUE)%>% mutate(word=reorder(word,-n))%>% filter(n>100)%>% 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))+ labs(x = "mots", y = "nombre d’occurence", title = "liste des mots apparaissant plus de 100 fois dans les tokens")April 23, 2018 46 / 241
  • 48. traiter les urls Example tidy_presses_graph<-presse%>% unnest_tokens(word,message)%>% mutate(word = str_replace_all(word,"https://t.co/[A-Za-zd]+ |http://[A-Za-zd]+ |&amp;|&lt;|&gt;|RT|https|[’‘^~’]|[:digit:]|[:punct:]",""))%>% mutate(word = str_replace_all(word, "https|//t|http|&amp;|&lt;|&gt;", ""))%>% 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)%>% dplyr::count(word, sort=TRUE)%>% mutate(word=reorder(word,-n))%>% filter(n>100) April 23, 2018 48 / 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
  • 50. notre proc´edure.... Example tidy_presses_graph<-presse%>% tidytext::unnest_tokens(word,message)%>% dplyr::mutate(word = stringr::str_replace_all(word,"https://t.co/[A-Za-zd]+ http://[A-Za-zd]+|&amp;|&lt;|&gt;|RT|https|[’‘^~’]|[:digit:]|[:punct:]",""))%>% mutate(word = str_replace_all(word, "https|//t|http|&amp;|&lt;|&gt;", ""))%>% filter(str_detect(word, "[a-z]"))%>% filter(word !="http")%>% filter(word !="bitly")%>% filter(nchar(word)>1)%>% anti_join(mystopwords, by = "word")%>% 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)%>% dplyr::count(word, sort=TRUE)%>% mutate(word=reorder(word,-n))%>% filter(n>100)%>% 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)) April 23, 2018 50 / 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]+ |&amp;|&lt;|&gt;|RT|https|[’‘^~’]|[:digit:]|[:punct:]",""))%>% mutate(word = str_replace_all(word, "https|//t|http|&amp;|&lt;|&gt;", ""))%>% 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
  • 59. un graphique illustratif Example origine_words <- page_mots%>% bind_tf_idf(word, from_name, n) origine_words <- origine_words %>% bind_tf_idf(word, from_name, n)%>% arrange(desc(tf_idf)) plot_words<-origine_words%>% arrange(desc(tf_idf))%>% top_n(50) %>% mutate(word = factor(word, levels = rev(unique(word))))%>% ggplot(aes(word, tf_idf, fill = from_name)) +theme_minimal()+ geom_bar(stat = "identity") + labs(x = NULL, y = "tf-idf") + coord_flip() April 23, 2018 59 / 241
  • 60. top 50 par tf-idf April 23, 2018 60 / 241
  • 61. vision par page Example origine_words <- page_mots%>% bind_tf_idf(word, from_name, n) origine_words <- origine_words %>% bind_tf_idf(word, from_name, n)%>% arrange(desc(tf_idf)) plot_plot_words<-origine_words %>% arrange(desc(tf_idf))%>% mutate(word = factor(word, levels = rev(unique(word)))) plot_plot_words_plot<-plot_plot_words %>% group_by(from_name) %>% top_n(15) %>% ungroup %>% ggplot(aes(word, 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 61 / 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
  • 65. une bonne approximation? April 23, 2018 65 / 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
  • 68. la structure du dataframe April 23, 2018 68 / 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]+|&amp;|&lt;|&gt;|RT|https|[’‘^~’] |[:digit:]|[:punct:]","") bigram_filtered$word2<-str_replace_all(bigram_filtered$word2, "https://t.co/[A-Za-zd]+|http://[A-Za-zd]+|&amp;|&lt;|&gt;|RT|https|[’‘^~’] |[:digit:]|[:punct:]","") bigram_filtered$word1<- str_replace_all(bigram_filtered$word1, "https|//t|http|&amp;|&lt;|&gt;", "") bigram_filtered$word2<- str_replace_all(bigram_filtered$word2, "https|//t|http|&amp;|&lt;|&gt;", "") 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
  • 74. la multiplication des r`egles de substitution April 23, 2018 74 / 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
  • 77. la structure d’organisation des donn´ees interm´ediaires April 23, 2018 77 / 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
  • 81. le graphique April 23, 2018 81 / 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
  • 85. le r´esultat de la fonction ggraph April 23, 2018 85 / 241
  • 86. ajoutons une notion d’intensit´e Example #je cree un objet suppl´ementaire avec une fl`eche a <- grid::arrow(type = "closed", length = unit(.10, "inches")) # je cr´ee un graphe avec le code suivant. ggraph(bigram_graph,layout = ’kk’) + geom_edge_link(aes(edge_alpha = n), show.legend = TRUE, arrow = a, end_cap = circle(.05, ’inches’)) + geom_node_point(color = "red", size = 1) + geom_node_text(aes(label = name),color = "blue", size = 3, vjust = 1, hjust = 1) theme_void() April 23, 2018 86 / 241
  • 87. le r´esultat de la fonction ggraph April 23, 2018 87 / 241
  • 88. le trigram pour la route Example #trigrams n=3 presse_trigram<-presse_ngram%>% unnest_tokens(trigram, message, token = "ngrams", n = 3) View(presse_trigram) presse_trigram%>% count(trigram,sort=TRUE) presse_trigram_separated <- presse_trigram%>% separate(trigram, c("word1", "word2", "word3"), sep = " ") April 23, 2018 88 / 241
  • 89. premi`ere phase de nettoyage Example trigram_filtered <- presse_trigram_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)%>% dplyr::filter(!word3 %in% stop_words$word) %>% dplyr::filter(!word3 %in% mystopwords$word) %>% dplyr::filter(!word3 %in% lsa::stopwords_en)%>% dplyr::filter(!word3 %in% lsa::stopwords_fr) April 23, 2018 89 / 241
  • 90. seconde phase de nettoyage: je duplique n fois mes r`egles Example trigram_filtered$word1<-gsub("l^aTMasile"," ",trigram_filtered$word1) trigram_filtered$word2<-gsub("l^aTMasile"," ",trigram_filtered$word2) trigram_filtered$word3<-gsub("l^aTMasile"," ",trigram_filtered$word3) trigram_filtered$word1<-gsub("~A","`a",trigram_filtered$word1) trigram_filtered$word2<-gsub("~A","`a",trigram_filtered$word2) trigram_filtered$word3<-gsub("~A","`a",trigram_filtered$word3) trigram_filtered$word1<-gsub("~A¡","´a",trigram_filtered$word1) trigram_filtered$word2<-gsub("~A¡","´a",trigram_filtered$word2) .................................................................................... trigram_filtered$word1<- str_replace_all(trigram_filtered$word1, "https|//t|http|&amp;|&lt;|&gt;", "") trigram_filtered$word2<- str_replace_all(trigram_filtered$word2, "https|//t|http|&amp;|&lt;|&gt;", "") trigram_filtered$word3<- str_replace_all(trigram_filtered$word3, "https|//t|http|&amp;|&lt;|&gt;", "") April 23, 2018 90 / 241
  • 91. les manipulations ex-post Example presse_trigram_united <- trigram_filtered %>% unite(trigram, word1, word2, word3,sep = " ") trigram_tf_idf <- presse_trigram_united %>% count(from_name,trigram) %>% bind_tf_idf(trigram, from_name, n) %>% arrange(desc(tf_idf)) trigram_tf_idf %>% select(-sum(n))%>% arrange(desc(tf_idf)) plot_trigram<-trigram_tf_idf%>% arrange(desc(tf_idf))%>% mutate(trigram = factor(trigram, levels = rev(unique(trigram)))) ggplot(plot_trigram[1:60,], aes(trigram, tf_idf, fill = from_name)) + geom_bar(stat = "identity") + labs(x = NULL, y = "tf-idf") + coord_flip() April 23, 2018 91 / 241
  • 92. a vos claviers.. April 23, 2018 92 / 241
  • 93. les manipulations ex-post Example plot_trigram<- plot_trigram%>% group_by(from_name) %>% top_n(20) %>% ungroup ggplot(plot_trigram, aes(trigram, 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 93 / 241
  • 94. le top 20 des trigrams par page April 23, 2018 94 / 241
  • 95. la repr´esentation en r´eseau April 23, 2018 95 / 241
  • 96. S´eance 5: l’analyse de sentiment avec r April 23, 2018 96 / 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
  • 107. le r´esultat April 23, 2018 107 / 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
  • 111. code graphique Example base_score_graphique<-extract_r_the_economist%>% tidytext::unnest_tokens(word,message)%>% filter(str_detect(word, "[a-z]"))%>% anti_join(tidytext::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)%>% filter(n>10)%>% ggplot(aes(x= reorder(word,(n)),y=n,fill = score))+ geom_bar(stat="identity")+ scale_fill_continuous(high = "#132B43", low = "#56B1F7")+ 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 = "occurence et score") April 23, 2018 111 / 241
  • 112. le r´esultat April 23, 2018 112 / 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
  • 115. le r´esultat April 23, 2018 115 / 241
  • 116. l’analyse des mots les plus pr´esents en mati`ere de polarit´e Example bing_word_counts_eco <-extract_r_the_economist%>% group_by(type)%>% tidytext::unnest_tokens(word,message)%>% dplyr::inner_join(get_sentiments("bing")) %>% count(word, sentiment, sort = TRUE) %>% dplyr::ungroup() bing_word_counts_eco %>% group_by(sentiment) %>% top_n(40) %>% ungroup() %>% mutate(word = reorder(word, n)) %>% ggplot(aes(word, n, fill = sentiment)) + scale_color_manual(values = economist_sentiment, name = "", breaks = c("negatif"," geom_col(show.legend = FALSE) + facet_grid(sentiment~., scales = "free_y") + theme_minimal()+ labs(y = "Contribution to sentiment", x = NULL) + coord_flip() April 23, 2018 116 / 241
  • 117. le r´esultat April 23, 2018 117 / 241
  • 118. l’analyse des mots les plus pr´esents en mati`ere de polarit´e Example library(wordcloud) library(reshape2) extract_r_the_economist%>% tidytext::unnest_tokens(word,message)%>% inner_join(get_sentiments("bing")) %>% count(word, sentiment, sort = TRUE) %>% reshape2::acast(word ~ sentiment, value.var = "n", fill = 0) %>% comparison.cloud(colors = c("firebrick4", "chartreuse4"), max.words = 100) April 23, 2018 118 / 241
  • 119. le r´esultat April 23, 2018 119 / 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
  • 122. le r´esultat April 23, 2018 122 / 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
  • 124. le r´esultat April 23, 2018 124 / 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
  • 129. le resultat April 23, 2018 129 / 241
  • 130. la fonction analyse sentiment Example sa_eco<-analyzeSentiment(extract_r_the_economist$message, language = "english", aggregate = NULL, removeStopwords = FALSE, stemming = FALSE) sa_extract<-extract_r_the_economist sa_extract<-cbind(sa_extract, sa_eco) #recr´ee ma base sa_extract<-sa_extract%>% filter(annee!= 2012) #pb extract ggplot(sa_extract, aes(time)) + geom_line(aes(y = sa_extract$SentimentGI,colour = "var0"))+ #geom_line(aes(y = sa_extract$SentimentHE,colour = "var1"))+ #geom_line(aes(y = sa_extract$SentimentLM,colour = "var2"))+ #geom_line(aes(y = sa_extract$SentimentQDAP,colour = "var3"))+ theme_minimal()+ labs(x = "date", y = "score", title = "calcul du sentiment total", subtitle = "m´ethode sentiment GI") # a adapter April 23, 2018 130 / 241
  • 131. le dictionnaire GI April 23, 2018 131 / 241
  • 132. le dictionnaire HE April 23, 2018 132 / 241
  • 133. le dictionnaire LM April 23, 2018 133 / 241
  • 134. le dictionnaire QDAP April 23, 2018 134 / 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
  • 136. une comparaison des m´ethodes April 23, 2018 136 / 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
  • 142. la m´ethode afinn April 23, 2018 142 / 241
  • 143. la m´ethode syuzhet April 23, 2018 143 / 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
  • 152. S´eance 6: syntactic parsing April 23, 2018 152 / 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
  • 161. visualiser cette premi`ere op´eration Example View (my texte 1 anno) April 23, 2018 161 / 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
  • 163. afficher cette seconde op´eration Example April 23, 2018 163 / 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
  • 165. afficher cette seconde op´eration April 23, 2018 165 / 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
  • 168. le r´esultat obtenu April 23, 2018 168 / 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
  • 171. mes donn´ees April 23, 2018 171 / 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
  • 173. mes donn´ees April 23, 2018 173 / 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
  • 175. mes donn´ees April 23, 2018 175 / 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
  • 177. mes donn´ees April 23, 2018 177 / 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
  • 179. mon r´esultat April 23, 2018 179 / 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
  • 181. mes donn´ees April 23, 2018 181 / 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
  • 184. mes donn´ees April 23, 2018 184 / 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
  • 186. mes donn´ees April 23, 2018 186 / 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
  • 188. un r´esultat graphique Example library(ggplot2) library(dplyr) co_es%>% 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))+ labs(x = "mots", y = "nombre de cooccurence", title = "coocurrence de terme") April 23, 2018 188 / 241
  • 189. mes donn´ees April 23, 2018 189 / 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
  • 192. r´esultat: 1 dataframe par topic April 23, 2018 192 / 241
  • 193. le topic modeling: afficher l’attribution de chaque document topic Example # j’extrais des donn´ees reli´ees `a mod´elisation terminology_2 <- predict(mymodel, dtm, type = c("topics", "terms"), min_posterior = -1, min_terms = 0) terminology_2 #min_posterior ==>filtre minimum probabilit´e ex-post ==>l’ensemble des termes -1 #min_terms ==>max de termes `a faire appara^ıtre ==>max =0 April 23, 2018 193 / 241
  • 194. mon r´esultat April 23, 2018 194 / 241
  • 195. le topic modeling: la m´ethode ”gibbs” Example # autre m´ethode de calcul sample ’’Gibbs’’ mymodel_bis <- LDA(x = dtm, k = 4, method = "Gibbs") terminology <- predict(mymodel_bis, type = "terms", min_posterior = 0.05, min_terms = 3) scores <- predict(mymodel_bis, type = "topics", newdata = dtm) head(scores) April 23, 2018 195 / 241
  • 196. r´esultat: 1 dataframe par topic April 23, 2018 196 / 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