library(tidyverse)
library(tidytext)
library(janeaustenr)
library(lsa)
library(gutenbergr)
library(scales)
library(textdata)
library(reshape2)
Text Mining in R
Librairies utilisées
Introduction à la manipulation de texte avec tibble et tidyverse
<- c("Because I could not stop for Death -",
text "He kindly stopped for me -",
"The Carriage held but just Ourselves -",
"and Immortality")
<- text |>
text_df as_tibble() |>
mutate(line = 1:4, text = value) |>
select(line, text)
Les lignes utilisées ici sont extraites du poème “Because I could not stop for Death” d’Emily Dickinson.
Tokenisation unnest_tokens()
|> unnest_tokens(word, text) text_df
# A tibble: 20 × 2
line word
<int> <chr>
1 1 because
2 1 i
3 1 could
4 1 not
5 1 stop
6 1 for
7 1 death
8 2 he
9 2 kindly
10 2 stopped
11 2 for
12 2 me
13 3 the
14 3 carriage
15 3 held
16 3 but
17 3 just
18 3 ourselves
19 4 and
20 4 immortality
Mise en forme tidy des romans de Jane Austen
<- austen_books() %>%
original_books group_by(book)%>%
mutate(linenumber = row_number(), chapter = cumsum(str_detect(text, regex("^chapter [\\divxlc]", ignore_case = TRUE)))) %>% ungroup()
original_books
# A tibble: 73,422 × 4
text book linenumber chapter
<chr> <fct> <int> <int>
1 "SENSE AND SENSIBILITY" Sense & Sensibility 1 0
2 "" Sense & Sensibility 2 0
3 "by Jane Austen" Sense & Sensibility 3 0
4 "" Sense & Sensibility 4 0
5 "(1811)" Sense & Sensibility 5 0
6 "" Sense & Sensibility 6 0
7 "" Sense & Sensibility 7 0
8 "" Sense & Sensibility 8 0
9 "" Sense & Sensibility 9 0
10 "CHAPTER 1" Sense & Sensibility 10 1
# ℹ 73,412 more rows
# Exemple simple text
[1] "Because I could not stop for Death -"
[2] "He kindly stopped for me -"
[3] "The Carriage held but just Ourselves -"
[4] "and Immortality"
str_detect(text,regex("Kindly",ignore_case = TRUE))
[1] FALSE TRUE FALSE FALSE
Commentaire du code
- On commence par charger les romans de Jane Austen sous forme de tableau (
tibble
). - Chaque ligne correspond à une ligne de texte dans un roman, avec le nom du livre.
- On groupe par roman pour pouvoir numéroter les lignes dans chaque livre.
- On ajoute une colonne
linenumber
qui donne le numéro de ligne dans le roman. - On crée aussi une colonne
chapter
en détectant les débuts de chapitres (“Chapter I”, “Chapter II”, etc.) à l’aide d’une expression régulière. cumsum()
permet de numéroter les chapitres de manière cumulative.- On enlève ensuite le regroupement pour revenir à une table simple et exploitable.
Exemple de détection d’un mot dans un texte
- On utilise
str_detect()
pour repérer la présence d’un mot précis dans le texte (par exemple “Kindly”). - L’option
ignore_case = TRUE
permet de ne pas tenir compte de la casse (majuscule/minuscule). - Le résultat est un vecteur logique (
TRUE
ouFALSE
) indiquant si le mot est présent dans chaque ligne.
library(tidytext)
<- original_books %>% unnest_tokens(word, text)
tidy_books tidy_books
# A tibble: 725,064 × 4
book linenumber chapter word
<fct> <int> <int> <chr>
1 Sense & Sensibility 1 0 sense
2 Sense & Sensibility 1 0 and
3 Sense & Sensibility 1 0 sensibility
4 Sense & Sensibility 3 0 by
5 Sense & Sensibility 3 0 jane
6 Sense & Sensibility 3 0 austen
7 Sense & Sensibility 5 0 1811
8 Sense & Sensibility 10 1 chapter
9 Sense & Sensibility 10 1 1
10 Sense & Sensibility 13 1 the
# ℹ 725,054 more rows
La fonction unnest_tokens()
du package tidytext sert à transformer une colonne de texte (par exemple une phrase ou un paragraphe) en plusieurs lignes, chacune contenant un token (généralement un mot, mais ça peut aussi être un n-gramme, une phrase, etc.).
Un n-gramme est une séquence de n mots consécutifs dans un texte. Par exemple, si n = 2, on parle de bigrammes (comme “data science”) ; si n = 3, ce sont des trigrammes (comme “I love data”). Les n-grammes permettent d’analyser des expressions fréquentes et de capturer les relations entre mots proches, utiles notamment en traitement automatique du langage ou en analyse textuelle.
Suppression des mots vides (stop words)
data(stop_words) ## J'appelle le df stop_words
## Je visualise le df stop_words
# A tibble: 1,149 × 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
# ℹ 1,139 more rows
<- tidy_books %>%
tidy_books anti_join(stop_words,by="word")
tidy_books
# A tibble: 217,602 × 4
book linenumber chapter word
<fct> <int> <int> <chr>
1 Sense & Sensibility 1 0 sense
2 Sense & Sensibility 1 0 sensibility
3 Sense & Sensibility 3 0 jane
4 Sense & Sensibility 3 0 austen
5 Sense & Sensibility 5 0 1811
6 Sense & Sensibility 10 1 chapter
7 Sense & Sensibility 10 1 1
8 Sense & Sensibility 13 1 family
9 Sense & Sensibility 13 1 dashwood
10 Sense & Sensibility 13 1 settled
# ℹ 217,592 more rows
names(tidy_books)
[1] "book" "linenumber" "chapter" "word"
names(stop_words)
[1] "word" "lexicon"
On utilise le jeu de données stop_words
(fourni par le package tidytext) pour supprimer les mots très fréquents mais peu informatifs (comme “the”, “and”, “of”, etc.).
La fonction anti_join()
permet d’éliminer ces mots de notre corpus tidy, en gardant uniquement les mots porteurs de sens.
Liste des mots vides en français (stopwords_fr)
data(stopwords_fr)
head(stopwords_fr,20)
[1] "$" "£" "a" "a" "à" "â"
[7] "abord" "afin" "ah" "ai" "aie" "aient"
[13] "aies" "ailleurs" "ainsi" "ait" "alentour" "alias"
[19] "allais" "allaient"
Si vous avez un texte en français, vous pouvez utiliser la liste stopwords_fr
fournie par le package lsa pour supprimer les mots vides courants comme “le”, “la”, “et”, etc.
Fréquence des mots dans le corpus
%>%
tidy_books count(word, sort = TRUE)
# A tibble: 13,910 × 2
word n
<chr> <int>
1 miss 1855
2 time 1337
3 fanny 862
4 dear 822
5 lady 817
6 sir 806
7 day 797
8 emma 787
9 sister 727
10 house 699
# ℹ 13,900 more rows
On calcule la fréquence d’apparition de chaque mot dans le corpus. Le résultat est trié par ordre décroissant pour identifier les mots les plus fréquents.
Visualisation des mots les plus fréquents
%>%
tidy_books count(word, sort = TRUE) %>%
filter(n > 600) %>%
mutate(word = reorder(word, n)) %>%
ggplot(aes(word, n)) +
geom_col(fill="red") +
labs(title = "Nombre d’occurrences des mots les plus communs dans les textes de Jane Austen", x = "Mots", y = "“Nombre d’occurrences") +
theme(plot.title = element_text(hjust = 0.5))+ coord_flip()
Ce graphique ggplot présente les mots les plus fréquents (plus de 600 occurrences) dans les textes de Jane Austen.
On utilise count()
pour calculer la fréquence, reorder()
pour trier les mots, et geom_col()
pour représenter les barres.
Les fonctions labs()
et theme()
permettent d’ajouter un titre centré et des étiquettes claires aux axes.
Le graphique est retourné horizontalement avec coord_flip()
pour une meilleure lisibilité.
Téléchargement et traitement des textes de H. G. Wells
Herbert George Wells (1866–1946), plus connu sous le nom de H. G. Wells, est un écrivain britannique célèbre pour ses romans de science-fiction tels que La Guerre des mondes, La Machine à explorer le temps ou L’Homme invisible. Ses œuvres ont souvent été adaptées au cinéma.
Récupération d’un corpus de 4 œuvres
<- "http://mirrors.xmission.com/gutenberg/"
my_mirror <- gutenberg_download(c(35, 36, 5230,159),mirror = my_mirror) hgwells
Warning: ! Could not download a book at
http://mirrors.xmission.com/gutenberg//1/5/159/159.zip.
ℹ The book may have been archived.
ℹ Alternatively, You may need to select a different mirror.
→ See https://www.gutenberg.org/MIRRORS.ALL for options.
<- readLines("https://mirror.csclub.uwaterloo.ca/gutenberg/1/5/159/159-0.txt", encoding = "UTF-8")
war_text
<- tibble(
war_df gutenberg_id = 159,
text = war_text
)<- bind_rows(hgwells, war_df)
hgwells_full
%>% count(gutenberg_id) hgwells_full
# A tibble: 4 × 2
gutenberg_id n
<dbl> <int>
1 35 3174
2 36 6372
3 159 5094
4 5230 5757
Lors de la tentative de téléchargement des œuvres de H. G. Wells à l’aide du package gutenbergr
, une difficulté est survenue : l’une des œuvres — The War of the Worlds (ID 159) — n’était plus disponible sur le miroir utilisé (mirrors.xmission.com
).
Pour compléter le corpus, le texte a été récupéré manuellement à partir d’un autre miroir fonctionnel (csclub.uwaterloo.ca
) à l’aide de readLines()
.
Une fois converti en tibble
, le texte a été intégré au corpus principal avec bind_rows()
.
Ce processus permet d’obtenir un corpus homogène de quatre œuvres, prêt pour l’analyse textuelle.
<- hgwells_full %>% unnest_tokens(word, text) %>%
tidy_hgwells anti_join(stop_words)
Joining with `by = join_by(word)`
head(hgwells,100)
# A tibble: 100 × 2
gutenberg_id text
<int> <chr>
1 35 "The Time Machine"
2 35 ""
3 35 "An Invention"
4 35 ""
5 35 "by H. G. Wells"
6 35 ""
7 35 ""
8 35 "CONTENTS"
9 35 ""
10 35 " I Introduction"
# ℹ 90 more rows
dim(hgwells)
[1] 15303 2
names(hgwells)
[1] "gutenberg_id" "text"
Le corpus complet, stocké dans hgwells_full
, contient les quatre œuvres, y compris celle ajoutée manuellement.
On applique unnest_tokens()
pour transformer chaque ligne de texte en une ligne par mot (format tidy),
puis anti_join(stop_words)
pour supprimer les mots vides.
Ce traitement permet d’obtenir un corpus lexical nettoyé, prêt pour les analyses textuelles.
Fréquence des mots dans le corpus
%>% count(word, sort = TRUE) tidy_hgwells
# A tibble: 12,040 × 2
word n
<chr> <int>
1 time 461
2 people 305
3 door 260
4 heard 249
5 black 232
6 stood 229
7 white 224
8 hand 218
9 kemp 213
10 eyes 210
# ℹ 12,030 more rows
Récupération partielle d’un corpus des sœurs Brontë
<- gutenberg_download(c(1260, 768, 969, 9182, 767),mirror = my_mirror) bronte
Warning: ! Could not download a book at
http://mirrors.xmission.com/gutenberg//1/2/6/1260/1260.zip.
ℹ The book may have been archived.
ℹ Alternatively, You may need to select a different mirror.
→ See https://www.gutenberg.org/MIRRORS.ALL for options.
<- bronte %>% unnest_tokens(word, text) %>%
tidy_bronte anti_join(stop_words)
Joining with `by = join_by(word)`
%>%
tidy_bronte count(word, sort = TRUE)
# A tibble: 20,686 × 2
word n
<chr> <int>
1 time 821
2 don’t 625
3 day 593
4 hand 585
5 miss 544
6 eyes 527
7 till 472
8 heart 469
9 half 449
10 night 430
# ℹ 20,676 more rows
Le corpus rassemble plusieurs œuvres des sœurs Brontë, mais l’œuvre associée à l’identifiant 1260 n’a pas pu être téléchargée depuis le miroir utilisé.
Le reste des textes a été transformé au format tidy, puis nettoyé des mots vides en vue d’une analyse lexicale.
Comparaison des fréquences lexicales entre auteurs
<- bind_rows(mutate(tidy_bronte, author = "Brontë Sisters"), mutate(tidy_hgwells, author = "H.G. Wells"), mutate(tidy_books, author = "Jane Austen")) %>%
frequency mutate(word = str_extract(word, "[a-z']+")) %>% count(author, word) %>% group_by(author) %>% mutate(proportion = n / sum(n))
<-frequency[,-c(3)] %>%
frequencyspread(author, proportion) %>%
gather(author, proportion, `Brontë Sisters`:`H.G. Wells`)
which(frequency$word=="a")
[1] 1 26823
frequency
# A tibble: 53,644 × 4
word `Jane Austen` author proportion
<chr> <dbl> <chr> <dbl>
1 a 0.00000919 Brontë Sisters 0.0000262
2 a'n't 0.00000460 Brontë Sisters NA
3 aback NA Brontë Sisters 0.00000524
4 abaht NA Brontë Sisters 0.00000524
5 abandon NA Brontë Sisters 0.0000262
6 abandoned 0.00000460 Brontë Sisters 0.0000785
7 abandoning NA Brontë Sisters 0.00000524
8 abandonment NA Brontë Sisters 0.0000157
9 abart NA Brontë Sisters NA
10 abase NA Brontë Sisters 0.00000524
# ℹ 53,634 more rows
On fusionne ici les trois corpus (Brontë Sisters
, H.G. Wells
, Jane Austen
) pour calculer la proportion d’apparition de chaque mot dans le vocabulaire de chaque auteur.
Après avoir extrait les mots valides et supprimé les doublons, on restructure les données pour pouvoir comparer les fréquences entre auteurs.
La fonction gather()
permet de retrouver un format long (mot, auteur, proportion) utile pour les visualisations ou comparaisons croisées.
Comparaison lexicale entre Jane Austen et les autres auteurs
%>% ggplot(aes(x = proportion, y = `Jane Austen`, color = abs(`Jane Austen` - proportion))) +
frequencygeom_abline(color = "gray40", lty = 2) + geom_jitter(alpha = 0.1, size = 2.5, width = 0.3, height = 0.3) +
geom_text(aes(label = word), check_overlap = TRUE, vjust = 1.5) +
scale_x_log10(labels = percent_format()) + scale_y_log10(labels = percent_format()) + scale_color_gradient(limits = c(0, 0.001), low = "darkslategray4", high = "gray75") +
facet_wrap(~author, ncol = 2) + theme(legend.position="none") + labs(y = "Jane Austen", x = NULL)
Warning: Removed 37770 rows containing missing values or values outside the scale range
(`geom_point()`).
Warning: Removed 37772 rows containing missing values or values outside the scale range
(`geom_text()`).
Ce graphique compare, pour chaque mot, la fréquence relative d’utilisation entre Jane Austen (axe vertical) et deux autres auteurs (axe horizontal), dans deux panneaux séparés.
Les mots situés près de la diagonale sont utilisés de manière similaire par les deux auteurs, tandis que ceux éloignés signalent une préférence lexicale marquée.
La couleur reflète l’écart absolu entre les fréquences. Les échelles logarithmiques sont utilisées pour mieux visualiser les différences, y compris pour les mots rares.
Les axes sont exprimés en pourcentage grâce à la fonction percent_format()
de la librairie scales
, ce qui rend la lecture des proportions plus intuitive.
Remarque : les proportions affichées ne tiennent compte que des mots communs aux deux auteurs comparés, sans correction explicite des valeurs manquantes (NA
).
Cela peut biaiser la visualisation, car les mots spécifiques à un seul auteur sont ignorés, et les proportions ne sont pas recalculées en conséquence.
Corrélation entre les fréquences lexicales
cor.test(data = frequency[frequency$author == "Brontë Sisters",], ~ proportion + `Jane Austen`)
Pearson's product-moment correlation
data: proportion and Jane Austen
t = 102.06, df = 9786, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.7083097 0.7275071
sample estimates:
cor
0.7180449
cor.test(data = frequency[frequency$author == "H.G. Wells",], ~ proportion + `Jane Austen`)
Pearson's product-moment correlation
data: proportion and Jane Austen
t = 35.703, df = 6084, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
0.3952067 0.4367561
sample estimates:
cor
0.4161986
Corrélation entre les fréquences lexicales
Ce code évalue la corrélation entre les proportions d’utilisation des mots chez Jane Austen et celles des sœurs Brontë d’une part, et de H.G. Wells d’autre part.
L’objectif est de déterminer dans quelle mesure la fréquence des mots employés par Jane Austen est associée à celle de ces autres auteurs.
- Première commande : teste la corrélation entre Jane Austen et les sœurs Brontë.
- Deuxième commande : teste la corrélation entre Jane Austen et H.G. Wells.
Chaque test produit un coefficient de corrélation accompagné d’une valeur p, indiquant si l’association observée est statistiquement significative.
Les résultats montrent :
- Une forte corrélation positive entre Jane Austen et les sœurs Brontë, suggérant une proximité lexicale ou stylistique dans les mots les plus fréquents.
- Une corrélation plus faible entre Jane Austen et H.G. Wells, ce qui est cohérent avec des différences de genre et de style littéraire (romans sentimentaux vs science-fiction).
La p-value associée à chaque test est très faible (souvent < 0.001), ce qui signifie que la corrélation observée est hautement significative statistiquement, et qu’elle n’est pas due au hasard.
Remarque : Les valeurs manquantes (NA
) dans les données peuvent affecter les résultats.
Il est donc recommandé de les gérer (par exemple, en les supprimant ou en les imputant) avant d’effectuer ces tests pour garantir des résultats fiables.
Sentiment Analysis
get_sentiments("afinn")
# A tibble: 2,477 × 2
word value
<chr> <dbl>
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
# ℹ 2,467 more rows
get_sentiments("bing")
# A tibble: 6,786 × 2
word sentiment
<chr> <chr>
1 2-faces negative
2 abnormal negative
3 abolish negative
4 abominable negative
5 abominably negative
6 abominate negative
7 abomination negative
8 abort negative
9 aborted negative
10 aborts negative
# ℹ 6,776 more rows
get_sentiments("nrc")
# A tibble: 13,872 × 2
word sentiment
<chr> <chr>
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
# ℹ 13,862 more rows
Analyse des sentiments
On charge ici trois lexiques de sentiments différents disponibles dans le package tidytext
:
afinn
: attribue à chaque mot un score numérique de sentiment allant de -5 (très négatif) à +5 (très positif).bing
: classe les mots en deux catégories : positif ou négatif.nrc
: associe les mots à plusieurs émotions (joie, colère, peur, tristesse, etc.) ainsi qu’à une polarité (positif ou négatif).
Ces lexiques permettent d’associer une valence émotionnelle aux mots d’un texte, et ainsi de réaliser des analyses de sentiment sur les corpus.
Préparation du corpus de Jane Austen
<- austen_books() %>% group_by(book) %>% mutate(linenumber = row_number(), chapter = cumsum(str_detect(text, regex("^chapter [\\divxlc]", ignore_case = TRUE)))) %>%
tidy_books ungroup() %>% unnest_tokens(word, text)
On extrait les textes avec austen_books()
puis on : - numérote les lignes dans chaque livre (linenumber
), - identifie les débuts de chapitres (chapter
) à l’aide de str_detect()
et cumsum()
, - convertit enfin le texte au format tidy avec unnest_tokens()
(une ligne par mot).
Analyse des mots associés à la joie dans Emma
<- get_sentiments("nrc") %>% filter(sentiment == "joy")
nrcjoy %>% filter(book == "Emma") %>% inner_join(nrcjoy) %>% count(word, sort = TRUE) tidy_books
Joining with `by = join_by(word)`
# A tibble: 301 × 2
word n
<chr> <int>
1 good 359
2 friend 166
3 hope 143
4 happy 125
5 love 117
6 deal 92
7 found 92
8 present 89
9 kind 82
10 happiness 76
# ℹ 291 more rows
On extrait ici les mots associés au sentiment joy dans le lexique nrc
, puis on filtre le corpus pour ne conserver que le livre Emma.
Grâce à inner_join()
, on identifie les mots du texte qui sont présents dans la liste des mots associés à la joie.
Enfin, count()
permet de classer ces mots joyeux selon leur fréquence d’apparition dans le roman.
Évolution du sentiment dans les romans de Jane Austen
<- tidy_books %>% inner_join(get_sentiments("bing")) %>%
janeaustensentiment count(book, index = linenumber %/% 80, sentiment) %>% spread(sentiment, n, fill = 0) %>%
mutate(sentiment = positive - negative)
Joining with `by = join_by(word)`
Warning in inner_join(., get_sentiments("bing")): Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 435443 of `x` matches multiple rows in `y`.
ℹ Row 5051 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship =
"many-to-many"` to silence this warning.
On associe ici chaque mot du corpus à une polarité (positive ou négative) à l’aide du lexique bing
.
Les mots sont regroupés par tranches de 80 lignes (linenumber %/% 80
) afin de visualiser l’évolution du sentiment au fil du texte.
On utilise spread()
pour séparer les sentiments, puis on calcule un score global (positive - negative
) indiquant la valence émotionnelle nette dans chaque segment du texte.
Visualisation de l’évolution des sentiments dans les romans de Jane Austen
%>%ggplot(aes(index, sentiment, fill = book)) +
janeaustensentimentgeom_col(show.legend = FALSE) +
facet_wrap(~book, ncol = 2, scales = "free_x")
Ce graphique représente la variation du score de sentiment au fil du texte pour chaque roman.
Chaque barre correspond à une tranche de 80 lignes, et sa hauteur reflète la valence émotionnelle nette (positif – négatif) calculée précédemment.
Le facettage par livre (facet_wrap
) permet de comparer l’évolution émotionnelle à l’intérieur de chaque œuvre, indépendamment des autres.
Comparaison des méthodes d’analyse des sentiments dans Pride & Prejudice
<- tidy_books %>% filter(book == "Pride & Prejudice")
pride_prejudice pride_prejudice
# A tibble: 122,204 × 4
book linenumber chapter word
<fct> <int> <int> <chr>
1 Pride & Prejudice 1 0 pride
2 Pride & Prejudice 1 0 and
3 Pride & Prejudice 1 0 prejudice
4 Pride & Prejudice 3 0 by
5 Pride & Prejudice 3 0 jane
6 Pride & Prejudice 3 0 austen
7 Pride & Prejudice 7 1 chapter
8 Pride & Prejudice 7 1 1
9 Pride & Prejudice 10 1 it
10 Pride & Prejudice 10 1 is
# ℹ 122,194 more rows
<- pride_prejudice %>% inner_join(get_sentiments("afinn")) %>%
afinn group_by(index = linenumber %/% 80) %>%
summarise(sentiment = sum(value)) %>% mutate(method = "AFINN")
Joining with `by = join_by(word)`
<- bind_rows( pride_prejudice %>% inner_join(get_sentiments("bing")) %>%
bing_and_nrc mutate(method = "Bing et al."), pride_prejudice %>% inner_join(get_sentiments("nrc") %>% filter(sentiment %in% c("positive", "negative"))) %>%
mutate(method = "NRC")) %>%
count(method, index = linenumber %/% 80, sentiment) %>%
spread(sentiment, n, fill = 0) %>% mutate(sentiment = positive - negative)
Joining with `by = join_by(word)`
Joining with `by = join_by(word)`
Warning in inner_join(., get_sentiments("nrc") %>% filter(sentiment %in% : Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 215 of `x` matches multiple rows in `y`.
ℹ Row 5178 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship =
"many-to-many"` to silence this warning.
bind_rows(afinn, bing_and_nrc) %>%
ggplot(aes(index, sentiment, fill = method)) + geom_col(show.legend = FALSE) +
facet_wrap(~method, ncol = 1, scales = "free_y")
Ce graphique compare trois méthodes de calcul de sentiment appliquées au roman Pride & Prejudice :
- AFINN : attribue des scores numériques aux mots (de -5 à +5) et calcule une somme par tranche de 80 lignes.
- Bing et NRC : classent les mots comme positifs ou négatifs, et calculent un score net (positifs – négatifs) pour chaque segment.
Les résultats sont visualisés avec geom_col()
et séparés par méthode (facet_wrap
). Cela permet d’observer les différences d’interprétation émotionnelle selon le lexique utilisé.
Mots les plus contributifs aux sentiments positifs et négatifs
get_sentiments("nrc") %>%
filter(sentiment %in% c("positive", "negative")) %>%
count(sentiment)
# A tibble: 2 × 2
sentiment n
<chr> <int>
1 negative 3316
2 positive 2308
get_sentiments("bing") %>%
count(sentiment)
# A tibble: 2 × 2
sentiment n
<chr> <int>
1 negative 4781
2 positive 2005
<- tidy_books %>%
bing_word_counts inner_join(get_sentiments("bing")) %>%
count(word, sentiment, sort = TRUE) %>% ungroup()
Joining with `by = join_by(word)`
Warning in inner_join(., get_sentiments("bing")): Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 435443 of `x` matches multiple rows in `y`.
ℹ Row 5051 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship =
"many-to-many"` to silence this warning.
%>% group_by(sentiment) %>%
bing_word_counts top_n(10) %>% ungroup() %>% mutate(word = reorder(word, n)) %>%
ggplot(aes(word, n, fill = sentiment)) + geom_col(show.legend = FALSE) + facet_wrap(~sentiment, scales = "free_y") + labs(y = "Contribution to sentiment", x = NULL) +
coord_flip()
Selecting by n
On commence par comparer le nombre total de mots associés à une polarité (positive ou négative) dans les lexiques nrc
et bing
.
Ensuite, on extrait les mots du corpus de Jane Austen présents dans le lexique bing
, et on calcule leur fréquence en fonction du sentiment associé.
Le graphique présente les 10 mots les plus fréquents pour chaque polarité.
On observe ainsi les mots qui contribuent le plus au sentiment global des textes, en les classant par fréquence décroissante et en les visualisant avec un graphique à barres horizontal.
Extension personnalisée des mots vides
<- bind_rows(data_frame(word = c("miss"), lexicon = c("custom")),stop_words) custom_stop_words
Warning: `data_frame()` was deprecated in tibble 1.1.0.
ℹ Please use `tibble()` instead.
custom_stop_words
# A tibble: 1,150 × 2
word lexicon
<chr> <chr>
1 miss custom
2 a SMART
3 a's SMART
4 able SMART
5 about SMART
6 above SMART
7 according SMART
8 accordingly SMART
9 across SMART
10 actually SMART
# ℹ 1,140 more rows
On crée ici une liste personnalisée de mots à exclure en ajoutant manuellement le mot "miss"
(fréquent mais peu informatif dans le corpus de Jane Austen).
Ce mot est ajouté sous un lexique nommé "custom"
, puis fusionné (bind_rows
) avec la liste standard stop_words
.
Le nouvel objet custom_stop_words
contient donc les mots vides classiques et les ajouts spécifiques à ce corpus.
Nuages de mots (Wordcloud)
Les nuages de mots permettent de visualiser les mots les plus fréquents d’un corpus de manière intuitive.
La taille des mots dans le nuage reflète leur fréquence dans le texte.
Nuage de mots global (sans mots vides)
library(wordcloud)
Loading required package: RColorBrewer
%>% anti_join(stop_words) %>% count(word) %>%
tidy_books with(wordcloud(word, n, max.words = 100))
Joining with `by = join_by(word)`
Le premier graphique affiche les 100 mots les plus fréquents dans le corpus de Jane Austen, après suppression des mots vides (stop_words
).
On utilise la fonction wordcloud()
pour générer ce nuage.
Nuage de mots comparatif selon le sentiment
Le second graphique distingue les mots associés à un sentiment positif ou négatif selon le lexique bing
.
On transforme la table avec acast()
(grâce au package reshape2
), puis on utilise comparison.cloud()
pour afficher les deux catégories dans un nuage de mots contrasté en deux couleurs.
library(reshape2)
%>% inner_join(get_sentiments("bing")) %>% count(word, sentiment, sort = TRUE) %>%
tidy_books acast(word ~ sentiment, value.var = "n", fill = 0) %>% comparison.cloud(colors = c("gray20", "gray80"), max.words = 100)
Joining with `by = join_by(word)`
Warning in inner_join(., get_sentiments("bing")): Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 435443 of `x` matches multiple rows in `y`.
ℹ Row 5051 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship =
"many-to-many"` to silence this warning.