library(tidyverse)
library(tidytext)
library(taylor)
library(tayloRswift)
library(ggridges)
library(scales)
theme_set(theme_minimal(base_size = 13))
Text analysis (Taylor’s Version)
Suggested answers
Taylor Swift is one of the most recognizable and popular recording artists on the planet. She is also a prolific songwriter, having written or co-written every song on each of her nine studio albums. Currently she is smashing records on her Eras concert tour.
In this application exercise we will use the taylor package to analyze the lyrics of Taylor Swift’s songs. The package contains a data frame taylor_albums
with information about each of her studio albums, including the release date, the number of tracks, and the album cover art. The package also contains a data frame taylor_album_songs
with the lyrics of each song from her official studio albums.1
1 This excludes singles released separately from an album as well as non-Taylor-owned albums that have a Taylor-owned alternative (e.g., Fearless is excluded in favor of Fearless (Taylor’s Version)).
Import Taylor Swift lyrics
We can load the relevant data files directly from the taylor package.
library(taylor)
data("taylor_album_songs")
data("taylor_albums")
taylor_album_songs
# A tibble: 209 × 29
album_name ep album_release track_number track_name artist featuring
<chr> <lgl> <date> <int> <chr> <chr> <chr>
1 Taylor Swift FALSE 2006-10-24 1 Tim McGraw Taylo… <NA>
2 Taylor Swift FALSE 2006-10-24 2 Picture To Bu… Taylo… <NA>
3 Taylor Swift FALSE 2006-10-24 3 Teardrops On … Taylo… <NA>
4 Taylor Swift FALSE 2006-10-24 4 A Place In Th… Taylo… <NA>
5 Taylor Swift FALSE 2006-10-24 5 Cold As You Taylo… <NA>
6 Taylor Swift FALSE 2006-10-24 6 The Outside Taylo… <NA>
7 Taylor Swift FALSE 2006-10-24 7 Tied Together… Taylo… <NA>
8 Taylor Swift FALSE 2006-10-24 8 Stay Beautiful Taylo… <NA>
9 Taylor Swift FALSE 2006-10-24 9 Should've Sai… Taylo… <NA>
10 Taylor Swift FALSE 2006-10-24 10 Mary's Song (… Taylo… <NA>
# ℹ 199 more rows
# ℹ 22 more variables: bonus_track <lgl>, promotional_release <date>,
# single_release <date>, track_release <date>, danceability <dbl>,
# energy <dbl>, key <int>, loudness <dbl>, mode <int>, speechiness <dbl>,
# acousticness <dbl>, instrumentalness <dbl>, liveness <dbl>, valence <dbl>,
# tempo <dbl>, time_signature <int>, duration_ms <int>, explicit <lgl>,
# key_name <chr>, mode_name <chr>, key_mode <chr>, lyrics <list>
taylor_albums
# A tibble: 16 × 5
album_name ep album_release metacritic_score user_score
<chr> <lgl> <date> <int> <dbl>
1 Taylor Swift FALSE 2006-10-24 67 8.4
2 The Taylor Swift Holiday Col… TRUE 2007-10-14 NA NA
3 Beautiful Eyes TRUE 2008-07-15 NA NA
4 Fearless FALSE 2008-11-11 73 8.4
5 Speak Now FALSE 2010-10-25 77 8.6
6 Red FALSE 2012-10-22 77 8.6
7 1989 FALSE 2014-10-27 76 8.3
8 reputation FALSE 2017-11-10 71 8.3
9 Lover FALSE 2019-08-23 79 8.4
10 folklore FALSE 2020-07-24 88 9
11 evermore FALSE 2020-12-11 85 8.9
12 Fearless (Taylor's Version) FALSE 2021-04-09 82 8.9
13 Red (Taylor's Version) FALSE 2021-11-12 91 8.9
14 Midnights FALSE 2022-10-21 85 8.3
15 Speak Now (Taylor's Version) FALSE 2023-07-07 81 9.2
16 1989 (Taylor's Version) FALSE 2023-10-27 95 NA
Convert to tidytext format
Currently, taylor_album_songs
is stored as one-row-song, with the lyrics nested in a list-column where each element is a tibble with one-row-per-line. The definition of a single “line” is somewhat arbitrary. For substantial analysis, we will convert the corpus to a tidy-text data frame of one-row-per-token. Initially, we will use unnest_tokens()
to tokenize all unigrams.
# tokenize taylor lyrics
<- taylor_album_songs |>
taylor_lyrics # select relevant columns
select(album_name, track_number, track_name, lyrics) |>
# factor albums by release date
mutate(album_name = fct(x = album_name, levels = taylor_albums$album_name)) |>
# unnest the list-column to one-row-per-song-per-line
unnest(col = lyrics) |>
# now tokenize the lyrics
unnest_tokens(output = word, input = lyric)
taylor_lyrics
# A tibble: 77,882 × 7
album_name track_number track_name line element element_artist word
<fct> <int> <chr> <int> <chr> <chr> <chr>
1 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift he
2 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift said
3 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift the
4 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift way
5 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift my
6 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift blue
7 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift eyes
8 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift shined
9 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift put
10 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift those
# ℹ 77,872 more rows
Remember that by default, unnest_tokens()
automatically converts all text to lowercase and strips out punctuation.
Length of songs by words
An initial check reveals the length of each song in terms of the number of words in its lyrics.
|>
taylor_lyrics count(album_name, track_number, track_name) |>
ggplot(mapping = aes(x = n)) +
geom_histogram() +
labs(
title = "Length of songs by Taylor Swift",
x = "Song length (in words)",
y = NULL,
caption = "Source: {taylor}"
)
Stop words
Generic stop words
Of course not all words are equally important. Consider the 10 most frequent words in the lyrics:
|>
taylor_lyrics count(word, sort = TRUE)
# A tibble: 4,102 × 2
word n
<chr> <int>
1 you 3585
2 i 3486
3 the 2731
4 and 2146
5 to 1381
6 me 1355
7 a 1287
8 it 1225
9 in 1195
10 my 1085
# ℹ 4,092 more rows
These are not particularly informative. We can identify a list of stop words then remove them via anti_join()
.
# get a set of stop words
get_stopwords(source = "smart")
# A tibble: 571 × 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
# ℹ 561 more rows
# remove stop words
<- anti_join(x = taylor_lyrics, y = get_stopwords(source = "smart"))
taylor_tidy taylor_tidy
# A tibble: 24,770 × 7
album_name track_number track_name line element element_artist word
<fct> <int> <chr> <int> <chr> <chr> <chr>
1 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift blue
2 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift eyes
3 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift shined
4 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift put
5 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift georgia
6 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift stars
7 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift shame
8 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift night
9 Taylor Swift 1 Tim McGraw 3 Verse 1 Taylor Swift lie
10 Taylor Swift 1 Tim McGraw 4 Verse 1 Taylor Swift boy
# ℹ 24,760 more rows
|>
taylor_tidy count(word) |>
slice_max(n = 20, order_by = n) |>
mutate(word = fct_reorder(.f = word, .x = n)) |>
ggplot(aes(x = n, y = word)) +
geom_col() +
labs(
title = "Frequency of tokens in Taylor Swift lyrics",
x = "Number of occurrences",
y = NULL,
caption = "Source: {taylor}"
)
This removes 53,112 words from the corpus.
Domain-specific stop words
While this takes care of generic stop words, we can also identify domain-specific stop words. For example, Taylor Swift’s lyrics are full of interjections and exclamations that are not particularly informative. We can identify these and remove them from the corpus.
# domain-specific stop words
# source: https://rpubs.com/RosieB/642806
<- c(
taylor_stop_words "oh", "ooh", "eh", "ha", "mmm", "mm", "yeah", "ah",
"hey", "eeh", "uuh", "uh", "la", "da", "di", "ra",
"huh", "hu", "whoa", "gonna", "wanna", "gotta", "em"
)
<- taylor_lyrics |>
taylor_tidy anti_join(get_stopwords(source = "smart")) |>
filter(!word %in% taylor_stop_words)
taylor_tidy
# A tibble: 23,107 × 7
album_name track_number track_name line element element_artist word
<fct> <int> <chr> <int> <chr> <chr> <chr>
1 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift blue
2 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift eyes
3 Taylor Swift 1 Tim McGraw 1 Verse 1 Taylor Swift shined
4 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift put
5 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift georgia
6 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift stars
7 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift shame
8 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift night
9 Taylor Swift 1 Tim McGraw 3 Verse 1 Taylor Swift lie
10 Taylor Swift 1 Tim McGraw 4 Verse 1 Taylor Swift boy
# ℹ 23,097 more rows
|>
taylor_tidy count(word, sort = TRUE)
# A tibble: 3,711 × 2
word n
<chr> <int>
1 love 402
2 time 349
3 back 287
4 baby 226
5 night 148
6 stay 134
7 red 133
8 home 125
9 made 124
10 feel 119
# ℹ 3,701 more rows
Words most relevant to each album
Since we know the songs for each album, we can examine the relative significance of different words to different albums. Term frequency-inverse document frequency (tf-idf) is a simple metric for measuring the importance of specific words to a corpus. Here let’s calculate the top ten words for each album.
<- taylor_tidy |>
taylor_tf_idf count(album_name, word) |>
bind_tf_idf(term = word, document = album_name, n = n)
taylor_tf_idf
# A tibble: 8,072 × 6
album_name word n tf idf tf_idf
<fct> <chr> <int> <dbl> <dbl> <dbl>
1 Taylor Swift a.m 1 0.000858 1.61 0.00138
2 Taylor Swift adore 1 0.000858 1.61 0.00138
3 Taylor Swift aisle 1 0.000858 1.20 0.00103
4 Taylor Swift album 1 0.000858 1.61 0.00138
5 Taylor Swift amen 3 0.00258 2.30 0.00593
6 Taylor Swift anymore 1 0.000858 0.357 0.000306
7 Taylor Swift babies 1 0.000858 1.61 0.00138
8 Taylor Swift baby 15 0.0129 0 0
9 Taylor Swift back 25 0.0215 0 0
10 Taylor Swift backroads 1 0.000858 2.30 0.00198
# ℹ 8,062 more rows
# visualize the top N terms per character by tf-idf score
|>
taylor_tf_idf group_by(album_name) |>
slice_max(n = 10, order_by = tf_idf, with_ties = FALSE) |>
ggplot(mapping = aes(x = tf_idf, y = word)) +
geom_col() +
facet_wrap(facets = vars(album_name), scales = "free")
Not very functional sorted alphabetically. Let’s sort all the facets from highest to lowest tf-idf scores.
|>
taylor_tf_idf group_by(album_name) |>
slice_max(n = 10, order_by = tf_idf, with_ties = FALSE) |>
# create word as a factor column ordered by n
mutate(word = fct_reorder(.f = word, .x = n)) |>
ggplot(mapping = aes(x = tf_idf, y = word)) +
geom_col() +
facet_wrap(facets = vars(album_name), scales = "free")
Still does not look right. The problem is that some tokens appear in multiple facets but with different tf-idf scores (and different orders). We need to order the rows within each facet independently. But ggplot2 does not support this operation. How can we do so? Using tidytext::reorder_within()
and tidytext::scale_y_reordered()
.
|>
taylor_tf_idf group_by(album_name) |>
slice_max(n = 10, order_by = tf_idf, with_ties = FALSE) |>
# create word as a factor column ordered by n
mutate(word = fct_reorder(.f = word, .x = n)) |>
# resolve ambiguities when same word appears for different characters
ungroup() |>
mutate(word = reorder_within(x = word, by = tf_idf, within = album_name)) |>
ggplot(mapping = aes(x = tf_idf, y = word)) +
geom_col() +
scale_y_reordered() +
labs(
title = "Most important words in each Taylor Swift album",
x = "tf-idf",
y = NULL,
caption = "Source: {taylor}"
+
) facet_wrap(
facets = vars(album_name), scales = "free",
# wrap each facet label so they fit in the plot
labeller = label_wrap_gen(width = 20)
)
Sentiment analysis
Sentiment analysis utilizes the text of the lyrics to classify content as positive or negative. Dictionary-based methods use pre-generated lexicons of words independently coded as positive/negative. We can combine one of these dictionaries with the Taylor Swift tidy-text data frame using inner_join()
to identify words with sentimental affect, and further analyze trends.
Here we use the afinn
dictionary which classifies 2,477 words on a scale of \([-5, +5]\).
# afinn dictionary
get_sentiments(lexicon = "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
# how many words for each value?
get_sentiments(lexicon = "afinn") |>
count(value)
# A tibble: 11 × 2
value n
<dbl> <int>
1 -5 16
2 -4 43
3 -3 264
4 -2 966
5 -1 309
6 0 1
7 1 208
8 2 448
9 3 172
10 4 45
11 5 5
# join with sentiment dictionary, drop words which are not defined
<- taylor_tidy |>
taylor_afinn inner_join(y = get_sentiments(lexicon = "afinn"))
taylor_afinn
# A tibble: 4,415 × 8
album_name track_number track_name line element element_artist word value
<fct> <int> <chr> <int> <chr> <chr> <chr> <dbl>
1 Taylor Swift 1 Tim McGraw 2 Verse 1 Taylor Swift shame -2
2 Taylor Swift 1 Tim McGraw 5 Verse 1 Taylor Swift stuck -2
3 Taylor Swift 1 Tim McGraw 10 Chorus Taylor Swift hope 2
4 Taylor Swift 1 Tim McGraw 10 Chorus Taylor Swift favo… 2
5 Taylor Swift 1 Tim McGraw 13 Chorus Taylor Swift happ… 3
6 Taylor Swift 1 Tim McGraw 14 Chorus Taylor Swift hope 2
7 Taylor Swift 1 Tim McGraw 18 Chorus Taylor Swift hope 2
8 Taylor Swift 1 Tim McGraw 19 Verse 2 Taylor Swift tears -2
9 Taylor Swift 1 Tim McGraw 20 Verse 2 Taylor Swift god 1
10 Taylor Swift 1 Tim McGraw 25 Verse 2 Taylor Swift hard -1
# ℹ 4,405 more rows
Sentimental affect of each song
First, we can examine the sentiment of each song individually by calculating the average sentiment of each word in the song.
|>
taylor_afinn summarize(sent = mean(value), .by = c(album_name, track_name)) |>
mutate(track_name = fct_reorder(.f = track_name, .x = sent)) |>
ggplot(mapping = aes(x = sent, y = track_name, fill = sent)) +
geom_col() +
scale_fill_viridis_c() +
labs(
title = "Sentimental affect of Taylor Swift songs",
x = "Average sentiment",
y = NULL,
caption = "Source: {taylor}"
+
) theme(
legend.position = "none",
plot.title.position = "plot"
)
Overall Taylor Swift has a wide range of songs based purely on this definition of sentimental affect/emotional valence.
Shake It Off
However, this also illustrates some problems with dictionary-based sentiment analysis. Consider “Shake It Off (Taylor’s Version)” which is scored as a -2.25.
# what's up with shake it off?
|>
taylor_afinn filter(track_name == "Shake It Off (Taylor's Version)") |>
count(word, value) |>
arrange(-value)
# A tibble: 12 × 3
word value n
<chr> <dbl> <int>
1 good 3 1
2 haha 3 3
3 god 1 1
4 stop -1 4
5 dirty -2 2
6 miss -2 1
7 sick -2 1
8 cheats -3 1
9 fake -3 18
10 hate -3 16
11 haters -3 4
12 liars -3 1
Would most listeners classify this song as full of negativity? Probs not. Herein lies the problem with dictionary-based methods. The AFINN lexicon codes “fake” and “hate” as negative terms, even though in this context they are being used more positively – the singer is shaking off the haters and going her own way in life.
This is a common problem with dictionary-based methods, and why it is important to carefully consider the context of the text being analyzed.
Sentimental affect of each album
We could also examine the general disposition of each album based on their overall positive/negative affect.
# errorbar plot
|>
taylor_afinn # calculate average sentiment by album with standard error
summarize(
sent = mean(value),
se = sd(value) / sqrt(n()),
.by = album_name
|>
) # reverse album order for vertical plot
mutate(album_name = fct_rev(f = album_name)) |>
# generate plot
ggplot(mapping = aes(y = album_name, x = sent)) +
geom_pointrange(mapping = aes(
xmin = sent - 2 * se,
xmax = sent + 2 * se
+
)) labs(
title = "Emotional affect in Taylor Swift albums",
x = "Average sentiment",
y = NULL,
caption = "Source: {taylor}"
)
# ggridge plot with tayloRswift color palette
|>
taylor_afinn summarize(sent = mean(x = value), .by = c(album_name, track_name)) |>
# reverse album order for vertical plot
mutate(album_name = fct_rev(f = album_name)) |>
ggplot(mapping = aes(x = sent, y = album_name, fill = after_stat(x))) +
geom_density_ridges_gradient(quantile_lines = TRUE, quantiles = 0.5) +
scale_fill_taylor_c(album = "Red", guide = "none") +
labs(
title = "Emotional affect in Taylor Swift albums",
x = "Average sentiment",
y = NULL,
caption = "Source: {taylor}"
)
Notice that we are visualizing the albums in chronological order, but the all the “Taylor’s Version” albums are re-recordings of albums she made early in her career. We can stan artists owning their own music, but what about her career arc? Has Taylor Swift gotten more positive or negative across her career?
In order to assess that, we have to go back to her original album recordings. We can do this by joining the taylor_afinn
data frame with the taylor_all_songs
data frame, which contains all of her original songs.
<- taylor_all_songs |>
taylor_all_tidy select(album_name, track_number, track_name, lyrics) |>
unnest(col = lyrics) |>
unnest_tokens(output = word, input = lyric) |>
# stop word removal
anti_join(get_stopwords(source = "smart")) |>
filter(!word %in% taylor_stop_words) |>
# filter to full studio albums
semi_join(y = taylor_albums |>
filter(!ep)) |>
# exclude rereleases
filter(!str_detect(string = album_name, pattern = "Taylor's Version")) |>
# order albums by release date
mutate(album_name = factor(x = album_name, levels = taylor_albums$album_name) |>
fct_rev())
# errorbar plot
|>
taylor_all_tidy # join with sentiment dictionary
inner_join(y = get_sentiments(lexicon = "afinn")) |>
# calculate average sentiment by album with standard error
summarize(
sent = mean(value),
se = sd(value) / sqrt(n()),
.by = album_name
|>
) # generate plot sorted from positive to negative
ggplot(mapping = aes(y = album_name, x = sent)) +
geom_pointrange(mapping = aes(
xmin = sent - 2 * se,
xmax = sent + 2 * se
+
)) labs(
title = "Emotional affect in Taylor Swift albums",
subtitle = "Original studio albums",
x = "Average sentiment",
y = NULL,
caption = "Source: {taylor}"
)
# ggridge plot with tayloRswift color palette
|>
taylor_all_tidy # join with sentiment dictionary
inner_join(y = get_sentiments(lexicon = "afinn")) |>
# calculate average sentiment by album with standard error
summarize(
sent = mean(value),
.by = c(album_name, track_name)
|>
) ggplot(mapping = aes(x = sent, y = album_name, fill = after_stat(x))) +
geom_density_ridges_gradient(quantile_lines = TRUE, quantiles = 0.5) +
scale_fill_taylor_c(album = "Red", guide = "none") +
labs(
title = "Emotional affect in Taylor Swift albums",
subtitle = "Original studio albums",
x = "Average sentiment",
y = NULL,
caption = "Source: {taylor}"
)
Depending on how you feel about her music, you might be surprised to see that her first album is the most positive. It’s also interesting to see that one of her most recent albums, evermore, is the most negative.
Varying types of sentiment
tidytext includes multiple sentiment dictionaries for different types of sentiment. We can use the nrc
dictionary to examine the different types of sentiment in Taylor Swift’s lyrics.
|>
taylor_all_tidy # join with sentiment dictionary
inner_join(y = get_sentiments(lexicon = "nrc"), relationship = "many-to-many") |>
filter(sentiment != "positive", sentiment != "negative") |>
count(album_name, sentiment) |>
# normalize for number of tokens per album
left_join(y = taylor_all_tidy |>
count(album_name, name = "n_all")) |>
mutate(n_pct = n / n_all) |>
# reverse album order for vertical plot
mutate(album_name = fct_rev(f = album_name)) |>
ggplot(mapping = aes(x = n_pct, y = album_name)) +
geom_col() +
scale_x_continuous(labels = percent_format()) +
facet_wrap(
facets = vars(sentiment)
+
) labs(
title = "Sentimental affect (by type) in Taylor Swift albums",
subtitle = "Original studio albums",
x = "Percentage of tokens in the album",
y = NULL,
caption = "Source: {taylor}"
)
::session_info() sessioninfo
─ Session info ───────────────────────────────────────────────────────────────
setting value
version R version 4.3.1 (2023-06-16)
os macOS Ventura 13.5.2
system aarch64, darwin20
ui X11
language (EN)
collate en_US.UTF-8
ctype en_US.UTF-8
tz America/New_York
date 2023-11-15
pandoc 3.1.1 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/ (via rmarkdown)
─ Packages ───────────────────────────────────────────────────────────────────
package * version date (UTC) lib source
cli 3.6.1 2023-03-23 [1] CRAN (R 4.3.0)
colorspace 2.1-0 2023-01-23 [1] CRAN (R 4.3.0)
digest 0.6.33 2023-07-07 [1] CRAN (R 4.3.0)
dplyr * 1.1.3 2023-09-03 [1] CRAN (R 4.3.0)
evaluate 0.22 2023-09-29 [1] CRAN (R 4.3.1)
fansi 1.0.5 2023-10-08 [1] CRAN (R 4.3.1)
farver 2.1.1 2022-07-06 [1] CRAN (R 4.3.0)
fastmap 1.1.1 2023-02-24 [1] CRAN (R 4.3.0)
forcats * 1.0.0 2023-01-29 [1] CRAN (R 4.3.0)
fs 1.6.3 2023-07-20 [1] CRAN (R 4.3.0)
generics 0.1.3 2022-07-05 [1] CRAN (R 4.3.0)
ggplot2 * 3.4.2 2023-04-03 [1] CRAN (R 4.3.0)
ggridges * 0.5.4 2022-09-26 [1] CRAN (R 4.3.0)
glue 1.6.2 2022-02-24 [1] CRAN (R 4.3.0)
gtable 0.3.3 2023-03-21 [1] CRAN (R 4.3.0)
here 1.0.1 2020-12-13 [1] CRAN (R 4.3.0)
hms 1.1.3 2023-03-21 [1] CRAN (R 4.3.0)
htmltools 0.5.6.1 2023-10-06 [1] CRAN (R 4.3.1)
htmlwidgets 1.6.2 2023-03-17 [1] CRAN (R 4.3.0)
janeaustenr 1.0.0 2022-08-26 [1] CRAN (R 4.3.0)
jsonlite 1.8.7 2023-06-29 [1] CRAN (R 4.3.0)
knitr 1.44 2023-09-11 [1] CRAN (R 4.3.0)
labeling 0.4.2 2020-10-20 [1] CRAN (R 4.3.0)
lattice 0.21-8 2023-04-05 [1] CRAN (R 4.3.0)
lifecycle 1.0.3 2022-10-07 [1] CRAN (R 4.3.0)
lubridate * 1.9.3 2023-09-27 [1] CRAN (R 4.3.1)
magrittr 2.0.3 2022-03-30 [1] CRAN (R 4.3.0)
Matrix 1.5-4.1 2023-05-18 [1] CRAN (R 4.3.0)
munsell 0.5.0 2018-06-12 [1] CRAN (R 4.3.0)
pillar 1.9.0 2023-03-22 [1] CRAN (R 4.3.0)
pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.3.0)
purrr * 1.0.2 2023-08-10 [1] CRAN (R 4.3.0)
R6 2.5.1 2021-08-19 [1] CRAN (R 4.3.0)
rappdirs 0.3.3 2021-01-31 [1] CRAN (R 4.3.0)
Rcpp 1.0.10 2023-01-22 [1] CRAN (R 4.3.0)
readr * 2.1.4 2023-02-10 [1] CRAN (R 4.3.0)
rlang 1.1.1 2023-04-28 [1] CRAN (R 4.3.0)
rmarkdown 2.25 2023-09-18 [1] CRAN (R 4.3.1)
rprojroot 2.0.3 2022-04-02 [1] CRAN (R 4.3.0)
rstudioapi 0.14 2022-08-22 [1] CRAN (R 4.3.0)
scales * 1.2.1 2022-08-20 [1] CRAN (R 4.3.0)
sessioninfo 1.2.2 2021-12-06 [1] CRAN (R 4.3.0)
SnowballC 0.7.1 2023-04-25 [1] CRAN (R 4.3.0)
stopwords 2.3 2021-10-28 [1] CRAN (R 4.3.0)
stringi 1.7.12 2023-01-11 [1] CRAN (R 4.3.0)
stringr * 1.5.0 2022-12-02 [1] CRAN (R 4.3.0)
taylor * 2.0.1.9000 2023-11-01 [1] Github (wjakethompson/taylor@1ac675f)
tayloRswift * 0.2.0 2023-11-02 [1] Github (asteves/tayloRswift@445a16a)
textdata 0.4.4 2022-09-02 [1] CRAN (R 4.3.0)
tibble * 3.2.1 2023-03-20 [1] CRAN (R 4.3.0)
tidyr * 1.3.0 2023-01-24 [1] CRAN (R 4.3.0)
tidyselect 1.2.0 2022-10-10 [1] CRAN (R 4.3.0)
tidytext * 0.4.1 2023-01-07 [1] CRAN (R 4.3.0)
tidyverse * 2.0.0 2023-02-22 [1] CRAN (R 4.3.0)
timechange 0.2.0 2023-01-11 [1] CRAN (R 4.3.0)
tokenizers 0.3.0 2022-12-22 [1] CRAN (R 4.3.0)
tzdb 0.4.0 2023-05-12 [1] CRAN (R 4.3.0)
utf8 1.2.4 2023-10-22 [1] CRAN (R 4.3.1)
vctrs 0.6.4 2023-10-12 [1] CRAN (R 4.3.1)
viridisLite 0.4.2 2023-05-02 [1] CRAN (R 4.3.0)
withr 2.5.2 2023-10-30 [1] CRAN (R 4.3.1)
xfun 0.40 2023-08-09 [1] CRAN (R 4.3.0)
yaml 2.3.7 2023-01-23 [1] CRAN (R 4.3.0)
[1] /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/library
──────────────────────────────────────────────────────────────────────────────