1 GIỚI THIỆU VỀ VẤN ĐỀ

1.1 Mục tiêu phân tích

Mục tiêu trọng tâm của việc phân tích hồ sơ vay là nhằm định lượng hóa rủi ro tín dụng một cách khách quan và có hệ thống, vượt qua các phương pháp thẩm định định tính truyền thống. Cụ thể, phân tích hướng đến việc xây dựng các mô hình chấm điểm tín dụng (credit scoring) hiệu quả, sử dụng dữ liệu lịch sử và các thuật toán thống kê (hoặc Machine Learning) để ước tính chính xác Xác suất vỡ nợ (Probability of Default - PD) của từng khách hàng. Kết quả phân tích này không chỉ phục vụ mục tiêu tức thời là hỗ trợ ra quyết định phê duyệt hay từ chối khoản vay, mà còn là cơ sở để xác định các yếu tố ảnh hưởng then chốt (key risk drivers) đến khả năng trả nợ. Thông qua đó, tổ chức tín dụng có thể thực thi chiến lược định giá dựa trên rủi ro (risk-based pricing), áp dụng các mức lãi suất, hạn mức và yêu cầu tài sản đảm bảo tương xứng với rủi ro, nhằm tối ưu hóa lợi nhuận và đảm bảo sự an toàn của danh mục cho vay. ## Giải thích thuật ngữ (biến)

TARGET: Biến mục tiêu (1 = khách hàng gặp khó khăn thanh toán, 0 = thanh toán đúng hạn) AMT_CREDIT: Tổng số tiền vay AMT_INCOME_TOTAL: Tổng thu nhập hàng năm DAYS_BIRTH: Số ngày từ ngày sinh đến thời điểm xin vay (âm) EXT_SOURCE: Điểm tín dụng từ nguồn bên ngoài (1-3) DAYS_EMPLOYED: Số ngày làm việc tại công ty hiện tại

2 THÔNG TIN CƠ BẢN VỀ BỘ DỮ LIỆU

library(dplyr)
library(ggplot2)
library(tidyr)
library(scales)
library(kableExtra)
library(tidyverse)
library(patchwork)
library(corrplot)
library(gridExtra)
library(ggthemes)


# Đọc dữ liệu
loan_data <- read.csv("C:/Users/HI HELEN/Downloads/dataFOR_I_am_atomic (1).csv", sep = ";")

# Kiểm tra cấu trúc cơ bản của dataset
cat("=== THÔNG TIN CƠ BẢN VỀ BỘ DỮ LIỆU ===\n")
## === THÔNG TIN CƠ BẢN VỀ BỘ DỮ LIỆU ===
cat("Số quan sát (dòng):", nrow(loan_data), "\n")  
## Số quan sát (dòng): 307511
cat("Số biến (cột):", ncol(loan_data), "\n")      
## Số biến (cột): 29
cat("\n")
# Kiểm tra dữ liệu trùng lặp
cat("Số quan sát trùng lặp:", sum(duplicated(loan_data)), "\n")  
## Số quan sát trùng lặp: 0
cat("\n")
# Kiểm tra dữ liệu thiếu (missing values)
cat("DỮ LIỆU THIẾU THEO TỪNG CỘT:\n")
## DỮ LIỆU THIẾU THEO TỪNG CỘT:
missing_summary <- sapply(loan_data, function(x) sum(is.na(x)))  
print(head(missing_summary, 15)) # Hiển thị 15 cột đầu
##          SK_ID_CURR              TARGET  NAME_CONTRACT_TYPE         CODE_GENDER 
##                   0                   0                   0                   0 
##        FLAG_OWN_CAR     FLAG_OWN_REALTY        CNT_CHILDREN    AMT_INCOME_TOTAL 
##                   0                   0                   0                   0 
##          AMT_CREDIT         AMT_ANNUITY     AMT_GOODS_PRICE     NAME_TYPE_SUITE 
##                   0                  12                 278                   0 
##    NAME_INCOME_TYPE NAME_EDUCATION_TYPE  NAME_FAMILY_STATUS 
##                   0                   0                   0
cat("\n")
# Giải thích ý nghĩa các biến trong dữ liệu 
thong_tin_bien <- data.frame(
  "Tên Biến" = c("TARGET", "AMT_INCOME_TOTAL", "AMT_CREDIT", "CODE_GENDER"),
  "Mô Tả" = c(
    "Biến mục tiêu (1: Khó khăn thanh toán, 0: Thanh toán tốt)",
"Tổng thu nhập hàng năm của khách hàng",
    "Số tiền tín dụng của khoản vay",
    "Giới tính (M: Nam, F: Nữ)"
  )
)

