---
title: "Group Project"
subtitle: Data Wrangling and Visualisation
author: Jiahua Wu
output: html_document
fontsize: 11pt
---

### **Cleaned Data** 

```{r}
library(readr)
dataset_cleaned <- read_csv("data/dataset_cleaned.csv")
View(dataset_cleaned)
set.seed(1)
```

```{r}
library(dplyr)
library(tibble)
library(tidyverse)

distinct_counts <- dataset_cleaned %>%
  summarise(across(everything(), ~ n_distinct(.x))) %>%
  pivot_longer(cols = everything(),
               names_to = "variable",
               values_to = "n_distinct") %>%
  arrange(desc(n_distinct))

distinct_counts
```
thus, remove customerid

with normalised
```{r}
library(dplyr)
library(ggplot2)
library(purrr)
library(tibble)
library(clustMixType)
library(readr)

df <- dataset_cleaned %>%
  mutate(
    across(
      c(PreferredLoginDevice, PreferredPaymentMode, Gender, PreferedOrderCat, MaritalStatus),
      ~ as.factor(.x)
    ),
    Churn = as.integer(Churn)
  )

df_clust <- df %>%
  select(-CustomerID, -Churn)

num_vars <- df_clust %>%
  select(where(is.numeric)) %>%
  names()

df_clust_scaled <- df_clust %>%
  mutate(
    across(all_of(num_vars), ~ as.numeric(scale(.x)), .names = "{.col}_z")
  )

df_kproto <- df_clust_scaled %>%
  select(
    where(is.factor),
    ends_with("_z")
  ) %>%
  na.omit()

k_grid <- 2:10

wss <- map_dbl(k_grid, function(k) {
  fit <- kproto(df_kproto, k = k)
  fit$tot.withinss
})

elbow_df <- tibble(k = k_grid, tot_withinss = wss)

ggplot(elbow_df, aes(x = k, y = tot_withinss)) +
  geom_line(linewidth = 0.9) +
  geom_point(size = 2) +
  scale_x_continuous(breaks = k_grid) +
  labs(
    x = "Number of clusters (k)",
    y = "Total within-cluster SS",
    title = "Elbow Plot for Determining the Optimal Number of Clusters "
  ) +
  theme_minimal()
```

```{r}
df <- dataset_cleaned %>%
  mutate(
    across(
      c(PreferredLoginDevice, PreferredPaymentMode, Gender, PreferedOrderCat, MaritalStatus),
      as.factor
    ),
    Churn = as.integer(Churn)
  )

df_clust <- df %>%
  select(-CustomerID, -Churn)

num_vars <- df_clust %>%
  select(where(is.numeric)) %>%
  names()

df_kproto <- df_clust %>%
  mutate(across(all_of(num_vars), ~ as.numeric(scale(.x)), .names = "{.col}_z")) %>%
  select(where(is.factor), ends_with("_z")) %>%
  na.omit()

set.seed(1)
k_final <- 4
fit_final <- kproto(df_kproto, k = k_final)

df_clustered <- df %>%
  mutate(row_id = row_number()) %>%
  semi_join(df_kproto %>% mutate(row_id = as.integer(rownames(df_kproto))), by = "row_id") %>%
  mutate(cluster = factor(fit_final$cluster)) %>%
  select(-row_id)

count(df_clustered, cluster)
fit_final$centers

```
```{r}
df_clustered %>%
  group_by(cluster) %>%
  summarise(mean_tenure = mean(Tenure))
```
```{r}

```


```{r}
cluster_counts <- df_clustered %>%
  count(cluster, name = "n") %>%
  mutate(pct = 100 * n / sum(n)) %>%
  arrange(cluster)

cluster_counts
```

```{r}
write.csv(
  df_clustered,
  file = "df_clustered.csv",
  row.names = TRUE
)
```

### **Plot Redefinment** 

```{r}
df_clustered <- df_clustered %>% mutate(cluster = factor(cluster))

churn_by_cluster <- df_clustered %>%
  group_by(cluster) %>%
  summarise(
    n = n(),
    churn_rate = mean(Churn == 1, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(churn_pct = 100 * churn_rate)

ggplot(churn_by_cluster, aes(x = cluster, y = churn_pct)) +
  geom_col(alpha = 0.9) +
  geom_text(aes(label = paste0(round(churn_pct, 1), "%")),
            vjust = -0.3, size = 3.4) +
  geom_text(aes(label = paste0("n=", n)),
            vjust = 1.4, size = 3.0) +
  scale_y_continuous(
    limits = c(0, max(churn_by_cluster$churn_pct) * 1.15),
    expand = c(0, 0)
  ) +
  labs(
    title = "Churn Percentage by Cluster",
    subtitle = "With churn rate (label above bar) and cluster size (label inside bar)",
    x = "Cluster",
    y = "Churn (%)"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```

