Load Required Libraries

library(ggplot2)
library(dplyr)
library(readr)
library(tidyr)
library(tm)        
library(wordcloud)     
library(RColorBrewer)
library(sqldf)

Load Datasets

my_working_dir_mac <- "/Users/matthewvasquez/Desktop/Sephora" 
myFile_products <- "products.csv"
myFile_reviews <- "reviews_updated.csv"
myFile_authors <- "authors.csv"

setwd(my_working_dir_mac)

products <- read.csv(myFile_products)
reviews <- read.csv(myFile_reviews)
authors <- read.csv(myFile_authors)

Data Overview

head(reviews)
##   X review_id   author_id product_id rating is_recommended helpfulness
## 1 1   1035085  5229029371    P387511      5              1    1.000000
## 2 2   1035086 35439265952    P387511      2              0    0.500000
## 3 3   1035087 27285381637    P387511      4              0    1.000000
## 4 4   1035088  1696370280    P387511      4              1    0.750000
## 5 5   1035089  2692934863    P387511      4              1    0.933333
## 6 6   1035090  7178152696    P387511      3              0    0.500000
##   total_feedback_count total_neg_feedback_count total_pos_feedback_count
## 1                    3                        0                        3
## 2                    4                        2                        2
## 3                    6                        0                        6
## 4                    4                        1                        3
## 5                   15                        1                       14
## 6                    4                        2                        2
##   submission_date
## 1        11/29/22
## 2         8/12/22
## 3         2/18/22
## 4         1/12/21
## 5         12/9/20
## 6        11/17/20
##                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  review_text
## 1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              This cream is pricey, but it is so worth it! I started getting acne in my 20s from a stressful job  and tried a bunch of expensive products and procedures (chemical peels, facials, microdermabrasion). None of them worked as effectively as this one did. Since using this cream, my face has gotten smooth and soft. I rarely gets pimples now, and when I see one coming, I just apply this cream and it pretty much disappears overnight. On the downside, the fragrance does take a while to get used to because L’Occitane products tend to have a strong (but still pleasant) scent.
## 2 I used this in rotation with the Divine Youth Oil. Neither of these products left me feeling wowed in any way. If anything I found the cream slightly more effective than the oil, but at a price...red itchy spots on my cheeks and jawline area after 2 weeks of use. I’m guessing this was down to the Rosemary extract (the same ingredient that brings a rush of short-lived color to your cheeks - due to its stimulating effect on the skin). The Vitamin C in this did give me a glow which was good, and the texture of this cream was light and totally non-greasy. However something in it reacted negatively with my skin, causing bumps in areas I’ve never had bumps before. Definitely not something I could use as a daily moisturizer, at best, I’d say this is something I could use sparingly, every so often.~ My Sephora Top 7 must-have list ~(My top 7 must-have beauty products of all time, focusing mainly on my purchases at Sephora)1. Hair Loss Treatment: ‘Divine Herbal’ - Hair Oil 2. Shampoo: ’Sephora Collection’ - Deep Cleaning Shampoo3. Face Mask: ‘Peter Thomas Roth’ – Pumpkin Enzyme Mask 4. Pigmentation + Anti-Aging Serum: ‘Divine Herbal’ - Facial Treatment Serum5. Face Scrub: ‘Sisley’ - Botanical Gentle Buffing Cream6. Lip Balm: ‘Nuxe’ – Reve De Miel Lip Balm7. Lip Liner: ‘Sephora Collection’ - Rouge Gel Lip Liner
## 3                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    I really did like this cream but I don’t think I’d buy it again just because of how expensive it is. It smells great with a slightly spicy scent and spreads so smoothly but leaves a slightly greasy feel after application. It’s really moisturizing and lasts a while too but I don’t think it’s a really good value for what it is.
## 4                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   Received a 5 ml sample of this cream, and it’s great! I love a high end moisturizer that is thick and rich, but absorbs easily into skin
## 5                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  I love this face cream - I don’t love the price lol. This weird thing always happens to me when I finish a jar - my skin is amazing while I’m using it, but then if I run out and don’t start a new jar right away, I get super dry patches around my nose and mouth area. It’s like it trains your skin to only accept this expensive af cream and then when you stop, your skin revolts. Anyway, I have oily skin and this never breaks me out. It’s a great cream, but the price makes replacing it annoying, and if I don’t replace it right away my skin freaks out.
## 6                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 It’s a nice cream. It has a smokey, earthy scent to it. When I put it on my skin felt oily, but it dried really quickly. But I can feel it on my skin. I don’t think it’s worth the price.
##             review_title   Pos   Neu   Neg But Compound ReviewTextChars
## 1          My holy grail 0.162 0.757 0.081   2    0.902             573
## 2            Not for me! 0.188 0.791 0.021   1    0.993            1322
## 3                        0.209 0.791 0.000   3    0.946             327
## 4                        0.320 0.680 0.000   1    0.870             136
## 5                        0.199 0.733 0.068   2    0.964             553
## 6 Great scent, oily feel 0.000 0.000 0.000   0    0.000             186
str(reviews)
## 'data.frame':    1536 obs. of  19 variables:
##  $ X                       : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ review_id               : int  1035085 1035086 1035087 1035088 1035089 1035090 1035091 1035092 1035093 1035094 ...
##  $ author_id               : num  5.23e+09 3.54e+10 2.73e+10 1.70e+09 2.69e+09 ...
##  $ product_id              : chr  "P387511" "P387511" "P387511" "P387511" ...
##  $ rating                  : int  5 2 4 4 4 3 2 5 3 3 ...
##  $ is_recommended          : int  1 0 0 1 1 0 0 1 0 1 ...
##  $ helpfulness             : num  1 0.5 1 0.75 0.933 ...
##  $ total_feedback_count    : int  3 4 6 4 15 4 7 2 12 15 ...
##  $ total_neg_feedback_count: int  0 2 0 1 1 2 2 0 7 8 ...
##  $ total_pos_feedback_count: int  3 2 6 3 14 2 5 2 5 7 ...
##  $ submission_date         : chr  "11/29/22" "8/12/22" "2/18/22" "1/12/21" ...
##  $ review_text             : chr  "This cream is pricey, but it is so worth it! I started getting acne in my 20s from a stressful job  and tried a"| __truncated__ "I used this in rotation with the Divine Youth Oil. Neither of these products left me feeling wowed in any way. "| __truncated__ "I really did like this cream but I don’t think I’d buy it again just because of how expensive it is. It smells "| __truncated__ "Received a 5 ml sample of this cream, and it’s great! I love a high end moisturizer that is thick and rich, but"| __truncated__ ...
##  $ review_title            : chr  "My holy grail" "Not for me!" "" "" ...
##  $ Pos                     : num  0.162 0.188 0.209 0.32 0.199 0 0 0 0 0 ...
##  $ Neu                     : num  0.757 0.791 0.791 0.68 0.733 0 0 0 0 0 ...
##  $ Neg                     : num  0.081 0.021 0 0 0.068 0 0 0 0 0 ...
##  $ But                     : int  2 1 3 1 2 0 0 0 0 0 ...
##  $ Compound                : num  0.902 0.993 0.946 0.87 0.964 0 0 0 0 0 ...
##  $ ReviewTextChars         : int  573 1322 327 136 553 186 56 133 207 90 ...

