LỜI CẢM ƠN

Nhóm thực hiện xin gửi lời cảm ơn sâu sắc đến giảng viên hướng dẫn ThS.Trần Mạnh Tường đã tận tình hướng dẫn và giải đáp những thắc mắc trong suốt quá trình thực hiện đề tài. Vì sự hạn chế về kiến thức cũng như kỹ năng nên đề tài còn những thiếu sót. Kính mong thầy đánh giá và đóng góp cải thiện để đề tài được hoàn thiện hơn trong tương lai.

PHẦN 1: PHÂN TÍCH HÀNH VI MUA SẮM CỦA KHÁCH HÀNG THEO ĐẶC ĐIỂM NHÂN KHẨU HỌC

1 . Giới thiệu và mã hóa dữ liệu

1.1 Giới thiệu dữ liệu

library(readxl)
## Warning: package 'readxl' was built under R version 4.4.3
library(data.table)
## Warning: package 'data.table' was built under R version 4.4.3
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.4.3
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:data.table':
## 
##     between, first, last
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(tidyr) 
## Warning: package 'tidyr' was built under R version 4.4.3
# 1. Đọc dữ liệu
file_path <- "customers_data.xlsx"
data <- read_excel(file_path)

# 2. Xem tổng quan kích thước dữ liệu
num_rows <- nrow(data)     # số quan sát
num_cols <- ncol(data)     # số biến
cat("Số quan sát:", num_rows, "\n")
## Số quan sát: 100000
cat("Số biến:", num_cols, "\n")
## Số biến: 12
# 3. Tên các biến trong bộ dữ liệu
names(data)
##  [1] "id"                 "age"                "gender"            
##  [4] "income"             "education"          "region"            
##  [7] "loyalty_status"     "purchase_frequency" "purchase_amount"   
## [10] "product_category"   "promotion_usage"    "satisfaction_score"
# 4. Kiểm tra kiểu dữ liệu của từng biến
sapply(data, class)
##                 id                age             gender             income 
##          "numeric"          "numeric"        "character"          "numeric" 
##          education             region     loyalty_status purchase_frequency 
##        "character"        "character"        "character"        "character" 
##    purchase_amount   product_category    promotion_usage satisfaction_score 
##          "numeric"        "character"          "numeric"          "numeric"
# 5. Kiểm tra giá trị thiếu
missing_total <- sum(is.na(data))
missing_by_var <- colSums(is.na(data))
cat("Tổng số giá trị thiếu:", missing_total, "\n")
## Tổng số giá trị thiếu: 0
missing_by_var
##                 id                age             gender             income 
##                  0                  0                  0                  0 
##          education             region     loyalty_status purchase_frequency 
##                  0                  0                  0                  0 
##    purchase_amount   product_category    promotion_usage satisfaction_score 
##                  0                  0                  0                  0
# 6. Kiểm tra các dòng bị trùng lặp 
dup_total <- sum(duplicated(data))
cat("Số quan sát trùng lặp:", dup_total, "\n")
## Số quan sát trùng lặp: 0
# 7. Kiểm tra cấu trúc chi tiết của dữ liệu
str(data)   # Xem cấu trúc: tên biến, kiểu dữ liệu, ví dụ giá trị
## tibble [100,000 × 12] (S3: tbl_df/tbl/data.frame)
##  $ id                : num [1:100000] 1 2 3 4 5 6 7 8 9 10 ...
##  $ age               : num [1:100000] 27 29 37 30 31 38 32 24 27 28 ...
##  $ gender            : chr [1:100000] "Male" "Male" "Male" "Male" ...
##  $ income            : num [1:100000] 40682 15317 38849 11568 46952 ...
##  $ education         : chr [1:100000] "Bachelor" "Masters" "Bachelor" "HighSchool" ...
##  $ region            : chr [1:100000] "East" "West" "West" "South" ...
##  $ loyalty_status    : chr [1:100000] "Gold" "Regular" "Silver" "Regular" ...
##  $ purchase_frequency: chr [1:100000] "frequent" "rare" "rare" "frequent" ...
##  $ purchase_amount   : num [1:100000] 18249 4557 11822 4098 19685 ...
##  $ product_category  : chr [1:100000] "Books" "Clothing" "Clothing" "Food" ...
##  $ promotion_usage   : num [1:100000] 0 1 0 0 1 0 0 0 0 0 ...
##  $ satisfaction_score: num [1:100000] 6 6 6 7 5 5 7 5 5 6 ...
# 8. Tóm tắt mô tả thống kê cơ bản (cho mọi biến)
summary(data)   # Trung bình, min, max, quartile, v.v.
##        id              age        gender              income     
##  Min.   :     1   Min.   :12   Length:100000      Min.   : 5000  
##  1st Qu.: 25001   1st Qu.:27   Class :character   1st Qu.:16272  
##  Median : 50001   Median :30   Mode  :character   Median :27585  
##  Mean   : 50001   Mean   :30                      Mean   :27516  
##  3rd Qu.: 75000   3rd Qu.:33                      3rd Qu.:38747  
##  Max.   :100000   Max.   :49                      Max.   :50000  
##   education            region          loyalty_status     purchase_frequency
##  Length:100000      Length:100000      Length:100000      Length:100000     
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##  purchase_amount product_category   promotion_usage  satisfaction_score
##  Min.   : 1118   Length:100000      Min.   :0.0000   Min.   : 0.00     
##  1st Qu.: 5583   Class :character   1st Qu.:0.0000   1st Qu.: 4.00     
##  Median : 9452   Mode  :character   Median :0.0000   Median : 5.00     
##  Mean   : 9635                      Mean   :0.3008   Mean   : 5.01     
##  3rd Qu.:13350                      3rd Qu.:1.0000   3rd Qu.: 6.00     
##  Max.   :26204                      Max.   :1.0000   Max.   :10.00
# 9. Kiểm tra dữ liệu rỗng hoặc khoảng trắng trong biến ký tự
char_vars <- names(Filter(is.character, data))
for (v in char_vars) {
  empty_count <- sum(trimws(data[[v]]) == "", na.rm = TRUE)
  cat("Biến", v, "có", empty_count, "giá trị rỗng\n")
}
## Biến gender có 0 giá trị rỗng
## Biến education có 0 giá trị rỗng
## Biến region có 0 giá trị rỗng
## Biến loyalty_status có 0 giá trị rỗng
## Biến purchase_frequency có 0 giá trị rỗng
## Biến product_category có 0 giá trị rỗng
# 10. Xem trước vài dòng đầu của dữ liệu
head(data, 10)
## # A tibble: 10 × 12
##       id   age gender income education  region loyalty_status purchase_frequency
##    <dbl> <dbl> <chr>   <dbl> <chr>      <chr>  <chr>          <chr>             
##  1     1    27 Male    40682 Bachelor   East   Gold           frequent          
##  2     2    29 Male    15317 Masters    West   Regular        rare              
##  3     3    37 Male    38849 Bachelor   West   Silver         rare              
##  4     4    30 Male    11568 HighSchool South  Regular        frequent          
##  5     5    31 Female  46952 College    North  Regular        occasional        
##  6     6    38 Male     7347 Bachelor   South  Silver         occasional        
##  7     7    32 Female   8265 Bachelor   South  Silver         frequent          
##  8     8    24 Female  47773 HighSchool North  Regular        rare              
##  9     9    27 Male    19154 College    East   Regular        occasional        
## 10    10    28 Female  24666 HighSchool North  Regular        rare              
## # ℹ 4 more variables: purchase_amount <dbl>, product_category <chr>,
## #   promotion_usage <dbl>, satisfaction_score <dbl>