```{r, message=FALSE, warning=FALSE}
var <- "Tenure"

summ <- df_clustered %>%
  group_by(cluster) %>%
  summarise(mean_val = mean(.data[[var]], na.rm = TRUE), .groups = "drop")

overall <- mean(df_clustered[[var]], na.rm = TRUE)

summ <- summ %>%
  mutate(
    label = round(mean_val, 2),
    vjust_lab = ifelse(mean_val < overall, 1.3, -0.8)
  )

ggplot(summ, aes(x = cluster, y = mean_val)) +
  geom_hline(yintercept = overall, linetype = "dashed", linewidth = 0.6) +
  geom_segment(aes(xend = cluster, y = overall, yend = mean_val), linewidth = 1.1) +
  geom_point(size = 2.6) +
  geom_text(aes(label = label, vjust = vjust_lab), size = 3.2) +
  scale_y_continuous(expand = expansion(mult = c(0.12, 0.18))) +
  labs(
    title = "Average Tenure by Cluster",
    subtitle = "Dashed line shows the overall mean tenure",
    x = "Cluster",
    y = "Mean Tenure"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```


```{r}
library(forcats)

num_vars <- df_clustered %>%
  select(where(is.numeric)) %>%
  names() %>%
  setdiff(c("CustomerID", "Churn"))

pretty_name <- function(x) {
  x %>%
    str_replace_all("([a-z])([A-Z])", "\\1 \\2") %>%
    str_replace_all("To", " to ") %>%
    str_squish()
}

diff_df <- df_clustered %>%
  group_by(cluster) %>%
  summarise(across(all_of(num_vars), ~ mean(.x, na.rm = TRUE)), .groups = "drop") %>%
  pivot_longer(-cluster, names_to = "variable", values_to = "mean_val") %>%
  group_by(variable) %>%
  mutate(z = as.numeric(scale(mean_val))) %>%
  summarise(max_abs_z = max(abs(z), na.rm = TRUE), .groups = "drop") %>%
  arrange(desc(max_abs_z)) %>%
  slice_head(n = 12) %>%
  mutate(
    variable_pretty = pretty_name(variable),
    variable_pretty = fct_reorder(variable_pretty, max_abs_z)
  )

ggplot(diff_df, aes(x = max_abs_z, y = variable_pretty)) +
  geom_point(size = 3) +
  labs(
    title = "Top Numeric Variables Separating the Clusters",
    x = "Maximum gap in z-score normalised cluster means",
    y = NULL
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```

```{r}
var <- "CityTier"

summ <- df_clustered %>%
  group_by(cluster) %>%
  summarise(mean_val = mean(.data[[var]], na.rm = TRUE), .groups = "drop")

overall <- mean(df_clustered[[var]], na.rm = TRUE)

ggplot(summ, aes(x = cluster, y = mean_val)) +
  geom_hline(yintercept = overall, linetype = "dashed", linewidth = 0.6) +
  geom_segment(aes(xend = cluster, y = overall, yend = mean_val), linewidth = 1.1) +
  geom_point(size = 2.6) +
  geom_text(aes(label = round(mean_val, 2)),
            vjust = 1.4, size = 3.2) +
  scale_y_continuous(expand = expansion(mult = c(0.18, 0.12))) +
  labs(
    title = "Average City tier by cluster",
    subtitle = "Dashed line indicates the overall mean city tier",
    x = "Cluster",
    y = "Mean CityTier"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```

```{r}
summ <- df_clustered %>%
  group_by(cluster) %>%
  summarise(mean_val = mean(OrderCount, na.rm = TRUE), .groups = "drop")

overall <- mean(df_clustered$OrderCount, na.rm = TRUE)

ggplot(summ, aes(x = cluster, y = mean_val)) +
  geom_hline(yintercept = overall, linetype = "dashed", linewidth = 0.6) +
  geom_col(alpha = 0.9) +
  geom_text(aes(label = round(mean_val, 2)), vjust = -0.3, size = 3.2) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.18))) +
  labs(
    title = "Average Order Count by Cluster",
    subtitle = "Dashed line indicates the overall mean order count",
    x = "Cluster",
    y = "# of Orders"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```

```{r}
summ <- df_clustered %>%
  group_by(cluster) %>%
  summarise(mean_val = mean(CouponUsed, na.rm = TRUE), .groups = "drop")

overall <- mean(df_clustered$CouponUsed, na.rm = TRUE)

ggplot(summ, aes(x = cluster, y = mean_val)) +
  geom_hline(yintercept = overall, linetype = "dashed", linewidth = 0.6) +
  geom_col(alpha = 0.9) +
  geom_text(aes(label = round(mean_val, 2)), vjust = -0.3, size = 3.2) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.18))) +
  labs(
    title = "Average Coupon Usage by Cluster",
    subtitle = "Dashed line indicates the overall mean coupon usage",
    x = "Cluster",
    y = "# of Coupons Used"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```

