Travailler avec des textes:

Partie 3: Traitement du langage naturel


L. Vaudor, ISIG, UMR 5600-EVS

Rencontres R 2018

Langage naturel

tibtot_commentaires <- read_csv("data/tibtot_commentaires.csv")
tibtot_commentaires
## # A tibble: 12 x 3
##    doc                        texte                             auteur    
##    <chr>                      <chr>                             <chr>     
##  1 data/blog_de_ginette.htm   Et pour une poule sur un mur qui~ Emma, 22 ~
##  2 data/blog_de_ginette.htm   Je vois que vous êtes, telle la ~ Michel, 5~
##  3 data/blog_de_jean-marc.htm Les thons, avec un t comme croco~ Eddie, 76~
##  4 data/blog_de_jean-marc.htm Pourquoi ces thons ne préféraien~ Yves, 40 ~
##  5 data/blog_de_jean-marc.htm Tout ça me fait penser au blog d~ Roberta, ~
##  6 data/blog_de_jean-marc.htm Je préfère la chanson qui parle ~ Eduardo, ~
##  7 data/blog_de_jean-marc.htm On ne comprend pas trop cette pa~ Lise, 35 ~
##  8 data/blog_de_jean-marc.htm Et pendant ce temps-là, le roi d~ Nadia, 43~
##  9 data/blog_de_norbert.htm   "A quel moment faut-il claquer d~ Jonas, 37~
## 10 data/blog_de_norbert.htm   Norbert, mon petit chat, ça fait~ Julie, 34~
## 11 data/blog_de_norbert.htm   L'ambiance doit être sympa quand~ Mickaël, ~
## 12 data/blog_de_norbert.htm   Vous devez avoir un grain pour é~ Viviane, ~

Tokenization

On va maintenant passer à l’étape de tokenisation de nos textes.

Tokeniser, ça revient à définir de quelle manière on découpe nos textes pour les analyses ultérieures.

Par exemple, on peut décider que l’unité d’analyse (l’individu) pour nos analyses textuelles seront un des éléments suivants:

Pour réaliser cette tokenisation nous allons utiliser le package tidytext et notamment sa fonction unnest_tokens().

Tokenization

tibtot_commentaires %>% 
  unnest_tokens(output="bigramme",input=texte,token="ngrams",n=2)
## # A tibble: 206 x 3
##    doc                      auteur                bigramme      
##    <chr>                    <chr>                 <chr>         
##  1 data/blog_de_ginette.htm Emma, 22 ans, Limoges et pour       
##  2 data/blog_de_ginette.htm Emma, 22 ans, Limoges pour une      
##  3 data/blog_de_ginette.htm Emma, 22 ans, Limoges une poule     
##  4 data/blog_de_ginette.htm Emma, 22 ans, Limoges poule sur     
##  5 data/blog_de_ginette.htm Emma, 22 ans, Limoges sur un        
##  6 data/blog_de_ginette.htm Emma, 22 ans, Limoges un mur        
##  7 data/blog_de_ginette.htm Emma, 22 ans, Limoges mur qui       
##  8 data/blog_de_ginette.htm Emma, 22 ans, Limoges qui picoterait
##  9 data/blog_de_ginette.htm Emma, 22 ans, Limoges picoterait du 
## 10 data/blog_de_ginette.htm Emma, 22 ans, Limoges du pain       
## # ... with 196 more rows
tib_mots=tibtot_commentaires %>% 
  unnest_tokens(output="mot",
                input=texte,
                token="words")
tib_mots
## # A tibble: 218 x 3
##    doc                      auteur                mot       
##    <chr>                    <chr>                 <chr>     
##  1 data/blog_de_ginette.htm Emma, 22 ans, Limoges et        
##  2 data/blog_de_ginette.htm Emma, 22 ans, Limoges pour      
##  3 data/blog_de_ginette.htm Emma, 22 ans, Limoges une       
##  4 data/blog_de_ginette.htm Emma, 22 ans, Limoges poule     
##  5 data/blog_de_ginette.htm Emma, 22 ans, Limoges sur       
##  6 data/blog_de_ginette.htm Emma, 22 ans, Limoges un        
##  7 data/blog_de_ginette.htm Emma, 22 ans, Limoges mur       
##  8 data/blog_de_ginette.htm Emma, 22 ans, Limoges qui       
##  9 data/blog_de_ginette.htm Emma, 22 ans, Limoges picoterait
## 10 data/blog_de_ginette.htm Emma, 22 ans, Limoges du        
## # ... with 208 more rows