1.2 Mã hóa dữ liệu

library(knitr)
## Warning: package 'knitr' was built under R version 4.4.3
library(kableExtra)
## Warning: package 'kableExtra' was built under R version 4.4.3
## 
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
## 
##     group_rows
#1.. Chuẩn hóa tên biến về dạng chuẩn
names(data) <- trimws(names(data))
names(data) <- gsub(" ", "_", names(data))
names(data) <- tolower(names(data))


#2. Loại bỏ trùng lặp
data <- distinct(data)

#3. Chuyển kiểu dữ liệu
data$region <- as.factor(data$region)
data$loyalty_status <- as.factor(data$loyalty_status)
data$promotion_usage <- as.factor(data$promotion_usage)
data$income <- as.numeric(data$income)
data$purchase_amount <- as.numeric(data$purchase_amount)
str(data)
## tibble [100,000 × 12] (S3: tbl_df/tbl/data.frame)
##  $ id                : num [1:100000] 1 2 3 4 5 6 7 8 9 10 ...
##  $ age               : num [1:100000] 27 29 37 30 31 38 32 24 27 28 ...
##  $ gender            : chr [1:100000] "Male" "Male" "Male" "Male" ...
##  $ income            : num [1:100000] 40682 15317 38849 11568 46952 ...
##  $ education         : chr [1:100000] "Bachelor" "Masters" "Bachelor" "HighSchool" ...
##  $ region            : Factor w/ 4 levels "East","North",..: 1 4 4 3 2 3 3 2 1 2 ...
##  $ loyalty_status    : Factor w/ 3 levels "Gold","Regular",..: 1 2 3 2 2 3 3 2 2 2 ...
##  $ purchase_frequency: chr [1:100000] "frequent" "rare" "rare" "frequent" ...
##  $ purchase_amount   : num [1:100000] 18249 4557 11822 4098 19685 ...
##  $ product_category  : chr [1:100000] "Books" "Clothing" "Clothing" "Food" ...
##  $ promotion_usage   : Factor w/ 2 levels "0","1": 1 2 1 1 2 1 1 1 1 1 ...
##  $ satisfaction_score: num [1:100000] 6 6 6 7 5 5 7 5 5 6 ...
#4. Tạo bảng mô tả với 4 cột: Biến, Ý nghĩa, Kiểu dữ liệu, Loại biến
variable_description <- data.frame(
  "Biến" = c("id", "age", "gender", "income", "education", "region",
             "loyalty_status", "purchase_frequency", "purchase_amount", 
             "product_category", "promotion_usage", "satisfaction_score"),
  "Ý nghĩa" = c(
    "Mã định danh khách hàng",
    "Tuổi của khách hàng",
    "Giới tính của khách hàng (Nam/Nữ)",
    "Thu nhập hằng năm (USD)",
    "Trình độ học vấn (HighSchool/College/Bachelor/Masters)",
    "Khu vực sinh sống",
    "Mức độ trung thành (Bronze/Silver/Gold/Platinum)",
    "Tần suất mua hàng trong kỳ",
    "Số tiền chi tiêu trong một lần mua (USD)",
    "Loại sản phẩm đã mua",
    "Có sử dụng khuyến mãi hay không (Yes/No)",
    "Mức độ hài lòng (1–10)"
  ),
  "Kiểu dữ liệu" = c(
    "integer",  # id
    "integer",  # age
    "character",  # gender
    "integer",  # income
    "character",  # education
    "character",  # region
    "character",  # loyalty_status
    "character",  # purchase_frequency
    "integer",  # purchase_amount
    "character",  # product_category
    "integer",  # promotion_usage
    "integer"   # satisfaction_score
  ),
  "Loại biến" = c(
    "Định danh",           # id
    "Định lượng",  # age
    "Định tính",  # gender
    "Định lượng",   # income
    "Định tính",  # education
    "Định tính",  # region
    "Định tính",  # loyalty_status
    "Định tính",  # purchase_frequency
    "Định lượng",  # purchase_amount
    "Định tính",  # product_category
    "Định lượng",   # promotion_usage
    "Định lượng"   # satisfaction_score
  )
)