cat("=== Ý NGHĨA CÁC BIẾN QUAN TRỌNG TRONG DATASET ===\n")
## === Ý NGHĨA CÁC BIẾN QUAN TRỌNG TRONG DATASET ===
print(thong_tin_bien)  # SỬA: kable() -> print()
##           Tên.Biến                                                     Mô.Tả
## 1           TARGET Biến mục tiêu (1: Khó khăn thanh toán, 0: Thanh toán tốt)
## 2 AMT_INCOME_TOTAL                     Tổng thu nhập hàng năm của khách hàng
## 3       AMT_CREDIT                            Số tiền tín dụng của khoản vay
## 4      CODE_GENDER                                 Giới tính (M: Nam, F: Nữ)
cat("\n")
# Hiển thị cấu trúc chi tiết của dữ liệu
cat("=== CẤU TRÚC DỮ LIỆU ===\n")
## === CẤU TRÚC DỮ LIỆU ===
str(loan_data[, c("TARGET", "AMT_INCOME_TOTAL", "AMT_CREDIT", "CODE_GENDER")])  
## 'data.frame':    307511 obs. of  4 variables:
##  $ TARGET          : int  1 0 0 0 0 0 0 0 0 0 ...
##  $ AMT_INCOME_TOTAL: chr  "202500.0" "270000.0" "67500.0" "135000.0" ...
##  $ AMT_CREDIT      : num  406598 1293503 135000 312683 513000 ...
##  $ CODE_GENDER     : chr  "M" "F" "M" "F" ...
cat("\n=== THỐNG KÊ MÔ TẢ ===\n")
## 
## === THỐNG KÊ MÔ TẢ ===
summary(loan_data[, c("AMT_INCOME_TOTAL", "AMT_CREDIT")])  
##  AMT_INCOME_TOTAL     AMT_CREDIT     
##  Length:307511      Min.   :  45000  
##  Class :character   1st Qu.: 270000  
##  Mode  :character   Median : 513531  
##                     Mean   : 599026  
##                     3rd Qu.: 808650  
##                     Max.   :4050000

3 DATA CLEANING & TRANSFORMATION

# Chuyển đổi kiểu dữ liệu và xử lý dữ liệu thiếu
data_clean <- loan_data %>%  # SỬA: data -> loan_data
  mutate(
    # Chuyển đổi sang kiểu số
    AMT_INCOME_TOTAL = as.numeric(AMT_INCOME_TOTAL),
    AMT_CREDIT = as.numeric(AMT_CREDIT),
    
    # Xử lý dữ liệu phân loại
    CODE_GENDER = as.factor(CODE_GENDER),
    TARGET = as.factor(TARGET),
    
    # Tạo biến mới phục vụ phân tích
    INCOME_CREDIT_RATIO = AMT_INCOME_TOTAL / AMT_CREDIT,
    
    # Phân loại thu nhập
    INCOME_GROUP = case_when(
      AMT_INCOME_TOTAL < 100000 ~ "Thu nhập thấp",
      AMT_INCOME_TOTAL < 200000 ~ "Thu nhập trung bình",
      TRUE ~ "Thu nhập cao"
    ),
    
    # Phân loại số tiền vay
    CREDIT_GROUP = case_when(
      AMT_CREDIT < 500000 ~ "Vay nhỏ",
      AMT_CREDIT < 1000000 ~ "Vay trung bình",
      TRUE ~ "Vay lớn"
    )
  ) %>%
  filter(!is.na(AMT_INCOME_TOTAL) & !is.na(AMT_CREDIT)) # Loại bỏ dòng thiếu dữ liệu

# Kiểm tra lại cấu trúc sau khi chuyển đổi
cat("=== CẤU TRÚC DỮ LIỆU SAU KHI LÀM SẠCH ===\n")
## === CẤU TRÚC DỮ LIỆU SAU KHI LÀM SẠCH ===
str(data_clean[, c("TARGET", "AMT_INCOME_TOTAL", "AMT_CREDIT", "CODE_GENDER", 
                   "INCOME_CREDIT_RATIO", "INCOME_GROUP", "CREDIT_GROUP")])
## 'data.frame':    307502 obs. of  7 variables:
##  $ TARGET             : Factor w/ 2 levels "0","1": 2 1 1 1 1 1 1 1 1 1 ...
##  $ AMT_INCOME_TOTAL   : num  202500 270000 67500 135000 121500 ...
##  $ AMT_CREDIT         : num  406598 1293503 135000 312683 513000 ...
##  $ CODE_GENDER        : Factor w/ 3 levels "F","M","XNA": 2 1 2 1 2 2 1 2 1 2 ...
##  $ INCOME_CREDIT_RATIO: num  0.498 0.209 0.5 0.432 0.237 ...
##  $ INCOME_GROUP       : chr  "Thu nhập cao" "Thu nhập cao" "Thu nhập thấp" "Thu nhập trung bình" ...
##  $ CREDIT_GROUP       : chr  "Vay nhỏ" "Vay lớn" "Vay nhỏ" "Vay nhỏ" ...
cat("\n=== 10 DÒNG ĐẦU TIÊN SAU KHI XỬ LÝ ===\n")
## 
## === 10 DÒNG ĐẦU TIÊN SAU KHI XỬ LÝ ===
head(data_clean[, c("TARGET", "AMT_INCOME_TOTAL", "AMT_CREDIT", "CODE_GENDER")], 10)
##    TARGET AMT_INCOME_TOTAL AMT_CREDIT CODE_GENDER
## 1       1           202500   406597.5           M
## 2       0           270000  1293502.5           F
## 3       0            67500   135000.0           M
## 4       0           135000   312682.5           F
## 5       0           121500   513000.0           M
## 6       0            99000   490495.5           M
## 7       0           171000  1560726.0           F
## 8       0           360000  1530000.0           M
## 9       0           112500  1019610.0           F
## 10      0           135000   405000.0           M

