** Data Source: Twitter data from February 2021 related to NGSS and CCSS Data processing: Tokenized and tided text Data analysis**: Word counts & Sentiment analysis
library(dplyr)
library(readr)
library(tidyr)
library(rtweet)
library(writexl)
library(readxl)
library(tidytext)
library(textdata)
library(ggplot2)
library(textdata)
library(scales)
ngss_tweets <- read_xlsx("data/ngss_tweets.xlsx")
ccss_tweets <- read_xlsx("data/csss_tweets.xlsx")
ngss_text <-
ngss_tweets %>%
filter(lang == "en") %>%
select(screen_name, created_at, text, location) %>%
mutate(standards = "ngss") %>%
relocate(standards)
tweets <- bind_rows(ngss_text, ccss_text)
#head(tweets)
#tail(tweets)
library(dplyr)
filtered_tweets <- filter(tweets, grepl("CA|California", location))
tweet_tokens <-
filtered_tweets %>%
unnest_tokens(output = word,
input = text,
token = "words")
tidy_tweets <-
tweet_tokens %>%
anti_join(stop_words, by = "word")
tidy_tweets <-
tweet_tokens %>%
anti_join(stop_words, by = "word") %>%
filter(!word == "amp")
afinn <- get_sentiments("afinn")
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
bing <- get_sentiments("bing")
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
nrc <- get_sentiments("nrc")
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
loughran <- get_sentiments("loughran")
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
sentiment_afinn <- inner_join(tidy_tweets, afinn, by = "word")
sentiment_afinn
## # A tibble: 106 × 6
## standards screen_name created_at location word value
## <chr> <chr> <dttm> <chr> <chr> <dbl>
## 1 ngss rjmama 2021-02-26 17:56:00 Ohlone homeland (Bay A… awes… 4
## 2 ngss STEM4Real 2021-02-26 01:17:20 California, USA join 1
## 3 ngss STEM4Real 2021-02-26 01:17:20 California, USA comm… 1
## 4 ngss STEM4Real 2021-02-26 01:17:20 California, USA just… 2
## 5 ngss STEM4Real 2021-02-26 15:50:26 California, USA raci… -3
## 6 ngss STEM4Real 2021-02-26 15:50:26 California, USA anti -1
## 7 ngss STEM4Real 2021-02-26 15:50:26 California, USA raci… -3
## 8 ngss STEM4Real 2021-02-26 15:50:26 California, USA share 1
## 9 ngss STEM4Real 2021-02-26 15:50:26 California, USA resp… 2
## 10 ngss STEM4Real 2021-02-23 15:56:57 California, USA comm… 1
## # ℹ 96 more rows
sentiment_bing <- inner_join(tidy_tweets, bing, by = "word")
sentiment_bing
## # A tibble: 111 × 6
## standards screen_name created_at location word sentiment
## <chr> <chr> <dttm> <chr> <chr> <chr>
## 1 ngss rjmama 2021-02-26 17:56:00 Ohlone homeland (B… awes… positive
## 2 ngss STEM4Real 2021-02-26 15:50:26 California, USA raci… negative
## 3 ngss STEM4Real 2021-02-26 15:50:26 California, USA raci… negative
## 4 ngss STEM4Real 2021-02-26 15:50:26 California, USA resp… positive
## 5 ngss SRVUSD_NGSS 2021-02-24 03:51:28 California, USA love positive
## 6 ngss SRVUSD_NGSS 2021-02-23 00:32:10 California, USA amaz… positive
## 7 ngss SRVUSD_NGSS 2021-02-23 00:32:10 California, USA insp… positive
## 8 ngss SRVUSD_NGSS 2021-02-23 00:32:10 California, USA impr… positive
## 9 ngss SRVUSD_NGSS 2021-02-23 20:59:28 California, USA love positive
## 10 ngss SRVUSD_NGSS 2021-02-20 17:47:41 California, USA cong… positive
## # ℹ 101 more rows
## Warning in inner_join(tidy_tweets, nrc, by = "word"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 21 of `x` matches multiple rows in `y`.
## ℹ Row 8556 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
## "many-to-many"` to silence this warning.
## Warning in inner_join(tidy_tweets, loughran, by = "word"): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 921 of `x` matches multiple rows in `y`.
## ℹ Row 3919 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
## "many-to-many"` to silence this warning.
summary_bing <- count(sentiment_bing, sentiment, sort = TRUE)
summary_bing
## # A tibble: 2 × 2
## sentiment n
## <chr> <int>
## 1 positive 63
## 2 negative 48
Since our main goal is to compare positive and negative sentiment
between CCSS and NGSS, let’s use the group_by function
again to get sentiment summaries for NGSS and CCSS
separately:
summary_bing <- sentiment_bing %>%
group_by(standards) %>%
count(sentiment)
summary_bing
## # A tibble: 4 × 3
## # Groups: standards [2]
## standards sentiment n
## <chr> <chr> <int>
## 1 ccss negative 43
## 2 ccss positive 36
## 3 ngss negative 5
## 4 ngss positive 27
summary_bing <- sentiment_bing %>%
group_by(standards) %>%
count(sentiment, sort = TRUE) %>%
spread(sentiment, n)
summary_bing
## # A tibble: 2 × 3
## # Groups: standards [2]
## standards negative positive
## <chr> <int> <int>
## 1 ccss 43 36
## 2 ngss 5 27
summary_bing <- sentiment_bing %>%
group_by(standards) %>%
count(sentiment, sort = TRUE) %>%
spread(sentiment, n) %>%
mutate(sentiment = positive - negative) %>%
mutate(lexicon = "bing") %>%
relocate(lexicon)
summary_bing
## # A tibble: 2 × 5
## # Groups: standards [2]
## lexicon standards negative positive sentiment
## <chr> <chr> <int> <int> <int>
## 1 bing ccss 43 36 -7
## 2 bing ngss 5 27 22
head(sentiment_afinn)
## # A tibble: 6 × 6
## standards screen_name created_at location word value
## <chr> <chr> <dttm> <chr> <chr> <dbl>
## 1 ngss rjmama 2021-02-26 17:56:00 Ohlone homeland (Bay Ar… awes… 4
## 2 ngss STEM4Real 2021-02-26 01:17:20 California, USA join 1
## 3 ngss STEM4Real 2021-02-26 01:17:20 California, USA comm… 1
## 4 ngss STEM4Real 2021-02-26 01:17:20 California, USA just… 2
## 5 ngss STEM4Real 2021-02-26 15:50:26 California, USA raci… -3
## 6 ngss STEM4Real 2021-02-26 15:50:26 California, USA anti -1
summary_afinn <- sentiment_afinn %>%
group_by(standards) %>%
summarise(sentiment = sum(value)) %>%
mutate(lexicon = "AFINN") %>%
relocate(lexicon)
summary_afinn
## # A tibble: 2 × 3
## lexicon standards sentiment
## <chr> <chr> <dbl>
## 1 AFINN ccss -15
## 2 AFINN ngss 53
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
## # A tibble: 2 × 5
## # Groups: standards [2]
## standards method negative positive sentiment
## <chr> <chr> <int> <int> <dbl>
## 1 ccss nrc 34 118 3.47
## 2 ngss nrc 4 67 16.8
## # A tibble: 2 × 5
## # Groups: standards [2]
## standards method negative positive sentiment
## <chr> <chr> <int> <int> <dbl>
## 1 ccss loughran 17 6 0.353
## 2 ngss loughran 3 4 1.33
ngss_text <-
ngss_tweets %>%
filter(lang == "en") %>%
select(status_id, text, location) %>%
mutate(standards = "ngss") %>%
relocate(standards)
ccss_text <-
ccss_tweets %>%
filter(lang == "en") %>%
select(status_id, text, location) %>%
mutate(standards = "ccss") %>%
relocate(standards)
tweets <- bind_rows(ngss_text, ccss_text)
library(dplyr)
filtered_tweets <- filter(tweets, grepl("CA|California", location))
filtered_tweets
## # A tibble: 87 × 4
## standards status_id text location
## <chr> <chr> <chr> <chr>
## 1 ngss 1365359977238433793 "@SRVUSD_NGSS @Meliseymo So Awesome! … Ohlone …
## 2 ngss 1365108654618210306 "@staciekunihisa @WilsonDolphins1 @NY… Califor…
## 3 ngss 1365328375737327620 "Our Clubhouse talk was called \"raci… Califor…
## 4 ngss 1364242855066148867 "What is The STEM4Real Network? \n\nC… Califor…
## 5 ngss 1364422668129234948 "@miss_schilling_ @NGSS_tweeps Unit m… Califor…
## 6 ngss 1364010124663169027 "Amazing panel of educators on this e… Califor…
## 7 ngss 1365325780608184322 "Thank you @Meliseymo for continuing … Califor…
## 8 ngss 1363869840222523396 "So many great suggestions from Edu-T… Califor…
## 9 ngss 1364318984628150273 "I love my job! I partnered a studen… Califor…
## 10 ngss 1363183556617379841 "@sraser88 @NCWITAIC Congratulations,… Califor…
## # ℹ 77 more rows
sentiment_afinn <- filtered_tweets %>%
unnest_tokens(output = word,
input = text,
token = "words") %>%
anti_join(stop_words, by = "word") %>%
filter(!word == "amp") %>%
inner_join(afinn, by = "word")
sentiment_afinn
## # A tibble: 106 × 5
## standards status_id location word value
## <chr> <chr> <chr> <chr> <dbl>
## 1 ngss 1365359977238433793 Ohlone homeland (Bay Area, CA) awesome 4
## 2 ngss 1365108654618210306 California, USA join 1
## 3 ngss 1365108654618210306 California, USA committed 1
## 4 ngss 1365108654618210306 California, USA justice 2
## 5 ngss 1365328375737327620 California, USA racist -3
## 6 ngss 1365328375737327620 California, USA anti -1
## 7 ngss 1365328375737327620 California, USA racism -3
## 8 ngss 1365328375737327620 California, USA share 1
## 9 ngss 1365328375737327620 California, USA responsive 2
## 10 ngss 1364242855066148867 California, USA committed 1
## # ℹ 96 more rows
afinn_score <- sentiment_afinn %>%
group_by(standards, status_id) %>%
summarise(value = sum(value))
afinn_score
## # A tibble: 56 × 3
## # Groups: standards [2]
## standards status_id value
## <chr> <chr> <dbl>
## 1 ccss 1363341600168894467 4
## 2 ccss 1363380595825414144 -2
## 3 ccss 1363664916234727427 0
## 4 ccss 1363677592004354048 -7
## 5 ccss 1363700630569713666 -3
## 6 ccss 1363723464138313728 -3
## 7 ccss 1363743035679404032 4
## 8 ccss 1363977333573439489 -6
## 9 ccss 1364021137370279938 -5
## 10 ccss 1364227817949437965 -4
## # ℹ 46 more rows
afinn_sentiment <- afinn_score %>%
filter(value != 0) %>%
mutate(sentiment = if_else(value < 0, "negative", "positive"))
afinn_sentiment
## # A tibble: 53 × 4
## # Groups: standards [2]
## standards status_id value sentiment
## <chr> <chr> <dbl> <chr>
## 1 ccss 1363341600168894467 4 positive
## 2 ccss 1363380595825414144 -2 negative
## 3 ccss 1363677592004354048 -7 negative
## 4 ccss 1363700630569713666 -3 negative
## 5 ccss 1363723464138313728 -3 negative
## 6 ccss 1363743035679404032 4 positive
## 7 ccss 1363977333573439489 -6 negative
## 8 ccss 1364021137370279938 -5 negative
## 9 ccss 1364227817949437965 -4 negative
## 10 ccss 1364230058647318530 -8 negative
## # ℹ 43 more rows
afinn_ratio <- afinn_sentiment %>%
group_by(standards) %>%
count(sentiment) %>%
spread(sentiment, n) %>%
mutate(ratio = negative/positive)
afinn_ratio
## # A tibble: 2 × 4
## # Groups: standards [2]
## standards negative positive ratio
## <chr> <int> <int> <dbl>
## 1 ccss 16 16 1
## 2 ngss 4 17 0.235
afinn_counts <- afinn_sentiment %>%
group_by(standards) %>%
count(sentiment) %>%
filter(standards == "ngss")
afinn_counts %>%
ggplot(aes(x="", y=n, fill=sentiment)) +
geom_bar(width = .6, stat = "identity") +
labs(title = "Next Gen Science Standards",
subtitle = "Proportion of Positive & Negative Tweets") +
coord_polar(theta = "y") +
theme_void()
summary_afinn2 <- sentiment_afinn %>%
group_by(standards) %>%
filter(value != 0) %>%
mutate(sentiment = if_else(value < 0, "negative", "positive")) %>%
count(sentiment, sort = TRUE) %>%
mutate(method = "AFINN")
summary_bing2 <- sentiment_bing %>%
group_by(standards) %>%
count(sentiment, sort = TRUE) %>%
mutate(method = "bing")
summary_nrc2 <- sentiment_nrc %>%
filter(sentiment %in% c("positive", "negative")) %>%
group_by(standards) %>%
count(sentiment, sort = TRUE) %>%
mutate(method = "nrc")
summary_loughran2 <- sentiment_loughran %>%
filter(sentiment %in% c("positive", "negative")) %>%
group_by(standards) %>%
count(sentiment, sort = TRUE) %>%
mutate(method = "loughran")
summary_sentiment <- bind_rows(summary_afinn2,
summary_bing2,
summary_nrc2,
summary_loughran2) %>%
arrange(method, standards) %>%
relocate(method)
summary_sentiment
## # A tibble: 16 × 4
## # Groups: standards [2]
## method standards sentiment n
## <chr> <chr> <chr> <int>
## 1 AFINN ccss negative 37
## 2 AFINN ccss positive 31
## 3 AFINN ngss positive 32
## 4 AFINN ngss negative 6
## 5 bing ccss negative 43
## 6 bing ccss positive 36
## 7 bing ngss positive 27
## 8 bing ngss negative 5
## 9 loughran ccss negative 17
## 10 loughran ccss positive 6
## 11 loughran ngss positive 4
## 12 loughran ngss negative 3
## 13 nrc ccss positive 118
## 14 nrc ccss negative 34
## 15 nrc ngss positive 67
## 16 nrc ngss negative 4
total_counts <- summary_sentiment %>%
group_by(method, standards) %>%
summarise(total = sum(n))
## `summarise()` has grouped output by 'method'. You can override using the
## `.groups` argument.
sentiment_counts <- left_join(summary_sentiment, total_counts)
## Joining with `by = join_by(method, standards)`
sentiment_counts
## # A tibble: 16 × 5
## # Groups: standards [2]
## method standards sentiment n total
## <chr> <chr> <chr> <int> <int>
## 1 AFINN ccss negative 37 68
## 2 AFINN ccss positive 31 68
## 3 AFINN ngss positive 32 38
## 4 AFINN ngss negative 6 38
## 5 bing ccss negative 43 79
## 6 bing ccss positive 36 79
## 7 bing ngss positive 27 32
## 8 bing ngss negative 5 32
## 9 loughran ccss negative 17 23
## 10 loughran ccss positive 6 23
## 11 loughran ngss positive 4 7
## 12 loughran ngss negative 3 7
## 13 nrc ccss positive 118 152
## 14 nrc ccss negative 34 152
## 15 nrc ngss positive 67 71
## 16 nrc ngss negative 4 71
sentiment_percents <- sentiment_counts %>%
mutate(percent = n/total * 100)
sentiment_percents
## # A tibble: 16 × 6
## # Groups: standards [2]
## method standards sentiment n total percent
## <chr> <chr> <chr> <int> <int> <dbl>
## 1 AFINN ccss negative 37 68 54.4
## 2 AFINN ccss positive 31 68 45.6
## 3 AFINN ngss positive 32 38 84.2
## 4 AFINN ngss negative 6 38 15.8
## 5 bing ccss negative 43 79 54.4
## 6 bing ccss positive 36 79 45.6
## 7 bing ngss positive 27 32 84.4
## 8 bing ngss negative 5 32 15.6
## 9 loughran ccss negative 17 23 73.9
## 10 loughran ccss positive 6 23 26.1
## 11 loughran ngss positive 4 7 57.1
## 12 loughran ngss negative 3 7 42.9
## 13 nrc ccss positive 118 152 77.6
## 14 nrc ccss negative 34 152 22.4
## 15 nrc ngss positive 67 71 94.4
## 16 nrc ngss negative 4 71 5.63
sentiment_percents %>%
ggplot(aes(x = standards, y = percent, fill=sentiment)) +
geom_bar(width = .8, stat = "identity") +
facet_wrap(~method, ncol = 1) +
coord_flip() +
labs(title = "Public Sentiment on Twitter",
subtitle = "The Common Core & Next Gen Science Standards",
x = "",
y = "Percentage of Words")
## Conclusion Overall, sentiment regarding educational reform was more
positive than negative. However, there is a difference in the extent of
negative and positive sentiment for each NGSS and CCSS. In the case of
CCSS, Californians expressed more negative sentiment than positive
sentiment. In contrast, they exhibited more positive sentiment than
negative regarding NGSS.
Even though educational reforms share a similar context, responses to them can vary. If negative sentiment is stronger than positive, such policies may not be successful.Given that the United States has various rules and policy implementations depending on states, it is meaningful to examine the sentiments California has. Studying the effects of CCSS should involve detailed research how stakeholders actually perceive and implement such policies in educational settings.