#5. Hiển thị bảng 
variable_description %>%
  kbl(caption = "Bảng 1. Mô tả các biến trong bộ dữ liệu") %>%
  kable_styling(
    full_width = FALSE,
    position = "center",
    bootstrap_options = c("striped", "hover", "condensed", "responsive")
  )
Bảng 1. Mô tả các biến trong bộ dữ liệu
Biến Ý.nghĩa Kiểu.dữ.liệu Loại.biến
id Mã định danh khách hàng integer Định danh
age Tuổi của khách hàng integer Định lượng
gender Giới tính của khách hàng (Nam/Nữ) character Định tính
income Thu nhập hằng năm (USD) integer Định lượng
education Trình độ học vấn (HighSchool/College/Bachelor/Masters) character Định tính
region Khu vực sinh sống character Định tính
loyalty_status Mức độ trung thành (Bronze/Silver/Gold/Platinum) character Định tính
purchase_frequency Tần suất mua hàng trong kỳ character Định tính
purchase_amount Số tiền chi tiêu trong một lần mua (USD) integer Định lượng
product_category Loại sản phẩm đã mua character Định tính
promotion_usage Có sử dụng khuyến mãi hay không (Yes/No) integer Định lượng
satisfaction_score Mức độ hài lòng (1–10) integer Định lượng
#6. Chuẩn hóa tên cột
names(data) <- tolower(names(data))
#7. Loại bỏ giá trị âm hoặc 0 trong purchase_amount
data <- filter(data, purchase_amount > 0)
#8.  Mã hóa promotion_usage thành nhãn
data$promotion_usage <- factor(data$promotion_usage,
                               levels = c(0, 1),
                               labels = c("No", "Yes"))