4 PHÂN TÍCH KHẢ NĂNG THANH TOÁN NỢ CỦA KHÁCH HÀNG QUA CÁC CHỈ TIÊU

4.1 PHÂN PHỐI BIẾN MỤC TIÊU

ggplot(loan_data, aes(x = factor(TARGET, labels = c("Thanh toán tốt", "Khó khăn thanh toán")))) +
  geom_bar(aes(y = ..count.., fill = factor(TARGET)), alpha = 0.8) +
  geom_text(aes(label = ..count..), stat = "count", vjust = -0.5, size = 5) +
  scale_fill_manual(values = c("0" = "#2E8B57", "1" = "#DC143C"), 
                    labels = c("Thanh toán tốt", "Khó khăn thanh toán")) +
  labs(title = "PHÂN PHỐI BIẾN MỤC TIÊU (TARGET)",
       subtitle = "Tỷ lệ khách hàng gặp khó khăn thanh toán",
       x = "Tình trạng thanh toán",
       y = "Số lượng khách hàng",
       fill = "Tình trạng") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5),
        legend.position = "top")

# Giải thích: Biểu đồ này cho thấy tỷ lệ mất cân bằng trong dữ liệu, với đa số khách hàng thanh toán tốt.

4.2 PHÂN PHỐI THU NHẬP THEO TÌNH TRẠNG THANH TOÁN

# CHUYỂN ĐỔI DỮ LIỆU TRƯỚC KHI VẼ BIỂU ĐỒ
loan_data_numeric <- loan_data %>%
  mutate(
    AMT_INCOME_TOTAL = as.numeric(AMT_INCOME_TOTAL),
    AMT_CREDIT = as.numeric(AMT_CREDIT)
  ) %>%
  filter(!is.na(AMT_INCOME_TOTAL) & !is.na(AMT_CREDIT))

p1 <- ggplot(loan_data_numeric, aes(x = AMT_INCOME_TOTAL, fill = factor(TARGET))) +
  geom_histogram(alpha = 0.7, bins = 30, position = "identity") +
  scale_fill_manual(values = c("0" = "#2E8B57", "1" = "#DC143C"),
                    labels = c("Thanh toán tốt", "Khó khăn thanh toán")) +
  scale_x_continuous(labels = comma) +
  labs(title = "Phân phối thu nhập theo tình trạng thanh toán",
       x = "Tổng thu nhập",
       y = "Tần suất",
       fill = "Tình trạng") +
  theme_minimal()

p2 <- ggplot(loan_data_numeric, aes(x = factor(TARGET), y = AMT_INCOME_TOTAL, fill = factor(TARGET))) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_manual(values = c("0" = "#2E8B57", "1" = "#DC143C")) +
  scale_y_continuous(labels = comma) +
  labs(title = "Boxplot thu nhập theo tình trạng thanh toán",
       x = "Tình trạng thanh toán",
       y = "Tổng thu nhập") +
  theme_minimal() +
  theme(legend.position = "none")

p1 + p2 + plot_layout(ncol = 2)

# Giải thích: Không có sự khác biệt rõ ràng về phân phối thu nhập giữa hai nhóm, 
# nhưng nhóm khó khăn thanh toán có xu hướng thu nhập thấp hơn.

4.3 MỐI QUAN HỆ GIỮA THU NHẬP VÀ SỐ TIỀN VAY

# ĐẢM BẢO DỮ LIỆU LÀ NUMERIC VÀ LOẠI BỎ GIÁ TRỊ <= 0
loan_data_log <- loan_data_numeric %>%
  filter(AMT_INCOME_TOTAL > 0 & AMT_CREDIT > 0) %>%  # LOẠI BỎ GIÁ TRỊ <= 0 VÌ KHÔNG THỂ LOG
  mutate(
    LOG_INCOME = log10(AMT_INCOME_TOTAL),  # TÍNH LOG TRƯỚC
    LOG_CREDIT = log10(AMT_CREDIT)
  )

ggplot(loan_data_log, aes(x = LOG_INCOME, y = LOG_CREDIT, color = factor(TARGET))) +
  geom_point(alpha = 0.6, size = 2) +
  geom_smooth(method = "lm", se = FALSE, aes(group = factor(TARGET))) +
  scale_color_manual(values = c("0" = "#2E8B57", "1" = "#DC143C"),
                     labels = c("Thanh toán tốt", "Khó khăn thanh toán")) +
  scale_x_continuous(labels = function(x) comma(10^x)) +  # CHUYỂN NGƯỢC LẠI ĐỂ HIỂN THỊ
  scale_y_continuous(labels = function(x) comma(10^x)) +
  labs(title = "MỐI QUAN HỆ GIỮA THU NHẬP VÀ SỐ TIỀN VAY",
       subtitle = "Thang logarit để dễ quan sát mối quan hệ tuyến tính",
       x = "Tổng thu nhập (log scale)",
       y = "Số tiền vay (log scale)",
       color = "Tình trạng thanh toán") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5))