Nettoyage de la table

Mots vides

Pour des textes en anglais, tidytext comprend une liste de mots vides (“stopwords”)

data(stop_words)
stop_words
## # A tibble: 1,149 x 2
##    word        lexicon
##    <chr>       <chr>  
##  1 a           SMART  
##  2 a's         SMART  
##  3 able        SMART  
##  4 about       SMART  
##  5 above       SMART  
##  6 according   SMART  
##  7 accordingly SMART  
##  8 across      SMART  
##  9 actually    SMART  
## 10 after       SMART  
## # ... with 1,139 more rows

Pour un texte en français, on peut avoir recours au package proustr lien ici

proust_stopwords()
## # A tibble: 783 x 1
##    word      
##  * <fct>     
##  1 a         
##  2 abord     
##  3 absolument
##  4 afin      
##  5 ah        
##  6 ai        
##  7 aie       
##  8 aient     
##  9 aies      
## 10 ailleurs  
## # ... with 773 more rows

Mots signifiants

Pour ne garder que les mots signifiants, on peut ainsi faire une anti-jointure entre notre table et la table renvoyée par proust_stopwords():

tib_mots_nonvides=tib_mots %>%
  anti_join(proust_stopwords(),by=c("mot"="word"))
tib_mots
## # A tibble: 218 x 3
##    doc                      auteur                mot       
##    <chr>                    <chr>                 <chr>     
##  1 data/blog_de_ginette.htm Emma, 22 ans, Limoges et        
##  2 data/blog_de_ginette.htm Emma, 22 ans, Limoges pour      
##  3 data/blog_de_ginette.htm Emma, 22 ans, Limoges une       
##  4 data/blog_de_ginette.htm Emma, 22 ans, Limoges poule     
##  5 data/blog_de_ginette.htm Emma, 22 ans, Limoges sur       
##  6 data/blog_de_ginette.htm Emma, 22 ans, Limoges un        
##  7 data/blog_de_ginette.htm Emma, 22 ans, Limoges mur       
##  8 data/blog_de_ginette.htm Emma, 22 ans, Limoges qui       
##  9 data/blog_de_ginette.htm Emma, 22 ans, Limoges picoterait
## 10 data/blog_de_ginette.htm Emma, 22 ans, Limoges du        
## # ... with 208 more rows

Racinisation (stemming)

La racinisation (ou désuffixation, ou stemming en anglais) consiste (comme son nom l’indique) à extraire la racine d’un mot. Souvent, cette racine ne correspond pas à un “vrai mot”…

pr_stem_words(tib_mots_nonvides,mot)
## # A tibble: 88 x 3
##    doc                      auteur                mot   
##  * <chr>                    <chr>                 <chr> 
##  1 data/blog_de_ginette.htm Emma, 22 ans, Limoges poul  
##  2 data/blog_de_ginette.htm Emma, 22 ans, Limoges mur   
##  3 data/blog_de_ginette.htm Emma, 22 ans, Limoges picot 
##  4 data/blog_de_ginette.htm Emma, 22 ans, Limoges pain  
##  5 data/blog_de_ginette.htm Emma, 22 ans, Limoges dur   
##  6 data/blog_de_ginette.htm Emma, 22 ans, Limoges c'est 
##  7 data/blog_de_ginette.htm Emma, 22 ans, Limoges nourr 
##  8 data/blog_de_ginette.htm Emma, 22 ans, Limoges petit 
##  9 data/blog_de_ginette.htm Emma, 22 ans, Limoges cochon
## 10 data/blog_de_ginette.htm Emma, 22 ans, Limoges qu'en 
## # ... with 78 more rows