#9. Tạo biến mới: thu nhập trung bình theo khu vực
region_income <- data %>%
  group_by(region) %>%
  summarise(mean_income = mean(income, na.rm = TRUE))
#10. Chuẩn hóa income
data$income_scaled <- scale(data$income)
#11. Thêm biến nhóm tuổi
data$age_group <- cut(data$age, breaks = c(18, 30, 45, 60, 100),
                      labels = c("18-30", "31-45", "46-60", "60+"))
#12.  Tạo biến nhóm tuổi (AgeGroup) từ biến age
library(dplyr)

data <- data %>%
  mutate(
    AgeGroup = case_when(
      age < 25 ~ "Dưới 25",
      age >= 25 & age < 35 ~ "25-34",
      age >= 35 & age < 45 ~ "35-44",
      age >= 45 & age < 55 ~ "45-54",
      age >= 55 ~ "55 trở lên",
      TRUE ~ NA_character_
    )
  )

# 13. Kiểm tra lại xem đã tạo được chưa
table(data$AgeGroup)
## 
##   25-34   35-44   45-54 Dưới 25 
##   73316   15732      62   10890

2 . Phân tích dữ liệu

2.1 Các thống kê cơ bản

# 1. Tổng quan lại cấu trúc dữ liệu
str(data)
## tibble [100,000 × 15] (S3: tbl_df/tbl/data.frame)
##  $ id                : num [1:100000] 1 2 3 4 5 6 7 8 9 10 ...
##  $ age               : num [1:100000] 27 29 37 30 31 38 32 24 27 28 ...
##  $ gender            : chr [1:100000] "Male" "Male" "Male" "Male" ...
##  $ income            : num [1:100000] 40682 15317 38849 11568 46952 ...
##  $ education         : chr [1:100000] "Bachelor" "Masters" "Bachelor" "HighSchool" ...
##  $ region            : Factor w/ 4 levels "East","North",..: 1 4 4 3 2 3 3 2 1 2 ...
##  $ loyalty_status    : Factor w/ 3 levels "Gold","Regular",..: 1 2 3 2 2 3 3 2 2 2 ...
##  $ purchase_frequency: chr [1:100000] "frequent" "rare" "rare" "frequent" ...
##  $ purchase_amount   : num [1:100000] 18249 4557 11822 4098 19685 ...
##  $ product_category  : chr [1:100000] "Books" "Clothing" "Clothing" "Food" ...
##  $ promotion_usage   : Factor w/ 2 levels "No","Yes": 1 2 1 1 2 1 1 1 1 1 ...
##  $ satisfaction_score: num [1:100000] 6 6 6 7 5 5 7 5 5 6 ...
##  $ income_scaled     : num [1:100000, 1] 1.013 -0.939 0.872 -1.227 1.495 ...
##   ..- attr(*, "scaled:center")= num 27516
##   ..- attr(*, "scaled:scale")= num 12997
##  $ age_group         : Factor w/ 4 levels "18-30","31-45",..: 1 1 2 1 2 2 2 1 1 1 ...
##  $ AgeGroup          : chr [1:100000] "25-34" "25-34" "35-44" "25-34" ...
# 2. Tóm tắt thống kê toàn bộ biến
summary(data)
##        id              age        gender              income     
##  Min.   :     1   Min.   :12   Length:100000      Min.   : 5000  
##  1st Qu.: 25001   1st Qu.:27   Class :character   1st Qu.:16272  
##  Median : 50001   Median :30   Mode  :character   Median :27585  
##  Mean   : 50001   Mean   :30                      Mean   :27516  
##  3rd Qu.: 75000   3rd Qu.:33                      3rd Qu.:38747  
##  Max.   :100000   Max.   :49                      Max.   :50000  
##   education           region      loyalty_status  purchase_frequency
##  Length:100000      East :30074   Gold   : 9898   Length:100000     
##  Class :character   North:19918   Regular:60138   Class :character  
##  Mode  :character   South:20073   Silver :29964   Mode  :character  
##                     West :29935                                     
##                                                                     
##                                                                     
##  purchase_amount product_category   promotion_usage satisfaction_score
##  Min.   : 1118   Length:100000      No :69920       Min.   : 0.00     
##  1st Qu.: 5583   Class :character   Yes:30080       1st Qu.: 4.00     
##  Median : 9452   Mode  :character                   Median : 5.00     
##  Mean   : 9635                                      Mean   : 5.01     
##  3rd Qu.:13350                                      3rd Qu.: 6.00     
##  Max.   :26204                                      Max.   :10.00     
##    income_scaled.V1   age_group       AgeGroup        
##  Min.   :-1.7324495   18-30:53918   Length:100000     
##  1st Qu.:-0.8651772   31-45:45554   Class :character  
##  Median : 0.0052498   46-60:   27   Mode  :character  
##  Mean   : 0.0000000   60+  :    0                     
##  3rd Qu.: 0.8641354   NA's :  501                     
##  Max.   : 1.7299459
# 3. Tính trung bình thu nhập khách hàng 
mean(data$income, na.rm = TRUE)
## [1] 27516.27
# 4. Tính trung vị thu nhập 
median(data$income, na.rm = TRUE)
## [1] 27584.5
# 5. Tính độ lệch chuẩn thu nhập 
sd(data$income, na.rm = TRUE)
## [1] 12996.78
# 6. Tính phương sai thu nhập
var(data$income, na.rm = TRUE)
## [1] 168916358
# 7. Tìm giá trị lớn nhất và nhỏ nhất của thu nhập
min(data$income, na.rm = TRUE)
## [1] 5000
max(data$income, na.rm = TRUE)
## [1] 50000
# 8. Tính tứ phân vị thu nhập 
quantile(data$income, probs = c(0.25, 0.5, 0.75), na.rm = TRUE)
##      25%      50%      75% 
## 16271.75 27584.50 38747.25
# 9. Tính hệ số biến thiên (CV) của thu nhập
cv_income <- sd(data$income, na.rm = TRUE) / mean(data$income, na.rm = TRUE)
cv_income
## [1] 0.4723308
# 10. Tần suất từng nhóm giới tính 
table(data$gender)
## 
## Female   Male 
##  50074  49926
# 11. Tỷ lệ phần trăm giới tính
prop.table(table(data$gender)) * 100
## 
## Female   Male 
## 50.074 49.926
# 12. Thống kê theo vùng (Region) 
table(data$region)
## 
##  East North South  West 
## 30074 19918 20073 29935
# 13. Trung bình thu nhập theo giới tính
aggregate(income ~ gender, data = data, FUN = mean)
##   gender   income
## 1 Female 27507.95
## 2   Male 27524.62
# 14. Trung bình thu nhập theo độ tuổi (Age Group)
aggregate(income ~ AgeGroup, data = data, FUN = mean)
##   AgeGroup   income
## 1    25-34 27517.88
## 2    35-44 27485.33
## 3    45-54 26567.61
## 4  Dưới 25 27555.51
# 15. Trung bình chi tiêu theo giới tính 
aggregate(purchase_amount ~ gender, data = data, FUN = mean)
##   gender purchase_amount
## 1 Female        9634.405
## 2   Male        9635.178
# 16. Hệ số tương quan giữa thu nhập và chi tiêu
cor(data$income, data$purchase_amount, use = "complete.obs")
## [1] 0.9484413
# 17. Kiểm tra phân phối chuẩn của thu nhập
shapiro.test(sample(data$income, 500))  # Lấy mẫu 500 để test
## 
##  Shapiro-Wilk normality test
## 
## data:  sample(data$income, 500)
## W = 0.95492, p-value = 3.158e-11
# 18. Thống kê tần suất khách hàng theo nhóm tuổi 
table(data$AgeGroup)
## 
##   25-34   35-44   45-54 Dưới 25 
##   73316   15732      62   10890
# 19. Tính tổng chi tiêu trung bình của toàn bộ khách hàng-
mean(data$purchase_amount, na.rm = TRUE)
## [1] 9634.791
# 20. So sánh chi tiêu trung bình giữa các vùng 
aggregate(purchase_amount ~ region, data = data, FUN = mean)
##   region purchase_amount
## 1   East        9615.411
## 2  North        9673.362
## 3  South        9648.787
## 4   West        9619.211
# 21. Đếm số lượng khách hàng mỗi nhóm thu nhập
table(cut(data$income, breaks = 5))
## 
## (4.95e+03,1.4e+04]  (1.4e+04,2.3e+04]  (2.3e+04,3.2e+04]  (3.2e+04,4.1e+04] 
##              20061              19816              20007              20206 
##    (4.1e+04,5e+04] 
##              19910
# 22. Phân phối thu nhập theo giới tính
aggregate(income ~ gender, data, summary)
##   gender income.Min. income.1st Qu. income.Median income.Mean income.3rd Qu.
## 1 Female     5000.00       16271.50      27554.50    27507.95       38718.75
## 2   Male     5000.00       16272.50      27615.50    27524.62       38786.75
##   income.Max.
## 1    49998.00
## 2    50000.00
# 23. Tính IQR (khoảng tứ phân vị)
IQR(data$income, na.rm = TRUE)
## [1] 22475.5
# 24. Tính hệ số tương quan Pearson và Spearman
cor(data$income, data$purchase_amount, method = "pearson", use = "complete.obs")
## [1] 0.9484413
cor(data$income, data$purchase_amount, method = "spearman", use = "complete.obs")
## [1] 0.9571268
# 25. Đếm số khách hàng có chi tiêu > trung bình
mean(data$purchase_amount > mean(data$purchase_amount, na.rm = TRUE))
## [1] 0.4882