# Giải thích: Có mối tương quan tích cực giữa thu nhập và số tiền vay. 
# Khách hàng có thu nhập cao thường vay nhiều hơn.
# Sử dụng log scale giúp quan sát rõ hơn mối quan hệ tuyến tính giữa các biến.

4.4 PHÂN PHỐI LOẠI HỢP ĐỒNG

contract_data <- loan_data %>%
  group_by(NAME_CONTRACT_TYPE, TARGET) %>%
  summarise(Count = n(), .groups = 'drop') %>%
  mutate(TARGET = factor(TARGET, labels = c("Thanh toán tốt", "Khó khăn thanh toán")))

ggplot(contract_data, aes(x = NAME_CONTRACT_TYPE, y = Count, fill = TARGET)) +
  geom_bar(stat = "identity", position = "fill", alpha = 0.8) +
  geom_text(aes(label = Count), position = position_fill(vjust = 0.5), 
            color = "white", size = 4, fontface = "bold") +
  scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  scale_y_continuous(labels = percent) +
  labs(title = "PHÂN PHỐI LOẠI HỢP ĐỒNG THEO TÌNH TRẠNG THANH TOÁN",
       subtitle = "Tỷ lệ phần trăm theo từng loại hợp đồng",
       x = "Loại hợp đồng",
       y = "Tỷ lệ phần trăm",
       fill = "Tình trạng thanh toán") +
  coord_flip() +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Giải thích: Cash loans chiếm đa số trong danh mục cho vay. 
# Tỷ lệ khó khăn thanh toán tương đối đồng đều giữa các loại hợp đồng.

4.5 PHÂN PHỐI GIỚI TÍNH

# XỬ LÝ DỮ LIỆU GIỚI TÍNH TRƯỚC
gender_data <- loan_data %>%
  mutate(
    # XỬ LÝ GIÁ TRỊ XNA TRONG CODE_GENDER
    CODE_GENDER = case_when(
      CODE_GENDER %in% c("M", "F") ~ CODE_GENDER,
      TRUE ~ "Other"  # GỘP CÁC GIÁ TRỊ KHÁC THÀNH "Other"
    ),
    # CHUYỂN ĐỔI TARGET VỚI ĐÚNG SỐ LƯỢNG LABELS
    TARGET_LABEL = factor(TARGET, levels = c(0, 1), labels = c("Thanh toán tốt", "Khó khăn thanh toán"))
  ) %>%
  group_by(CODE_GENDER, TARGET_LABEL) %>%
  summarise(Count = n(), .groups = 'drop') %>%
  group_by(CODE_GENDER) %>%
  mutate(Percentage = Count / sum(Count) * 100)

ggplot(gender_data, aes(x = CODE_GENDER, y = Count, fill = TARGET_LABEL)) +
  geom_bar(stat = "identity", position = "stack", alpha = 0.8) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_stack(vjust = 0.5), 
            color = "white", size = 5, fontface = "bold") +
  scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  scale_x_discrete(labels = c("M" = "Nam", "F" = "Nữ", "Other" = "Khác")) +
  labs(title = "PHÂN PHỐI GIỚI TÍNH THEO TÌNH TRẠNG THANH TOÁN",
       subtitle = "Tỷ lệ phần trăm cho mỗi nhóm giới tính",
       x = "Giới tính",
       y = "Số lượng khách hàng",
fill = "Tình trạng thanh toán") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Giải thích: Nữ giới chiếm tỷ lệ cao hơn trong danh mục cho vay. 
# Tỷ lệ khó khăn thanh toán có sự khác biệt theo giới tính.

4.6 TUỔI KHÁCH HÀNG VÀ RỦI RO TÍN DỤNG

# Chuyển đổi DAYS_BIRTH sang tuổi
loan_data$AGE <- round(-loan_data$DAYS_BIRTH / 365.25, 1)

ggplot(loan_data, aes(x = AGE, fill = factor(TARGET))) +
  geom_histogram(aes(y = ..density..), alpha = 0.7, bins = 30, position = "identity") +
  geom_density(alpha = 0.5, aes(color = factor(TARGET))) +
  scale_fill_manual(values = c("0" = "#2E8B57", "1" = "#DC143C"),
                    labels = c("Thanh toán tốt", "Khó khăn thanh toán")) +
  scale_color_manual(values = c("0" = "#2E8B57", "1" = "#DC143C"),
                     labels = c("Thanh toán tốt", "Khó khăn thanh toán")) +
  labs(title = "PHÂN PHỐI TUỔI THEO TÌNH TRẠNG THANH TOÁN",
       subtitle = "Mật độ phân phối tuổi khách hàng",
       x = "Tuổi",
       y = "Mật độ",
       fill = "Tình trạng thanh toán",
       color = "Tình trạng thanh toán") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Giải thích: Khách hàng trẻ tuổi có xu hướng gặp khó khăn thanh toán cao hơn, 
# phù hợp với lý thuyết rủi ro tín dụng.

4.7 TRẠNG THÁI VIỆC LÀM

# Xử lý DAYS_EMPLOYED (giá trị lớn bất thường)
loan_data$EMPLOYMENT_STATUS <- ifelse(loan_data$DAYS_EMPLOYED > 0, "Đã nghỉ hưu", "Đang làm việc")

