# only need to run once if you don't have it
#install.packages("readxl")
#install.packages("sqldf")
#install.packages("vader")
# install if you don't have it. 
# only need to run this once, ever
# don't show warnings while knitting
knitr::opts_chunk$set(warning = FALSE, message = FALSE)
library(readxl); library(sqldf); library(vader)
vader::get_vader("The texture is terrible.  Fragrance is nice though.")
##                     word_scores                        compound 
## "{0, 0, 0, -2.1, 0, 0, 1.8, 0}"                        "-0.077" 
##                             pos                             neu 
##                         "0.235"                         "0.504" 
##                             neg                       but_count 
##                         "0.261"                             "0"
# constants
my_working_dir_mac <- "/Users/cassiemarte/Desktop/GBUS461/Sephora"  # working directory if on a Mac

myFile_products <- "products.csv"
myFile_reviews <- "reviews.csv"
myFile_authors <- "authors.csv"
# import data
setwd(my_working_dir_mac)
products <- read.csv(myFile_products)
reviews <- read.csv(myFile_reviews)
authors <- read.csv(myFile_authors)
# take a look at the last 6 rows of a table
tail(reviews)
# calculate VADER sentiments
# first, create a placeholder table, "d"
d <- sqldf("
  SELECT  review_id AS ReviewId, review_text AS ReviewText, 
          0 AS Pos, 0 AS Neu, 0 AS Neg, 0 AS But, 0 AS Compound
  FROM  reviews
")

# then, loop through each review and calculate VADER
for (i in 1:nrow(d)){ #will take ~2 to 10 min., literally
#for (i in 1:5){
  voutput <- get_vader(d[i,2])
  pos <- as.numeric(voutput["pos"])
  neu <- as.numeric(voutput["neu"])
  neg <- as.numeric(voutput["neg"])
  but <- as.numeric(voutput["but_count"])
  compound <- as.numeric(voutput["compound"])
  
  # store the VADER scores inside the placeholder table "d"
  d[i,3] <- pos
  d[i,4] <- neu
  d[i,5] <- neg
  d[i,6] <- but
  d[i,7] <- compound
}
# a sql INNER JOIN to merge reviews with the VADER sentiments we calculated
reviews <- sqldf(
  "SELECT r.*, d.pos, d.neu, d.neg, d.but, d.compound
   FROM   reviews r INNER JOIN d ON
    r.review_id = d.ReviewId
  ")
# output the top 10 lines from a table
head(reviews, 10)
# average VADER sentiments for 1-star reviews
sqldf("
      SELECT AVG(Pos) AS AvgPos, AVG(Neu) AS AvgNeu, AVG(Neg) AS AvgNeg,
            AVG(But) AS AvgBut, AVG(Compound) AS AvgCompound, STDEV(Compound), COUNT(review_id)
      FROM  reviews
      WHERE rating = 1
      ")

On average, 1-star reviews have a low positive sentiment (0.102), high neutral sentiment (0.819), moderate negative sentiment (0.078), and moderate avg “but” count (0.575). The average compound sentiment score is 0.176, which indicates a slightly negative overall sentiment. The standard deviation of the compound score is approximately 0.560, showing there is variability in sentiment within the 1-star reviews.

# average VADER sentiments for 5-star reviews
sqldf("
      SELECT AVG(Pos) AS AvgPos, AVG(Neu) AS AvgNeu, AVG(Neg) AS AvgNeg,
            AVG(But) AS AvgBut, AVG(Compound) AS AvgCompound, STDEV(Compound), COUNT(review_id)
      FROM  reviews
      WHERE rating = 5
      ")

The 5-star reviews are showing high positive sentiment(1.895), moderate neutral sentiment (0.7832), very low negative sentiment (0.027), and a higher avg “but” count compared to 1-star reviews. The average compound sentiment score indicates a positive overall sentiment. The standard deviation of the compound score is 0.331, showing there is variability in sentiment within the 5-star reviews.

# t test. Are the sentiment scores statistically different, 5 star versus 1 star
t.test(reviews[reviews$rating == 5, ]$Compound, reviews[reviews$rating == 1, ]$Compound)
## 
##  Welch Two Sample t-test
## 
## data:  reviews[reviews$rating == 5, ]$Compound and reviews[reviews$rating == 1, ]$Compound
## t = 13.028, df = 187.67, p-value < 2.2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.4941456 0.6704875
## sample estimates:
## mean of x mean of y 
## 0.7584542 0.1761377
# t test. Are the sentiment scores statistically different, 5 star versus 1 star
t.test(reviews[reviews$rating == 5, ]$Compound, reviews[reviews$rating == 1, ]$Compound)
## 
##  Welch Two Sample t-test
## 
## data:  reviews[reviews$rating == 5, ]$Compound and reviews[reviews$rating == 1, ]$Compound
## t = 13.028, df = 187.67, p-value < 2.2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.4941456 0.6704875
## sample estimates:
## mean of x mean of y 
## 0.7584542 0.1761377

The results of the two sample t-test suggest a significant difference in sentiment scores between 5-star and 1-star reviews, with 5-star reviews with substantially higher sentiment scores than 1-star reviews.

t_statistic = 13.028
df = 187.67
p_value_two_tailed <- 2 * (1 - pt(t_statistic, df))
format(p_value_two_tailed, scientific = TRUE, digits = 20)
## [1] "0e+00"
# what is the average length of reviews
# first calculate the lengths in characters
reviews$ReviewTextChars <- nchar(reviews$review_text)

# then take the mean
mean_review_length <- mean(reviews$ReviewTextChars)
print(mean_review_length)
## [1] 404.1374
# select the top 30 rows by review length in SQL
# in other words, here is the list of reviews with the 30 longest lengths
sqldf(" SELECT * 
        FROM reviews
        ORDER BY ReviewTextChars DESC
        LIMIT 30
      ")
# select the bottom 30 rows by review length in SQL
# in other words, here is the list of reviews with the shortest lengths
sqldf(" SELECT * 
        FROM reviews
        ORDER BY ReviewTextChars ASC
        LIMIT 30
      ")
setwd(my_working_dir_mac)
write.csv(reviews, "reviews_updated.csv")
# Define thresholds for long and short reviews 
long_threshold <- mean_review_length + sd(reviews$ReviewTextChars) 
short_threshold <- mean_review_length - sd(reviews$ReviewTextChars) 

# Review length column:
reviews$ReviewLengthCategory <- ifelse(reviews$ReviewTextChars > long_threshold, "Long",
                                       ifelse(reviews$ReviewTextChars < short_threshold, "Short", "Medium"))

# Calculate the average VADER scores for the one-star reviews, long versus short reviews:
average_vader_scores <- aggregate(cbind(Pos, Neu, Neg, But, Compound) ~ ReviewLengthCategory,
                                  data = subset(reviews, rating == 1),
                                  FUN = mean)
average_vader_scores

The VADER output of one-star reviews by review length shows shorter reviews tend have higher negative sentiment (0.105). Longer reviews show slightly higher positive (0.107) and neutral sentiments (0.835) but maintain an overall negative tone.

# Calculate the average VADER scores for the five-star reviews, long versus short reviews:
average_vader_scores_5star <- aggregate(cbind(Pos, Neu, Neg, But, Compound) ~ ReviewLengthCategory,
                                        data = subset(reviews, rating == 5),
                                        FUN = mean)
average_vader_scores_5star

When examining five-star reviews based on length, we find short reviews have the highest amount of positivity (0.293). Medium-length reviews have a positive VADER score of (0.1846). Long reviews, have the lowest positive sentiment compared to other review lengths (0.146).

# t test comparing sentiment scores for long and short reviews in both five-star and one-star ratings
t_test_5star_long_short <- t.test(reviews[reviews$rating == 5 & reviews$ReviewLengthCategory == "Long", ]$Compound,
                                  reviews[reviews$rating == 5 & reviews$ReviewLengthCategory == "Short", ]$Compound)

t_test_1star_long_short <- t.test(reviews[reviews$rating == 1 & reviews$ReviewLengthCategory == "Long", ]$Compound,
                                  reviews[reviews$rating == 1 & reviews$ReviewLengthCategory == "Short", ]$Compound)

t_test_5star_long_short
## 
##  Welch Two Sample t-test
## 
## data:  reviews[reviews$rating == 5 & reviews$ReviewLengthCategory == "Long", ]$Compound and reviews[reviews$rating == 5 & reviews$ReviewLengthCategory == "Short", ]$Compound
## t = 8.1609, df = 135.05, p-value = 2.06e-13
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.2816821 0.4618735
## sample estimates:
## mean of x mean of y 
## 0.8857778 0.5140000
t_test_1star_long_short
## 
##  Welch Two Sample t-test
## 
## data:  reviews[reviews$rating == 1 & reviews$ReviewLengthCategory == "Long", ]$Compound and reviews[reviews$rating == 1 & reviews$ReviewLengthCategory == "Short", ]$Compound
## t = 3.0724, df = 24.008, p-value = 0.00522
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.1843285 0.9387434
## sample estimates:
##   mean of x   mean of y 
## 0.562647059 0.001111111

5-star reviews: The sentiment scores of long reviews are significantly higher than those of short reviews (p < 0.001), with a mean difference of approximately 0.371 to 0.574.

1-star reviews: The sentiment scores of long reviews are also significantly higher than those of short reviews (p = 0.005), with a mean difference of approximately 0.184 to 0.939.

The results suggest that both for one-star and five-star ratings, long reviews tend to have higher sentiment scores compared to short reviews.