2.2 Trực quan hóa dữ liệu

library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.4.3
library(dplyr)
library(reshape2)
## Warning: package 'reshape2' was built under R version 4.4.3
## 
## Attaching package: 'reshape2'
## The following object is masked from 'package:tidyr':
## 
##     smiths
## The following objects are masked from 'package:data.table':
## 
##     dcast, melt
# Biểu đồ 1. Phân phối thu nhập khách hàng
ggplot(data, aes(x = income)) +
  geom_histogram(fill = "skyblue", color = "black", bins = 30) +
  geom_vline(aes(xintercept = mean(income, na.rm = TRUE)), color = "red", linetype = "dashed") +
  labs(title = "Biểu đồ 1. Phân phối thu nhập khách hàng", x = "Thu nhập", y = "Tần suất") +
  theme_minimal()

# Biểu đồ 2. Phân phối chi tiêu khách hàng
ggplot(data, aes(x = purchase_amount)) +
  geom_histogram(fill = "lightgreen", color = "black", bins = 25) +
  geom_vline(aes(xintercept = mean(purchase_amount, na.rm = TRUE)), color = "red", linetype = "dotted") +
  labs(title = "Biểu đồ 2. Phân phối chi tiêu khách hàng", x = "Chi tiêu", y = "Tần suất") +
  theme_light()