employment_data <- loan_data %>%
  group_by(EMPLOYMENT_STATUS, TARGET) %>%
  summarise(Count = n(), .groups = 'drop') %>%
  group_by(EMPLOYMENT_STATUS) %>%
  mutate(Percentage = Count / sum(Count) * 100,
         TARGET = factor(TARGET, labels = c("Thanh toán tốt", "Khó khăn thanh toán")))

ggplot(employment_data, aes(x = EMPLOYMENT_STATUS, y = Count, fill = TARGET)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.8) +
  geom_text(aes(label = paste0(Count, "\n(", round(Percentage, 1), "%)")), 
            position = position_dodge(width = 0.9), 
            vjust = -0.3, size = 3.5) +
  scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  labs(title = "TRẠNG THÁI VIỆC LÀM VÀ TÌNH TRẠNG THANH TOÁN",
       subtitle = "So sánh giữa người đang làm việc và đã nghỉ hưu",
       x = "Trạng thái việc làm",
       y = "Số lượng khách hàng",
       fill = "Tình trạng thanh toán") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Giải thích: Người đang làm việc chiếm đa số.
# Tỷ lệ khó khăn thanh toán có thể khác nhau giữa hai nhóm.

4.8 Mối quan hệ giữa điểm tín dụng và rủi ro

# CHUYỂN ĐỔI TẤT CẢ EXT_SOURCE VỀ NUMERIC TRƯỚC
ext_source_long <- loan_data %>%
  mutate(
    EXT_SOURCE_1 = as.numeric(EXT_SOURCE_1),
    EXT_SOURCE_2 = as.numeric(EXT_SOURCE_2),
    EXT_SOURCE_3 = as.numeric(EXT_SOURCE_3),
    TARGET_LABEL = factor(TARGET, labels = c("Thanh toán tốt", "Khó khăn thanh toán"))
  ) %>%
  select(EXT_SOURCE_1, EXT_SOURCE_2, EXT_SOURCE_3, TARGET_LABEL) %>%
  pivot_longer(
    cols = c(EXT_SOURCE_1, EXT_SOURCE_2, EXT_SOURCE_3),
    names_to = "Score_Type",
    values_to = "Score_Value"
  ) %>%
  filter(!is.na(Score_Value))  # LOẠI BỎ GIÁ TRỊ NA

# VẼ BOXPLOT
ggplot(ext_source_long, aes(x = TARGET_LABEL, y = Score_Value, fill = TARGET_LABEL)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.5) +
  facet_wrap(~ Score_Type, ncol = 3, 
             labeller = as_labeller(c(
               "EXT_SOURCE_1" = "EXT_SOURCE_1", 
               "EXT_SOURCE_2" = "EXT_SOURCE_2", 
               "EXT_SOURCE_3" = "EXT_SOURCE_3"
             ))) +
  scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  labs(title = "PHÂN PHỐI ĐIỂM TÍN DỤNG THEO TÌNH TRẠNG THANH TOÁN",
       subtitle = "So sánh phân vị điểm tín dụng giữa hai nhóm",
       x = "Tình trạng thanh toán",
       y = "Điểm tín dụng",
       fill = "Tình trạng thanh toán") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5),
        legend.position = "none",
        axis.text.x = element_text(angle = 0, hjust = 0.5))

# Giải thích: Boxplot cho thấy sự khác biệt rõ ràng về phân phối điểm tín dụng giữa hai nhóm. 
# Nhóm khó khăn thanh toán có median điểm thấp hơn đáng kể ở cả 3 loại điểm.

4.9 LOẠI HÌNH THU NHẬP

# XỬ LÝ DỮ LIỆU - TẠO TARGET_LABEL TRƯỚC KHI GROUP
income_type_data <- loan_data %>%
  mutate(
    TARGET_LABEL = factor(TARGET, levels = c(0, 1), labels = c("Thanh toán tốt", "Khó khăn thanh toán"))
  ) %>%
  group_by(NAME_INCOME_TYPE, TARGET_LABEL) %>%
  summarise(Count = n(), .groups = 'drop') %>%
  group_by(NAME_INCOME_TYPE) %>%
  mutate(Percentage = Count / sum(Count) * 100,
         Total = sum(Count)) %>%
  ungroup()

# KIỂM TRA CÁC NHÓM CÓ ÍT DỮ LIỆU
small_groups <- income_type_data %>%
  group_by(NAME_INCOME_TYPE) %>%
  summarise(Total_Count = sum(Count)) %>%
  filter(Total_Count < 10)

if(nrow(small_groups) > 0) {
  cat("Các nhóm có ít dữ liệu (sẽ được gộp vào 'Other'):\n")
  print(small_groups)
}
## Các nhóm có ít dữ liệu (sẽ được gộp vào 'Other'):
## # A tibble: 1 × 2
##   NAME_INCOME_TYPE Total_Count
##   <chr>                  <int>
## 1 Maternity leave            5
# GỘP CÁC NHÓM NHỎ THÀNH 'Other'
income_type_clean <- income_type_data %>%
  mutate(
NAME_INCOME_TYPE_CLEAN = ifelse(Total < 10, "Other", NAME_INCOME_TYPE)
  ) %>%
  group_by(NAME_INCOME_TYPE_CLEAN, TARGET_LABEL) %>%
  summarise(Count = sum(Count), .groups = 'drop') %>%
  group_by(NAME_INCOME_TYPE_CLEAN) %>%
  mutate(Percentage = Count / sum(Count) * 100,
         Total = sum(Count))

