0. INTRODUCTION

As a follow up study about sentiment analysis on the Next Generation Science Standards (NGSS) and Common Core State Standards (CCSS), the purpose of this analysis is to investigate how bigrams in sentiment analysis can provide context that should be considered when words are combined with negation words (e.g., not, without, no, and never). Previous analyses of sentiments toward the NGSS and CCSS showed that positive sentiments outweighed negative ones. However, these analyses did not consider how sentiment words could have the opposite meaning when preceded by negation words. Therefore, this analysis using bigrams aims to explore: 1) how many words in the tweets of NGSS and CSSS datasets are combined with negation words, and 2) how much those combinations could impact overall sentiment analysis.


1. PREPARE - set up

library(dplyr)
library(readr)
library(tidyr)
library(rtweet)
library(writexl)
library(readxl)
library(tidytext)
library(textdata)
library(ggplot2)
library(textdata)
library(scales)

2. WRANGLE

2a. Importing Data and Setting up the Dataset

# Importing data 
ngss_tweets <- read_xlsx("/cloud/project/dataset/ngss_tweets.xlsx")
ccss_tweets <- read_xlsx("/cloud/project/dataset/csss_tweets.xlsx")

# Setting up the dataset 
ngss_text <-
  ngss_tweets %>%
  filter(lang == "en") %>%
  select(screen_name, created_at, text) %>%
  mutate(standards = "ngss") %>%
  relocate(standards)

ccss_text <-
  ccss_tweets %>%
  filter(lang == "en") %>%
  select(screen_name, created_at, text) %>%
  mutate(standards = "ccss") %>%
  relocate(standards)

tweets <- bind_rows(ngss_text, ccss_text)

2b. Tokenizing text into bigrams

tweets_bigrams <- tweets %>%
  unnest_tokens(bigram, text, token = "ngrams", n = 2)

tweets_bigrams %>%
  count(bigram, sort = TRUE)
## # A tibble: 25,435 × 2
##    bigram          n
##    <chr>       <int>
##  1 common core  1098
##  2 https t       623
##  3 t co          623
##  4 core math     251
##  5 the common    117
##  6 of the        102
##  7 in the         90
##  8 this is        72
##  9 core is        59
## 10 to the         59
## # ℹ 25,425 more rows
bigrams_separated <- tweets_bigrams %>%
  separate(bigram, c("word1", "word2"), sep = " ")

Now I will count the number of bigrams that are combined with negation words:

bigrams_separated %>%
  filter(word1 == "not") %>%
  count(word1, word2, sort = TRUE)
## # A tibble: 103 × 3
##    word1 word2        n
##    <chr> <chr>    <int>
##  1 not   common       9
##  2 not   a            7
##  3 not   sure         7
##  4 not   in           6
##  5 not   the          6
##  6 not   just         4
##  7 not   as           3
##  8 not   on           3
##  9 not   teaching     3
## 10 not   that         3
## # ℹ 93 more rows
bigrams_separated %>%
  filter(word1 == "no") %>%
  count(word1, word2, sort = TRUE)
## # A tibble: 48 × 3
##    word1 word2              n
##    <chr> <chr>          <int>
##  1 no    one                8
##  2 no    child              7
##  3 no    sense              5
##  4 no    common             4
##  5 no    way                4
##  6 no    idea               3
##  7 no    longer             3
##  8 no    more               3
##  9 no    right              3
## 10 no    indoctrination     2
## # ℹ 38 more rows
bigrams_separated %>%
  filter(word1 == "never") %>%
  count(word1, word2, sort = TRUE)
## # A tibble: 22 × 3
##    word1 word2       n
##    <chr> <chr>   <int>
##  1 never mention     2
##  2 never balance     1
##  3 never be          1
##  4 never been        1
##  5 never brought     1
##  6 never forgive     1
##  7 never get         1
##  8 never hated       1
##  9 never have        1
## 10 never heard       1
## # ℹ 12 more rows
bigrams_separated %>%
  filter(word1 == "without") %>%
  count(word1, word2, sort = TRUE)