Lemmatisation

La lemmatisation consiste faire correspondre à un mot (ou forme) la forme neutre (ou lemme) que ce mot aurait par exemple par défaut dans un dictionnaire.

Pour ce tuto je me suis contentée de lemmatiser en me basant sur une base de données lexicales libre, Lexique qui fait correspondre formes et lemmes de très nombreux mots en français. J’ai réalisé une simple jointure, sans considération syntaxique.

Il est également possible de lemmatiser en utilisant l’outil TreeTagger (gratuit, mais propriétaire).

Cet outil est utilisable dans R via le package koRpus vignette ici

Lemmatisation avec les données Lexique

Voilà concrètement comment j’ai lemmatisé mes mots en utilisant la base de données Lexique:

lexique382=read.delim("https://rawgit.com/lvaudor/Tuto_texte_Marmiton/master/Lexique382/Lexique382.txt",
                      encoding="UTF-8")
lexique382=select(lexique382,
                  mot= X1_ortho,
                  lemme= X3_lemme) %>%
  distinct()
sample_n(lexique382,10)
##                 mot        lemme
## 119896     sûrement     sûrement
## 76741        matant        mater
## 123951 transportait  transporter
## 17044        bronze      bronzer
## 73449          liée         lier
## 103841   rencardées    rencarder
## 63652     humectage    humectage
## 29414     convulsés     convulsé
## 127612       vendis       vendre
## 118353 supranaturel supranaturel

Dans ce cas on réalise une jointure pour récupérer le lemme de chaque mot dans notre table:

tib_mots_nonvides=left_join(tib_mots_nonvides,
                   lexique382,
                   by="mot")
tib_mots_nonvides %>% select(mot,lemme)
## # A tibble: 93 x 2
##    mot        lemme  
##    <chr>      <fct>  
##  1 poule      poule  
##  2 mur        mur    
##  3 picoterait <NA>   
##  4 pain       pain   
##  5 dur        dur    
##  6 c'est      <NA>   
##  7 nourrir    nourrir
##  8 petits     petit  
##  9 cochons    cochon 
## 10 qu'en      <NA>   
## # ... with 83 more rows

Sentiments

proust_sentiments() %>% 
  head(n=10)
## # A tibble: 10 x 2
##    word            polarity
##    <chr>           <chr>   
##  1 à ce endroit là positive
##  2 à le hâte       negative
##  3 à part          negative
##  4 à pic           negative
##  5 à rallonge      negative
##  6 abasourdir      negative
##  7 ablation        negative
##  8 abominable      negative
##  9 abrupt          negative
## 10 absent          negative
proust_sentiments(type="score") %>% 
  head(n=10)
## # A tibble: 10 x 2
##    word        sentiment
##    <chr>       <chr>    
##  1 abaissement sadness  
##  2 abaisser    sadness  
##  3 abandon     fear     
##  4 abandon     sadness  
##  5 abandon     anger    
##  6 abandon     surprise 
##  7 abandonner  fear     
##  8 abandonner  sadness  
##  9 abandonner  anger    
## 10 abandonner  disgust
tib_mots_polarite <- tib_mots_nonvides %>%
    left_join(proust_sentiments(), by=c("lemme"="word")) 

tib_mots_polarite  %>%
  group_by(lemme,polarity) %>% 
  summarise(n=n()) %>% 
  arrange(desc(n)) %>% 
  head(n=15)
## # A tibble: 15 x 3
## # Groups:   lemme [15]
##    lemme    polarity     n
##    <chr>    <chr>    <int>
##  1 <NA>     <NA>        15
##  2 canard   positive     5
##  3 thon     negative     5
##  4 cochon   negative     4
##  5 danser   positive     4
##  6 petit    negative     4
##  7 chat     positive     3
##  8 poule    positive     3
##  9 chose    negative     2
## 10 choses   <NA>         2
## 11 écrire   positive     2
## 12 gaiement <NA>         2
## 13 grain    positive     2
## 14 préférer positive     2
## 15 aimable  positive     1