ggplot(income_type_clean, aes(x = reorder(NAME_INCOME_TYPE_CLEAN, Total), y = Count, fill = TARGET_LABEL)) +
  geom_bar(stat = "identity", alpha = 0.8) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_stack(vjust = 0.5), 
            color = "white", size = 3, fontface = "bold") +
  scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  labs(title = "LOẠI HÌNH THU NHẬP VÀ TÌNH TRẠNG THANH TOÁN",
       subtitle = "Sắp xếp theo tổng số lượng (các nhóm nhỏ được gộp thành 'Other')",
       x = "Loại hình thu nhập",
       y = "Số lượng khách hàng",
       fill = "Tình trạng thanh toán") +
  coord_flip() +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Giải thích: Working (lao động tự do) chiếm tỷ lệ cao nhất. 
# Một số loại hình thu nhập có tỷ lệ rủi ro cao hơn đáng kể..

4.10 TRÌNH ĐỘ HỌC VẤN

education_data <- loan_data %>%
  group_by(NAME_EDUCATION_TYPE, TARGET) %>%
  summarise(Count = n(), .groups = 'drop') %>%
  group_by(NAME_EDUCATION_TYPE) %>%
  mutate(Percentage = Count / sum(Count) * 100,
         Total = sum(Count),
         TARGET = factor(TARGET, labels = c("Thanh toán tốt", "Khó khăn thanh toán")))

ggplot(education_data, aes(x = reorder(NAME_EDUCATION_TYPE, Total), y = Count, fill = TARGET)) +
  geom_bar(stat = "identity", alpha = 0.8) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_stack(vjust = 0.5), 
            color = "white", size = 3.5, fontface = "bold") +
  scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  labs(title = "TRÌNH ĐỘ HỌC VẤN VÀ TÌNH TRẠNG THANH TOÁN",
       subtitle = "Tỷ lệ phần trăm theo từng trình độ",
       x = "Trình độ học vấn",
       y = "Số lượng khách hàng",
       fill = "Tình trạng thanh toán") +
  coord_flip() +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Giải thích: Trình độ học vấn Secondary/secondary special chiếm đa số. 
# Có sự khác biệt về tỷ lệ rủi ro theo trình độ học vấn.

4.11 TÌNH TRẠNG HÔN NHÂN

# CHỈ LẤY CÁC NHÓM CÓ ĐỦ DỮ LIỆU
main_family_status <- loan_data %>%
  count(NAME_FAMILY_STATUS) %>%
  filter(n >= 10) %>%  # CHỈ GIỮ LẠI NHÓM CÓ >= 10 QUAN SÁT
pull(NAME_FAMILY_STATUS)

family_data <- loan_data %>%
  filter(NAME_FAMILY_STATUS %in% main_family_status) %>%
  mutate(
    TARGET_LABEL = factor(TARGET, levels = c(0, 1), labels = c("Thanh toán tốt", "Khó khăn thanh toán"))
  ) %>%
  group_by(NAME_FAMILY_STATUS, TARGET_LABEL) %>%
  summarise(Count = n(), .groups = 'drop') %>%
  group_by(NAME_FAMILY_STATUS) %>%
  mutate(Percentage = Count / sum(Count) * 100,
         Total = sum(Count))

ggplot(family_data, aes(x = reorder(NAME_FAMILY_STATUS, Total), y = Count, fill = TARGET_LABEL)) +
  geom_bar(stat = "identity", alpha = 0.8) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_stack(vjust = 0.5), 
            color = "white", size = 3.5, fontface = "bold") +
  scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  labs(title = "TÌNH TRẠNG HÔN NHÂN VÀ TÌNH TRẠNG THANH TOÁN",
       subtitle = "Phân phối theo tình trạng gia đình (các nhóm nhỏ đã được lọc)",
       x = "Tình trạng hôn nhân",
       y = "Số lượng khách hàng",
       fill = "Tình trạng thanh toán") +
  coord_flip() +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# THÔNG BÁO CÁC NHÓM ĐÃ BỊ LOẠI BỎ
excluded_family <- loan_data %>%
  count(NAME_FAMILY_STATUS) %>%
  filter(n < 10)

if(nrow(excluded_family) > 0) {
  cat("Các nhóm tình trạng hôn nhân bị loại bỏ (ít dữ liệu):\n")
  print(excluded_family)
}
## Các nhóm tình trạng hôn nhân bị loại bỏ (ít dữ liệu):
##   NAME_FAMILY_STATUS n
## 1            Unknown 2
# Giải thích: Married (đã kết hôn) chiếm tỷ lệ cao nhất. 
# Tình trạng hôn nhân có thể ảnh hưởng đến khả năng thanh toán.

4.12 SỐ LƯỢNG CON CÁI