# Biểu đồ 3. So sánh thu nhập giữa các giới tính
ggplot(data, aes(x = gender, y = income, fill = gender)) +
  geom_boxplot() +
  geom_jitter(width = 0.2, alpha = 0.4) +
  labs(title = "Biểu đồ 3. So sánh thu nhập giữa các giới tính", x = "Giới tính", y = "Thu nhập") +
  theme_bw()

# Biểu đồ 4. Chi tiêu trung bình theo vùng
ggplot(data, aes(x = region, y = purchase_amount, fill = region)) +
  geom_boxplot() +
  labs(title = "Biểu đồ 4. Chi tiêu trung bình theo vùng", x = "Vùng", y = "Chi tiêu") +
  theme_minimal() +
  coord_flip()

# Biểu đồ 5. Phân bố khách hàng theo giới tính
ggplot(data, aes(x = gender, fill = gender)) +
  geom_bar() +
  geom_text(stat = "count", aes(label = after_stat(count)), vjust = -0.5) +
  labs(title = "Biểu đồ 5. Phân bố khách hàng theo giới tính", x = "Giới tính", y = "Số lượng") +
  theme_classic()

# Biểu đồ 6. Số lượng khách hàng theo vùng
ggplot(data, aes(x = region, fill = region)) +
  geom_bar() +
  geom_text(stat = "count", aes(label = after_stat(count)), vjust = -0.3) +
  labs(title = "Biểu đồ 6. Số lượng khách hàng theo vùng địa lý", x = "Vùng", y = "Số lượng") +
  theme_minimal()

