R Markdown

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

Including Plots

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()