# GỘP CÁC NHÓM CÓ ÍT CON THÀNH NHÓM LỚN HƠN
children_data <- loan_data %>%
  mutate(
    TARGET_LABEL = factor(TARGET, levels = c(0, 1), labels = c("Thanh toán tốt", "Khó khăn thanh toán")),
    # GỘP SỐ CON THÀNH NHÓM
    CHILDREN_GROUP = case_when(
      CNT_CHILDREN == 0 ~ "0 con",
      CNT_CHILDREN == 1 ~ "1 con", 
      CNT_CHILDREN == 2 ~ "2 con",
      CNT_CHILDREN >= 3 ~ "3+ con"  # GỘP TẤT CẢ >= 3 CON
    )
  ) %>%
  group_by(CHILDREN_GROUP, TARGET_LABEL) %>%
  summarise(Count = n(), .groups = 'drop') %>%
  group_by(CHILDREN_GROUP) %>%
  mutate(Percentage = Count / sum(Count) * 100,
         Total = sum(Count))

ggplot(children_data, aes(x = factor(CHILDREN_GROUP, levels = c("0 con", "1 con", "2 con", "3+ con")), 
                         y = Count, fill = TARGET_LABEL)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.8) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_dodge(width = 0.9), 
            vjust = -0.3, size = 3.5, fontface = "bold") +
scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  labs(title = "SỐ LƯỢNG CON CÁI VÀ TÌNH TRẠNG THANH TOÁN",
       subtitle = "Phân tích theo nhóm số con (các nhóm >= 3 con được gộp chung)",
       x = "Số lượng con cái",
       y = "Số lượng khách hàng",
       fill = "Tình trạng thanh toán") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Giải thích: Khách hàng không có con chiếm đa số. 
# Số lượng con cái có thể ảnh hưởng đến gánh nặng tài chính.

4.13 LOẠI HÌNH NHÀ Ở

housing_data <- loan_data %>%
  group_by(NAME_HOUSING_TYPE, TARGET) %>%
  summarise(Count = n(), .groups = 'drop') %>%
  group_by(NAME_HOUSING_TYPE) %>%
  mutate(Percentage = Count / sum(Count) * 100,
         Total = sum(Count),
         TARGET = factor(TARGET, labels = c("Thanh toán tốt", "Khó khăn thanh toán")))

ggplot(housing_data, aes(x = reorder(NAME_HOUSING_TYPE, Total), y = Count, fill = TARGET)) +
  geom_bar(stat = "identity", alpha = 0.8) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_stack(vjust = 0.5), 
            color = "white", size = 3, fontface = "bold") +
  scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  labs(title = "LOẠI HÌNH NHÀ Ở VÀ TÌNH TRẠNG THANH TOÁN",
       subtitle = "Phân phối theo điều kiện nhà ở",
       x = "Loại hình nhà ở",
       y = "Số lượng khách hàng",
       fill = "Tình trạng thanh toán") +
  coord_flip() +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Giải thích: House/apartment (nhà/chung cư sở hữu) chiếm đa số. 
# Loại hình nhà ở có thể phản ánh ổn định tài chính.

4.14 Phân phối số tiền trả hằng năm

ggplot(loan_data, aes(x = AMT_ANNUITY, fill = factor(TARGET))) +
  geom_histogram(aes(y = ..density..), alpha = 0.7, bins = 30, position = "identity") +
  geom_density(alpha = 0.5, aes(color = factor(TARGET))) +
  scale_fill_manual(values = c("0" = "#2E8B57", "1" = "#DC143C"),
                    labels = c("Thanh toán tốt", "Khó khăn thanh toán")) +
  scale_color_manual(values = c("0" = "#2E8B57", "1" = "#DC143C"),
                     labels = c("Thanh toán tốt", "Khó khăn thanh toán")) +
  scale_x_continuous(labels = comma) +
  labs(title = "PHÂN PHỐI SỐ TIỀN TRẢ HÀNG NĂM (ANNUITY)",
       subtitle = "So sánh giữa hai nhóm thanh toán",
       x = "Số tiền trả hàng năm",
       y = "Mật độ",
       fill = "Tình trạng thanh toán",
       color = "Tình trạng thanh toán") +
  theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Giải thích: Phân phối annuity tương đối giống nhau giữa hai nhóm, 
# nhưng nhóm khó khăn thanh toán có xu hướng annuity thấp hơn.

4.15 TỶ LỆ VAY TRÊN THU NHẬP

# ĐẢM BẢO DỮ LIỆU LÀ NUMERIC TRƯỚC KHI TÍNH TOÁN
loan_data_ratio <- loan_data %>%
  mutate(
    AMT_INCOME_TOTAL = as.numeric(AMT_INCOME_TOTAL),
    AMT_CREDIT = as.numeric(AMT_CREDIT)
  ) %>%
  filter(
    !is.na(AMT_INCOME_TOTAL) & !is.na(AMT_CREDIT),
    AMT_INCOME_TOTAL > 0,  # LOẠI BỎ THU NHẬP <= 0
    AMT_CREDIT > 0         # LOẠI BỎ SỐ TIỀN VAY <= 0
  ) %>%
  mutate(
    CREDIT_TO_INCOME_RATIO = AMT_CREDIT / AMT_INCOME_TOTAL,
    TARGET_LABEL = factor(TARGET, labels = c("Thanh toán tốt", "Khó khăn thanh toán"))
  ) %>%
  filter(CREDIT_TO_INCOME_RATIO <= 20)  # LOẠI BỎ OUTLIERS LỚN