```{r}
summ <- df_clustered %>%
  group_by(cluster) %>%
  summarise(mean_val = mean(NumberOfDeviceRegistered, na.rm = TRUE), .groups = "drop")

overall <- mean(df_clustered$NumberOfDeviceRegistered, na.rm = TRUE)

ggplot(summ, aes(x = cluster, y = mean_val)) +
  geom_hline(yintercept = overall, linetype = "dashed", linewidth = 0.6) +
  geom_col(alpha = 0.9) +
  geom_text(aes(label = round(mean_val, 2)), vjust = -0.3, size = 3.2) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.18))) +
  labs(
    title = "Average Number of Registered Devices by Cluster",
    subtitle = "Dashed line indicates the overall mean number of registered devices",
    x = "Cluster",
    y = "# Of Registered Devices"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```


```{r}
summ <- df_clustered %>%
  group_by(cluster) %>%
  summarise(mean_val = mean(HourSpendOnApp, na.rm = TRUE), .groups = "drop")

overall <- mean(df_clustered$HourSpendOnApp, na.rm = TRUE)

ggplot(summ, aes(x = cluster, y = mean_val)) +
  geom_hline(yintercept = overall, linetype = "dashed", linewidth = 0.6) +
  geom_col(alpha = 0.9) +
  geom_text(aes(label = round(mean_val, 2)), vjust = -0.3, size = 3.2) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.18))) +
  labs(
    title = "Average Hours Spent on App by Cluster",
    subtitle = "Dashed line indicates the overall mean hours spent on app",
    x = "Cluster",
    y = "# of Hours Spend On App"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```

```{r}
summ <- df_clustered %>%
  group_by(cluster) %>%
  summarise(mean_val = mean(NumberOfAddress, na.rm = TRUE), .groups = "drop")

overall <- mean(df_clustered$NumberOfAddress, na.rm = TRUE)

ggplot(summ, aes(x = cluster, y = mean_val)) +
  geom_hline(yintercept = overall, linetype = "dashed", linewidth = 0.6) +
  geom_col(alpha = 0.9) +
  geom_text(aes(label = round(mean_val, 2)), vjust = -0.3, size = 3.2) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.18))) +
  labs(
    title = "Average Number of Saved Addresses by Cluster",
    subtitle = "Dashed line indicates the overall mean number of saved addresses",
    x = "Cluster",
    y = "# Of Address"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```

```{r}
summ <- df_clustered %>%
  group_by(cluster) %>%
  summarise(mean_val = mean(DaySinceLastOrder, na.rm = TRUE), .groups = "drop")

overall <- mean(df_clustered$DaySinceLastOrder, na.rm = TRUE)

ggplot(summ, aes(x = cluster, y = mean_val)) +
  geom_hline(yintercept = overall, linetype = "dashed", linewidth = 0.6) +
  geom_col(alpha = 0.9) +
  geom_text(aes(label = round(mean_val, 2)), vjust = -0.3, size = 3.2) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.18))) +
  labs(
    title = "Average Days Since Last Order by Cluster",
    subtitle = "Dashed line indicates the overall mean days since last order",
    x = "Cluster",
    y = "# of Days Since Last Order"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```

```{r}
var <- "CityTier"

summ <- df_clustered %>%
  group_by(cluster) %>%
  summarise(mean_val = mean(.data[[var]], na.rm = TRUE), .groups = "drop")

overall <- mean(df_clustered[[var]], na.rm = TRUE)

summ <- summ %>%
  mutate(
    label = round(mean_val, 2),
    vjust_lab = ifelse(mean_val < overall, 1.4, -0.8)
  )

ggplot(summ, aes(x = cluster, y = mean_val)) +
  geom_hline(yintercept = overall, linetype = "dashed", linewidth = 0.6) +
  geom_segment(aes(xend = cluster, y = overall, yend = mean_val), linewidth = 1.1) +
  geom_point(size = 2.6) +
  geom_text(aes(label = label, vjust = vjust_lab), size = 3.2) +
  scale_y_continuous(expand = expansion(mult = c(0.22, 0.18))) +
  labs(
    title = "Average City Tier by Cluster",
    subtitle = "Dashed line indicates the overall mean city tier",
    x = "Cluster",
    y = "City Tier"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```