Word Cloud of 5-Star Reviews

docsS <- Corpus(VectorSource(reviews[reviews$rating == 5,]$review_text))

toSpace <- content_transformer(function (x, pattern) gsub(pattern, " ", x))
docsS <- tm_map(docsS, toSpace, "“")
docsS <- tm_map(docsS, toSpace, "”")
docsS <- tm_map(docsS, toSpace, "’")
docsS <- tm_map(docsS, toSpace, "—")
docsS <- tm_map(docsS, content_transformer(tolower))
docsS <- tm_map(docsS, removeNumbers)
docsS <- tm_map(docsS, removePunctuation)
docsS <- tm_map(docsS, removeWords, stopwords("english"))
docsS <- tm_map(docsS, removeWords, c("mer", "la", "loccitane", "cream", "product", "skin", "lamer", "use", "using", "face"))
docsS <- tm_map(docsS, stripWhitespace)

mS <- sort(rowSums(as.matrix(TermDocumentMatrix(docsS))), decreasing = TRUE)
dS <- data.frame(word = names(mS), freq = mS)
head(dS, 20)
##                    word freq
## love               love  335
## dry                 dry  288
## like               like  276
## moisturizer moisturizer  272
## little           little  268
## really           really  268
## long               long  239
## just               just  225
## worth             worth  222
## can                 can  222
## will               will  220
## way                 way  218
## soft               soft  194
## goes               goes  183
## one                 one  175
## amazing         amazing  170
## used               used  169
## creme             creme  167
## time               time  165
## price             price  163