ggplot(loan_data_ratio, aes(x = CREDIT_TO_INCOME_RATIO, fill = TARGET_LABEL)) +
  geom_histogram(aes(y = ..density..), alpha = 0.7, bins = 30, position = "identity") +
  geom_density(alpha = 0.5, aes(color = TARGET_LABEL)) +
  scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  scale_color_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  labs(title = "TỶ LỆ VAY TRÊN THU NHẬP",
       subtitle = "Chỉ số đòn bẩy tài chính (giới hạn tỷ lệ ≤ 20 để dễ quan sát)",
       x = "Tỷ lệ vay/thu nhập",
       y = "Mật độ",
       fill = "Tình trạng thanh toán",
       color = "Tình trạng thanh toán") +
  xlim(0, 10) + # GIỚI HẠN ĐỂ DỄ QUAN SÁT
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

# Giải thích: Tỷ lệ vay/thu nhập cao thường liên quan đến rủi ro cao hơn, 
# phù hợp với nguyên tắc đánh giá tín dụng truyền thống..

4.16 PHÂN TÍCH TỔNG HỢP RỦI RO

# ĐẢM BẢO TẤT CẢ DỮ LIỆU LÀ NUMERIC TRƯỚC KHI PHÂN TÍCH
risk_data <- loan_data %>%
  mutate(
    # CHUYỂN ĐỔI CÁC BIẾN SỐ VỀ NUMERIC
    AMT_INCOME_TOTAL = as.numeric(AMT_INCOME_TOTAL),
    EXT_SOURCE_1 = as.numeric(EXT_SOURCE_1),
    EXT_SOURCE_2 = as.numeric(EXT_SOURCE_2),
    EXT_SOURCE_3 = as.numeric(EXT_SOURCE_3),
    DAYS_BIRTH = as.numeric(DAYS_BIRTH)
  ) %>%
  filter(
    !is.na(AMT_INCOME_TOTAL) & 
    !is.na(EXT_SOURCE_1) & 
    !is.na(EXT_SOURCE_2) & 
    !is.na(EXT_SOURCE_3)
  ) %>%
  mutate(
    # TÍNH TUỔI
    AGE = round(-DAYS_BIRTH / 365.25, 1),
    AGE_GROUP = cut(AGE, 
                   breaks = c(20, 30, 40, 50, 60, 70), 
                   labels = c("20-30", "30-40", "40-50", "50-60", "60+"),
                   include.lowest = TRUE),
    
    # PHÂN NHÓM THU NHẬP
INCOME_GROUP = cut(AMT_INCOME_TOTAL, 
                      breaks = quantile(AMT_INCOME_TOTAL, probs = seq(0, 1, 0.2), na.rm = TRUE),
                      labels = c("Rất thấp", "Thấp", "Trung bình", "Cao", "Rất cao"),
                      include.lowest = TRUE),
    
    # TÍNH ĐIỂM RỦI RO TRUNG BÌNH
    RISK_SCORE = (EXT_SOURCE_1 + EXT_SOURCE_2 + EXT_SOURCE_3) / 3
  ) %>%
  filter(!is.na(AGE_GROUP) & !is.na(INCOME_GROUP)) %>%
  group_by(AGE_GROUP, INCOME_GROUP) %>%
  summarise(
    DEFAULT_RATE = mean(TARGET, na.rm = TRUE) * 100,
    AVG_RISK_SCORE = mean(RISK_SCORE, na.rm = TRUE),
    COUNT = n(),
    .groups = 'drop'
  ) %>%
  filter(COUNT >= 5)  # CHỈ GIỮ LẠI CÁC Ô CÓ ĐỦ DỮ LIỆU

# VẼ HEATMAP
ggplot(risk_data, aes(x = AGE_GROUP, y = INCOME_GROUP, fill = DEFAULT_RATE)) +
  geom_tile(color = "white", alpha = 0.8) +
  geom_text(aes(label = paste0(round(DEFAULT_RATE, 1), "%")), 
            color = "white", size = 4, fontface = "bold") +
  scale_fill_gradient2(low = "#2E8B57", mid = "#FFD700", high = "#DC143C", 
                       midpoint = median(risk_data$DEFAULT_RATE, na.rm = TRUE),
                       name = "Tỷ lệ vỡ nợ (%)") +
  labs(title = "MA TRẬN RỦI RO THEO TUỔI VÀ THU NHẬP",
       subtitle = "Heatmap tỷ lệ khó khăn thanh toán",
       x = "Nhóm tuổi",
       y = "Nhóm thu nhập") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5),
        axis.text.x = element_text(angle = 45, hjust = 1))

# Giải thích: Heatmap cho thấy rõ các nhóm có rủi ro cao (màu đỏ) và thấp (màu xanh). 
# Nhóm trẻ tuổi với thu nhập thấp có tỷ lệ rủi ro cao nhất.