```{r}
library(scales)

top_n <- 6

tab <- df_clustered %>%
  filter(!is.na(PreferedOrderCat)) %>%
  mutate(order_cat = fct_lump_n(as.factor(PreferedOrderCat), n = top_n, other_level = "Other")) %>%
  count(cluster, order_cat, name = "n") %>%
  group_by(cluster) %>%
  mutate(pct = n / sum(n)) %>%
  ungroup()

ggplot(tab, aes(x = cluster, y = pct, fill = order_cat)) +
  geom_col(position = "fill") +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  labs(
    title = "Preferred Product Category Mix by Cluster",
    subtitle = paste0("Top ", top_n, " categories shown (remaining grouped as Other)"),
    x = "Cluster",
    y = "% of Customers",
    fill = "Preferred category"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank(),
    legend.position = "right"
  )
```

```{r}
top_n <- 6

tab <- df_clustered %>%
  filter(!is.na(MaritalStatus)) %>%
  mutate(ms = fct_lump_n(as.factor(MaritalStatus), n = top_n, other_level = "Other")) %>%
  count(cluster, ms, name = "n") %>%
  group_by(cluster) %>%
  mutate(pct_in_cluster = n / sum(n)) %>%
  ungroup()

ggplot(tab, aes(x = cluster, y = pct_in_cluster, fill = cluster)) +
  geom_col(alpha = 0.9) +
  facet_wrap(~ms, scales = "free_y") +
  scale_y_continuous(labels = percent_format(accuracy = 1)) +
  labs(
    title = "Marital Status across Clusters",
    x = "Cluster",
    y = "% of customers",
    fill = "Cluster"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank(),
    legend.position = "bottom"
  )
```

```{r}
var <- "Complain"

summ <- df_clustered %>%
  group_by(cluster) %>%
  summarise(mean_val = mean(.data[[var]], na.rm = TRUE), .groups = "drop")

overall <- mean(df_clustered[[var]], na.rm = TRUE)

summ <- summ %>%
  mutate(
    label = round(mean_val, 2),
    vjust_lab = ifelse(mean_val < overall, 1.4, -0.8)
  )

ggplot(summ, aes(x = cluster, y = mean_val)) +
  geom_hline(yintercept = overall, linetype = "dashed", linewidth = 0.6) +
  geom_segment(aes(xend = cluster, y = overall, yend = mean_val), linewidth = 1.1) +
  geom_point(size = 2.6) +
  geom_text(aes(label = label, vjust = vjust_lab), size = 3.2) +
  scale_y_continuous(expand = expansion(mult = c(0.22, 0.18))) +
  labs(
    title = "Average Complaint Rate by Cluster",
    subtitle = "Dashed line indicates the overall mean complaint rate",
    x = "Cluster",
    y = "# of Complains"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank()
  )
```

```{r}
var <- "CashbackAmount"

summ <- df_clustered %>%
  group_by(cluster) %>%
  summarise(cluster_mean = mean(.data[[var]], na.rm = TRUE), .groups = "drop")

overall <- mean(df_clustered[[var]], na.rm = TRUE)

summ <- summ %>%
  mutate(
    overall_mean = overall,
    direction = ifelse(cluster_mean >= overall, "Above overall mean", "Below overall mean")
  )

ggplot(summ, aes(y = cluster)) +
  geom_segment(aes(x = overall_mean, xend = cluster_mean, yend = cluster, colour = direction),
               linewidth = 1.2) +
  geom_point(aes(x = overall_mean), size = 2.8) +
  geom_point(aes(x = cluster_mean, colour = direction), size = 2.8) +
  labs(
    title = "Cashback Amount by Cluster vs Overall Average",
    subtitle = "Dot on the left is the overall mean; dot on the right is the cluster mean",
    x = "Cashback Amount",
    y = "Cluster",
    colour = NULL
  ) +
  theme_minimal(base_size = 11) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.minor = element_blank(),
    legend.position = "bottom"
  )
```




```{r}
library(dplyr)

# df_clustered is what you already created (has cluster + original columns)
cluster_means <- df_clustered %>%
  group_by(cluster) %>%
  summarise(
    n = n(),
    churn_rate = mean(Churn, na.rm = TRUE),
    mean_tenure = mean(Tenure, na.rm = TRUE),
    mean_ordercount = mean(OrderCount, na.rm = TRUE),
    mean_couponused = mean(CouponUsed, na.rm = TRUE),
    mean_cashback = mean(CashbackAmount, na.rm = TRUE),
    complain_rate = mean(Complain, na.rm = TRUE),   # assumes Complain is 0/1
    mean_satisfaction = mean(SatisfactionScore, na.rm = TRUE),
    mean_distance = mean(WarehouseToHome, na.rm = TRUE),
    mean_hours_app = mean(HourSpendOnApp, na.rm = TRUE),
    mean_devices = mean(NumberOfDeviceRegistered, na.rm = TRUE),
    mean_days_since_last = mean(DaySinceLastOrder, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  arrange(cluster)

cluster_means
```