## # A tibble: 8 × 3
##   word1   word2        n
##   <chr>   <chr>    <int>
## 1 without being        1
## 2 without blurring     1
## 3 without early        1
## 4 without god          1
## 5 without grades       1
## 6 without him          1
## 7 without the          1
## 8 without your         1

Results show that the number of words that combined with “not” and “no” is greater than the number of words that combined with “never” and “without”.

2c. Sentiment Analysis

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
not_words <- bigrams_separated %>%
  filter(word1 == "not") %>%
  inner_join(afinn, by = c(word2 = "word")) %>%
  count(word2, value, sort = TRUE)

not_words
## # A tibble: 12 × 3
##    word2     value     n
##    <chr>     <dbl> <int>
##  1 like          2     2
##  2 bad          -3     1
##  3 creative      2     1
##  4 free          1     1
##  5 hard         -1     1
##  6 helpful       2     1
##  7 important     2     1
##  8 liked         2     1
##  9 limited      -1     1
## 10 smart         1     1
## 11 support       2     1
## 12 true          2     1
negation_words <- c("not", "no", "never", "without")

negated_words <- bigrams_separated %>%
  filter(word1 %in% negation_words) %>%
  inner_join(afinn, by = c(word2 = "word")) %>%
  count(word1, word2, value, sort = TRUE)

3. VISUALIZATION

negated_words %>%
  mutate(contribution = n * value) %>%
  arrange(desc(abs(contribution))) %>%
  group_by(word1) %>%  
  mutate(word2 = reorder(word2, contribution)) %>%
  ggplot(aes(x = contribution, y = word2, fill = contribution > 0)) +
  geom_col(show.legend = FALSE) +
  labs(x = "Sentiment value * number of occurrences",
       y = "Words preceded by negation term") + 
  facet_wrap(~word1, scales = "free_y", ncol = 1) +
  theme_minimal() +
  theme(axis.text.y = element_text(size = 8))  

The length of the bars represents the influence of a word, calculated as the product of the word’s sentiment score and its frequency of occurrence. This length notably longer in the “no” and “not” graph, indicating that the sentiment conveyed by those words might be substantially altered by the negation. Additionally, the direction of sentiment, shown by the color of the bar, demonstrates that observing whether words following negation words tend to have positive or negative sentiment scores can help understand the overall shift in sentiment caused by the negation.

4. Conclusion

Most negation words except for “without”, show a considerable magnitude of influence that researchers conducting sentiment analysis should consider. This implies that when researchers analyze the sentiments toward NGSS and CCSS, the context of sentiment words should be carefully considered.