# Biểu đồ 7. Chi tiêu trung bình theo giới tính
avg_purchase_amount_gender <- data %>% group_by(gender) %>% summarise(Avgpurchase_amount = mean(purchase_amount, na.rm = TRUE))
ggplot(avg_purchase_amount_gender, aes(x = gender, y = Avgpurchase_amount, fill = gender)) +
  geom_col() +
  geom_text(aes(label = round(Avgpurchase_amount, 0)), vjust = -0.5) +
  labs(title = "Biểu đồ 7. Chi tiêu trung bình theo giới tính", y = "Chi tiêu trung bình") +
  theme_light()

# Biểu đồ 8. Mối quan hệ giữa thu nhập và chi tiêu
ggplot(data, aes(x = income, y = purchase_amount, color = gender)) +
  geom_point(alpha = 0.6) +
  geom_smooth(method = "lm", se = FALSE, color = "black") +
  labs(title = "Biểu đồ 8. Mối quan hệ giữa thu nhập và chi tiêu", x = "Thu nhập", y = "Chi tiêu") +
  theme_bw()
## `geom_smooth()` using formula = 'y ~ x'

# Biểu đồ 9. Quan hệ thu nhập - chi tiêu theo từng vùng
ggplot(data, aes(x = income, y = purchase_amount, color = region)) +
  geom_point(size = 2) +
  geom_smooth(method = "lm", se = FALSE) +
  facet_wrap(~region) +
  labs(title = "Biểu đồ 9. Quan hệ thu nhập - chi tiêu theo từng vùng") +
  theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

# Biểu đồ 10. Phân phối chi tiêu theo giới tính (Violin Plot)
ggplot(data, aes(x = gender, y = purchase_amount, fill = gender)) +
  geom_violin(trim = FALSE) +
  geom_boxplot(width = 0.1, fill = "white") +
  labs(title = "Biểu đồ 10. Phân phối chi tiêu theo giới tính", x = "Giới tính", y = "Chi tiêu") +
  theme_classic()

# Biểu đồ 11. Mật độ phân phối thu nhập theo giới tính
ggplot(data, aes(x = income, fill = gender)) +
  geom_density(alpha = 0.5) +
  labs(title = "Biểu đồ 11. Mật độ phân phối thu nhập theo giới tính", x = "Thu nhập", y = "Mật độ") +
  theme_light()

# Biểu đồ 12. Chi tiêu trung bình theo nhóm tuổi
avg_age <- data %>% group_by(AgeGroup) %>% summarise(Avgpurchase_amount = mean(purchase_amount, na.rm = TRUE))
ggplot(avg_age, aes(x = AgeGroup, y = Avgpurchase_amount, group = 1)) +
  geom_line(color = "blue") +
  geom_point(size = 3) +
  labs(title = "Biểu đồ 12. Chi tiêu trung bình theo nhóm tuổi", x = "Nhóm tuổi", y = "Chi tiêu trung bình") +
  theme_minimal()

