Load the data

library(ggplot2)
library(dplyr)
library(knitr)

customers <- read.csv("Mall_Customers.csv",
                      stringsAsFactors = FALSE)

names(customers) <- c(
  "CustomerID",
  "Gender",
  "Age",
  "Annual_Income",
  "Spending_Score"
)

original_observations <- nrow(customers)
original_variables <- ncol(customers)

original_observations
## [1] 200
original_variables
## [1] 5

Select half of the observations

set.seed(2026)

sample_data <- customers %>%
  slice_sample(n = floor(nrow(customers) / 2))

analysis_observations <- nrow(sample_data)

sample_sizes <- data.frame(
  Dataset = c("Original dataset",
              "Sample used for analysis"),
  Observations = c(original_observations,
                   analysis_observations),
  Variables = c(original_variables,
                original_variables)
)

kable(sample_sizes,
      caption = "Sample sizes used in the analysis")
Sample sizes used in the analysis
Dataset Observations Variables
Original dataset 200 5
Sample used for analysis 100 5

The original dataset contains 200 observations and 5 variables. I used 100 observations for the analysis, which is half of the original dataset.

EDA 1: Number of customers by gender

The first exploratory analysis is a bar graph showing the number of customers by gender. This helps describe the makeup of the customer sample.

gender_table <- sample_data %>%
  count(Gender, name = "Number_of_Customers")

kable(gender_table,
      caption = "Number of customers by gender")
Number of customers by gender
Gender Number_of_Customers
Female 56
Male 44
ggplot(gender_table,
       aes(x = Gender,
           y = Number_of_Customers,
           fill = Gender)) +
  geom_col() +
  labs(
    title = "Number of Mall Customers by Gender",
    x = "Gender",
    y = "Number of customers"
  ) +
  theme_minimal() +
  theme(legend.position = "none")

EDA 2: Annual income and spending score

The second exploratory analysis is a scatterplot comparing annual income with spending score. This shows how spending behavior is spread across customers with different income levels.

correlation <- cor(
  sample_data$Annual_Income,
  sample_data$Spending_Score
)

income_spending_summary <- sample_data %>%
  summarise(
    Average_Annual_Income = mean(Annual_Income),
    Average_Spending_Score = mean(Spending_Score),
    Correlation = correlation
  )

kable(
  round(income_spending_summary, 2),
  caption = "Income and spending score calculations"
)
Income and spending score calculations
Average_Annual_Income Average_Spending_Score Correlation
60.87 47.5 -0.17
ggplot(sample_data,
       aes(x = Annual_Income,
           y = Spending_Score)) +
  geom_point(color = "steelblue",
             size = 3,
             alpha = 0.8) +
  geom_smooth(method = "lm",
              se = FALSE,
              color = "darkred") +
  labs(
    title = "Annual Income Compared with Spending Score",
    subtitle = paste("Correlation:",
                     round(correlation, 2)),
    x = "Annual income (thousands of dollars)",
    y = "Spending score (1-100)"
  ) +
  theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

Dataset source

Lokkagle. (n.d.). Mall Customers [Data set]. Kaggle.

https://www.kaggle.com/datasets/lokkagle/mall-customers