Word Cloud Visualization

set.seed(1234)
wordcloud(words = dS$word, freq = dS$freq, min.freq = 2,
          max.words = 200, random.order = FALSE, rot.per = 0.4, 
          scale = c(2.2, 0.44), colors = brewer.pal(8, "Dark2"))

Analysis of “Immortelle” 5-Star Reviews

FiveStarImmortelle <- sqldf::sqldf("
   SELECT r.review_text
   FROM   products p INNER JOIN reviews r
       ON p.product_id = r.product_id
   WHERE  r.rating = 5 AND product_name LIKE 'Immortelle%'
")

docs <- Corpus(VectorSource(FiveStarImmortelle$review_text))
docs <- tm_map(docs, removePunctuation)
customRemovePunctuation <- content_transformer(function(x) gsub("[[:punct:]]+", "", x))
docs <- tm_map(docs, customRemovePunctuation)
docs <- tm_map(docs, content_transformer(tolower))
docs <- tm_map(docs, removeNumbers)
docs <- tm_map(docs, removeWords, stopwords("english"))
docs <- tm_map(docs, removeWords, c("skin", "cream", "ive", "loccitane"))

m <- sort(rowSums(as.matrix(TermDocumentMatrix(docs))), decreasing = TRUE)
d <- data.frame(word = names(m), freq = m)
head(d, 20)
##                    word freq
## face               face   35
## using             using   32
## product         product   31
## use                 use   31
## like               like   31
## love               love   29
## oily               oily   26
## soft               soft   23
## amazing         amazing   22
## sample           sample   22
## night             night   21
## just               just   20
## one                 one   20
## used               used   20
## dont               dont   20
## really           really   20
## feels             feels   19
## dry                 dry   19
## will               will   19
## moisturizer moisturizer   19

Word Cloud for Immortelle Reviews

set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1, 
          max.words = 200, random.order = FALSE, 
          rot.per = 0.35, colors = brewer.pal(8, "Dark2"))

Product Reviews Data

reviews_products <- sqldf::sqldf("
SELECT r.*, p.brand_name, p.product_name
FROM reviews r 
INNER JOIN products p 
ON r.product_id = p.product_id
")

mean_rating <- mean(reviews_products$rating, na.rm = TRUE)
mean_rating
## [1] 4.038411

Distribution of Ratings

hist(reviews_products$rating, breaks = seq(0.5, 5.5, by = 1), 
     main = "Distribution of Ratings", xlab = "Review Ratings (in Stars)")

Review Length Analysis

mean_length <- mean(reviews$ReviewTextChars, na.rm = TRUE)

ggplot(reviews, aes(x = ReviewTextChars)) +
  geom_histogram(bins = 30, fill = "blue", color = "black") +
  labs(title = "Histogram of Review Lengths", 
       x = "Review Length (Characters)", 
       y = "Frequency")

Classifying Review Types

reviews_products$ReviewType <- ifelse(reviews_products$ReviewTextChars > 404 + 50, "Long",
                                      ifelse(reviews_products$ReviewTextChars < 404 - 50, "Short", "Average"))