607 Week 10 A

Author

Enrique Delamonica

Introduction

This exercise consist of three parts. First, the results in Chapter 2 of Text Mining with R by J. Silge and D. Robinson (https://www.tidytextmining.com/) are reproduced.Then there are two extensions, one with a different set of books and another one with a different sentiment lexicon applied to Jane Austen’s novels.

These are some of the libraries and packages that may be needed to reproduce the results in Chapter 2.

library(dplyr)

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
library(tidyr)
library(tidytext)
library(stringr)
install.packages("textdata")
Error in `contrib.url()`:
! trying to use CRAN without setting a mirror
library(ggplot2)
library(wordcloud)
Loading required package: RColorBrewer
library(reshape2)

Attaching package: 'reshape2'
The following object is masked from 'package:tidyr':

    smiths
library(janeaustenr)
library(gutenbergr)

These are the sentiment lexicons that will be used.

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

Reproducing Chapter 2 results

First basic steps

Following the steps in the book, first the books are retrieved and converted to a tidy format.

tidy_books <- austen_books() |>
  group_by(book) |>
  mutate(
    linenumber = row_number(),
    chapter = cumsum(str_detect(text, 
                                regex("^chapter [\\divxlc]", 
                                      ignore_case = TRUE)))) |>
  ungroup() |>
  unnest_tokens(word, text)

I check what is in the data frame.

glimpse(tidy_books)
Rows: 725,055
Columns: 4
$ book       <fct> Sense & Sensibility, Sense & Sensibility, Sense & Sensibili…
$ linenumber <int> 1, 1, 1, 3, 3, 3, 5, 10, 10, 13, 13, 13, 13, 13, 13, 13, 13…
$ chapter    <int> 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ word       <chr> "sense", "and", "sensibility", "by", "jane", "austen", "181…

Then, for the book “Emma”, the lexicon nrc is used to look for words related to “joy”.

nrc_joy <- get_sentiments("nrc") |> 
  filter(sentiment == "joy")

tidy_books |>
  filter(book == "Emma") |>
  inner_join(nrc_joy) |>
  count(word, sort = TRUE)
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

It seems to work, However, “young” was not picked up here (it is in the textbook example). All the other ones match, both in terms of rank and the word count. The only exception is “happiness” that is not shown in the book. It seems to have moved up the list as “young” has not appeared here.

Something similar is done across all six novels. However, in these graphs, the prevalence of positive or negative sentiments is plotted along the narrative of each novel. This is done by estimating the prevalence of these sentiments in sections of 80 lines.

jane_austen_sentiment <- tidy_books |>
  inner_join(get_sentiments("bing")) |>
  count(book, index = linenumber %/% 80, sentiment) |>
  pivot_wider(names_from = sentiment, values_from = n, values_fill = 0) |> 
  mutate(sentiment = positive - negative)
Joining with `by = join_by(word)`
Warning in inner_join(tidy_books, get_sentiments("bing")): Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 435434 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.

There is an error message. However, it does not seem to affect the construction of the following graphs.

ggplot(jane_austen_sentiment, aes(index, sentiment, fill = book)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~book, ncol = 2, scales = "free_x")

The graphs seem to correspond to the ones in the textbook. However they do not show up in the Plots tab in the R pane.

Small detour to explore the lexicons

In the textbook, the book Pride and Prejudice is selected to explore the three sentiment lexicons. Thus, first, Pride and prejudice is set up as a tidy data frame.

pride_prejudice <- tidy_books %>% 
  filter(book == "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

In the next step, what was done above for all six novels using the Bing et al sentiment lexicon is done with the other two lexicons only for Pride and Prejudice. Then, all three abalyses are shown together.

afinn <- pride_prejudice |> 
  inner_join(get_sentiments("afinn")) |> 
  group_by(index = linenumber %/% 80) |> 
  summarise(sentiment = sum(value)) |> 
  mutate(method = "AFINN")
Joining with `by = join_by(word)`
bing_and_nrc <- bind_rows(
  pride_prejudice |> 
    inner_join(get_sentiments("bing")) |>
    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) |>
  pivot_wider(names_from = sentiment,
              values_from = n,
              values_fill = 0) |> 
  mutate(sentiment = positive - negative)
Joining with `by = join_by(word)`
Joining with `by = join_by(word)`
Warning in inner_join(pride_prejudice, filter(get_sentiments("nrc"), 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.

Same error message as above. However, the graphs do work out below.

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")

Clearly, each sentiment lexicon provides different results. Part of the reason is due to different counts of positive and negative words in each lexicon, These can be counted and compared (in a bar chart, below).

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

The results are slightly different from the ones in the text book (3324 neg and 2312 pos)

get_sentiments("bing") |> 
  count(sentiment)
# A tibble: 2 × 2
  sentiment     n
  <chr>     <int>
1 negative   4781
2 positive   2005

These numbers do match the ones in the textbook.

bing_word_counts <- tidy_books |>
  inner_join(get_sentiments("bing")) |>
  count(word, sentiment, sort = TRUE) |>
  ungroup()
Joining with `by = join_by(word)`
Warning in inner_join(tidy_books, get_sentiments("bing")): Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 435434 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.

Similar error message as above

bing_word_counts
# A tibble: 2,585 × 3
   word     sentiment     n
   <chr>    <chr>     <int>
 1 miss     negative   1855
 2 well     positive   1523
 3 good     positive   1380
 4 great    positive    981
 5 like     positive    725
 6 better   positive    639
 7 enough   positive    613
 8 happy    positive    534
 9 love     positive    495
10 pleasure positive    462
# ℹ 2,575 more rows

Same results as in the text book

bing_word_counts |>
  group_by(sentiment) |>
  slice_max(n, n = 10) |> 
  ungroup() |>
  mutate(word = reorder(word, n)) |>
  ggplot(aes(n, word, fill = sentiment)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~sentiment, scales = "free_y") +
  labs(x = "Contribution to sentiment",
       y = NULL)

In the textbook, it is mentioned that the word “miss” is counted as a negative word but, in these books, “miss” is an unmarried woman. It is also mentioned that the word “miss” can be added to the list of “stop words” (which in chapter 1 of the textbook are described as: “words that are not useful for an analysis, typically extremely common words such as “the”, “of”, “to”, and so forth in English”).

custom_stop_words <- bind_rows(tibble(word = c("miss"),  
                                      lexicon = c("custom")), 
                               stop_words)

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

Continuing the analysis of Austen’s novels

A wordcloud can be constructed. This is done for all six novels.

tidy_books |>
  anti_join(stop_words) |>
  count(word) |>
  with(wordcloud(word, n, max.words = 100))
Joining with `by = join_by(word)`

In a wordcloud, it is also possible to separate positive and negative words.

tidy_books |>
  inner_join(get_sentiments("bing")) |>
  count(word, sentiment, sort = TRUE) |>
  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(tidy_books, get_sentiments("bing")): Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 435434 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.

Interpreting this wordcloud is a bit complicated as the size of the words show their relative importance within each group (i.e. among the positive and the negative sentiments). Thus, as it says in the textbook: “the sizes of the words are not comparable across sentiments”

Also, the words in this graph are different from the ones in the textbook. And the wordcloud does not appear in the Plots tab in the R panel.

Another type of analysis involves exploring sentences instead of individual words.

p_and_p_sentences <- tibble(text = prideprejudice)|>
   unnest_tokens(sentence, text, token = "sentences")

The second sentence in the book Pride and Prejudice is:

p_and_p_sentences$sentence[2]
[1] "by jane austen"

It obviously comes after the title, which is the first sentence:

p_and_p_sentences$sentence[1]
[1] "pride and prejudice"

The final type of analysis in the textbook involves an analysis by chapter.

austen_chapters <- austen_books() |>
  group_by(book) |>
  unnest_tokens(chapter, text, token = "regex", 
                pattern = "Chapter|CHAPTER [\\dIVXLC]") |>
  ungroup()

austen_chapters |> 
  group_by(book) |> 
  summarise(chapters = n())
# A tibble: 6 × 2
  book                chapters
  <fct>                  <int>
1 Sense & Sensibility       51
2 Pride & Prejudice         62
3 Mansfield Park            49
4 Emma                      56
5 Northanger Abbey          32
6 Persuasion                25

Then, the negative sentiments are counted in each chapter. As different chapters have varying amounts of words, the ratio of negative words to total words in the chapter is calculated, This is used to find the chapter with the highest ratio of negative words.

bingnegative <- get_sentiments("bing") |> 
  filter(sentiment == "negative")

wordcounts <- tidy_books |>
  group_by(book, chapter) |>
  summarize(words = n())
`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by book and chapter.
ℹ Output is grouped by book.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(book, chapter))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.
tidy_books |>
  semi_join(bingnegative) |>
  group_by(book, chapter) |>
  summarize(negativewords = n()) |>
  left_join(wordcounts, by = c("book", "chapter")) |>
  mutate(ratio = negativewords/words) |>
  filter(chapter != 0) |>
  slice_max(ratio, n = 1) |> 
  ungroup()
Joining with `by = join_by(word)`
`summarise()` has regrouped the output.
# A tibble: 6 × 5
  book                chapter negativewords words  ratio
  <fct>                 <int>         <int> <int>  <dbl>
1 Sense & Sensibility      43           161  3405 0.0473
2 Pride & Prejudice        34           111  2104 0.0528
3 Mansfield Park           46           173  3685 0.0469
4 Emma                     15           151  3340 0.0452
5 Northanger Abbey         21           149  2982 0.0500
6 Persuasion                4            62  1807 0.0343

The results are the same as in the textbook

Exploring different books

In order to explore different books, I use the gutenbergr package. It had been retrieved above and I can explore what it contains and how to find information about it with

?gutenbergr
starting httpd help server ... done
??gutenbergr
 View(gutenberg_metadata)

The data frame gutenberg_metadata has 8 elements from each book such as author, the language, and the subject matter or category. The latter is called gutenberg_bookshelf. It can be arranged alphabetically. This allowed me to find books on economics. There are about 45 titles. From these ones I have selected four important classic book from the history of economic thought: A. Smith’s The Wealth of Nations (gutenbergr ID: 38194), D. Ricardo’s Principles of Political Economy and Taxation (33310), W. Jevons’ Political Economy (33219), and J. M. Keynes’ General Theory (65278).

econ_big4 <- gutenberg_download(c(38194, 33310, 33219, 65278))
Using mirror https://gutenberg.pglaf.org.
tidy_books_g <- econ_big4 |>
  group_by(gutenberg_id) |>
  mutate(
    linenumber = row_number(),
    chapter = cumsum(str_detect(text, 
                                regex("^chapter [\\divxlc]", 
                                      ignore_case = TRUE)))) |>
  ungroup() |>
  unnest_tokens(word, text)
tidy_books_g
# A tibble: 638,325 × 4
   gutenberg_id linenumber chapter word   
          <int>      <int>   <int> <chr>  
 1        38194          1       0 harvard
 2        38194          1       0 college
 3        38194          1       0 library
 4        38194          5       0 an     
 5        38194          6       0 inquiry
 6        38194          6       0 into   
 7        38194          6       0 the    
 8        38194          6       0 nature 
 9        38194          6       0 and    
10        38194          6       0 causes 
# ℹ 638,315 more rows
glimpse(tidy_books_g)
Rows: 638,325
Columns: 4
$ gutenberg_id <int> 38194, 38194, 38194, 38194, 38194, 38194, 38194, 38194, 3…
$ linenumber   <int> 1, 1, 1, 5, 6, 6, 6, 6, 6, 6, 7, 7, 8, 8, 8, 10, 11, 11, …
$ chapter      <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ word         <chr> "harvard", "college", "library", "an", "inquiry", "into",…

As it is explained below, I was not expecting the results I found. As this pertains to the book by Jevons, I explored its content a bit further. Although I did this afterwards, it seems logical to mention it here.

jevons <- tidy_books_g %>% 
  filter(gutenberg_id == "33219")

jevons
# A tibble: 44,810 × 4
   gutenberg_id linenumber chapter word        
          <int>      <int>   <int> <chr>       
 1        33219          1       0 transcribers
 2        33219          1       0 note        
 3        33219          3       0 in          
 4        33219          3       0 this        
 5        33219          3       0 book        
 6        33219          3       0 all         
 7        33219          3       0 words       
 8        33219          3       0 and         
 9        33219          3       0 phrases     
10        33219          3       0 surrounded  
# ℹ 44,800 more rows

The list of chapters does not match the version of Jevon’s classic book “The Theory of Political Economy”. Also, the title in gutenbergr is only “Political Economy”, not the full title and it is an edition from 1880, which is not the first one (from 1871), nor one of the editions listed in https://www.hetwebsite.net/het/profiles/jevons.htm, which is one of the best websites for history of economic thought. Besides biographies of major economists throughout history it has links to PDFs or online versions of the original books and articles. For instance, in this case, it has a link to https://books.google.com.ar/books?id=Sw8ZAAAAYAAJ&pg=PR3&redir_esc=y#v=onepage&q&f=false (a PDF of a photocopy of the book at the Littauer Library of Harvard University)

In spite of these challenges, I have used the book in the exercise that follows. Some of the conclusions below would have to be taken with caution and require further exploration. Nevertheless, I was able to carry out the exercise.

I looked for other lexicons online, using “tidytext sentiment lexicon” in Google.

I have found a reference to chapter 5.3.1 in “Text Mining with R: A Tidy Approach”!

There I found the Loughran and McDonald dictionary of financial sentiment terms

get_sentiments("loughran")
# A tibble: 4,150 × 2
   word         sentiment
   <chr>        <chr>    
 1 abandon      negative 
 2 abandoned    negative 
 3 abandoning   negative 
 4 abandonment  negative 
 5 abandonments negative 
 6 abandons     negative 
 7 abdicated    negative 
 8 abdicates    negative 
 9 abdicating   negative 
10 abdication   negative 
# ℹ 4,140 more rows

I explored the words in the lexicon in “https://sraf.nd.edu/loughranmcdonald-master-dictionary/”

From my work on macroeconomics years ago, I have always been interested in uncertainty. So I chose uncertainty over the other words they use for sentiment categories (which are: negative, positive, litigious, strong modal, weak modal, and constraining)

l_unc <- get_sentiments("loughran") |> 
    filter(sentiment == "uncertainty")
l_unc
# A tibble: 297 × 2
   word        sentiment  
   <chr>       <chr>      
 1 abeyance    uncertainty
 2 abeyances   uncertainty
 3 almost      uncertainty
 4 alteration  uncertainty
 5 alterations uncertainty
 6 ambiguities uncertainty
 7 ambiguity   uncertainty
 8 ambiguous   uncertainty
 9 anomalies   uncertainty
10 anomalous   uncertainty
# ℹ 287 more rows

I explored Keynes’ book, as Keynes did write a lot about uncertainty. I did this to see if what I was doing was working.

tidy_books_g |>
  filter(gutenberg_id == "65278") |>
  inner_join(l_unc) |>
  count(word, sort = TRUE)
Joining with `by = join_by(word)`
# A tibble: 104 × 2
   word             n
   <chr>        <int>
 1 may            143
 2 could           51
 3 might           47
 4 risk            43
 5 fluctuations    41
 6 possible        33
 7 depends         25
 8 perhaps         23
 9 fluctuation     22
10 nearly          21
# ℹ 94 more rows

As it seemed to work, I have reproduced the work done for Jane Austen above, to the four classic economics books (trying to analyze the presence of sentiments about uncertainty).

econ_sentiment <- tidy_books_g |>
  inner_join(get_sentiments("loughran")) |>
  count(gutenberg_id, index = linenumber %/% 80, sentiment) |>
  pivot_wider(names_from = sentiment, values_from = n, values_fill = 0) |> 
  mutate(sentiment = positive - negative)
Joining with `by = join_by(word)`
Warning in inner_join(tidy_books_g, get_sentiments("loughran")): Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 3116 of `x` matches multiple rows in `y`.
ℹ Row 2914 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship =
  "many-to-many"` to silence this warning.

I tried to plot the results.

ggplot(econ_sentiment, aes(index, sentiment, fill = gutenberg_id)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~gutenberg_id, ncol = 2, scales = "free_x")

As expected, it does seem there are more occurrences of words related to uncertainty on Keynes’ General Theory than the other three books. Also, they tend to be more negative.

Also, just in case, I also explored combining less lines than in the novels, under the assumption that in novels more lines may be need to capture sentiments than in theoretical books about econonmics. I have used 40 instead of 80 lines.

econ_sentiment_40 <- tidy_books_g |>
  inner_join(get_sentiments("loughran")) |>
  count(gutenberg_id, index = linenumber %/% 40, sentiment) |>
  pivot_wider(names_from = sentiment, values_from = n, values_fill = 0) |> 
  mutate(sentiment = positive - negative)
Joining with `by = join_by(word)`
Warning in inner_join(tidy_books_g, get_sentiments("loughran")): Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 3116 of `x` matches multiple rows in `y`.
ℹ Row 2914 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship =
  "many-to-many"` to silence this warning.

I tried to plot the results.

ggplot(econ_sentiment_40, aes(index, sentiment, fill = gutenberg_id)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~gutenberg_id, ncol = 2, scales = "free_x")

Although there is more granularity, the pattern is consitent with what I had found using 80 lines.

Then I tried to reproduce the analysis by chapter (which is not affected by the number of lines).

uncertainty_g <- get_sentiments("loughran") |> 
  filter(sentiment == "uncertainty")

wordcounts <- tidy_books_g |>
  group_by(gutenberg_id, chapter) |>
  summarize(words = n())
`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gutenberg_id and chapter.
ℹ Output is grouped by gutenberg_id.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gutenberg_id, chapter))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.
tidy_books_g |>
  semi_join(uncertainty_g) |>
  group_by(gutenberg_id, chapter) |>
  summarize(negativewords = n()) |>
  left_join(wordcounts, by = c("gutenberg_id", "chapter")) |>
  mutate(ratio = negativewords/words) |>
  filter(chapter != 0) |>
  slice_max(ratio, n = 1) |> 
  ungroup()
Joining with `by = join_by(word)`
`summarise()` has regrouped the output.
# A tibble: 3 × 5
  gutenberg_id chapter negativewords words  ratio
         <int>   <int>         <int> <int>  <dbl>
1        33219       6            46  1848 0.0249
2        33310       3            27   875 0.0309
3        65278       3           311 16814 0.0185

Here I was surprised by two elements. First, A. Smith’s book does not appear. It is strange because it does show in the graph.

Secondly, as a proportion of the words in the chapter with more occurrences, the book by Keynes comes in last. I was intrigued by Jevons’ book having more occurrences of words associated to sentiments of uncertainty than Keynes’. At this point I explored in depth the book by Jevons as mentioned above. The results probably need to be taken with a grain of salt.

Exploring uncertainty in Jane Austen’s novels

As I have worked with the Loughran and McDonald lexicon to explore uncertainty, I have used it to analyze Jane Austen’s novels too. I thought it could be interesting to check if Jane Austen used words related to uncertainty (given she deals with family and romantic relationships).

I have used the uncertainty lexicon to explore Jane Austen’s Emma. This is a first step to check if the analysis can work.

tidy_books |>
  filter(book == "Emma") |>
  inner_join(l_unc) |>
  count(word, sort = TRUE)
Joining with `by = join_by(word)`
# A tibble: 91 × 2
   word         n
   <chr>    <int>
 1 could      837
 2 might      326
 3 may        221
 4 believe    102
 5 perhaps     99
 6 doubt       98
 7 almost      88
 8 possible    84
 9 appeared    49
10 believed    46
# ℹ 81 more rows

It seems to work. It is interesting to note that seven of these words are verbs. Among the other words there is one substantive, one adverb, and one adjective. However, the substantive (“doubt”) could also be a verb.

As it does seem to work, I look at all the novels at the same time.

jane_austen_uncertainty <- tidy_books |>
  inner_join(get_sentiments("loughran")) |>
  count(book, index = linenumber %/% 80, sentiment) |>
  pivot_wider(names_from = sentiment, values_from = n, values_fill = 0) |> 
  mutate(sentiment = positive - negative)
Joining with `by = join_by(word)`
Warning in inner_join(tidy_books, get_sentiments("loughran")): Detected an unexpected many-to-many relationship between `x` and `y`.
ℹ Row 1252 of `x` matches multiple rows in `y`.
ℹ Row 2772 of `y` matches multiple rows in `x`.
ℹ If a many-to-many relationship is expected, set `relationship =
  "many-to-many"` to silence this warning.

There is an error message (as it was the case when trying to reproduce the results from chapter 2. However, it does not seem to affect the constructions of the following graphs.

ggplot(jane_austen_uncertainty, aes(index, sentiment, fill = book)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~book, ncol = 2, scales = "free_x")

There are many instances of words related to uncertainty on the negative side in all six novels. In particular, “Negative uncertainty” appears towards, but just before, the end. This is particularly the case in Mansfield Park.

Moreover, in all then there seem to be “early crises” with a lot of negative uncertainty related words: Emma (around 50), Mansfield Park, (post 50 and post 100), Pride and Prejudice (=~ 80 and 120).

Finally, in Sense and Sensibility there are longer stretches of “Negative uncertainty” than in the other novels.

It would be interesting to explore if this is any way related to the particular times in which they were written.