LS0tCnRpdGxlOiAiRXhwbG9yaW5nIHRoZSBjb250ZXh0dWFsIGltcGFjdCBvZiBuZWdhdGlvbiB3b3JkcyBvbiBzZW50aW1lbnQgYW5hbHlzaXMiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiBUUlVFCmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyMgMC4gSU5UUk9EVUNUSU9OCgpBcyBhIGZvbGxvdyB1cCBzdHVkeSBhYm91dCBzZW50aW1lbnQgYW5hbHlzaXMgb24gdGhlIE5leHQgR2VuZXJhdGlvbiBTY2llbmNlIApTdGFuZGFyZHMgKE5HU1MpIGFuZCBDb21tb24gQ29yZSBTdGF0ZSBTdGFuZGFyZHMgKENDU1MpLCB0aGUgcHVycG9zZSBvZiB0aGlzIAphbmFseXNpcyBpcyB0byBpbnZlc3RpZ2F0ZSBob3cgYmlncmFtcyBpbiBzZW50aW1lbnQgYW5hbHlzaXMgY2FuIHByb3ZpZGUgCmNvbnRleHQgdGhhdCBzaG91bGQgYmUgY29uc2lkZXJlZCB3aGVuIHdvcmRzIGFyZSBjb21iaW5lZCB3aXRoIG5lZ2F0aW9uIHdvcmRzIAooZS5nLiwgbm90LCB3aXRob3V0LCBubywgYW5kIG5ldmVyKS4gUHJldmlvdXMgYW5hbHlzZXMgb2Ygc2VudGltZW50cyB0b3dhcmQgCnRoZSBOR1NTIGFuZCBDQ1NTIHNob3dlZCB0aGF0IHBvc2l0aXZlIHNlbnRpbWVudHMgb3V0d2VpZ2hlZCBuZWdhdGl2ZSBvbmVzLiAKSG93ZXZlciwgdGhlc2UgYW5hbHlzZXMgZGlkIG5vdCBjb25zaWRlciBob3cgc2VudGltZW50IHdvcmRzIGNvdWxkIGhhdmUgCnRoZSBvcHBvc2l0ZSBtZWFuaW5nIHdoZW4gcHJlY2VkZWQgYnkgbmVnYXRpb24gd29yZHMuIApUaGVyZWZvcmUsIHRoaXMgYW5hbHlzaXMgdXNpbmcgYmlncmFtcyBhaW1zIHRvIGV4cGxvcmU6IAoxKSBob3cgbWFueSB3b3JkcyBpbiB0aGUgdHdlZXRzIG9mIE5HU1MgYW5kIENTU1MgZGF0YXNldHMgYXJlIGNvbWJpbmVkIHdpdGggCm5lZ2F0aW9uIHdvcmRzLCBhbmQgMikgaG93IG11Y2ggdGhvc2UgY29tYmluYXRpb25zIGNvdWxkIGltcGFjdCBvdmVyYWxsIApzZW50aW1lbnQgYW5hbHlzaXMuIAoKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgMS4gUFJFUEFSRSAtIHNldCB1cCAKCmBgYHtyIGxvYWQtcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkocnR3ZWV0KQpsaWJyYXJ5KHdyaXRleGwpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHRleHRkYXRhKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkodGV4dGRhdGEpCmxpYnJhcnkoc2NhbGVzKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgMi4gV1JBTkdMRQoKIyMjIDJhLiBJbXBvcnRpbmcgRGF0YSBhbmQgU2V0dGluZyB1cCB0aGUgRGF0YXNldCAKCmBgYHtyfQojIEltcG9ydGluZyBkYXRhIApuZ3NzX3R3ZWV0cyA8LSByZWFkX3hsc3goIi9jbG91ZC9wcm9qZWN0L2RhdGFzZXQvbmdzc190d2VldHMueGxzeCIpCmNjc3NfdHdlZXRzIDwtIHJlYWRfeGxzeCgiL2Nsb3VkL3Byb2plY3QvZGF0YXNldC9jc3NzX3R3ZWV0cy54bHN4IikKCiMgU2V0dGluZyB1cCB0aGUgZGF0YXNldCAKbmdzc190ZXh0IDwtCiAgbmdzc190d2VldHMgJT4lCiAgZmlsdGVyKGxhbmcgPT0gImVuIikgJT4lCiAgc2VsZWN0KHNjcmVlbl9uYW1lLCBjcmVhdGVkX2F0LCB0ZXh0KSAlPiUKICBtdXRhdGUoc3RhbmRhcmRzID0gIm5nc3MiKSAlPiUKICByZWxvY2F0ZShzdGFuZGFyZHMpCgpjY3NzX3RleHQgPC0KICBjY3NzX3R3ZWV0cyAlPiUKICBmaWx0ZXIobGFuZyA9PSAiZW4iKSAlPiUKICBzZWxlY3Qoc2NyZWVuX25hbWUsIGNyZWF0ZWRfYXQsIHRleHQpICU+JQogIG11dGF0ZShzdGFuZGFyZHMgPSAiY2NzcyIpICU+JQogIHJlbG9jYXRlKHN0YW5kYXJkcykKCnR3ZWV0cyA8LSBiaW5kX3Jvd3Mobmdzc190ZXh0LCBjY3NzX3RleHQpCgpgYGAKCiMjIyAyYi4gVG9rZW5pemluZyB0ZXh0IGludG8gYmlncmFtcwoKYGBge3IgdG9rZW5pemV9CnR3ZWV0c19iaWdyYW1zIDwtIHR3ZWV0cyAlPiUKICB1bm5lc3RfdG9rZW5zKGJpZ3JhbSwgdGV4dCwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDIpCgp0d2VldHNfYmlncmFtcyAlPiUKICBjb3VudChiaWdyYW0sIHNvcnQgPSBUUlVFKQoKYmlncmFtc19zZXBhcmF0ZWQgPC0gdHdlZXRzX2JpZ3JhbXMgJT4lCiAgc2VwYXJhdGUoYmlncmFtLCBjKCJ3b3JkMSIsICJ3b3JkMiIpLCBzZXAgPSAiICIpCgpgYGAKCk5vdyBJIHdpbGwgY291bnQgdGhlIG51bWJlciBvZiBiaWdyYW1zIHRoYXQgYXJlIGNvbWJpbmVkIHdpdGggbmVnYXRpb24gd29yZHM6CgpgYGB7ciBjb3VudC1iaWdyYW1zfQpiaWdyYW1zX3NlcGFyYXRlZCAlPiUKICBmaWx0ZXIod29yZDEgPT0gIm5vdCIpICU+JQogIGNvdW50KHdvcmQxLCB3b3JkMiwgc29ydCA9IFRSVUUpCgpiaWdyYW1zX3NlcGFyYXRlZCAlPiUKICBmaWx0ZXIod29yZDEgPT0gIm5vIikgJT4lCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkKCmJpZ3JhbXNfc2VwYXJhdGVkICU+JQogIGZpbHRlcih3b3JkMSA9PSAibmV2ZXIiKSAlPiUKICBjb3VudCh3b3JkMSwgd29yZDIsIHNvcnQgPSBUUlVFKQoKYmlncmFtc19zZXBhcmF0ZWQgJT4lCiAgZmlsdGVyKHdvcmQxID09ICJ3aXRob3V0IikgJT4lCiAgY291bnQod29yZDEsIHdvcmQyLCBzb3J0ID0gVFJVRSkKYGBgCgpSZXN1bHRzIHNob3cgdGhhdCB0aGUgbnVtYmVyIG9mIHdvcmRzIHRoYXQgY29tYmluZWQgd2l0aCAibm90IiBhbmQgIm5vIiBpcyBncmVhdGVyIHRoYW4gdGhlIG51bWJlciBvZiB3b3JkcyB0aGF0IGNvbWJpbmVkIHdpdGggIm5ldmVyIiBhbmQgIndpdGhvdXQiLgoKIyMjIDJjLiBTZW50aW1lbnQgQW5hbHlzaXMgCgpgYGB7ciBTZW50aW1lbnQgQW5hbHlzaXN9CmFmaW5uIDwtIGdldF9zZW50aW1lbnRzKCJhZmlubiIpCgphZmlubgoKbm90X3dvcmRzIDwtIGJpZ3JhbXNfc2VwYXJhdGVkICU+JQogIGZpbHRlcih3b3JkMSA9PSAibm90IikgJT4lCiAgaW5uZXJfam9pbihhZmlubiwgYnkgPSBjKHdvcmQyID0gIndvcmQiKSkgJT4lCiAgY291bnQod29yZDIsIHZhbHVlLCBzb3J0ID0gVFJVRSkKCm5vdF93b3JkcwoKbmVnYXRpb25fd29yZHMgPC0gYygibm90IiwgIm5vIiwgIm5ldmVyIiwgIndpdGhvdXQiKQoKbmVnYXRlZF93b3JkcyA8LSBiaWdyYW1zX3NlcGFyYXRlZCAlPiUKICBmaWx0ZXIod29yZDEgJWluJSBuZWdhdGlvbl93b3JkcykgJT4lCiAgaW5uZXJfam9pbihhZmlubiwgYnkgPSBjKHdvcmQyID0gIndvcmQiKSkgJT4lCiAgY291bnQod29yZDEsIHdvcmQyLCB2YWx1ZSwgc29ydCA9IFRSVUUpCgpgYGAKCiMjIDMuIFZJU1VBTElaQVRJT04KCgpgYGB7cn0KbmVnYXRlZF93b3JkcyAlPiUKICBtdXRhdGUoY29udHJpYnV0aW9uID0gbiAqIHZhbHVlKSAlPiUKICBhcnJhbmdlKGRlc2MoYWJzKGNvbnRyaWJ1dGlvbikpKSAlPiUKICBncm91cF9ieSh3b3JkMSkgJT4lICAKICBtdXRhdGUod29yZDIgPSByZW9yZGVyKHdvcmQyLCBjb250cmlidXRpb24pKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBjb250cmlidXRpb24sIHkgPSB3b3JkMiwgZmlsbCA9IGNvbnRyaWJ1dGlvbiA+IDApKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGxhYnMoeCA9ICJTZW50aW1lbnQgdmFsdWUgKiBudW1iZXIgb2Ygb2NjdXJyZW5jZXMiLAogICAgICAgeSA9ICJXb3JkcyBwcmVjZWRlZCBieSBuZWdhdGlvbiB0ZXJtIikgKyAKICBmYWNldF93cmFwKH53b3JkMSwgc2NhbGVzID0gImZyZWVfeSIsIG5jb2wgPSAxKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpICAKCmBgYAoKVGhlIGxlbmd0aCBvZiB0aGUgYmFycyByZXByZXNlbnRzIHRoZSBpbmZsdWVuY2Ugb2YgYSB3b3JkLCBjYWxjdWxhdGVkIGFzIHRoZSBwcm9kdWN0IG9mIHRoZSB3b3JkJ3Mgc2VudGltZW50IHNjb3JlIGFuZCBpdHMgZnJlcXVlbmN5IG9mIG9jY3VycmVuY2UuIFRoaXMgbGVuZ3RoIG5vdGFibHkgbG9uZ2VyIGluIHRoZSAibm8iIGFuZCAibm90IiBncmFwaCwgaW5kaWNhdGluZyB0aGF0IHRoZSBzZW50aW1lbnQgY29udmV5ZWQgYnkgdGhvc2Ugd29yZHMgbWlnaHQgYmUgc3Vic3RhbnRpYWxseSBhbHRlcmVkIGJ5IHRoZSBuZWdhdGlvbi4gQWRkaXRpb25hbGx5LCB0aGUgZGlyZWN0aW9uIG9mIHNlbnRpbWVudCwgc2hvd24gYnkgdGhlIGNvbG9yIG9mIHRoZSBiYXIsIGRlbW9uc3RyYXRlcyB0aGF0IG9ic2VydmluZyB3aGV0aGVyIHdvcmRzIGZvbGxvd2luZyBuZWdhdGlvbiB3b3JkcyB0ZW5kIHRvIGhhdmUgcG9zaXRpdmUgb3IgbmVnYXRpdmUgc2VudGltZW50IHNjb3JlcyBjYW4gaGVscCB1bmRlcnN0YW5kIHRoZSBvdmVyYWxsIHNoaWZ0IGluIHNlbnRpbWVudCBjYXVzZWQgYnkgdGhlIG5lZ2F0aW9uLgoKIyMgNC4gQ29uY2x1c2lvbiAKCk1vc3QgbmVnYXRpb24gd29yZHMgZXhjZXB0IGZvciAid2l0aG91dCIsIHNob3cgYSBjb25zaWRlcmFibGUgbWFnbml0dWRlIG9mIGluZmx1ZW5jZSB0aGF0IHJlc2VhcmNoZXJzIGNvbmR1Y3Rpbmcgc2VudGltZW50IGFuYWx5c2lzIHNob3VsZCBjb25zaWRlci4gVGhpcyBpbXBsaWVzIHRoYXQgd2hlbiByZXNlYXJjaGVycyBhbmFseXplIHRoZSBzZW50aW1lbnRzIHRvd2FyZCBOR1NTIGFuZCBDQ1NTLCB0aGUgY29udGV4dCBvZiBzZW50aW1lbnQgd29yZHMgc2hvdWxkIGJlIGNhcmVmdWxseSBjb25zaWRlcmVkLiA=