This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.
When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
summary(cars)
## speed dist
## Min. : 4.0 Min. : 2.00
## 1st Qu.:12.0 1st Qu.: 26.00
## Median :15.0 Median : 36.00
## Mean :15.4 Mean : 42.98
## 3rd Qu.:19.0 3rd Qu.: 56.00
## Max. :25.0 Max. :120.00
You can also embed plots, for example:
Note that the echo = FALSE parameter was added to the
code chunk to prevent printing of the R code that generated the
plot.
library(readxl)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.2 ✔ tibble 3.2.1
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.0.4
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggplot2)
library(dplyr)
#loading the dataset
df<- read_xlsx("C:/Users/PC/Documents/school of statistics/coffee_shop_survey.xlsx")
Coffee <- df
rm(df)
rm(coffee)
## Warning in rm(coffee): object 'coffee' not found
#set the working directory
setwd("C:/Users/PC/Documents/school of statistics")
#view structure of the data
head(Coffee)
## # A tibble: 6 × 9
## Customer_ID Age Gender Visit_Frequency Favorite_Product Satisfaction_Score
## <chr> <dbl> <chr> <dbl> <chr> <dbl>
## 1 CUST001 56 Male 1 Sandwich 2
## 2 CUST002 46 Male 2 Sandwich 1
## 3 CUST003 32 Male 6 Pastry 5
## 4 CUST004 60 Female 2 Pastry 4
## 5 CUST005 25 Female 3 Tea 2
## 6 CUST006 38 Female 7 Pastry 1
## # ℹ 3 more variables: `Time_Spent (min)` <dbl>, Loyalty_Member <chr>,
## # Would_Recommend <chr>
tail(Coffee)
## # A tibble: 6 × 9
## Customer_ID Age Gender Visit_Frequency Favorite_Product Satisfaction_Score
## <chr> <dbl> <chr> <dbl> <chr> <dbl>
## 1 CUST095 42 Male 7 Pastry 2
## 2 CUST096 24 Female 6 Coffee 1
## 3 CUST097 26 Female 2 Tea 5
## 4 CUST098 41 Female 0 Pastry 5
## 5 CUST099 18 Male 7 Tea 4
## 6 CUST100 61 Male 0 Pastry 2
## # ℹ 3 more variables: `Time_Spent (min)` <dbl>, Loyalty_Member <chr>,
## # Would_Recommend <chr>
str(Coffee)
## tibble [100 × 9] (S3: tbl_df/tbl/data.frame)
## $ Customer_ID : chr [1:100] "CUST001" "CUST002" "CUST003" "CUST004" ...
## $ Age : num [1:100] 56 46 32 60 25 38 56 36 40 28 ...
## $ Gender : chr [1:100] "Male" "Male" "Male" "Female" ...
## $ Visit_Frequency : num [1:100] 1 2 6 2 3 7 6 3 0 0 ...
## $ Favorite_Product : chr [1:100] "Sandwich" "Sandwich" "Pastry" "Pastry" ...
## $ Satisfaction_Score: num [1:100] 2 1 5 4 2 1 4 5 4 1 ...
## $ Time_Spent (min) : num [1:100] 53 32 36 31 24 28 16 54 39 37 ...
## $ Loyalty_Member : chr [1:100] "Yes" "No" "Yes" "Yes" ...
## $ Would_Recommend : chr [1:100] "No" "Yes" "Yes" "Yes" ...
#Data cleaning
coffee1<-na.omit(Coffee)
#removing duplicates
coffee2<-coffee1[!duplicated(coffee1),]
ls()
## [1] "Coffee" "coffee1" "coffee2"
#DESCRIPTIVE ANALYSIS #average age of customers visiting the shop
average_age<-mean(coffee2$Age)
print(average_age)
## [1] 40.88
#Gender distribution
library(dplyr)
library(conflicted)
conflicts_prefer(dplyr::filter)
## [conflicted] Will prefer dplyr::filter over any other package.
colnames(coffee2)
## [1] "Customer_ID" "Age" "Gender"
## [4] "Visit_Frequency" "Favorite_Product" "Satisfaction_Score"
## [7] "Time_Spent (min)" "Loyalty_Member" "Would_Recommend"
coffee2%>%
filter(Gender!='')%>%
group_by(Gender)%>%
count()
## # A tibble: 3 × 2
## # Groups: Gender [3]
## Gender n
## <chr> <int>
## 1 Female 43
## 2 Male 49
## 3 Other 8
library(dplyr)
gender_distribution <- coffee2 %>%
filter(!is.na(Gender) & Gender != "") %>%
group_by(Gender) %>%
summarise(count = n())
#Plotting the distribution
ggplot(gender_distribution, aes(x = Gender, y = count, fill = Gender)) +
geom_col() +
labs(
title = "Gender Distribution of Customers",
y = "Total Number of Customers",
x = "Gender of Customers"
) +
theme_minimal()
#count frequency of each favourite product
product_counts <- coffee2 %>%
group_by(Favorite_Product) %>%
summarise(Count = n())%>%
arrange(desc(Count))
most_popular <-product_counts %>%
filter(Count==max(Count))
print(most_popular)
## # A tibble: 1 × 2
## Favorite_Product Count
## <chr> <int>
## 1 Tea 27
#least popular product
least_popular <- product_counts %>%
filter(Count == min(Count))
print(least_popular)
## # A tibble: 2 × 2
## Favorite_Product Count
## <chr> <int>
## 1 Coffee 24
## 2 Sandwich 24
#RELATIONSHIPS & COMPARISON #relationship between age and visit frequency # Spearman correlation
cor.test(coffee2$Visit_Frequency, coffee2$Age, method = "spearman")
## Warning in cor.test.default(coffee2$Visit_Frequency, coffee2$Age, method =
## "spearman"): Cannot compute exact p-value with ties
##
## Spearman's rank correlation rho
##
## data: coffee2$Visit_Frequency and coffee2$Age
## S = 175578, p-value = 0.5965
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
## rho
## -0.05357387
ggplot(coffee2, aes(x = Age, y = Visit_Frequency)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "lm", color = "red") +
ggtitle("Scatter Plot: Age vs Visit Frequency") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
result <- cor.test(coffee2$Visit_Frequency, coffee2$Age, method = "spearman")
## Warning in cor.test.default(coffee2$Visit_Frequency, coffee2$Age, method =
## "spearman"): Cannot compute exact p-value with ties
print(result)
##
## Spearman's rank correlation rho
##
## data: coffee2$Visit_Frequency and coffee2$Age
## S = 175578, p-value = 0.5965
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
## rho
## -0.05357387
#relationship between visit frequency and satisfaction score # Spearman correlation
cor.test(coffee2$Visit_Frequency, coffee2$Satisfaction_Score, method = "spearman")
## Warning in cor.test.default(coffee2$Visit_Frequency,
## coffee2$Satisfaction_Score, : Cannot compute exact p-value with ties
##
## Spearman's rank correlation rho
##
## data: coffee2$Visit_Frequency and coffee2$Satisfaction_Score
## S = 168487, p-value = 0.9133
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
## rho
## -0.01102338
ggplot(coffee2, aes(x = Visit_Frequency, y = Satisfaction_Score)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "lm", color = "red") +
ggtitle("Scatter Plot: Visit_Frequency vs Satisfaction_Score ") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
result <- cor.test(coffee2$Satisfaction_Score, coffee2$Visit_Frequency, method = "spearman")
## Warning in cor.test.default(coffee2$Satisfaction_Score,
## coffee2$Visit_Frequency, : Cannot compute exact p-value with ties
print(result)
##
## Spearman's rank correlation rho
##
## data: coffee2$Satisfaction_Score and coffee2$Visit_Frequency
## S = 168487, p-value = 0.9133
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
## rho
## -0.01102338
#relationship between member and non member
coffee2$Loyalty_Member <- as.factor(coffee2$Loyalty_Member)
#Boxplot
ggplot(coffee2, aes(x = Loyalty_Member, y = `Time_Spent (min)`, fill = Loyalty_Member)) +
geom_boxplot() +
labs(title = "Time Spent: Loyalty Member vs Non-Member",
x = 'Loyalty Member',
y = 'Time Spent (min)') +
theme_minimal()
#customers who would recommend the coffee shop more likely to be loyal
members?
recommend_loyalty <- coffee2 %>%
filter(!is.na(Would_Recommend), !is.na(Loyalty_Member)) %>%
group_by(Would_Recommend, Loyalty_Member) %>%
summarise(count = n()) %>%
ungroup()
## `summarise()` has grouped output by 'Would_Recommend'. You can override using
## the `.groups` argument.
ggplot(recommend_loyalty, aes(x = Loyalty_Member, y = count, fill = Would_Recommend)) +
geom_col(position = "dodge") +
labs(
title = "Recommendation vs Loyalty Membership",
x = "Loyalty Member Status",
y = "Number of Customers"
) +
theme_minimal()
#INSIGHTFUL/ADVANCED QUESTIONS #Factors (age, loyalty status, product
preference) are associated with higher satisfaction scores
# Checking correlations
coffee2 %>%
select(Age, Satisfaction_Score) %>%
cor(use = "complete.obs")
## Age Satisfaction_Score
## Age 1.00000000 -0.01436614
## Satisfaction_Score -0.01436614 1.00000000
# Visual: Satisfaction by Loyalty Status
ggplot(coffee2, aes(x = Loyalty_Member, y = Satisfaction_Score, fill = Loyalty_Member)) +
geom_boxplot() +
labs(
title = "Satisfaction Score by Loyalty Status",
x = "Loyalty Member",
y = "Satisfaction Score"
) +
theme_minimal()
# Visual: Satisfaction by Product Preference
ggplot(coffee2, aes(x = Favorite_Product, y = Satisfaction_Score, fill = Favorite_Product)) +
geom_boxplot() +
labs(
title = "Satisfaction Score by Favorite Product",
x = "Favorite Product",
y = "Satisfaction Score"
) +
theme_minimal()
#Difference in satisfaction scores between customers who prefer coffee
and those who prefer pastries
coffee_pastry <- coffee2 %>%
filter(Favorite_Product %in% c("Coffee", "Pastry")) %>%
group_by(Favorite_Product) %>%
summarise(Average_Satisfaction = mean(Satisfaction_Score, na.rm = TRUE))
# create a bar plot
ggplot(coffee_pastry, aes(x = Favorite_Product, y = Average_Satisfaction, fill = Favorite_Product)) +
geom_col(width = 0.6) +
labs(title = "Average Satisfaction by Favorite Product",
x = "Favorite Product",
y = "Average Satisfaction Score") +
theme_minimal()
#Can we predict whether a customer would recommend the coffee shop based
on other variables?
coffee2$Would_Recommend <- as.factor(coffee2$Would_Recommend)
#Build a model
recommend_model <- glm(Would_Recommend ~ Age + Gender + Visit_Frequency +
Favorite_Product + `Time_Spent (min)` + Loyalty_Member,
data = coffee2, family = "binomial")
# Add predicted varibles from the model dataset
coffee2$predicted_prob <-predict(recommend_model, type = "response")
# convert numerical to characters for consistency
coffee_long <- coffee2 %>%
select(Age, `Time_Spent (min)`, Visit_Frequency, Gender, Favorite_Product, Loyalty_Member,
predicted_prob) %>%
mutate(Age = cut(Age, breaks = 5),
`Time_Spent (min)` = cut(`Time_Spent (min)`, breaks = 5),
Visit_Frequency = as.character(Visit_Frequency),
Gender = as.character(Gender),
Favorite_Product = as.character(Favorite_Product),
Loyalty_Member = as.character(Loyalty_Member)) %>%
pivot_longer(
cols = -predicted_prob,
names_to = "variable",
values_to = "value"
)
ggplot(coffee_long, aes(x = interaction(variable, value), y = predicted_prob, fill = variable)) +
geom_boxplot() +
labs(title = "Predicted Probability of Recommendation",
x = "Variable and Value",
y = "Predicted Probability") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))
#TIME-SPECIFIC
ggplot(coffee2, aes(x = Visit_Frequency)) +
geom_bar(fill = "orange") +
labs(
title = "Visit Frequency Distribution",
x = "Visit Frequency",
y = "Number of Customers"
) +
theme_minimal()
#Is there any seasonality in satisfaction levels?
# Example if you had 'Visit_Date'
set.seed(123) # For reproducibility
coffee <- coffee2 %>%
mutate(Month = factor(sample(month.abb, n(), replace = TRUE), levels = month.abb))
# Now plot Satisfaction Score across Months
ggplot(coffee, aes(x = Month, y = Satisfaction_Score)) +
geom_boxplot(fill = "skyblue") +
labs(
title = "Satisfaction Levels Across Months (Simulated)",
x = "Month",
y = "Satisfaction Score"
) +
theme_minimal()