Jane Austen Sentiment Analysis
library (janeaustenr)
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 (stringr)
library (tidytext)
library (tidyr)
library (textdata)
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)
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
library (tidyr)
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(., 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.
library (ggplot2)
ggplot (jane_austen_sentiment, aes (index, sentiment, fill = book)) +
geom_col (show.legend = FALSE ) +
facet_wrap (~ book, ncol = 2 , scales = "free_x" )
Load Giants ESPN Articles
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ forcats 1.0.1 ✔ readr 2.2.0
✔ lubridate 1.9.5 ✔ tibble 3.3.1
✔ purrr 1.2.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library (tidytext)
giants_talent <- read_lines ("Jaxson_Dart_all_angles .txt" )
giants_injury <- read_lines ("dart_knee_surgery.txt" )
Tokenize the Articles
giants_text <- tibble (
article = c (
rep ("Talent" , length (giants_talent)),
rep ("Injury" , length (giants_injury))
),
text = c (giants_talent, giants_injury)
)
giants_tidy <- giants_text %>%
unnest_tokens (word, text)
Identify Positive and Negative words
giants_bing <- giants_tidy %>%
inner_join (get_sentiments ("bing" ), by = "word" )
giants_bing %>%
count (article, sentiment)
# A tibble: 4 × 3
article sentiment n
<chr> <chr> <int>
1 Injury negative 26
2 Injury positive 33
3 Talent negative 23
4 Talent positive 80
Sentiment Metrics
giants_sentiment <- giants_bing %>%
count (article, sentiment) %>%
pivot_wider (
names_from = sentiment,
values_from = n,
values_fill = 0
) %>%
mutate (sentiment_score = positive - negative)
giants_sentiment
# A tibble: 2 × 4
article negative positive sentiment_score
<chr> <int> <int> <int>
1 Injury 26 33 7
2 Talent 23 80 57
Visualize
library (ggplot2)
ggplot (giants_sentiment,
aes (x = article, y = sentiment_score, fill = article)) +
geom_col () +
labs (
title = "Sentiment Analysis of ESPN Giants Articles" ,
x = "Article" ,
y = "Sentiment Score (Positive - Negative)"
) +
theme_minimal () +
guides (fill = "none" )
Using Vader (lexicon) for Sentiment
library (vader)
giants_vader <- vader_df (c (
paste (giants_talent, collapse = " " ),
paste (giants_injury, collapse = " " )
))
giants_vader <- giants_vader %>%
mutate (article = c ("Talent" , "Injury" )) %>%
select (article, compound, pos, neg, neu)
giants_vader
article compound pos neg neu
1 Talent 1.000 0.154 0.033 0.813
2 Injury 0.972 0.105 0.088 0.807
Comparing Vader and Bing
sentiment_comparison <- giants_sentiment %>%
select (article, bing_score = sentiment_score) %>%
left_join (
giants_vader %>%
mutate (vader_net = pos - neg) %>%
select (article, compound, vader_net),
by = "article"
)
sentiment_comparison
# A tibble: 2 × 4
article bing_score compound vader_net
<chr> <int> <dbl> <dbl>
1 Injury 7 0.972 0.017
2 Talent 57 1 0.121
Discussion and Findings
The sentiment analysis shows that both ESPN articles contain more positive than negative language. Using the Bing lexicon, the article discussing Jaxson Dart’s talent received a sentiment score of +57, compared to +7 for the article discussing his injury.
VADER produced similar findings, with positive-minus-negative scores of 0.121 for the talent article and 0.017 for the injury article. Both methods suggest that the talent article contains more positive language.
One limitation is that the articles may differ in length, which affects raw Bing scores. Additionally, sentiment analysis does not always capture the full context of sports journalism.