# Biểu đồ 13. Tỷ trọng khách hàng theo giới tính (Pie Chart)
gender_share <- data %>% count(gender)
ggplot(gender_share, aes(x = "", y = n, fill = gender)) +
  geom_col(width = 1) +
  coord_polar("y") +
  labs(title = "Biểu đồ 13. Tỷ trọng khách hàng theo giới tính") +
  theme_void()

# Biểu đồ 14. Tỷ trọng khách hàng theo vùng (Pie Chart)
region_share <- data %>% count(region)
ggplot(region_share, aes(x = "", y = n, fill = region)) +
  geom_col(width = 1) +
  coord_polar("y") +
  labs(title = "Biểu đồ 14. Tỷ trọng khách hàng theo vùng") +
  theme_void()

# Biểu đồ 15. Ma trận tương quan giữa các biến số (Heatmap)
num_vars <- select_if(data, is.numeric)
corr_matrix <- cor(num_vars, use = "complete.obs")
melted_corr <- melt(corr_matrix)
ggplot(melted_corr, aes(Var1, Var2, fill = value)) +
  geom_tile() +
  scale_fill_gradient2(low = "red", high = "blue", mid = "white") +
  labs(title = "Biểu đồ 15. Ma trận tương quan giữa các biến số") +
  theme_minimal()

# Biểu đồ 16. So sánh chi tiêu theo giới tính và vùng
ggplot(data, aes(x = gender, y = purchase_amount, fill = gender)) +
  geom_boxplot() +
  facet_wrap(~region) +
  labs(title = "Biểu đồ 16. So sánh chi tiêu theo giới tính và vùng") +
  theme_bw()

# Biểu đồ 17. Thu nhập trung bình theo vùng (Lollipop Chart)
avg_income_region <- data %>% group_by(region) %>% summarise(Avgincome = mean(income, na.rm = TRUE))
ggplot(avg_income_region, aes(x = reorder(region, Avgincome), y = Avgincome)) +
  geom_segment(aes(xend = region, y = 0, yend = Avgincome), color = "gray") +
  geom_point(size = 4, color = "blue") +
  labs(title = "Biểu đồ 17. Thu nhập trung bình theo vùng", x = "Vùng", y = "Thu nhập trung bình") +
  theme_light() +
  coord_flip()

# Biểu đồ 18. Chi tiêu trung bình theo giới tính và vùng
avg_purchase_amount <- data %>% group_by(region, gender) %>% summarise(Avgpurchase_amount = mean(purchase_amount, na.rm = TRUE))
## `summarise()` has grouped output by 'region'. You can override using the
## `.groups` argument.
ggplot(avg_purchase_amount, aes(x = region, y = Avgpurchase_amount, fill = gender)) +
  geom_col(position = "dodge") +
  labs(title = "Biểu đồ 18. Chi tiêu trung bình theo giới tính và vùng", x = "Vùng", y = "Chi tiêu trung bình") +
  theme_minimal()

# Biểu đồ 19. Phân phối chi tiêu theo vùng
ggplot(data, aes(x = purchase_amount, fill = region)) +
  geom_histogram(alpha = 0.6, position = "identity", bins = 30) +
  labs(title = "Biểu đồ 19. Phân phối chi tiêu theo vùng", x = "Chi tiêu", y = "Tần suất") +
  theme_light()

# Biểu đồ 20. Quan hệ giữa thu nhập và chi tiêu (vẽ kèm trendline)
ggplot(data, aes(x = income, y = purchase_amount)) +
  geom_point(aes(color = region), alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, color = "black") +
  labs(title = "Biểu đồ 20. Quan hệ giữa thu nhập và chi tiêu (có đường xu hướng)", 
       x = "Thu nhập", y = "Chi tiêu") +
  theme_classic()
## `geom_smooth()` using formula = 'y ~ x'