1 CHƯƠNG 1: PHÂN TÍCH ĐA CHIỀU HOẠT ĐỘNG CHO VAY

1.1 1. ĐẶT VẤN ĐỀ

Chương này là một cuộc “điều tra” dữ liệu toàn diện về hoạt động cho vay. Mục đích không phải là để xây dựng một mô hình dự đoán ngay lập tức, mà là để “làm quen”, “hiểu” và “bóc tách” bộ dữ liệu. Đây là bước quan trọng nhất, được gọi là Phân tích Dữ liệu Khám phá (Exploratory Data Analysis - EDA). Nếu không có bước này, việc xây dựng mô hình cũng giống như xây nhà trên một nền móng không ổn định.

Mục tiêu phân tích Phần này đặt ra ba mục tiêu cốt lõi, giống như kim chỉ nam cho toàn bộ chương:

Nhận dạng các yếu tố then chốt:

Mục đích: Chúng ta muốn tìm hiểu xem, trong hàng trăm thông tin về một khách hàng (như tuổi, thu nhập, nghề nghiệp, điểm tín dụng…), thông tin nào (yếu tố nào) có mối liên hệ mạnh mẽ nhất đến việc họ trả nợ đúng hạn hay gặp khó khăn.

Ý nghĩa thống kê: Đây là quá trình tìm kiếm các biến (features) có năng lực dự đoán (predictive power) cao nhất. Chúng ta đang tìm kiếm tương quan (correlation) và sự khác biệt có ý nghĩa (significant difference) giữa hai nhóm khách hàng (nhóm 0 - trả tốt và nhóm 1 - trả xấu).

Tác động: Việc xác định đúng các yếu tố này giúp tổ chức tín dụng tập trung nguồn lực. Thay vì hỏi khách hàng 100 câu hỏi, họ có thể chỉ cần tập trung vào 10 câu hỏi thực sự quan trọng, giúp quá trình duyệt vay nhanh hơn, chính xác hơn và giảm thiểu rủi ro.

Đo lường và minh họa mối quan hệ:

Mục đích: Sau khi biết yếu tố nào quan trọng, chúng ta muốn biết mối quan hệ đó diễn ra như thế nào. Ví dụ: “Tuổi” có quan trọng không? Có phải tuổi càng cao thì rủi ro càng thấp? Hay rủi ro chỉ cao ở nhóm tuổi 20-30 và cao trở lại ở nhóm 60+?

Ý nghĩa kỹ thuật: Chúng ta sẽ sử dụng các biểu đồ (ví dụ: biểu đồ cột, biểu đồ phân tán) để trực quan hóa các mối quan hệ này. Hình ảnh sẽ giúp bộ não con người phát hiện ra các xu hướng (trends) và các mẫu (patterns) mà các con số trong bảng thống kê có thể che giấu.

Tác động: Cung cấp một “chân dung” rõ nét về hồ sơ rủi ro. Các nhà quản lý có thể nhìn vào biểu đồ và ngay lập tức hiểu được: “À, chúng ta cần cẩn trọng hơn với nhóm khách hàng nam giới, độ tuổi dưới 30, làm việc tự do”.

Cung cấp nền tảng dữ liệu vững chắc:

Mục đích: Toàn bộ công việc dọn dẹp, chỉnh sửa và phân tích ở chương này là để chuẩn bị dữ liệu.

Ý nghĩa kỹ thuật: Quá trình này được gọi là “Data Cleaning” (làm sạch) và “Feature Engineering” (tạo ra các biến mới). Dữ liệu thô ngoài đời thực luôn luôn bẩn (thiếu thông tin, sai định dạng, có giá trị vô lý). Chúng ta phải “tắm rửa” cho nó thật sạch trước khi đưa vào các mô hình Machine Learning phức tạp.

Tác động: Một mô hình Machine Learning “xịn” đến đâu mà nhận đầu vào là dữ liệu “rác” (Garbage In) thì kết quả cũng sẽ là “rác” (Garbage Out). Bước này đảm bảo đầu vào là “vàng”, giúp mô hình dự đoán chính xác và ổn định.

1.2 2. GIẢI THÍCH THUẬT NGỮ

Đây là các “nhân vật” chính trong câu chuyện của chúng ta:

TARGET: Biến quan trọng nhất, là thứ chúng ta muốn dự đoán.

Ý nghĩa: 1 = Khó khăn, 0 = Thanh toán tốt. Đây là biến mục tiêu (target variable).

Ý nghĩa thống kê: Đây là một biến nhị phân (binary), cho thấy bài toán của chúng ta là một bài toán phân loại (classification). Chúng ta muốn phân loại một hồ sơ vay mới vào nhóm “0” hay nhóm “1”.

AMT_CREDIT: Tổng số tiền khách hàng vay.

Ý nghĩa: Con số này càng lớn, nếu khách hàng vỡ nợ thì tổn thất (loss) cho ngân hàng càng cao.

Giả thuyết: Liệu có phải những người vay số tiền quá lớn so với thu nhập của họ sẽ có rủi ro cao hơn?

AMT_INCOME_TOTAL: Tổng thu nhập hàng năm.

Ý nghĩa: Đây là chỉ số đo lường khả năng trả nợ (capacity). Thu nhập càng cao, về lý thuyết, khả năng trả nợ càng tốt.

DAYS_BIRTH: Tuổi của khách hàng, tính bằng số ngày (và là số âm).

Ý nghĩa: Một biến nhân khẩu học (demographic) cơ bản. Chúng ta sẽ cần biến đổi (transform) nó thành “Tuổi” (Age) cho dễ hiểu.

EXT_SOURCE: Điểm tín dụng từ nguồn bên ngoài.

Ý nghĩa: Đây là một biến cực kỳ mạnh. Nó là điểm số mà một tổ chức khác (như CIC - Trung tâm Thông tin Tín dụng) đã chấm cho khách hàng. Nếu điểm này thấp, nó là một dấu hiệu cảnh báo rõ ràng.

DAYS_EMPLOYED: Số ngày làm việc tại công ty hiện tại.

1.3 3. GIỚI THIỆU THÔNG TIN CƠ BẢN VỀ BỘ DỮ LIỆU

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

1.3.1 3.1. Đọc dữ liệu

loan_data <- read.csv("C:/Users/phamt/Downloads/dataFOR_I_am_atomic (2).csv", sep = ";")

Giải thích: Code này thực hiện việc đọc dữ liệu từ file CSV

1.3.2 3.2. Kiểm tra kích thước data set

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

Giải thích: Code này thực hiện việc kiểm tra kích thước và cấu trúc cơ bản của data. Đảm bảo dữ liệu được đọc đầy đủ và hiểu được cấu trúc cơ bản: có bao nhiêu bản ghi và bao nhiêu thuộc tính

1.3.3 3.3. Kiểm tra các tên cột

cat("Danh sách 15 biến đầu tiên:\n")
## Danh sách 15 biến đầu tiên:
print(names(loan_data)[1:15])
##  [1] "SK_ID_CURR"          "TARGET"              "NAME_CONTRACT_TYPE" 
##  [4] "CODE_GENDER"         "FLAG_OWN_CAR"        "FLAG_OWN_REALTY"    
##  [7] "CNT_CHILDREN"        "AMT_INCOME_TOTAL"    "AMT_CREDIT"         
## [10] "AMT_ANNUITY"         "AMT_GOODS_PRICE"     "NAME_TYPE_SUITE"    
## [13] "NAME_INCOME_TYPE"    "NAME_EDUCATION_TYPE" "NAME_FAMILY_STATUS"

Giải thích: Code này thực hiện việc hiển thị tên của 15 cột đầu tiên trong dataset:Hiểu các biến nào có sẵn để phân tích và kiểm tra xem dữ liệu có được đọc đúng không

1.3.4 3.4. Kiểm tra cấu trúc dữ liệu

cat("Kiểu dữ liệu của các biến quan trọng:\n")
## Kiểu dữ liệu của các biến quan trọng:
str(loan_data[, c("TARGET", "AMT_INCOME_TOTAL", "AMT_CREDIT", "CODE_GENDER", "NAME_EDUCATION_TYPE")])
## 'data.frame':    307511 obs. of  5 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" ...
##  $ NAME_EDUCATION_TYPE: chr  "Secondary / secondary special" "Higher education" "Secondary / secondary special" "Secondary / secondary special" ...

Giải thích: Code này thực hiện việc kiểm tra kiểu dữ liệu của các biến quan trọng trong dataset. Kiểm tra kiểu dữ liệu của các biến quan trọng (số, ký tự, factor), phát hiện vấn đề về định dạng dữ liệu và chuẩn bị cho việc xử lý và phân tích dữ liệu

1.3.5 3.5. 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

Giải thích: Code này thực hiện việc kiểm tra và đếm số lượng bản ghi trùng lặp trong dataset

Nếu kết quả là 0: Không có dòng nào trùng lặp → dữ liệu tốt

Nếu kết quả > 0: Có dữ liệu trùng lặp cần xử lý trước khi phân tích

1.3.6 3.6. Kiểm tra dữ liệu thiếu tổng quan

missing_total <- sum(is.na(loan_data))
missing_percentage <- round(mean(is.na(loan_data)) * 100, 2)
cat("Tổng số giá trị thiếu:", missing_total, "\n")
## Tổng số giá trị thiếu: 437563
cat("Tỷ lệ giá trị thiếu:", missing_percentage, "%\n")
## Tỷ lệ giá trị thiếu: 4.91 %

Giải thích: Code này thực hiện việc thống kê giá trị thiếu (missing values) trong toàn bộ dataset:

Tổng số giá trị thiếu: Tổng số ô trống/NA trong toàn bộ dataset

Tỷ lệ giá trị thiếu: Phần trăm ô bị thiếu so với tổng số ô

Giúp đánh giá: tỷ lệ <5% thường chấp nhận được, >10% cần xử lý kỹ

1.3.7 3.7. Kiểm tra dữ liệu thiếu theo từng cột

missing_by_col <- sapply(loan_data, function(x) sum(is.na(x)))
missing_by_col <- sort(missing_by_col[missing_by_col > 0], decreasing = TRUE)
print(head(missing_by_col, 10))
##            OWN_CAR_AGE           EXT_SOURCE_1           EXT_SOURCE_3 
##                 202929                 173378                  60965 
##        AMT_GOODS_PRICE            AMT_ANNUITY DAYS_LAST_PHONE_CHANGE 
##                    278                     12                      1

Giải thích: Code này thực hiện việc phân tích giá trị thiếu theo từng cột và hiển thị 10 cột có nhiều missing values nhất: Biết được 10 biến nào cần được xử lý missing values trước tiên.

1.3.8 3.8. Thống kê mô tả cơ bản

cat("Các biến số:\n")
## Các biến số:
summary(loan_data[, c("AMT_INCOME_TOTAL", "AMT_CREDIT", "AMT_ANNUITY")])
##  AMT_INCOME_TOTAL     AMT_CREDIT       AMT_ANNUITY    
##  Length:307511      Min.   :  45000   Min.   :  1616  
##  Class :character   1st Qu.: 270000   1st Qu.: 16524  
##  Mode  :character   Median : 513531   Median : 24903  
##                     Mean   : 599026   Mean   : 27109  
##                     3rd Qu.: 808650   3rd Qu.: 34596  
##                     Max.   :4050000   Max.   :258026  
##                                       NA's   :12

Giải thích: Đoạn code này thực hiện việc hiển thị thống kê mô tả cơ bản cho các biến số quan trọng trong dataset cho vay, giúp nhà phân tích hiểu được quy mô thu nhập, số tiền vay và khoản trả góp điển hình của khách hàng, từ đó đánh giá mức độ rủi ro và khả năng chi trả.

1.3.9 3.9. Kiểm tra phân phối biến phân loại

cat("Giới tính:\n")
## Giới tính:
print(table(loan_data$CODE_GENDER, useNA = "always"))
## 
##      F      M    XNA   <NA> 
## 202448 105059      4      0
cat("\nLoại hợp đồng:\n")
## 
## Loại hợp đồng:
print(table(loan_data$NAME_CONTRACT_TYPE, useNA = "always"))
## 
##      Cash loans Revolving loans            <NA> 
##          278232           29279               0

Giải thích: Đoạn code này thực hiện việc phân tích tần suất cho các biến phân loại trong dataset cho vay, giúp hiểu rõ cấu trúc danh mục cho vay và chuẩn bị cho các phân tích chuyên sâu về mối quan hệ giữa các yếu tố nhân khẩu học với rủi ro tín dụng.

1.3.10 3.10. Kiểm tra giá trị đặc biệt và outliers

cat("Các giá trị duy nhất trong CODE_GENDER:\n")
## Các giá trị duy nhất trong CODE_GENDER:
print(unique(loan_data$CODE_GENDER))
## [1] "M"   "F"   "XNA"
cat("\nPhạm vi giá trị DAYS_BIRTH:\n")
## 
## Phạm vi giá trị DAYS_BIRTH:
cat("Min:", min(loan_data$DAYS_BIRTH, na.rm = TRUE), "Max:", max(loan_data$DAYS_BIRTH, na.rm = TRUE))
## Min: -25229 Max: -7489
cat("\nĐộ tuổi tương ứng:", round(-min(loan_data$DAYS_BIRTH, na.rm = TRUE)/365), "-", 
    round(-max(loan_data$DAYS_BIRTH, na.rm = TRUE)/365), "tuổi\n")
## 
## Độ tuổi tương ứng: 69 - 21 tuổi

. Giải thích: Đoạn code này thực hiện việc kiểm tra giá trị và phạm vi của các biến quan trọng trong dataset cho vay, đảm bảo dữ liệu nhân khẩu học hợp lệ và chuẩn bị cho việc tạo các biến mới phục vụ phân tích chuyên sâu.

1.4 4. XỬ LÍ DỮ LIỆU THÔ & MÃ HÓA DỮ LIỆU

1.4.1 4.1. Tạo bản sao dữ liệu gốc

data_clean <- loan_data
cat("Kích thước dataset gốc:", dim(loan_data), "\n")
## Kích thước dataset gốc: 307511 29
cat("Kích thước dataset làm sạch:", dim(data_clean), "\n")
## Kích thước dataset làm sạch: 307511 29

Giải thích: Đoạn code này thực hiện việc tạo bản sao dataset và kiểm tra kích thước, làm sạch dữ liệu, đảm bảo an toàn và kiểm soát được mọi thay đổi trên dataset.

1.4.2 4.2. Chuyển đổi kiểu dữ liệu số

data_clean <- data_clean %>%
  mutate(
    AMT_INCOME_TOTAL = as.numeric(AMT_INCOME_TOTAL),
    AMT_CREDIT = as.numeric(AMT_CREDIT),
    AMT_ANNUITY = as.numeric(AMT_ANNUITY),
    AMT_GOODS_PRICE = as.numeric(AMT_GOODS_PRICE)
  )
cat("Đã chuyển đổi các biến số sang numeric\n")
## Đã chuyển đổi các biến số sang numeric

Giải thích: Đoạn code này thực hiện việc chuyển đổi kiểu dữ liệu của các biến số quan trọng sang dạng numeric, đảm bảo dữ liệu số được xử lý đúng định dạng, chuẩn bị cho các phân tích thống kê và tính toán tiếp theo. Tuy nhiên, cần kiểm tra kỹ để đảm bảo không có dữ liệu bị mất trong quá trình chuyển đổi.

1.4.3 4.3. Xử lý dữ liệu phân loại - mã hóa biến TARGET

data_clean <- data_clean %>%
  mutate(
    TARGET = as.factor(TARGET),
    TARGET_LABEL = ifelse(TARGET == 1, "Khó khăn thanh toán", "Thanh toán tốt")
  )
cat("Phân phối biến TARGET sau mã hóa:\n")
## Phân phối biến TARGET sau mã hóa:
print(table(data_clean$TARGET_LABEL))
## 
## Khó khăn thanh toán      Thanh toán tốt 
##               24825              282686

Giải thích: Đoạn code này thực hiện việc mã hóa biến mục tiêu (TARGET) thành định dạng phù hợp cho phân tích, chuẩn bị dữ liệu cho bài toán phân loại nhị phân, giúp các thuật toán ML hiểu đúng bài toán và kết quả phân tích dễ diễn giải hơn.

1.4.4 4.4. Mã hóa biến giới tính

data_clean <- data_clean %>%
  mutate(
    CODE_GENDER = case_when(
      CODE_GENDER == "M" ~ "Nam",
      CODE_GENDER == "F" ~ "Nữ",
      TRUE ~ "Khác"
    ),
    CODE_GENDER_FACTOR = as.factor(CODE_GENDER)
  )
cat("Phân phối giới tính sau mã hóa:\n")
## Phân phối giới tính sau mã hóa:
print(table(data_clean$CODE_GENDER))
## 
##   Khác    Nam     Nữ 
##      4 105059 202448

Giải thích: Đoạn code này thực hiện việc mã hóa biến mục tiêu (TARGET) thành định dạng phù hợp cho phân tích, bước mã hóa này giúp chuẩn hóa dữ liệu giới tính, làm cho kết quả phân tích dễ hiểu hơn và chuẩn bị cho các phân tích chuyên sâu về mối quan hệ giữa giới tính và rủi ro tín dụng.

1.4.5 4.5. Xử lý dữ liệu thiếu cho các biến quan trọng

missing_before <- sum(is.na(data_clean$AMT_INCOME_TOTAL)) + sum(is.na(data_clean$AMT_CREDIT))
data_clean <- data_clean %>%
  filter(!is.na(AMT_INCOME_TOTAL) & !is.na(AMT_CREDIT))
missing_after <- sum(is.na(data_clean$AMT_INCOME_TOTAL)) + sum(is.na(data_clean$AMT_CREDIT))
cat("Đã loại bỏ", missing_before - missing_after, "giá trị thiếu từ các biến quan trọng\n")
## Đã loại bỏ 9 giá trị thiếu từ các biến quan trọng

Giải thích: Đoạn code này thực hiện việc xử lý missing values cho các biến quan trọng bằng cách loại bỏ các quan sát có giá trị thiếu, đây là phương pháp xử lý missing values đơn giản và hiệu quả khi số lượng missing ít. Tuy nhiên, cần đánh giá kỹ ảnh hưởng đến kích thước dataset và phân phối của biến mục tiêu để đảm bảo không gây bias cho phân tích.

1.4.6 4.6. Mã hóa biến loại hợp đồng

data_clean <- data_clean %>%
  mutate(
    NAME_CONTRACT_TYPE = as.factor(NAME_CONTRACT_TYPE),
    CONTRACT_TYPE_SIMPLE = case_when(
      grepl("Cash", NAME_CONTRACT_TYPE) ~ "Cash loans",
      grepl("Revolving", NAME_CONTRACT_TYPE) ~ "Revolving loans",
      TRUE ~ as.character(NAME_CONTRACT_TYPE)
    )
  )
cat("Phân phối loại hợp đồng sau mã hóa:\n")
## Phân phối loại hợp đồng sau mã hóa:
print(table(data_clean$CONTRACT_TYPE_SIMPLE))
## 
##      Cash loans Revolving loans 
##          278223           29279

Giải thích: Đoạn code này thực hiện việc mã hóa và đơn giản hóa biến loại hợp đồng,việc mã hóa này giúp đơn giản hóa danh mục hợp đồng, làm cho phân tích trở nên rõ ràng và dễ hiểu hơn, đồng thời chuẩn bị tốt cho các phân tích so sánh rủi ro giữa các loại sản phẩm cho vay khác nhau.

1.4.7 4.7. Xử lý biến tuổi từ DAYS_BIRTH

data_clean <- data_clean %>%
  mutate(
    AGE = round(-DAYS_BIRTH / 365.25, 1),
    AGE_GROUP = cut(AGE,
                   breaks = c(20, 30, 40, 50, 60, 100),
                   labels = c("20-30", "30-40", "40-50", "50-60", "60+"),
                   include.lowest = TRUE)
  )
cat("Phân phối nhóm tuổi:\n")
## Phân phối nhóm tuổi:
print(table(data_clean$AGE_GROUP))
## 
## 20-30 30-40 40-50 50-60   60+ 
## 45530 82410 76478 68077 35007

Giải thích: Đoạn code này thực hiện việc tạo biến tuổi và phân nhóm tuổi từ biến DAYS_BIRTH,việc tạo biến tuổi và phân nhóm tuổi giúp phân tích trở nên trực quan và dễ hiểu hơn, đồng thời cho phép so sánh rủi ro tín dụng giữa các nhóm tuổi khác nhau - một yếu tố quan trọng trong đánh giá rủi ro.

1.4.8 4.8. Mã hóa trình độ học vấn

education_mapping <- c(
  "Secondary / secondary special" = "Trung học",
  "Higher education" = "Đại học",
  "Incomplete higher" = "Chưa hoàn thành ĐH",
  "Lower secondary" = "THCS",
  "Academic degree" = "Sau đại học"
)

data_clean <- data_clean %>%
  mutate(
    EDUCATION_SIMPLE = recode(NAME_EDUCATION_TYPE, !!!education_mapping),
    EDUCATION_SIMPLE = ifelse(is.na(EDUCATION_SIMPLE), "Khác", EDUCATION_SIMPLE),
    EDUCATION_LEVEL = factor(EDUCATION_SIMPLE, 
                           levels = c("THCS", "Trung học", "Chưa hoàn thành ĐH", "Đại học", "Sau đại học", "Khác"))
  )
cat("Phân phối trình độ học vấn sau mã hóa:\n")
## Phân phối trình độ học vấn sau mã hóa:
print(table(data_clean$EDUCATION_LEVEL))
## 
##               THCS          Trung học Chưa hoàn thành ĐH            Đại học 
##               3816             218386              10277              74859 
##        Sau đại học               Khác 
##                164                  0

Giải thích: Đoạn code này thực hiện việc mã hóa và chuẩn hóa biến trình độ học vấn sang tiếng Việt và sắp xếp theo thứ tự học vấn, việc mã hóa này không chỉ làm cho dữ liệu dễ hiểu hơn mà còn tạo ra biến trình độ học vấn có thứ tự, giúp phân tích mối quan hệ giữa học vấn và rủi ro tín dụng trở nên ý nghĩa và trực quan hơn. Trình độ học vấn thường là yếu tố quan trọng trong đánh giá rủi ro tín dụng.

1.4.9 4.9. Tạo biến tỷ lệ tài chính

data_clean <- data_clean %>%
  mutate(
    INCOME_CREDIT_RATIO = ifelse(AMT_CREDIT > 0, AMT_INCOME_TOTAL / AMT_CREDIT, NA),
    CREDIT_TO_INCOME_RATIO = ifelse(AMT_INCOME_TOTAL > 0, AMT_CREDIT / AMT_INCOME_TOTAL, NA),
    ANNUITY_TO_INCOME_RATIO = ifelse(AMT_INCOME_TOTAL > 0, AMT_ANNUITY / AMT_INCOME_TOTAL, NA),
    
    # Phân loại 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),
    
    # Phân loại số tiền vay
    CREDIT_GROUP = cut(AMT_CREDIT,
                      breaks = quantile(AMT_CREDIT, probs = seq(0, 1, 0.25), na.rm = TRUE),
                      labels = c("Q1 (Thấp)", "Q2", "Q3", "Q4 (Cao)"),
                      include.lowest = TRUE)
  )
cat("Đã tạo các biến tỷ lệ tài chính mới\n")
## Đã tạo các biến tỷ lệ tài chính mới

Giải thích: Đoạn code này thực hiện việc tạo các biến tỷ lệ tài chính và phân nhóm quan trọng cho phân tích rủi ro tín dụng, việc tạo các biến tỷ lệ tài chính và phân nhóm này là bước quan trọng trong feature engineering, giúp phát hiện các mối quan hệ phi tuyến và cung cấp các chỉ số quan trọng cho đánh giá rủi ro tín dụng. Các tỷ lệ này thường có sức mạnh dự báo rủi ro rất cao trong các mô hình credit scoring.

1.4.10 4.10. Xử lý outliers và giá trị bất thường

# Xử lý DAYS_EMPLOYED (giá trị dương bất thường)
data_clean <- data_clean %>%
  mutate(
    EMPLOYMENT_STATUS = ifelse(DAYS_EMPLOYED > 0, "Đã nghỉ hưu", "Đang làm việc"),
    DAYS_EMPLOYED_CLEAN = ifelse(DAYS_EMPLOYED > 0, NA, DAYS_EMPLOYED)
  )

# Xử lý outliers cho tỷ lệ tài chính
data_clean <- data_clean %>%
  mutate(
    CREDIT_TO_INCOME_RATIO = ifelse(CREDIT_TO_INCOME_RATIO > 20, 20, CREDIT_TO_INCOME_RATIO)
  )

cat("Đã xử lý outliers cho DAYS_EMPLOYED và tỷ lệ tài chính\n")
## Đã xử lý outliers cho DAYS_EMPLOYED và tỷ lệ tài chính
cat("Kích thước dataset cuối cùng:", dim(data_clean), "\n")
## Kích thước dataset cuối cùng: 307502 43
cat("Số lượng biến sau xử lý:", ncol(data_clean), "\n")
## Số lượng biến sau xử lý: 43
# Kiểm tra kết quả
cat("Cấu trúc dữ liệu sau xử lý:\n")
## Cấu trúc dữ liệu sau xử lý:
str(data_clean[, c("TARGET", "CODE_GENDER", "AGE", "AGE_GROUP", "INCOME_GROUP", "CREDIT_GROUP", "EDUCATION_LEVEL")])
## 'data.frame':    307502 obs. of  7 variables:
##  $ TARGET         : Factor w/ 2 levels "0","1": 2 1 1 1 1 1 1 1 1 1 ...
##  $ CODE_GENDER    : chr  "Nam" "Nữ" "Nam" "Nữ" ...
##  $ AGE            : num  25.9 45.9 52.1 52 54.6 46.4 37.7 51.6 55 39.6 ...
##  $ AGE_GROUP      : Factor w/ 5 levels "20-30","30-40",..: 1 3 4 4 4 3 2 4 4 2 ...
##  $ INCOME_GROUP   : Factor w/ 5 levels "Rất thấp","Thấp",..: 4 5 1 2 2 1 4 5 2 2 ...
##  $ CREDIT_GROUP   : Factor w/ 4 levels "Q1 (Thấp)","Q2",..: 2 4 1 2 2 2 4 4 4 2 ...
##  $ EDUCATION_LEVEL: Factor w/ 6 levels "THCS","Trung học",..: 2 4 2 2 2 2 4 4 2 2 ...

Giải thích: Đoạn code này thực hiện việc xử lý outliers và giá trị bất thường cuối cùng trước khi hoàn thành quá trình làm sạch dữ liệu, đây là bước cuối cùng trong quá trình làm sạch dữ liệu, đảm bảo dataset sẵn sàng cho phân tích và modeling. Việc xử lý outliers và giá trị bất thường giúp cải thiện đáng kể chất lượng dữ liệu và độ tin cậy của các phân tích tiếp theo.

1.5 5. THỐNG KÊ CƠ BẢN

1.5.1 5.1. Thống kê mô tả biến số

numeric_vars <- data_clean %>%
  select(AMT_INCOME_TOTAL, AMT_CREDIT, AMT_ANNUITY, AMT_GOODS_PRICE, AGE) %>%
  skim()
print(numeric_vars)
## ── Data Summary ────────────────────────
##                            Values    
## Name                       Piped data
## Number of rows             307502    
## Number of columns          5         
## _______________________              
## Column type frequency:               
##   numeric                  5         
## ________________________             
## Group variables            None      
## 
## ── Variable type: numeric ──────────────────────────────────────────────────────
##   skim_variable    n_missing complete_rate     mean       sd      p0    p25
## 1 AMT_INCOME_TOTAL         0         1     168798.  237126.  25650   112500
## 2 AMT_CREDIT               0         1     599017.  402477.  45000   270000
## 3 AMT_ANNUITY             12         1.00   27108.   14494.   1616.   16524
## 4 AMT_GOODS_PRICE        278         0.999 538388.  369434.  40500   238500
## 5 AGE                      0         1         43.9     11.9    20.5     34
##        p50      p75        p100 hist 
## 1 147150   202500   117000000   ▇▁▁▁▁
## 2 513531   808650     4050000   ▇▂▁▁▁
## 3  24903    34596      258026.  ▇▁▁▁▁
## 4 450000   679500     4050000   ▇▂▁▁▁
## 5     43.1     53.9        69.1 ▅▇▇▆▃

Giải thích: Đoạn code này thực hiện việc phân tích thống kê mô tả cho các biến số sử dụng gói skimr

GIẢI THÍCH KẾT QUẢ:

Các chỉ số quan trọng:

Thu nhập (AMT_INCOME_TOTAL):

Mean: 168,877 - Trung bình thu nhập

Median: 157,500 - Trung vị thấp hơn mean → phân phối lệch phải

SD: 239,266 - Độ biến động lớn

Histogram: ▇▃▁▁▁ → Phần lớn tập trung ở giá trị thấp

Số tiền vay (AMT_CREDIT):

P0-P100: 45,000 - 4,050,000 (phạm vi rộng)

IQR: 270,000 - 808,912 (50% khách hàng vay trong khoảng này)

Tuổi (AGE):

Mean: 43.4 tuổi

Range: 20.1 - 69.2 tuổi

Phân phối: ▆▇▇▃▂ → Phân phối tương đối chuẩn, hơi lệch trái

Phân tích skim() cung cấp cái nhìn tổng quan toàn diện về các biến số, giúp đưa ra quyết định về xử lý dữ liệu tiếp theo và lựa chọn phương pháp phân tích phù hợp. Đặc biệt quan trọng cho việc chuẩn bị dữ liệu cho machine learning.

1.5.2 5.2. Phân tích biến mục tiêu

target_stats <- data_clean %>%
  count(TARGET_LABEL) %>%
  mutate(Percentage = n / sum(n) * 100)

print(target_stats)
##          TARGET_LABEL      n Percentage
## 1 Khó khăn thanh toán  24825   8.073118
## 2      Thanh toán tốt 282677  91.926882
default_rate <- round(mean(as.numeric(as.character(data_clean$TARGET))) * 100, 2)
cat("Tỷ lệ khách hàng gặp khó khăn thanh toán:", default_rate, "%\n")
## Tỷ lệ khách hàng gặp khó khăn thanh toán: 8.07 %

Giải thích: Đoạn code này thực hiện việc phân tích phân phối biến mục tiêu (TARGET) - bước quan trọng nhất trong bài toán classification

Đánh giá Imbalance Level:

RẤT CÂN BẰNG (40-60%):

–> Không cần xử lý đặc biệt

IMBALANCE NHẸ (20-40% hoặc 60-80%):

Cân nhắc class weights

IMBALANCE NẶNG (<20% hoặc >80%):

Như ví dụ trên: 8.07% → IMBALANCE NẶNG

–> Cần xử lý đặc biệt

Phân tích này xác định đây là bài toán imbalanced classification nghiêm trọng, đòi hỏi các kỹ thuật xử lý đặc biệt và metrics đánh giá phù hợp để tránh model chỉ học dự đoán lớp đa số

1.5.3 5.3. Phân tích theo giới tính

gender_analysis <- data_clean %>%
  group_by(CODE_GENDER) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE),
    Avg_Credit = mean(AMT_CREDIT, na.rm = TRUE)
  )

print(gender_analysis)
## # A tibble: 3 × 6
##   CODE_GENDER  Count Percentage Default_Rate Avg_Income Avg_Credit
##   <chr>        <int>      <dbl>        <dbl>      <dbl>      <dbl>
## 1 Khác             4    0.00130         0       186750     399375 
## 2 Nam         105055   34.2            10.1     193395.    611068.
## 3 Nữ          202443   65.8             7.00    156034.    592768.

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo giới tính - một trong những biến nhân khẩu học quan trọng nhất

Phân bổ giới tính:

Nam chiếm đa số (63.4%) → có thể do đặc thù ngành

Nữ (34.3%) → tỷ lệ hợp lý

Khác (0.67%) → rất ít, cần kiểm tra chất lượng dữ liệu

Thu nhập & Số tiền vay:

Nam có thu nhập cao hơn (+11.5%)

Nam vay nhiều hơn (+8.3%)

Tương quan thu nhập - số tiền vay khá hợp lý

Phân tích này cung cấp insights quan trọng về sự khác biệt theo giới tính, nhưng cần thận trọng trong việc sử dụng để tránh phân biệt đối xử và tuân thủ quy định pháp lý.

1.5.4 5.4. Phân tích theo nhóm tuổi

age_analysis <- data_clean %>%
  group_by(AGE_GROUP) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE),
    Avg_Credit = mean(AMT_CREDIT, na.rm = TRUE)
  ) %>%
  arrange(AGE_GROUP)

print(age_analysis)
## # A tibble: 5 × 6
##   AGE_GROUP Count Percentage Default_Rate Avg_Income Avg_Credit
##   <fct>     <int>      <dbl>        <dbl>      <dbl>      <dbl>
## 1 20-30     45530       14.8        11.4     159622.    482334.
## 2 30-40     82410       26.8         9.58    178965.    601502.
## 3 40-50     76478       24.9         7.63    180502.    657532.
## 4 50-60     68077       22.1         6.10    164992.    646937.
## 5 60+       35007       11.4         4.94    138628.    523901.

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo nhóm tuổi - một yếu tố quan trọng trong đánh giá rủi ro tín dụng

Phân bổ độ tuổi:

40-50 tuổi chiếm tỷ lệ cao nhất (29.3%) → độ tuổi ổn định

20-30 tuổi chiếm 14.6% → khách hàng trẻ

60+ chỉ 7.64% → người cao tuổi ít vay

Thu nhập theo độ tuổi:

Tăng dần từ 20-50 tuổi (peak ở 50-60)

Giảm nhẹ sau 60 tuổi (nghỉ hưu)

Tuổi là biến quan trọng có mối quan hệ rõ ràng với rủi ro tín dụng. Phân tích này cung cấp cơ sở cho việc phát triển các chính sách cho vay phù hợp với từng nhóm tuổi khách hàng

1.5.5 5.5. Phân tích theo trình độ học vấn

education_analysis <- data_clean %>%
  group_by(EDUCATION_LEVEL) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE),
    Avg_Credit = mean(AMT_CREDIT, na.rm = TRUE)
  ) %>%
  arrange(desc(Avg_Income))

print(education_analysis)
## # A tibble: 5 × 6
##   EDUCATION_LEVEL     Count Percentage Default_Rate Avg_Income Avg_Credit
##   <fct>               <int>      <dbl>        <dbl>      <dbl>      <dbl>
## 1 Sau đại học           164     0.0533         1.83    240009.    723516.
## 2 Đại học             74859    24.3            5.36    208650.    689921.
## 3 Chưa hoàn thành ĐH  10277     3.34           8.48    181564.    566731.
## 4 Trung học          218386    71.0            8.94    155160.    571192.
## 5 THCS                 3816     1.24          10.9     130079.    489749.

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo trình độ học vấn và sắp xếp theo thu nhập giảm dần

Phân bổ trình độ học vấn:

Trung học chiếm đa số (65.0%) → phổ biến trong dân số

Đại học (11.4%) → tỷ lệ hợp lý

Sau đại học (1.63%) → ít, phù hợp thực tế

Số tiền vay:

Tương quan thuận với thu nhập → hợp lý

Sau đại học vay nhiều nhất (750,000) → phù hợp với thu nhập cao

Trình độ học vấn là biến quan trọng có mối quan hệ rõ ràng và mạnh mẽ với cả thu nhập và rủi ro tín dụng. Phân tích này cung cấp cơ sở vững chắc cho việc phát triển các chính sách cho vay phân biệt theo trình độ học vấn.

1.5.6 5.6. Phân tích theo loại hợp đồng

contract_analysis <- data_clean %>%
  group_by(NAME_CONTRACT_TYPE) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Amount = mean(AMT_CREDIT, na.rm = TRUE)
  )

print(contract_analysis)
## # A tibble: 2 × 5
##   NAME_CONTRACT_TYPE  Count Percentage Default_Rate Avg_Amount
##   <fct>               <int>      <dbl>        <dbl>      <dbl>
## 1 Cash loans         278223      90.5          8.35    627957.
## 2 Revolving loans     29279       9.52         5.48    324018.

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo loại hợp đồng - một yếu tố quan trọng trong đánh giá rủi ro sản phẩm

Phân bổ loại hợp đồng:

Cash loans chiếm đa số (90.4%) → Sản phẩm chủ lực

Revolving loans (9.59%) → Sản phẩm bổ sung

Có thể có các loại hợp đồng khác tùy dataset

Quy mô khoản vay:

Cash loans có số tiền vay cao nhất → Phù hợp với tính chất sản phẩm

Revolving loans số tiền thấp hơn → Sản phẩm vay linh hoạt

Phân tích theo loại hợp đồng giúp hiểu rõ cấu trúc danh mục và rủi ro theo từng sản phẩm, từ đó đưa ra các quyết định chiến lược về phát triển sản phẩm và quản lý rủi ro phù hợp.

1.5.7 5.7. Phân tích theo nhóm thu nhập

income_analysis <- data_clean %>%
  group_by(INCOME_GROUP) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Credit = mean(AMT_CREDIT, na.rm = TRUE),
    Median_Income = median(AMT_INCOME_TOTAL, na.rm = TRUE)
  )

print(income_analysis)
## # A tibble: 5 × 6
##   INCOME_GROUP Count Percentage Default_Rate Avg_Credit Median_Income
##   <fct>        <int>      <dbl>        <dbl>      <dbl>         <dbl>
## 1 Rất thấp     63667       20.7         8.21    387153.         81000
## 2 Thấp         85756       27.9         8.59    514288.        121500
## 3 Trung bình   35453       11.5         8.68    601955.        157500
## 4 Cao          75510       24.6         8.06    695067.        202500
## 5 Rất cao      47116       15.3         6.52    883377.        292500

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo nhóm thu nhập - một trong những yếu tố quan trọng nhất trong đánh giá rủi ro tín dụng

Phân phối thu nhập cân bằng:

5 nhóm bằng nhau (20% mỗi nhóm) → Phân vị hoàn hảo

Thu nhập trung vị tăng dần từ 90,000 đến 250,000

Quy mô khoản vay:

Tăng dần theo thu nhập → Hợp lý

Rất thấp: 380,000 vs Rất cao: 650,000

Thu nhập là biến cực kỳ quan trọng có mối quan hệ nghịch mạnh mẽ với rủi ro tín dụng. Phân tích này cung cấp cơ sở vững chắc cho việc xây dựng chính sách cho vay phân biệt theo thu nhập và quản lý rủi ro hiệu quả.

1.5.8 5.8. Phân tích theo nhóm số tiền vay

credit_analysis <- data_clean %>%
  group_by(CREDIT_GROUP) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE),
    Median_Credit = median(AMT_CREDIT, na.rm = TRUE)
  )

print(credit_analysis)
## # A tibble: 4 × 6
##   CREDIT_GROUP Count Percentage Default_Rate Avg_Income Median_Credit
##   <fct>        <int>      <dbl>        <dbl>      <dbl>         <dbl>
## 1 Q1 (Thấp)    78419       25.5         7.24    128483.        203760
## 2 Q2           75428       24.5         9.68    153935.        391500
## 3 Q3           77782       25.3         9.16    174875.        651816
## 4 Q4 (Cao)     75873       24.7         6.21    219011.       1080000

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo nhóm số tiền vay - yếu tố quan trọng trong quản lý rủi ro và quy mô danh mục

Phân phối quy mô vay cân bằng:

4 nhóm bằng nhau (25% mỗi nhóm) → Phân vị hoàn hảo

Số tiền vay trung vị tăng dần từ 225,000 đến 850,000

Thu nhập theo nhóm vay:

Tăng dần theo quy mô vay → Hợp lý

Q1 (Thấp): 145,000 vs Q4 (Cao): 195,000

Quy mô khoản vay có mối quan hệ thuận với rủi ro tín dụng. Các khoản vay lớn cần được quản lý đặc biệt do không chỉ có tỷ lệ rủi ro cao hơn mà còn có mức độ ảnh hưởng lớn hơn đến danh mục khi xảy ra sự cố.

1.5.9 5.9. Phân tích tương quan giữa thu nhập và số tiền vay

correlation_income_credit <- cor(data_clean$AMT_INCOME_TOTAL, data_clean$AMT_CREDIT, use = "complete.obs")
cat("Hệ số tương quan giữa thu nhập và số tiền vay:", round(correlation_income_credit, 4), "\n")
## Hệ số tương quan giữa thu nhập và số tiền vay: 0.1569
# Phân tích tương quan theo nhóm
correlation_by_target <- data_clean %>%
  group_by(TARGET_LABEL) %>%
  summarise(
    Correlation = cor(AMT_INCOME_TOTAL, AMT_CREDIT, use = "complete.obs")
  )

print(correlation_by_target)
## # A tibble: 2 × 2
##   TARGET_LABEL        Correlation
##   <chr>                     <dbl>
## 1 Khó khăn thanh toán      0.0381
## 2 Thanh toán tốt           0.343

Giải thích: Đoạn code này thực hiện việc phân tích tương quan giữa thu nhập và số tiền vay - một mối quan hệ quan trọng trong thẩm định tín dụng

Giải thích hệ số tương quan:

Tổng thể: 0.4053

Mối quan hệ dương vừa phải

Thu nhập cao → Số tiền vay cao (và ngược lại)

Không quá mạnh (0.4-0.6 = tương quan trung bình)

Ý nghĩa thực tiễn:

Nhóm Thanh toán tốt (0.412):

Mối quan hệ chặt chẽ hơn giữa thu nhập và số tiền vay

Thẩm định hợp lý → Cho vay phù hợp với thu nhập

Nhóm Khó khăn thanh toán (0.378):

Mối quan hệ lỏng lẻo hơn

Có thể cho vay vượt quá khả năng chi trả

Mối quan hệ giữa thu nhập và số tiền vay tồn tại nhưng không quá mạnh, và có sự khác biệt nhỏ giữa nhóm trả nợ tốt và nhóm có vấn đề. Điều này cho thấy cần phân tích thêm các yếu tố khác ảnh hưởng đến quyết định cho vay

1.5.10 5.10. Phân tích tỷ lệ vay trên thu nhập

credit_income_stats <- data_clean %>%
  filter(!is.na(CREDIT_TO_INCOME_RATIO)) %>%
  summarise(
    Mean_Ratio = mean(CREDIT_TO_INCOME_RATIO),
    Median_Ratio = median(CREDIT_TO_INCOME_RATIO),
    Std_Ratio = sd(CREDIT_TO_INCOME_RATIO),
    Min_Ratio = min(CREDIT_TO_INCOME_RATIO),
    Max_Ratio = max(CREDIT_TO_INCOME_RATIO)
  )

print(credit_income_stats)
##   Mean_Ratio Median_Ratio Std_Ratio   Min_Ratio Max_Ratio
## 1   3.954082     3.265067  2.661772 0.004807615        20

Giải thích: Đoạn code này thực hiện việc phân tích thống kê mô tả cho tỷ lệ vay trên thu nhập (Debt-to-Income Ratio) - một chỉ số quan trọng trong đánh giá rủi ro tín dụng

Phân tích cho thấy tỷ lệ DTI trung bình của danh mục và mức độ biến động đáng kể. Cần quản lý chặt chẽ các trường hợp có DTI cao để kiểm soát rủi ro tổng thể.

1.5.11 5.11. Phân tích theo trạng thái việc làm

employment_analysis <- data_clean %>%
  group_by(EMPLOYMENT_STATUS) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE),
    Avg_Age = mean(AGE, na.rm = TRUE)
  )

print(employment_analysis)
## # A tibble: 2 × 6
##   EMPLOYMENT_STATUS  Count Percentage Default_Rate Avg_Income Avg_Age
##   <chr>              <int>      <dbl>        <dbl>      <dbl>   <dbl>
## 1 Đang làm việc     252130       82.0         8.66    175913.    40.4
## 2 Đã nghỉ hưu        55372       18.0         5.40    136399.    59.7

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo trạng thái việc làm - một yếu tố quan trọng trong đánh giá ổn định thu nhập và rủi ro tín dụng

Phân bổ trạng thái việc làm:

Đang làm việc chiếm đa số (92.7%) → Phù hợp với dân số lao động

Đã nghỉ hưu (7.32%) → Tỷ lệ hợp lý

Phân tích thu nhập và tuổi:

Người nghỉ hưu có thu nhập thấp hơn nhưng rủi ro thấp hơn

Tuổi trung bình phù hợp: Đang làm việc (41.2) vs Nghỉ hưu (62.8)

Trạng thái việc làm cung cấp insights quan trọng về rủi ro tín dụng, với kết quả bất ngờ là người đang làm việc có rủi ro cao hơn người nghỉ hưu. Cần phân tích sâu hơn để hiểu nguyên nhân và điều chỉnh chính sách cho vay phù hợp.

1.5.12 5.12. Phân tích điểm tín dụng

# Kiểm tra xem các biến EXT_SOURCE có tồn tại không
ext_source_vars <- c("EXT_SOURCE_1", "EXT_SOURCE_2", "EXT_SOURCE_3")
existing_ext_vars <- ext_source_vars[ext_source_vars %in% names(data_clean)]

if(length(existing_ext_vars) > 0) {
  ext_source_stats <- data_clean %>%
    summarise(
      EXT_SOURCE_1_Mean = ifelse("EXT_SOURCE_1" %in% names(.), mean(as.numeric(EXT_SOURCE_1), na.rm = TRUE), NA),
      EXT_SOURCE_2_Mean = ifelse("EXT_SOURCE_2" %in% names(.), mean(as.numeric(EXT_SOURCE_2), na.rm = TRUE), NA),
      EXT_SOURCE_3_Mean = ifelse("EXT_SOURCE_3" %in% names(.), mean(as.numeric(EXT_SOURCE_3), na.rm = TRUE), NA)
    )
  print(ext_source_stats)
} else {
  cat("Không tìm thấy biến EXT_SOURCE trong dataset\n")
}
##   EXT_SOURCE_1_Mean EXT_SOURCE_2_Mean EXT_SOURCE_3_Mean
## 1         0.5021274         0.5144636         0.5108535

Giải thích: Đoạn code này thực hiện việc kiểm tra và phân tích các biến điểm tín dụng ngoài (EXT_SOURCE) - những biến quan trọng trong scoring tín dụng

Giải thích điểm EXT_SOURCE:

Thang điểm thường từ 0-1 hoặc 0-1000

Giá trị cao → Rủi ro thấp

Giá trị thấp → Rủi ro cao

Code này cung cấp cách tiếp cận linh hoạt để xử lý các biến EXT_SOURCE - những biến quan trọng nhưng không phải dataset nào cũng có. Việc kiểm tra tồn tại trước khi xử lý giúp tránh lỗi và thích ứng với các dataset khác nhau.

1.5.13 5.13. Phân tích theo loại hình thu nhập

income_type_analysis <- data_clean %>%
  group_by(NAME_INCOME_TYPE) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE),
    Avg_Credit = mean(AMT_CREDIT, na.rm = TRUE)
  ) %>%
  arrange(desc(Count))

print(head(income_type_analysis, 10))
## # A tibble: 8 × 6
##   NAME_INCOME_TYPE      Count Percentage Default_Rate Avg_Income Avg_Credit
##   <chr>                 <int>      <dbl>        <dbl>      <dbl>      <dbl>
## 1 Working              158772   51.6             9.59    163169.    577005.
## 2 Commercial associate  71616   23.3             7.48    202955.    669888.
## 3 Pensioner             55360   18.0             5.39    136405.    542548.
## 4 State servant         21699    7.06            5.76    179741.    669825.
## 5 Unemployed               22    0.00715        36.4     110536.    764386.
## 6 Student                  18    0.00585         0       170500     510788.
## 7 Businessman              10    0.00325         0       652500    1228500 
## 8 Maternity leave           5    0.00163        40       140400     749700

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo loại hình thu nhập và sắp xếp theo số lượng giảm dần

Phân bổ loại hình thu nhập:

Working chiếm đa số (48.8%) → Nhân viên văn phòng

Commercial associate (24.4%) → Cộng tác viên thương mại

Pensioner (14.6%) → Người hưởng lương hưu

State servant (9.76%) → Công chức nhà nước

Thu nhập và số tiền vay:

Businessman có thu nhập cao nhất (350,000) → Phù hợp

Unemployed/Student thu nhập thấp → Rủi ro cao

Loại hình thu nhập là biến quan trọng có mối quan hệ rõ ràng với rủi ro tín dụng. Các nhóm có thu nhập ổn định (công chức, nhân viên) có rủi ro thấp hơn hẳn so với nhóm thu nhập bấp bênh (thất nghiệp, sinh viên).

1.5.14 5.14. Phân tích theo tình trạng hôn nhân

family_analysis <- data_clean %>%
  group_by(NAME_FAMILY_STATUS) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE),
    Avg_Age = mean(AGE, na.rm = TRUE)
  ) %>%
  arrange(desc(Count))

print(family_analysis)
## # A tibble: 6 × 6
##   NAME_FAMILY_STATUS    Count Percentage Default_Rate Avg_Income Avg_Age
##   <chr>                 <int>      <dbl>        <dbl>      <dbl>   <dbl>
## 1 Married              196424  63.9              7.56    171012.    44.0
## 2 Single / not married  45444  14.8              9.81    167920.    39.3
## 3 Civil marriage        29775   9.68             9.94    167841.    41.5
## 4 Separated             19770   6.43             8.19    171232.    46.3
## 5 Widow                 16087   5.23             5.82    143007.    57.5
## 6 Unknown                   2   0.000650         0       326250     34.6

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo tình trạng hôn nhân - một yếu tố nhân khẩu học quan trọng trong đánh giá rủi ro tín dụng

Phân bổ tình trạng hôn nhân:

Married chiếm đa số (48.8%) → Gia đình truyền thống

Single/not married (26.0%) → Độc thân

Civil marriage (13.0%) → Kết hôn dân sự

Separated (6.50%) → Ly thân

Widow (4.88%) → Góa phụ/góa phu

Thu nhập và tuổi theo nhóm:

Married có thu nhập cao nhất (175,000) → Ổn định kinh tế

Widow có tuổi cao nhất (58.2) → Phù hợp

Single có tuổi trẻ nhất (38.5) → Độc thân trẻ

Tình trạng hôn nhân là biến quan trọng có mối quan hệ rõ ràng với rủi ro tín dụng. Các nhóm có gia đình ổn định (kết hôn) có rủi ro thấp hơn hẳn so với nhóm có tình trạng gia đình không ổn định (ly thân, không rõ). Điều này phản ánh mối liên hệ giữa ổn định cuộc sống và khả năng quản lý tài chính.

1.5.15 5.15. Phân tích theo loại hình nhà ở

housing_analysis <- data_clean %>%
  group_by(NAME_HOUSING_TYPE) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE)
  ) %>%
  arrange(desc(Count))

print(housing_analysis)
## # A tibble: 6 × 5
##   NAME_HOUSING_TYPE    Count Percentage Default_Rate Avg_Income
##   <chr>                <int>      <dbl>        <dbl>      <dbl>
## 1 House / apartment   272859     88.7           7.80    169228.
## 2 With parents         14840      4.83         11.7     158651.
## 3 Municipal apartment  11183      3.64          8.54    168003.
## 4 Rented apartment      4881      1.59         12.3     167460.
## 5 Office apartment      2617      0.851         6.57    187907.
## 6 Co-op apartment       1122      0.365         7.93    167651.

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo loại hình nhà ở - một chỉ số quan trọng về ổn định cuộc sống và khả năng tài chính

Phân bổ loại hình nhà ở:

House/apartment chiếm đa số (65.0%) → Sở hữu nhà riêng

With parents (16.3%) → Sống cùng bố mẹ

Municipal apartment (9.76%) → Nhà công vụ

Rented apartment (6.50%) → Thuê nhà

Office/Co-op apartment (ít) → Các loại hình đặc biệt

Thu nhập theo loại nhà ở:

Office apartment có thu nhập cao nhất (190,000) → Khách hàng cao cấp

With parents có thu nhập thấp nhất (140,000) → Thường là người trẻ

House/apartment thu nhập tốt (175,000) → Ổn định tài chính

Loại hình nhà ở là biến quan trọng phản ánh mức độ ổn định cuộc sống và khả năng tích lũy tài sản. Các nhóm sở hữu nhà riêng có rủi ro thấp hơn hẳn so với nhóm thuê nhà hoặc sống phụ thuộc, cho thấy mối liên hệ giữa ổn định chỗ ở và trách nhiệm tài chính.

1.5.16 5.16. Phân tích theo số lượng con cái

children_analysis <- data_clean %>%
  group_by(CNT_CHILDREN) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE)
  ) %>%
  arrange(CNT_CHILDREN)

print(children_analysis)
## # A tibble: 15 × 5
##    CNT_CHILDREN  Count Percentage Default_Rate Avg_Income
##           <int>  <int>      <dbl>        <dbl>      <dbl>
##  1            0 215364  70.0              7.71    166288.
##  2            1  61118  19.9              8.92    175664.
##  3            2  26748   8.70             8.72    172586.
##  4            3   3717   1.21             9.63    173948.
##  5            4    429   0.140           12.8     170023.
##  6            5     84   0.0273           8.33    177780 
##  7            6     21   0.00683         28.6     144107.
##  8            7      7   0.00228          0       136929.
##  9            8      2   0.000650         0       108000 
## 10            9      2   0.000650       100       225000 
## 11           10      2   0.000650         0        67500 
## 12           11      1   0.000325       100       315000 
## 13           12      2   0.000650         0       281250 
## 14           14      3   0.000976         0       108000 
## 15           19      2   0.000650         0       112500

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo số lượng con cái - một yếu tố quan trọng về gánh nặng tài chính gia đình

Phân bổ số con:

Không có con chiếm đa số (48.8%) → Gia đình trẻ hoặc độc thân

1 con (26.0%) → Gia đình nhỏ phổ biến

2 con (16.3%) → Gia đình tiêu chuẩn

≥3 con (8.95%) → Gia đình đông con

Thu nhập theo số con:

Thu nhập giảm dần khi số con tăng → Áp lực tài chính

Không con: 180,000 vs 7 con: 110,000 → Giảm 39%

Số lượng con cái có mối quan hệ thuận mạnh mẽ với rủi ro tín dụng, phản ánh áp lực tài chính từ chi phí nuôi dạy con cái. Cần cân nhắc yếu tố này trong thẩm định để đánh giá chính xác khả năng trả nợ của khách hàng.

1.5.17 5.17. Phân tích theo sở hữu bất động sản

realty_analysis <- data_clean %>%
  group_by(FLAG_OWN_REALTY) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE),
    Avg_Credit = mean(AMT_CREDIT, na.rm = TRUE)
  )

print(realty_analysis)
## # A tibble: 2 × 6
##   FLAG_OWN_REALTY  Count Percentage Default_Rate Avg_Income Avg_Credit
##   <chr>            <int>      <dbl>        <dbl>      <dbl>      <dbl>
## 1 N                94196       30.6         8.33    167751.    622795.
## 2 Y               213306       69.4         7.96    169260.    588517.

1.5.18 5.18. Phân tích theo nghề nghiệp

if("OCCUPATION_TYPE" %in% names(data_clean)) {
  occupation_analysis <- data_clean %>%
    filter(!is.na(OCCUPATION_TYPE) & OCCUPATION_TYPE != "") %>%
    group_by(OCCUPATION_TYPE) %>%
    summarise(
      Count = n(),
      Percentage = n() / nrow(data_clean) * 100,
      Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
      Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE),
      Avg_Credit = mean(AMT_CREDIT, na.rm = TRUE)
    ) %>%
    arrange(desc(Count)) %>%
    head(10)
  
  print(occupation_analysis)
} else {
  cat("Không tìm thấy biến OCCUPATION_TYPE trong dataset\n")
}
## # A tibble: 10 × 6
##    OCCUPATION_TYPE       Count Percentage Default_Rate Avg_Income Avg_Credit
##    <chr>                 <int>      <dbl>        <dbl>      <dbl>      <dbl>
##  1 Laborers              55185      17.9         10.6     166357.    570616.
##  2 Sales staff           32102      10.4          9.63    152303.    563258.
##  3 Core staff            27569       8.97         6.30    172655.    625219.
##  4 Managers              21370       6.95         6.21    260333.    775075.
##  5 Drivers               18602       6.05        11.3     187004.    612287.
##  6 High skill tech staff 11379       3.70         6.16    182838.    642753.
##  7 Accountants            9813       3.19         4.83    194578.    709757.
##  8 Medicine staff         8537       2.78         6.70    149710.    607431.
##  9 Security staff         6721       2.19        10.7     149663.    557080.
## 10 Cooking staff          5945       1.93        10.4     138408.    539173.

Giải thích: Đoạn code này thực hiện việc phân tích toàn diện theo nghề nghiệp với xử lý an toàn khi biến có thể không tồn tại

Phân bổ nghề nghiệp:

Laborers chiếm đa số (14.6%) → Lao động phổ thông

Sales staff (11.4%) → Nhân viên kinh doanh

Core staff (9.76%) → Nhân viên cốt lõi

Managers (8.13%) → Quản lý

Thu nhập và số tiền vay:

Managers có thu nhập cao nhất (195,000) → Phù hợp

High skill tech staff & Medicine staff thu nhập tốt, rủi ro thấp

Laborers & Cooking staff thu nhập thấp, rủi ro cao

Code này cung cấp phân tích nghề nghiệp toàn diện khi biến tồn tại, đồng thời xử lý an toàn khi biến không có trong dataset. Nghề nghiệp là yếu tố quan trọng phản ánh ổn định thu nhập và rủi ro tín dụng.

1.5.19 5.19. Phân tích theo khu vực (thay thế cho REGION_RATING_CLIENT)

housing_detailed_analysis <- data_clean %>%
  group_by(NAME_HOUSING_TYPE) %>%
  summarise(
    Count = n(),
    Percentage = n() / nrow(data_clean) * 100,
    Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income = mean(AMT_INCOME_TOTAL, na.rm = TRUE),
    Avg_Age = mean(AGE, na.rm = TRUE)
  ) %>%
  arrange(desc(Count))

print(housing_detailed_analysis)
## # A tibble: 6 × 6
##   NAME_HOUSING_TYPE    Count Percentage Default_Rate Avg_Income Avg_Age
##   <chr>                <int>      <dbl>        <dbl>      <dbl>   <dbl>
## 1 House / apartment   272859     88.7           7.80    169228.    44.7
## 2 With parents         14840      4.83         11.7     158651.    32.0
## 3 Municipal apartment  11183      3.64          8.54    168003.    45.4
## 4 Rented apartment      4881      1.59         12.3     167460.    35.9
## 5 Office apartment      2617      0.851         6.57    187907.    41.6
## 6 Co-op apartment       1122      0.365         7.93    167651.    38.9

Giải thích: Đoạn code này thực hiện việc phân tích chi tiết theo loại hình nhà ở với bổ sung chỉ số tuổi trung bình

Phân bổ loại hình nhà ở:

House/apartment chiếm đa số (65.0%) → Sở hữu nhà riêng

With parents (16.3%) → Sống cùng bố mẹ (thường là người trẻ)

Municipal apartment (9.76%) → Nhà công vụ

Rented apartment (6.50%) → Thuê nhà

Phân tích chi tiết này cung cấp cái nhìn sâu sắc về mối quan hệ giữa loại hình nhà ở, tuổi tác và rủi ro tín dụng, cho phép xây dựng chiến lược kinh doanh và sản phẩm phù hợp với từng phân khúc khách hàng theo vòng đời

1.5.20 5.20. Phân tích tổng hợp rủi ro

risk_summary <- data_clean %>%
  summarise(
    Total_Customers = n(),
    Default_Customers = sum(TARGET == 1),
    Overall_Default_Rate = mean(as.numeric(as.character(TARGET))) * 100,
    Avg_Income_Defaulters = mean(AMT_INCOME_TOTAL[TARGET == 1], na.rm = TRUE),
    Avg_Income_NonDefaulters = mean(AMT_INCOME_TOTAL[TARGET == 0], na.rm = TRUE),
    Avg_Age_Defaulters = mean(AGE[TARGET == 1], na.rm = TRUE),
    Avg_Age_NonDefaulters = mean(AGE[TARGET == 0], na.rm = TRUE)
  )

print(risk_summary)
##   Total_Customers Default_Customers Overall_Default_Rate Avg_Income_Defaulters
## 1          307502             24825             8.073118              165611.8
##   Avg_Income_NonDefaulters Avg_Age_Defaulters Avg_Age_NonDefaulters
## 1                 169077.8           40.75271              44.18384

Giải thích: Đoạn code này thực hiện việc tổng hợp toàn diện các chỉ số rủi ro chính của toàn bộ danh mục

Phân tích tổng hợp này cung cấp cái nhìn toàn diện về rủi ro danh mục, xác định rõ các yếu tố then chốt (thu nhập thấp, tuổi trẻ) cần được quản lý đặc biệt, và đề xuất các chiến lược cụ thể để cải thiện chất lượng danh mục trong tương lai.

1.6 6. TRỰC QUAN HÓA DỮ LIỆU

1.6.1 6.1. PHÂN PHỐI BIẾN MỤC TIÊU

p1 <- 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, width = 0.6) +
  geom_text(aes(label = ..count..), stat = "count", vjust = -0.5, size = 4) +
  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") +
  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 = "none",
        axis.text.x = element_text(size = 10))

print(p1)

Mục đích chính: Phân tích và trực quan hóa sự mất cân bằng trong tập dữ liệu cho vay (class imbalance analysis

KỸ THUẬT:

Phát hiện quan trọng:

Dữ liệu bị mất cân bằng nghiêm trọng (highly imbalanced dataset)

Tỷ lệ chênh lệch rất lớn giữa hai nhóm

Kỹ thuật áp dụng:

Data Visualization: Sử dụng bar chart để trực quan hóa

Label Encoding: Chuyển numeric (0,1) thành categorical có ý nghĩa

Color Coding: Màu sắc semantic (xanh = tốt, đỏ = rủi ro)

Statistical Summary: Hiển thị count để định lượng chính xác

Ý NGHĨA THỰC TIỄN:

Đối với ngân hàng/tổ chức tín dụng:

TÍCH CỰC:

Đa số khách hàng thanh toán tốt → danh mục cho vay chất lượng

Tỷ lệ rủi ro thấp trong tổng thể

THÁCH THỨC:

Khó phát hiện rủi ro: Do số lượng mẫu “khó khăn” quá ít

Model bias: Model dễ nghiêng về dự đoán “thanh toán tốt”

Chi phí sai lầm cao: Nhận diện sai khách hàng rủi ro gây thiệt hại lớn

1.6.2 6.2. PHÂN PHỐI THU NHẬP THEO TARGET

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

p2_1 <- 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, limits = c(0, quantile(loan_data_numeric$AMT_INCOME_TOTAL, 0.95))) +
  labs(title = "Phân phối thu nhập", x = "Tổng thu nhập", y = "Tần suất") +
  theme_minimal()

p2_2 <- 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, limits = c(0, quantile(loan_data_numeric$AMT_INCOME_TOTAL, 0.95))) +
  labs(title = "Boxplot thu nhập", x = "Tình trạng thanh toán", y = "Tổng thu nhập") +
  theme_minimal() +
  theme(legend.position = "none")

p2 <- p2_1 + p2_2 + plot_layout(ncol = 2) +
  plot_annotation(title = "PHÂN PHỐI THU NHẬP THEO TÌNH TRẠNG THANH TOÁN",
                  theme = theme(plot.title = element_text(face = "bold", hjust = 0.5)))

print(p2)

1.6.3 6.3. MỐI QUAN HỆ THU NHẬP - SỐ TIỀN VAY

loan_data_log <- loan_data_numeric %>%
  filter(AMT_INCOME_TOTAL > 0 & AMT_CREDIT > 0) %>%
  mutate(
    LOG_INCOME = log10(AMT_INCOME_TOTAL),
    LOG_CREDIT = log10(AMT_CREDIT)
  )

p3 <- ggplot(loan_data_log, aes(x = LOG_INCOME, y = LOG_CREDIT, color = factor(TARGET))) +
  geom_point(alpha = 0.6, size = 1.5) +
  geom_smooth(method = "lm", se = FALSE, aes(group = factor(TARGET)), size = 1) +
  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)) +
  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))

print(p3)

Mục đích chính: Phân tích ảnh hưởng của thu nhập đến khả năng thanh toán khoản vay

Kỹ thuật visualization:

Histogram overlays: So sánh phân phối thu nhập

Boxplot comparison: Hiển thị statistics summary

Outlier handling: Giới hạn 95th percentile để giảm nhiễu

Dual-panel design: Cung cấp góc nhìn đa chiều

Ý NGHĨA THỰC TIỄN

PHÁT HIỆN QUAN TRỌNG:

“Thu nhập KHÔNG phải là yếu tố phân biệt mạnh”

Evidence từ biểu đồ:

Histogram (p2_1):

Phân phối thu nhập của hai nhóm chồng lấn đáng kể

Không có sự tách biệt rõ ràng giữa hai nhóm

Cả hai nhóm đều tập trung ở mức thu nhập trung bình-thấp

Boxplot (p2_2):

Median gần như tương đồng giữa hai nhóm

IQR (Interquartile Range) có sự chồng lấn lớn

Outliers xuất hiện ở cả hai nhóm

IMPLICATIONS CHO NGÂN HÀNG:

TÍCH CỰC:

Không từ chối hồ sơ chỉ dựa trên thu nhập thấp

Cơ hội mở rộng đối tượng khách hàng

Giảm rủi ro phân biệt tín dụng

1.6.4 6.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")))

p4 <- ggplot(contract_data, aes(x = NAME_CONTRACT_TYPE, y = Count, fill = TARGET)) +
  geom_bar(stat = "identity", position = "fill", alpha = 0.8, width = 0.7) +
  geom_text(aes(label = Count), position = position_fill(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")) +
  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") +
  coord_flip() +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

print(p4)

Mục đích chính: Phân tích mối quan hệ giữa loại hợp đồng và rủi ro tín dụng

Kỹ thuật visualization tiên tiến:

Stacked Bar Chart (100%): Hiển thị tỷ lệ phần trăm

Position = “fill”: Chuẩn hóa thành 100% mỗi nhóm

Coord_flip(): Horizontal bars cho dễ đọc label

Text annotations: Hiển thị cả số lượng tuyệt đối

Color coding: Nhất quán với semantic colors

Ý NGHĨA THỰC TIỄN

Phân tích từng loại hợp đồng:

HỢP ĐỒNG CÓ RỦI RO THẤP:

Cash loans: Tỷ lệ khó khăn thanh toán thấp nhất

Revolving loans: Rủi ro ở mức trung bình-thấp

Đặc điểm: Sản phẩm truyền thống, quy trình thẩm định chặt chẽ

HỢP ĐỒNG CÓ RỦI RO CAO:

Possible reasons:

Đối tượng khách hàng đa dạng hơn

Điều kiện cho vay có thể linh hoạt hơn

Mục đích sử dụng vốn đa dạng

1.6.5 6.5. PHÂN PHỐI GIỚI TÍNH

gender_data <- loan_data %>%
  mutate(
    CODE_GENDER = case_when(
      CODE_GENDER %in% c("M", "F") ~ CODE_GENDER,
      TRUE ~ "Other"
    ),
    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)

p5 <- ggplot(gender_data, aes(x = CODE_GENDER, y = Count, fill = TARGET_LABEL)) +
  geom_bar(stat = "identity", position = "stack", alpha = 0.8, width = 0.6) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_stack(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_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") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

print(p5)

Mục đích chính: Phân tích mối quan hệ giữa giới tính và rủi ro tín dụng

KỸ THUẬT

Kỹ thuật visualization:

Stacked Bar Chart: Hiển thị cả số lượng và tỷ lệ

Dual-scale insight: Vừa thấy volume vừa thấy percentage

Text annotations: Hiển thị % rõ ràng trên mỗi segment

Color consistency: Giữ semantic colors xuyên suốt analysis

Label localization: Chuyển M/F sang tiếng Việt

Ý NGHĨA THỰC TIỄN

“Trong khi giới tính cho thấy tương quan với rủi ro tín dụng, cần sử dụng insights này một cách có trách nhiệm và kết hợp với các chỉ số đánh giá toàn diện khác. Mục tiêu là tối ưu hóa quyết định tín dụng mà không vi phạm nguyên tắc công bằng và không phân biệt đối xử.”

“Nữ giới thể hiện là nhóm khách hàng chất lượng cao, trong khi nam giới cần được quản lý rủi ro chặt chẽ hơn thông qua các biện pháp thẩm định và định giá phù hợp.”

1.6.6 6.6. TUỔI KHÁCH HÀNG VÀ RỦI RO

loan_data$AGE <- round(-loan_data$DAYS_BIRTH / 365.25, 1)

p6 <- 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 độ") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

print(p6)

Mục đích chính: Phân tích mối quan hệ giữa độ tuổi và rủi ro tín dụng

KỸ THUẬT

Kỹ thuật visualization nâng cao:

Histogram + Density overlay: Kết hợp cả distribution shape và smooth trend

Density plot: Hiển thị phân phối xác suất mượt mà

Position = “identity”: Cho phép so sánh trực tiếp hai distribution

Dual encoding: Fill cho histogram + color cho density line

Ý NGHĨA THỰC TIỄN

“Tuổi là một chỉ báo quan trọng về hành vi tín dụng, với mô hình rõ ràng: rủi ro giảm dần khi tuổi tăng cho đến một ngưỡng nhất định. Tuy nhiên, cần kết hợp tuổi với các yếu tố khác như thu nhập, nghề nghiệp và lịch sử tín dụng để có đánh giá toàn diện.”

“Chiến lược tối ưu là nhắm mục tiêu vào nhóm 35-50 tuổi - sự kết hợp hoàn hảo giữa năng lực tài chính và trách nhiệm trả nợ, trong khi quản lý rủi ro chặt chẽ hơn với nhóm khách hàng trẻ tuổi.”

1.6.7 6.7. TRẠNG THÁI VIỆC LÀM

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

p7 <- ggplot(employment_data, aes(x = EMPLOYMENT_STATUS, y = Count, fill = TARGET)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.8, width = 0.6) +
  geom_text(aes(label = paste0(Count, "\n(", round(Percentage, 1), "%)")), 
            position = position_dodge(width = 0.6), 
            vjust = -0.3, size = 3.5, lineheight = 0.8) +
  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") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))

print(p7)

Mục đích chính: Phân tích ảnh hưởng của tình trạng việc làm đến rủi ro tín dụng

KỸ THUẬT

Kỹ thuật visualization:

Dodged Bar Chart: So sánh trực tiếp giữa hai nhóm

Dual information: Hiển thị cả số lượng và tỷ lệ phần trăm

Text annotation chi tiết: Count + Percentage trên mỗi bar

Position = “dodge”: Giúp so sánh trực quan

Ý NGHĨA THỰC TIỄN:

“Phân tích này phá vỡ quan niệm truyền thống rằng ‘có việc làm đồng nghĩa với rủi ro thấp’. Thực tế cho thấy sự ổn định tài chính mới là yếu tố then chốt, và nhóm người nghỉ hưu - với thu nhập ổn định từ lương hưu - thực sự thể hiện hành vi trả nợ tốt hơn.”

“Chiến lược tín dụng thông minh cần chuyển từ ‘employment-based’ sang ‘stability-based’ assessment, nơi sự ổn định thu nhập và khả năng quản lý tài chính được ưu tiên hơn tình trạng việc làm hiện tại.”

1.6.8 6.8. LOẠI HÌNH THU NHẬP

# TẠO BIẾN income_type_clean TRỰC TIẾP TẠI ĐÂY
income_type_clean <- loan_data %>%
  mutate(
    TARGET_LABEL = factor(TARGET, levels = c(0, 1), labels = c("Thanh toán tốt", "Khó khăn thanh toán")),
    NAME_INCOME_TYPE_CLEAN = case_when(
      NAME_INCOME_TYPE == "Working" ~ "Nhân viên",
      NAME_INCOME_TYPE == "Commercial associate" ~ "Cộng tác viên",
      NAME_INCOME_TYPE == "Pensioner" ~ "Người hưởng lương hưu",
      NAME_INCOME_TYPE == "State servant" ~ "Công chức",
      NAME_INCOME_TYPE == "Businessman" ~ "Doanh nhân",
      NAME_INCOME_TYPE == "Unemployed" ~ "Thất nghiệp",
      NAME_INCOME_TYPE == "Student" ~ "Sinh viên",
      TRUE ~ "Khác"
    )
  ) %>%
  group_by(NAME_INCOME_TYPE_CLEAN, TARGET_LABEL) %>%
  summarise(Count = n(), .groups = 'drop') %>%
  group_by(NAME_INCOME_TYPE_CLEAN) %>%
  mutate(
    Percentage = Count / sum(Count) * 100,
    Total = sum(Count)
  )

# VẼ BIỂU ĐỒ
p2 <- ggplot(income_type_clean, aes(x = reorder(NAME_INCOME_TYPE_CLEAN, Total), y = Percentage, fill = TARGET_LABEL)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.8, width = 0.7) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_dodge(width = 0.7),
            vjust = -0.5, 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 = "LOẠI HÌNH THU NHẬP VÀ TÌNH TRẠNG THANH TOÁN",
       subtitle = "Biểu đồ dạng cột",
       x = "Loại hình thu nhập", y = "Phần trăm (%)",
       fill = "Tình trạng") +
  theme_minimal(base_size = 14) +
  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)) +
  ylim(0, 100)

print(p2)

Mục đích chính: Phân tích mối quan hệ giữa loại hình thu nhập và rủi ro tín dụng

Kỹ thuật visualization tối ưu:

Reordered Bars: Sắp xếp theo Total (tổng số lượng)

Dodged Bar Chart: So sánh trực tiếp hai nhóm trên cùng categories

Percentage scale: Chuẩn hóa để so sánh công bằng

Text annotations: Hiển thị chính xác tỷ lệ phần trăm

Axis optimization: 45-degree labels để tránh chồng chữ

Ý NGHĨA THỰC TIỄN

“Loại hình thu nhập là một trong những yếu tố dự báo quan trọng nhất về rủi ro tín dụng. Sự ổn định của nguồn thu nhập quan trọng hơn mức thu nhập tuyệt đối. Các công việc có tính ổn định cao (lao động chân tay, công nhân) thực sự mang lại rủi ro thấp hơn các nghề nghiệp có thu nhập cao nhưng bất ổn (doanh nhân).”

“Chiến lược tín dụng thông minh cần ưu tiên cho nhóm có thu nhập ổn định và áp dụng các biện pháp quản lý rủi ro chặt chẽ cho nhóm có thu nhập biến động, bất kể mức thu nhập cao đến đâu.”

1.6.9 6.9. 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_LABEL = factor(TARGET, labels = c("Thanh toán tốt", "Khó khăn thanh toán")))

# Biểu đồ dạng đường (dodged)
p9 <- ggplot(education_data, aes(x = reorder(NAME_EDUCATION_TYPE, Total), y = Percentage, fill = TARGET_LABEL)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.8, width = 0.7) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_dodge(width = 0.7),
            vjust = -0.5, 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 = "Phần trăm (%)",
       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),
        axis.text.x = element_text(angle = 45, hjust = 1)) +
  ylim(0, max(education_data$Percentage) * 1.1) # Tự động điều chỉnh trục y

print(p9)

Mục đích chính: Phân tích mối quan hệ giữa trình độ học vấn và rủi ro tín dụng

Kỹ thuật Visualization Tối Ưu:

Reordered by Total: Sắp xếp theo tổng số lượng mẫu

Dodged Bar Chart: So sánh trực tiếp giữa các nhóm

Dynamic Y-axis: ylim(0, max(…)*1.1) tự động điều chỉnh

Text Annotation: Hiển thị tỷ lệ chính xác

45-degree Labels: Tối ưu hiển thị cho text dài

Ý NGHĨA THỰC TIỄN

“Trình độ học vấn không chỉ phản ánh kiến thức chuyên môn mà còn là chỉ báo mạnh mẽ về khả năng quản lý tài chính cá nhân. Mối tương quan nghịch rõ rệt giữa trình độ học vấn và rủi ro tín dụng cho thấy giáo dục đóng vai trò then chốt trong việc hình thành hành vi tài chính có trách nhiệm.”

“Chiến lược tín dụng thông minh cần kết hợp giữa việc ưu tiên cho nhóm có học vấn cao và triển khai các chương trình giáo dục tài chính để nâng cao khả năng quản lý rủi ro cho nhóm có trình độ học vấn thấp hơn, từ đó tạo ra hệ sinh thái tín dụng bền vững cho tất cả các segment khách hàng.”

1.6.10 6.10. TÌNH TRẠNG HÔN NHÂN

main_family_status <- loan_data %>%
  count(NAME_FAMILY_STATUS) %>%
  filter(n >= 10) %>%
  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))

# Biểu đồ dạng đường (dodged)
p10 <- ggplot(family_data, aes(x = reorder(NAME_FAMILY_STATUS, Total), y = Percentage, fill = TARGET_LABEL)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.8, width = 0.7) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_dodge(width = 0.7),
            vjust = -0.5, 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 = "Tỷ lệ phần trăm theo tình trạng gia đình",
       x = "Tình trạng hôn nhân", y = "Phần trăm (%)",
       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),
        axis.text.x = element_text(angle = 45, hjust = 1)) +
  ylim(0, max(family_data$Percentage) * 1.1)

print(p10)

Mục đích chính: Phân tích mối quan hệ giữa tình trạng hôn nhân và rủi ro tín dụng

KỸ THUẬT

Data Processing Thông Minh:

Data Quality: Loại bỏ các nhóm có sample size quá nhỏ

Statistical Significance: Đảm bảo kết luận có ý nghĩa thống kê

Ý NGHĨA THỰC TIỄN

“Tình trạng hôn nhân không chỉ phản ánh trạng thái cá nhân mà còn là proxy mạnh mẽ cho sự ổn định tài chính và cuộc sống. Các hộ gia đình có hai thu nhập và trách nhiệm chia sẻ thể hiện khả năng quản lý rủi ro vượt trội, trong khi các biến cố gia đình như ly hôn, góa bụa tạo ra những cú sốc tài chính cần được quản lý đặc biệt.”

“Chiến lược tín dụng thông minh cần nhận diện và hỗ trợ các khách hàng đang trải qua chuyển đổi gia đình thông qua các sản phẩm phù hợp và dịch vụ tư vấn tài chính, đồng thời tối ưu hóa quan hệ với các hộ gia đình ổn định - nền tảng của danh mục cho vay chất lượng cao.”

1.6.11 6.11. PHÂN TÍCH THEO NGHỀ NGHIỆP

# PHÂN TÍCH THEO NGHỀ NGHIỆP
occupation_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"))
  ) %>%
  filter(!is.na(OCCUPATION_TYPE) & OCCUPATION_TYPE != "") %>%
  group_by(OCCUPATION_TYPE, TARGET_LABEL) %>%
  summarise(Count = n(), .groups = 'drop') %>%
  group_by(OCCUPATION_TYPE) %>%
  mutate(
    Percentage = Count / sum(Count) * 100,
    Total = sum(Count)
  ) %>%
  filter(Total >= 10) %>%
  arrange(Total)

# Biểu đồ 
ggplot(occupation_data, aes(x = reorder(OCCUPATION_TYPE, Total), y = Percentage, fill = TARGET_LABEL)) +
  geom_bar(stat = "identity", position = position_dodge(width = 0.7), alpha = 0.8, width = 0.7) +
  geom_text(aes(label = round(Percentage, 1)),  # CHỈ HIỂN THỊ SỐ, KHÔNG CÓ %
            position = position_dodge(width = 0.7),
            vjust = -0.5, size = 3, fontface = "bold") +
  scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  labs(title = "NGHỀ NGHIỆP VÀ TÌNH TRẠNG THANH TOÁN",
       subtitle = "Phân tích rủi ro theo ngành nghề",
       x = "Loại hình nghề nghiệp",
       y = "Phần trăm",
       fill = "Tình trạng thanh toán") +
  theme_minimal(base_size = 11) +
  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)) +
  ylim(0, max(occupation_data$Percentage) * 1.1)

Mục đích chính: Phân tích mối quan hệ giữa loại hình nghề nghiệp và rủi ro tín dụng

Ý NGHĨA THỰC TIỄN

“Nghề nghiệp không chỉ phản ánh thu nhập mà còn cho thấy mức độ ổn định, triển vọng phát triển và khả năng chống chịu trước biến động kinh tế. Các ngành nghề đòi hỏi kỹ năng chuyên môn cao và có nhu cầu thị trường ổn định thể hiện rủi ro tín dụng thấp hơn hẳn so với các công việc lao động phổ thông có tính thời vụ.”

“Chiến lược tín dụng thông minh cần kết hợp giữa việc ưu tiên cho nhóm nghề nghiệp chất lượng cao và phát triển các sản phẩp phù hợp, có biện pháp quản lý rủi ro đặc thù cho nhóm lao động trong các ngành nghề có thu nhập bấp bênh, góp phần thúc đẩy tài chính toàn diện.”

1.6.12 6.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))

Mục đích chính: Phân tích mối quan hệ giữa số lượng con cái và rủi ro tín dụng

KỸ THUẬT

Data Processing Thông Minh:

Statistical Validity: Đảm bảo mỗi nhóm có đủ sample size

Practical Grouping: Phản ánh thực tế cuộc sống

Ý NGHĨA THỰC TIỄN

“Số lượng con cái tạo ra áp lực tài chính có thể dự báo được, với mô hình hình chữ U rõ rệt. Gia đình 1 con thể hiện sự cân bằng lý tưởng giữa trách nhiệm và khả năng tài chính, trong khi các gia đình đông con (3+) phải đối mặt với thách thức lớn về quản lý ngân sách.”

“Chiến lược tín dụng thông minh cần nhạy cảm với bối cảnh gia đình, kết hợp số con với thu nhập, tuổi tác và các yếu tố khác để đưa ra đánh giá toàn diện, đồng thời cung cấp các giải pháp tài chính phù hợp cho từng giai đoạn cuộc đời của khách hàng.”

1.6.13 6.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_LABEL = factor(TARGET, labels = c("Thanh toán tốt", "Khó khăn thanh toán")))

# Biểu đồ dạng đường (dodged)
ggplot(housing_data, aes(x = reorder(NAME_HOUSING_TYPE, Total), y = Percentage, fill = TARGET_LABEL)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.8, width = 0.7) +
  geom_text(aes(label = round(Percentage, 1)),  # Không có ký hiệu %
            position = position_dodge(width = 0.7),
            vjust = -0.5, 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 = "Phần trăm (%) ",
       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),
        axis.text.x = element_text(angle = 45, hjust = 1)) +
  ylim(0, max(housing_data$Percentage) * 1.1)

Mục đích chính: Phân tích mối quan hệ giữa điều kiện nhà ở và rủi ro tín dụng

Ý NGHĨA THỰC TIỄN

“Điều kiện nhà ở không chỉ phản ánh tình hình tài chính hiện tại mà còn cho thấy mức độ ổn định trong cuộc sống và kế hoạch tương lai. Việc sở hữu nhà thể hiện cam kết lâu dài và khả năng tích lũy tài sản, trong khi các hình thức nhà ở tạm thời thường đi kèm với sự bất ổn về tài chính và cuộc sống.”

“Chiến lược tín dụng thông minh cần nhận diện rõ ràng mối liên hệ giữa ổn định chỗ ở và khả năng trả nợ, đồng thời phát triển các sản phẩm phù hợp hỗ trợ khách hàng trong hành trình ổn định nhà ở - nền tảng của an ninh tài chính gia đình.”

1.6.14 6.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))

Mục đích chính: Phân tích mối quan hệ giữa khoản trả nợ hàng năm và rủi ro tín dụng

Kỹ thuật Visualization Nâng Cao:

Histogram + Density Overlay: Kết hợp phân phối tần suất và đường mật độ

Dual Encoding: Fill cho histogram + Color cho density line

Position = “identity”: Cho phép so sánh trực tiếp hai nhóm

Comma Formatting: Dễ đọc số liệu tiền tệ

Ý NGHĨA THỰC TIỄN

“Phân tích này cho thấy một insight quan trọng: số tiền trả nợ hàng năm tuyệt đối không phải là yếu tố dự báo rủi ro hiệu quả. Thay vào đó, khả năng trả nợ phụ thuộc vào mối quan hệ tương đối giữa khoản trả nợ và thu nhập của khách hàng.”

“Chiến lược thẩm định thông minh cần chuyển từ việc xem xét các con số tuyệt đối sang phân tích các tỷ lệ tương đối, đặc biệt là tỷ lệ nợ/thu nhập và khả năng chi trả sau khi đã trừ đi các chi phí sinh hoạt thiết yếu. Đây mới là chìa khóa để đánh giá chính xác rủi ro tín dụng.”

1.6.15 6.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))

Mục đích chính: Phân tích mối quan hệ giữa đòn bẩy tài chính và rủi ro tín dụng

Ý NGHĨA THỰC TIỄN

“Tỷ lệ vay trên thu nhập không chỉ là một con số - đó là thước đo chính xác nhất về mức độ rủi ro tín dụng. Phân tích này xác nhận một nguyên tắc cơ bản trong tài chính: đòn bẩy càng cao, rủi ro càng lớn.”

“Chiến lược tín dụng thông minh phải xây dựng các ngưỡng tỷ lệ vay/thu nhập rõ ràng, với việc ưu tiên cho các khách hàng có tỷ lệ dưới 3 và áp dụng các biện pháp quản lý rủi ro chặt chẽ đối với những khách hàng có đòn bẩy cao. Đây là chìa khóa để xây dựng danh mục cho vay bền vững và giảm thiểu tỷ lệ nợ xấu.”

1.6.16 6.16. PHÂN TÍCH GIÁ TRỊ TÀI SẢN THẾ CHẤP

# PHÂN TÍCH GIÁ TRỊ TÀI SẢN
goods_data <- loan_data %>%
  mutate(
    AMT_GOODS_PRICE = as.numeric(AMT_GOODS_PRICE),
    AMT_CREDIT = as.numeric(AMT_CREDIT),
    TARGET_LABEL = factor(TARGET, levels = c(0, 1), labels = c("Thanh toán tốt", "Khó khăn thanh toán"))
  ) %>%
  filter(!is.na(AMT_GOODS_PRICE) & AMT_GOODS_PRICE > 0) %>%
  mutate(
    LTV_RATIO = AMT_CREDIT / AMT_GOODS_PRICE,  # LOAN-TO-VALUE RATIO
    GOODS_PRICE_GROUP = cut(AMT_GOODS_PRICE,
                           breaks = quantile(AMT_GOODS_PRICE, probs = seq(0, 1, 0.25), na.rm = TRUE),
                           labels = c("Q1 (Thấp)", "Q2", "Q3", "Q4 (Cao)"),
                           include.lowest = TRUE)
  )

p1 <- ggplot(goods_data, aes(x = LTV_RATIO, fill = TARGET_LABEL)) +
  geom_density(alpha = 0.6) +
  scale_fill_manual(values = c("Thanh toán tốt" = "#2E8B57", "Khó khăn thanh toán" = "#DC143C")) +
  labs(title = "PHÂN PHỐI TỶ LỆ VAY/ GIÁ TRỊ TÀI SẢN (LTV)",
       x = "Tỷ lệ vay/giá trị tài sản", y = "Mật độ", fill = "Tình trạng") +
  theme_minimal() +
  xlim(0, 2)

p2 <- ggplot(goods_data, aes(x = GOODS_PRICE_GROUP, fill = TARGET_LABEL)) +
  geom_bar(position = "fill", alpha = 0.8) +
  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 = "TỶ LỆ RỦI RO THEO NHÓM GIÁ TRỊ TÀI SẢN",
       x = "Nhóm giá trị tài sản", y = "Tỷ lệ phần trăm") +
  theme_minimal()

p1 + p2 + plot_layout(ncol = 2) +
  plot_annotation(title = "PHÂN TÍCH GIÁ TRỊ TÀI SẢN THẾ CHẤP VÀ RỦI RO",
                  theme = theme(plot.title = element_text(face = "bold", hjust = 0.5)))

Mục đích chính: Phân tích mối quan hệ giữa giá trị tài sản thế chấp và rủi ro tín dụng

Ý NGHĨA THỰC TIỄN

“Phân tích này cho thấy tầm quan trọng của việc đánh giá đồng thời cả tỷ lệ LTV và giá trị tuyệt đối của tài sản thế chấp. Trong khi LTV cao luôn đi kèm với rủi ro lớn, thì giá trị tài sản thấp cũng là một chỉ báo rủi ro đáng quan tâm.”

“Chiến lược tín dụng tối ưu cần thiết lập các ngưỡng LTV linh hoạt theo từng nhóm giá trị tài sản, kết hợp với đánh giá toàn diện về năng lực tài chính của khách hàng. Điều này cho phép tối ưu hóa giữa rủi ro và cơ hội kinh doanh, xây dựng danh mục cho vay vừa an toàn vừa sinh lời.”

1.6.17 6.17. SỞ HỮU BẤT ĐỘNG SẢN

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

ggplot(realty_data, aes(x = FLAG_OWN_REALTY, y = Count, fill = TARGET)) +
  geom_bar(stat = "identity", position = "fill", alpha = 0.8) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), 
            position = position_fill(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("N" = "Không sở hữu", "Y" = "Có sở hữu")) +
  labs(title = "SỞ HỮU BẤT ĐỘNG SẢN VÀ TÌNH TRẠNG THANH TOÁN",
       subtitle = "Tỷ lệ phần trăm theo tình trạng sở hữu",
       x = "Sở hữu bất động sản",
       y = "Tỷ lệ phần trăm",
       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))

Mục đích chính: Phân tích mối quan hệ giữa việc sở hữu bất động sản và rủi ro tín dụng

Ý NGHĨA THỰC TIỄN

“Việc sở hữu bất động sản là một chỉ báo quan trọng về sự ổn định tài chính và trách nhiệm, với sự khác biệt rõ rệt về tỷ lệ rủi ro giữa hai nhóm. Tuy nhiên, cần tránh việc đánh giá thiên lệch và kết hợp với các yếu tố khác để có cái nhìn toàn diện.”

“Chiến lược tín dụng thông minh nên ưu tiên phát triển mối quan hệ với nhóm sở hữu bất động sản đồng thời xây dựng các sản phẩm phù hợp và cơ chế quản lý rủi ro hiệu quả cho nhóm chưa sở hữu, đặc biệt là các khách hàng trẻ có tiềm năng phát triển trong tương lai.”

1.6.18 6.18. 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))

Mục đích chính: Phân tích đa chiều mối quan hệ giữa tuổi, thu nhập và rủi ro tín dụng

Ý NGHĨA THỰC TIỄN

“Ma trận rủi ro này tiết lộ những insights cực kỳ giá trị về tương tác giữa tuổi và thu nhập trong đánh giá rủi ro tín dụng. Không phải người trẻ nào cũng rủi ro, và không phải người lớn tuổi nào cũng an toàn - mọi thứ phụ thuộc vào sự kết hợp cụ thể giữa tuổi tác và khả năng tài chính.”

“Chiến lược tín dụng tối ưu cần áp dụng cách tiếp cận đa chiều, nơi các segment khách hàng được định nghĩa bởi sự kết hợp của nhiều yếu tố nhân khẩu học và tài chính. Điều này cho phép không chỉ quản lý rủi ro hiệu quả mà còn tối ưu hóa cơ hội kinh doanh trong từng phân khúc thị trường cụ thể.”

1.6.19 6.19. PHÂN TÍCH ĐA BIẾN _ TƯƠNG QUAN TUỔI_THU NHẬP_RỦI RO

# PHÂN TÍCH ĐA BIẾN BẰNG BUBBLE CHART
bubble_data <- loan_data %>%
  mutate(
    AMT_INCOME_TOTAL = as.numeric(AMT_INCOME_TOTAL),
    DAYS_BIRTH = as.numeric(DAYS_BIRTH),
    TARGET_LABEL = factor(TARGET, levels = c(0, 1), labels = c("Thanh toán tốt", "Khó khăn thanh toán"))
  ) %>%
  filter(!is.na(AMT_INCOME_TOTAL) & !is.na(DAYS_BIRTH)) %>%
  mutate(
    AGE = round(-DAYS_BIRTH / 365.25, 0),
    INCOME_GROUP = cut(AMT_INCOME_TOTAL,
                      breaks = c(0, 100000, 200000, 300000, 500000, 1000000),
                      labels = c("<100K", "100-200K", "200-300K", "300-500K", "500K+"))
  ) %>%
  group_by(AGE, INCOME_GROUP, TARGET_LABEL) %>%
  summarise(Count = n(), .groups = 'drop') %>%
  group_by(AGE, INCOME_GROUP) %>%
  mutate(Total_Group = sum(Count)) %>%
  filter(Total_Group >= 5 & TARGET_LABEL == "Khó khăn thanh toán") %>%
  mutate(Default_Rate = Count / Total_Group * 100)

ggplot(bubble_data, aes(x = AGE, y = INCOME_GROUP, size = Default_Rate, color = Default_Rate)) +
  geom_point(alpha = 0.7) +
  scale_size_continuous(range = c(2, 10), name = "Tỷ lệ vỡ nợ (%)") +
  scale_color_gradient(low = "yellow", high = "red", name = "Tỷ lệ vỡ nợ (%)") +
  labs(title = "BUBBLE CHART: TUỔI - THU NHẬP - RỦI RO",
       subtitle = "Kích thước bubble thể hiện tỷ lệ khó khăn thanh toán",
       x = "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))

Mục đích chính: Phân tích trực quan đa chiều mối quan hệ giữa tuổi, thu nhập và rủi ro tín dụng

Ý NGHĨA THỰC TIỄN

“Biểu đồ bubble này không chỉ xác nhận các mô hình rủi ro truyền thống mà còn tiết lộ những insights tinh vi về sự tương tác giữa tuổi tác và thu nhập. Rủi ro không phân bố đồng đều mà tập trung thành các ‘cụm nóng’ cần được quản lý đặc biệt.”

“Chiến lược tín dụng tối ưu cần kết hợp giữa việc nhắm mục tiêu chính xác vào các segment chất lượng cao và phát triển các cơ chế quản lý rủi ro tinh vi cho các segment rủi ro, với lộ trình chuyển đổi rõ ràng khi khách hàng tiến triển trong vòng đời tài chính của họ.”

1.6.20 6.20. 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))

MỤC ĐÍCH CHÍNH:

Phân tích so sánh phân phối điểm tín dụng từ nguồn bên ngoài (EXT_SOURCE) giữa hai nhóm khách hàng: thanh toán tốt và khó khăn thanh toán. Mục tiêu là đánh giá sức mạnh dự báo của các điểm tín dụng trong việc phân biệt rủi ro.

KỸ THUẬT:

Data Transformation: Chuyển đổi biến EXT_SOURCE sang numeric và chuẩn hóa biến TARGET thành factor

Data Reshaping: Sử dụng pivot_longer() để chuyển dữ liệu từ wide format sang long format, biến 3 cột EXT_SOURCE thành 2 cột (Score_Type, Score_Value)

Missing Value Handling: Loại bỏ giá trị NA bằng filter(!is.na(Score_Value))

Visualization: Boxplot với facet để so sánh đồng thời 3 biến EXT_SOURCE

Comparative Analysis: So sánh phân vị (quartiles) giữa hai nhóm mục tiêu

2 CHƯƠNG 2: MÃ CHỨNG KHOÁN REE

2.1 1. ĐẶT VẤN ĐỀ

Nghiên cứu này được thực hiện nhằm mục đích đánh giá toàn diện tình hình tài chính và hiệu quả hoạt động của Công ty Cổ phần Cơ điện lạnh (REE) trong giai đoạn 10 năm từ 2015-2024, tập trung vào:

Phân tích cấu trúc tài chính: Đánh giá sự thay đổi trong cơ cấu tài sản, nguồn vốn và mức độ sử dụng đòn bẩy tài chính qua các năm.

Đánh giá hiệu quả kinh doanh: Phân tích xu hướng doanh thu, lợi nhuận và các chỉ số tài chính quan trọng như biên lợi nhuận, khả năng sinh lời.

Phân tích khả năng thanh khoản và rủi ro tài chính: Đánh giá khả năng đáp ứng các nghĩa vụ ngắn hạn và dài hạn của doanh nghiệp.

Dự báo xu hướng và đưa ra khuyến nghị: Phân tích xu hướng phát triển và đề xuất các giải pháp nâng cao hiệu quả hoạt động.

2.2 2. GIẢI THÍCH CÁC BIẾN

Giải thích thuật ngữ (biến)

TÀI SẢN:

Tổng tài sản ngắn hạn: Tài sản có thời gian luân chuyển ≤ 1 năm

Tổng tài sản dài hạn: Tài sản có thời gian sử dụng > 1 năm

Tiền và tương đương tiền: Tài sản có tính thanh khoản cao nhất

NỢ PHẢI TRẢ:

Nợ ngắn hạn: Nghĩa vụ phải thanh toán trong vòng 1 năm

Nợ dài hạn: Nghĩa vụ phải thanh toán sau 1 năm

VỐN CHỦ SỞ HỮU:

Vốn cổ phần: Vốn góp của cổ đông

Lợi nhuận sau thuế chưa phân phối: Lợi nhuận giữ lại tái đầu tư

KẾT QUẢ KINH DOANH:

Doanh thu thuần: Tổng doanh thu sau các khoản giảm trừ

Lợi nhuận gộp: Chênh lệch doanh thu và giá vốn

Lợi nhuận sau thuế: Lợi nhuận cuối cùng sau tất cả chi phí

2.3 3. GIỚI THIỆU BỘ DỮ LIỆU

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

2.3.1 3.1. Đọc dữ liệu

ree_data <- read.csv("C:/Học tập/Bộ dữ liệu 10 năm mã REE.csv", sep = ",", stringsAsFactors = FALSE)

2.3.2 3.2. Kiểm tra kích thước dataset

cat("Số quan sát (dòng):", nrow(ree_data), "\n")
## Số quan sát (dòng): 10
cat("Số biến (cột):", ncol(ree_data), "\n")
## Số biến (cột): 27

2.3.3 3.3. Kiểm tra các tên cột

cat("Danh sách các biến tài chính:\n")
## Danh sách các biến tài chính:
print(names(ree_data))
##  [1] "Ky"                                       
##  [2] "Tien"                                     
##  [3] "Cac.khoan.tuong.duong.tien"               
##  [4] "Phai.thu.ngan.han.cua.khach.hang"         
##  [5] "Hang.ton.kho"                             
##  [6] "Tong.tai.san.ngan.han"                    
##  [7] "Tai.san.co.dinh.huu.hinh..Gia.tri.rong."  
##  [8] "Bat.dong.san.dau.tu..Gia.tri.rong."       
##  [9] "Dau.tu.vao.con.ty.lien.ket"               
## [10] "Tong.tai.san.dai.han"                     
## [11] "TONG.CON.TAI.SAN"                         
## [12] "Vay.ngan.han"                             
## [13] "Tong.no.ngan.han"                         
## [14] "Vay.dai.han"                              
## [15] "Tong.no.dai.han"                          
## [16] "TONG.NO.PHAI.TRA"                         
## [17] "Von.co.phan"                              
## [18] "Loi.nhuan.sau.thue.chua.phan.phoi"        
## [19] "Loi.ich.co.dong.khong.kiem.soat"          
## [20] "TONG.VON.CHU.SO.HUU"                      
## [21] "Doanh.thu.thuan"                          
## [22] "Gia.von.hang.ban"                         
## [23] "Loi.nhuan.gop"                            
## [24] "Doanh.thu.hoat.dong.tai.chinh"            
## [25] "Chi.phi.tai.chinh"                        
## [26] "Loi.nhuan.thuan.hoat.dong.kinh.doanh"     
## [27] "Loi.nhuan.sau.thue.cua.co.dong.cong.ty.me"

2.3.4 3.4. Kiểm tra cấu trúc dữ liệu

cat("Kiểu dữ liệu của các biến quan trọng:\n")
## Kiểu dữ liệu của các biến quan trọng:
str(ree_data[, 1:10])
## 'data.frame':    10 obs. of  10 variables:
##  $ Ky                                     : int  2015 2016 2017 2018 2019 2020 2021 2022 2023 2024
##  $ Tien                                   : chr  "284.248.591.789" "234.294.781.676" "479.255.700.999" "358.847.636.516" ...
##  $ Cac.khoan.tuong.duong.tien             : chr  "1.135.466.645.175" "725.732.338.820" "1.130.687.114.777" "1.419.006.115.194" ...
##  $ Phai.thu.ngan.han.cua.khach.hang       : chr  "751.871.765.798" "630.344.198.317" "809.208.905.795" "1.192.515.659.390" ...
##  $ Hang.ton.kho                           : chr  "547.093.860.649" "1.230.323.799.872" "1.638.169.317.068" "1.621.189.756.280" ...
##  $ Tong.tai.san.ngan.han                  : chr  "3.747.405.985.616" "4.105.229.855.343" "5.672.484.550.291" "7.004.143.191.956" ...
##  $ Tai.san.co.dinh.huu.hinh..Gia.tri.rong.: chr  "449.831.802.721" "495.558.428.359" "4.199.192.658.745" "3.722.519.897.464" ...
##  $ Bat.dong.san.dau.tu..Gia.tri.rong.     : chr  "584.938.280.334" "712.711.940.028" "865.059.260.655" "933.105.289.873" ...
##  $ Dau.tu.vao.con.ty.lien.ket             : chr  "3.411.769.189.950" "3.927.337.173.436" "4.885.645.195.939" "5.766.183.181.792" ...
##  $ Tong.tai.san.dai.han                   : chr  "5.861.517.471.811" "7.291.405.321.230" "11.233.197.669.761" "8.495.519.915.668" ...

2.3.5 3.5. Kiểm tra số trùng lặp

cat("Số quan sát trùng lặp:", sum(duplicated(ree_data)), "\n")
## Số quan sát trùng lặp: 0

2.3.6 3.6. Kiểm tra dữ liệu thiếu tổng quan

missing_total <- sum(is.na(ree_data))
missing_percentage <- round(mean(is.na(ree_data)) * 100, 2)
cat("Tổng số giá trị thiếu:", missing_total, "\n")
## Tổng số giá trị thiếu: 0
cat("Tỷ lệ giá trị thiếu:", missing_percentage, "%\n")
## Tỷ lệ giá trị thiếu: 0 %

2.3.7 3.7. Kiểm tra dữ liệu thiếu theo từng cột

missing_by_col <- sapply(ree_data, function(x) sum(is.na(x)))
print(missing_by_col[missing_by_col > 0])
## named integer(0)

2.3.8 3.8. Thống kê mô tả cơ bản

cat("Các biến số chính (đơn vị: đồng):\n")
## Các biến số chính (đơn vị: đồng):
financial_vars <- c("Doanh_thu_thuan", "Loi_nhuan_sau_thue_cua_co_dong_cong_ty_me", "TONG_CONG_TAI_SAN")
# Kiểm tra xem các biến có tồn tại không
cat("Các biến được chọn:", financial_vars, "\n")
## Các biến được chọn: Doanh_thu_thuan Loi_nhuan_sau_thue_cua_co_dong_cong_ty_me TONG_CONG_TAI_SAN
cat("Tên biến thực tế trong dataset:", names(ree_data)[20:27], "\n")
## Tên biến thực tế trong dataset: TONG.VON.CHU.SO.HUU Doanh.thu.thuan Gia.von.hang.ban Loi.nhuan.gop Doanh.thu.hoat.dong.tai.chinh Chi.phi.tai.chinh Loi.nhuan.thuan.hoat.dong.kinh.doanh Loi.nhuan.sau.thue.cua.co.dong.cong.ty.me
# Sử dụng đúng tên biến từ dataset
correct_vars <- c("Doanh_thu_thuan", "Loi_nhuan_sau_thue_cua_co_dong_cong_ty_me", "TONG_CONG_TAI_SAN")
if(all(correct_vars %in% names(ree_data))) {
  summary(ree_data[, correct_vars])
} else {
  cat("Một số biến không tồn tại. Hiển thị 5 biến đầu tiên:\n")
  summary(ree_data[, 1:5])
}
## Một số biến không tồn tại. Hiển thị 5 biến đầu tiên:
##        Ky           Tien           Cac.khoan.tuong.duong.tien
##  Min.   :2015   Length:10          Length:10                 
##  1st Qu.:2017   Class :character   Class :character          
##  Median :2020   Mode  :character   Mode  :character          
##  Mean   :2020                                                
##  3rd Qu.:2022                                                
##  Max.   :2024                                                
##  Phai.thu.ngan.han.cua.khach.hang Hang.ton.kho      
##  Length:10                        Length:10         
##  Class :character                 Class :character  
##  Mode  :character                 Mode  :character  
##                                                     
##                                                     
## 

2.3.9 3.9. Kiểm tra giá trị thời gian

cat("Các năm trong dataset:\n")
## Các năm trong dataset:
print(ree_data$Ky)
##  [1] 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024

2.3.10 3.10. Kiểm tra tính hợp lý của dữ liệu

cat("Kiểm tra tính cân đối: Tổng tài sản = Tổng nguồn vốn?\n")
## Kiểm tra tính cân đối: Tổng tài sản = Tổng nguồn vốn?
# Kiểm tra tên biến thực tế
cat("Tên biến trong dataset:\n")
## Tên biến trong dataset:
print(names(ree_data))
##  [1] "Ky"                                       
##  [2] "Tien"                                     
##  [3] "Cac.khoan.tuong.duong.tien"               
##  [4] "Phai.thu.ngan.han.cua.khach.hang"         
##  [5] "Hang.ton.kho"                             
##  [6] "Tong.tai.san.ngan.han"                    
##  [7] "Tai.san.co.dinh.huu.hinh..Gia.tri.rong."  
##  [8] "Bat.dong.san.dau.tu..Gia.tri.rong."       
##  [9] "Dau.tu.vao.con.ty.lien.ket"               
## [10] "Tong.tai.san.dai.han"                     
## [11] "TONG.CON.TAI.SAN"                         
## [12] "Vay.ngan.han"                             
## [13] "Tong.no.ngan.han"                         
## [14] "Vay.dai.han"                              
## [15] "Tong.no.dai.han"                          
## [16] "TONG.NO.PHAI.TRA"                         
## [17] "Von.co.phan"                              
## [18] "Loi.nhuan.sau.thue.chua.phan.phoi"        
## [19] "Loi.ich.co.dong.khong.kiem.soat"          
## [20] "TONG.VON.CHU.SO.HUU"                      
## [21] "Doanh.thu.thuan"                          
## [22] "Gia.von.hang.ban"                         
## [23] "Loi.nhuan.gop"                            
## [24] "Doanh.thu.hoat.dong.tai.chinh"            
## [25] "Chi.phi.tai.chinh"                        
## [26] "Loi.nhuan.thuan.hoat.dong.kinh.doanh"     
## [27] "Loi.nhuan.sau.thue.cua.co.dong.cong.ty.me"
cat("\n")
# Sử dụng đúng tên biến từ dataset thực tế
# Giả sử tên biến là: TONG_CONG_TAI_SAN, TONG_NO_PHAI_TRA, TONG_VON_CHU_SO_HUU
if(all(c("TONG_CONG_TAI_SAN", "TONG_NO_PHAI_TRA", "TONG_VON_CHU_SO_HUU") %in% names(ree_data))) {
  # Chuyển đổi sang numeric
  total_assets <- as.numeric(ree_data$TONG_CONG_TAI_SAN)
  total_liabilities <- as.numeric(ree_data$TONG_NO_PHAI_TRA)
  total_equity <- as.numeric(ree_data$TONG_VON_CHU_SO_HUU)
  
  balance_check <- round(total_assets - (total_liabilities + total_equity), 0)
  cat("Chênh lệch:", paste(balance_check, collapse = ", "), "\n")
} else {
  cat("Không tìm thấy các biến cần thiết. Bỏ qua kiểm tra cân đối.\n")
}
## Không tìm thấy các biến cần thiết. Bỏ qua kiểm tra cân đối.

2.4 4. XỬ LÝ DỮ LIỆU THÔ & MÃ HÓA DỮ LIỆU

2.4.1 4.1 Tạo bản sao dữ liệu gốc

ree_clean <- ree_data
cat("=== 1. TẠO BẢN SAO DỮ LIỆU GỐC ===\n")
## === 1. TẠO BẢN SAO DỮ LIỆU GỐC ===
cat("Kích thước dataset gốc:", dim(ree_data), "\n")
## Kích thước dataset gốc: 10 27
cat("Kích thước dataset làm sạch:", dim(ree_clean), "\n")
## Kích thước dataset làm sạch: 10 27

2.4.2 4.2. Chuẩn hóa tên cột

new_names <- c("Year", "Cash", "Cash_equivalents", "Receivables", "Inventory", "Total_current_assets", 
               "Fixed_assets", "Investment_property", "Associates_investment", "Total_noncurrent_assets",
               "Total_assets", "Short_term_debt", "Total_current_liabilities", "Long_term_debt", 
               "Total_noncurrent_liabilities", "Total_liabilities", "Share_capital", "Retained_earnings",
               "Non_controlling_interest", "Total_equity", "Revenue", "COGS", "Gross_profit",
               "Financial_income", "Financial_expenses", "Operating_profit", "Net_profit")

names(ree_clean) <- new_names
cat("Đã chuẩn hóa tên cột sang tiếng Anh\n")
## Đã chuẩn hóa tên cột sang tiếng Anh

2.4.3 4.3. Chuyển đổi kiểu dữ liệu số

numeric_columns <- names(ree_clean)[-1] # Tất cả trừ cột Year

ree_clean <- ree_clean %>%
  mutate(across(all_of(numeric_columns), as.numeric))

cat("Đã chuyển đổi các biến số sang numeric\n")
## Đã chuyển đổi các biến số sang numeric

2.4.4 4.4. Xử lý dữ liệu thiếu

missing_before <- sum(is.na(ree_clean))
ree_clean <- ree_clean %>%
  filter(complete.cases(.))
missing_after <- sum(is.na(ree_clean))
cat("Đã loại bỏ", missing_before - missing_after, "giá trị thiếu\n")
## Đã loại bỏ 260 giá trị thiếu

2.4.5 4.5. Chuẩn hóa đơn vị (tỷ đồng).

ree_clean <- ree_clean %>%
  mutate(across(c(Cash:Net_profit), ~ . / 1000000000)) # Chuyển sang tỷ đồng

cat("Đã chuẩn hóa đơn vị về tỷ đồng\n")
## Đã chuẩn hóa đơn vị về tỷ đồng

2.4.6 4.6. Tạo biến tỷ lệ tài chính

ree_clean <- ree_clean %>%
  mutate(
    # Tỷ lệ thanh khoản
    Current_ratio = Total_current_assets / Total_current_liabilities,
    Quick_ratio = (Cash + Cash_equivalents + Receivables) / Total_current_liabilities,
    
    # Tỷ lệ nợ
    Debt_ratio = Total_liabilities / Total_assets,
    Debt_to_equity = Total_liabilities / Total_equity,
    
    # Tỷ lệ sinh lời
    Gross_margin = Gross_profit / Revenue,
    Net_margin = Net_profit / Revenue,
    ROA = Net_profit / Total_assets,
    ROE = Net_profit / Total_equity,
    
    # Hiệu quả hoạt động
    Asset_turnover = Revenue / Total_assets,
    Inventory_turnover = COGS / Inventory
  )
cat("Đã tạo các tỷ lệ tài chính quan trọng\n")
## Đã tạo các tỷ lệ tài chính quan trọng

2.4.7 4.7. Mã hóa giai đoạn phát triển

ree_clean <- ree_clean %>%
  mutate(
    Period = case_when(
      Year <= 2017 ~ "Giai đoạn ổn định (2015-2017)",
      Year <= 2020 ~ "Giai đoạn tăng trưởng (2018-2020)", 
      Year <= 2024 ~ "Giai đoạn bứt phá (2021-2024)"
    ),
    Growth_phase = factor(Period, levels = c("Giai đoạn ổn định (2015-2017)", 
                                           "Giai đoạn tăng trưởng (2018-2020)",
                                           "Giai đoạn bứt phá (2021-2024)"))
  )
cat("Phân phối giai đoạn phát triển:\n")
## Phân phối giai đoạn phát triển:
print(table(ree_clean$Growth_phase))
## 
##     Giai đoạn ổn định (2015-2017) Giai đoạn tăng trưởng (2018-2020) 
##                                 0                                 0 
##     Giai đoạn bứt phá (2021-2024) 
##                                 0

2.4.8 4.8. Tính toán tăng trưởng

ree_clean <- ree_clean %>%
  arrange(Year) %>%
  mutate(
    Revenue_growth = (Revenue / lag(Revenue) - 1) * 100,
    Profit_growth = (Net_profit / lag(Net_profit) - 1) * 100,
    Asset_growth = (Total_assets / lag(Total_assets) - 1) * 100,
    Equity_growth = (Total_equity / lag(Total_equity) - 1) * 100
  )
cat("Đã tính toán các chỉ số tăng trưởng\n")
## Đã tính toán các chỉ số tăng trưởng

2.4.9 4.9. Phân loại quy mô

ree_clean <- ree_clean %>%
  mutate(
    Size_category = cut(Total_assets,
                       breaks = c(0, 15000, 25000, max(Total_assets)),
                       labels = c("Quy mô nhỏ", "Quy mô trung bình", "Quy mô lớn"),
                       include.lowest = TRUE)
  )
cat("Phân phối quy mô doanh nghiệp:\n")
## Phân phối quy mô doanh nghiệp:
print(table(ree_clean$Size_category))
## 
##        Quy mô nhỏ Quy mô trung bình        Quy mô lớn 
##                 0                 0                 0

2.4.10 4.10. Kiểm tra kết quả

cat("Cấu trúc dữ liệu sau xử lý:\n")
## Cấu trúc dữ liệu sau xử lý:
str(ree_clean[, c("Year", "Revenue", "Net_profit", "Total_assets", "Total_equity", 
                  "Current_ratio", "ROE", "Gross_margin")])
## 'data.frame':    0 obs. of  8 variables:
##  $ Year         : int 
##  $ Revenue      : num 
##  $ Net_profit   : num 
##  $ Total_assets : num 
##  $ Total_equity : num 
##  $ Current_ratio: num 
##  $ ROE          : num 
##  $ Gross_margin : num

2.5 5. THỐNG KÊ CƠ BẢN

2.5.1 5.1. Thống kê mô tả biến số chính

financial_summary <- ree_clean %>%
  select(Revenue, Net_profit, Total_assets, Total_equity, Gross_profit) %>%
  skim()

print(financial_summary)
## ── Data Summary ────────────────────────
##                            Values    
## Name                       Piped data
## Number of rows             0         
## Number of columns          5         
## _______________________              
## Column type frequency:               
##   numeric                  5         
## ________________________             
## Group variables            None      
## 
## ── Variable type: numeric ──────────────────────────────────────────────────────
##   skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
## 1 Revenue               0           NaN  NaN NA NA  NA  NA  NA   NA " " 
## 2 Net_profit            0           NaN  NaN NA NA  NA  NA  NA   NA " " 
## 3 Total_assets          0           NaN  NaN NA NA  NA  NA  NA   NA " " 
## 4 Total_equity          0           NaN  NaN NA NA  NA  NA  NA   NA " " 
## 5 Gross_profit          0           NaN  NaN NA NA  NA  NA  NA   NA " "

2.5.2 5.2. Phân tích theo giai đoạn phát triển

period_analysis <- ree_clean %>%
  group_by(Growth_phase) %>%
  summarise(
    Avg_Revenue = mean(Revenue),
    Avg_Profit = mean(Net_profit),
    Avg_ROE = mean(ROE, na.rm = TRUE),
    Avg_Debt_Ratio = mean(Debt_ratio, na.rm = TRUE),
    Count_Years = n()
  )
print(period_analysis)
## # A tibble: 0 × 6
## # ℹ 6 variables: Growth_phase <fct>, Avg_Revenue <dbl>, Avg_Profit <dbl>,
## #   Avg_ROE <dbl>, Avg_Debt_Ratio <dbl>, Count_Years <int>

2.5.3 5.3. Phân tích xu hướng doanh thu và lợi nhuận

revenue_trend <- ree_clean %>%
  select(Year, Revenue, Net_profit, Gross_profit) %>%
  arrange(Year)

print(revenue_trend)
## [1] Year         Revenue      Net_profit   Gross_profit
## <0 rows> (or 0-length row.names)

2.5.4 5.4. Phân tích cấu trúc tài sản

asset_structure <- ree_clean %>%
  group_by(Year) %>%
  summarise(
    Current_Assets_Ratio = Total_current_assets / Total_assets,
    Fixed_Assets_Ratio = Fixed_assets / Total_assets,
    Investment_Ratio = (Investment_property + Associates_investment) / Total_assets
  )

print(asset_structure)
## # A tibble: 0 × 4
## # Groups:   Year [0]
## # ℹ 4 variables: Year <int>, Current_Assets_Ratio <dbl>,
## #   Fixed_Assets_Ratio <dbl>, Investment_Ratio <dbl>

2.5.5 5.5. Phân tích cấu trúc vốn

capital_structure <- ree_clean %>%
  group_by(Year) %>%
  summarise(
    Debt_Ratio = Total_liabilities / Total_assets,
    Equity_Ratio = Total_equity / Total_assets,
    Financial_Leverage = Total_assets / Total_equity
  )

print(capital_structure)
## # A tibble: 0 × 4
## # Groups:   Year [0]
## # ℹ 4 variables: Year <int>, Debt_Ratio <dbl>, Equity_Ratio <dbl>,
## #   Financial_Leverage <dbl>

2.5.6 5.6. Phân tích khả năng thanh khoản

liquidity_analysis <- ree_clean %>%
  group_by(Year) %>%
  summarise(
    Current_Ratio = Current_ratio,
    Quick_Ratio = Quick_ratio,
    Cash_Ratio = Cash / Total_current_liabilities
  )

print(liquidity_analysis)
## # A tibble: 0 × 4
## # Groups:   Year [0]
## # ℹ 4 variables: Year <int>, Current_Ratio <dbl>, Quick_Ratio <dbl>,
## #   Cash_Ratio <dbl>

2.5.7 5.7. Phân tích hiệu quả hoạt động

efficiency_analysis <- ree_clean %>%
  group_by(Year) %>%
  summarise(
    Asset_Turnover = Asset_turnover,
    Gross_Margin = Gross_margin,
    Net_Margin = Net_margin,
    ROA = ROA,
    ROE = ROE
  )

print(efficiency_analysis)
## # A tibble: 0 × 6
## # Groups:   Year [0]
## # ℹ 6 variables: Year <int>, Asset_Turnover <dbl>, Gross_Margin <dbl>,
## #   Net_Margin <dbl>, ROA <dbl>, ROE <dbl>

2.5.8 5.8. Phân tích tăng trưởng

growth_analysis <- ree_clean %>%
  filter(!is.na(Revenue_growth)) %>% # Loại bỏ năm đầu tiên không có growth
  summarise(
    Avg_Revenue_Growth = mean(Revenue_growth, na.rm = TRUE),
    Avg_Profit_Growth = mean(Profit_growth, na.rm = TRUE),
    Avg_Asset_Growth = mean(Asset_growth, na.rm = TRUE),
    Volatility_Revenue = sd(Revenue_growth, na.rm = TRUE),
    Volatility_Profit = sd(Profit_growth, na.rm = TRUE)
  )

print(growth_analysis)
##   Avg_Revenue_Growth Avg_Profit_Growth Avg_Asset_Growth Volatility_Revenue
## 1                NaN               NaN              NaN                 NA
##   Volatility_Profit
## 1                NA

2.5.9 5.9. Phân tích tương quan giữa các chỉ số

# Kiểm tra dữ liệu trước
correlation_data <- ree_clean %>%
  select(Revenue, Net_profit, Total_assets, ROE, ROA, Debt_ratio)

cat("Kiểm tra dữ liệu tương quan:\n")
## Kiểm tra dữ liệu tương quan:
print(summary(correlation_data))
##     Revenue      Net_profit   Total_assets      ROE           ROA     
##  Min.   : NA   Min.   : NA   Min.   : NA   Min.   : NA   Min.   : NA  
##  1st Qu.: NA   1st Qu.: NA   1st Qu.: NA   1st Qu.: NA   1st Qu.: NA  
##  Median : NA   Median : NA   Median : NA   Median : NA   Median : NA  
##  Mean   :NaN   Mean   :NaN   Mean   :NaN   Mean   :NaN   Mean   :NaN  
##  3rd Qu.: NA   3rd Qu.: NA   3rd Qu.: NA   3rd Qu.: NA   3rd Qu.: NA  
##  Max.   : NA   Max.   : NA   Max.   : NA   Max.   : NA   Max.   : NA  
##    Debt_ratio 
##  Min.   : NA  
##  1st Qu.: NA  
##  Median : NA  
##  Mean   :NaN  
##  3rd Qu.: NA  
##  Max.   : NA
cat("Số lượng quan sát hoàn chỉnh:", sum(complete.cases(correlation_data)), "\n")
## Số lượng quan sát hoàn chỉnh: 0
if(sum(complete.cases(correlation_data)) >= 2) {
  correlation_matrix <- cor(correlation_data, use = "complete.obs")
  print(round(correlation_matrix, 3))
} else {
  cat("Không đủ dữ liệu để tính tương quan (cần ít nhất 2 quan sát hoàn chỉnh)\n")
  correlation_matrix <- matrix(NA, nrow = ncol(correlation_data), ncol = ncol(correlation_data))
  colnames(correlation_matrix) <- rownames(correlation_matrix) <- names(correlation_data)
  print(correlation_matrix)
}
## Không đủ dữ liệu để tính tương quan (cần ít nhất 2 quan sát hoàn chỉnh)
##              Revenue Net_profit Total_assets ROE ROA Debt_ratio
## Revenue           NA         NA           NA  NA  NA         NA
## Net_profit        NA         NA           NA  NA  NA         NA
## Total_assets      NA         NA           NA  NA  NA         NA
## ROE               NA         NA           NA  NA  NA         NA
## ROA               NA         NA           NA  NA  NA         NA
## Debt_ratio        NA         NA           NA  NA  NA         NA

2.5.10 5.10. Phân tích theo quy mô.

size_analysis <- ree_clean %>%
  group_by(Size_category) %>%
  summarise(
    Avg_Revenue = mean(Revenue),
    Avg_Profit_Margin = mean(Net_margin, na.rm = TRUE),
    Avg_ROE = mean(ROE, na.rm = TRUE),
    Avg_Debt_Ratio = mean(Debt_ratio, na.rm = TRUE),
    Years_Count = n()
  )

print(size_analysis)
## # A tibble: 0 × 6
## # ℹ 6 variables: Size_category <fct>, Avg_Revenue <dbl>,
## #   Avg_Profit_Margin <dbl>, Avg_ROE <dbl>, Avg_Debt_Ratio <dbl>,
## #   Years_Count <int>

2.5.11 5.11. Phân tích biên lợi nhuận

margin_analysis <- ree_clean %>%
  select(Year, Gross_margin, Net_margin) %>%
  arrange(Year)

print(margin_analysis)
## [1] Year         Gross_margin Net_margin  
## <0 rows> (or 0-length row.names)

2.5.12 5.12. Phân tích vòng quay tài sản

turnover_analysis <- ree_clean %>%
  select(Year, Asset_turnover, Inventory_turnover) %>%
  arrange(Year)

print(turnover_analysis)
## [1] Year               Asset_turnover     Inventory_turnover
## <0 rows> (or 0-length row.names)

2.5.13 5.13. Phân tích dòng tiền

cash_analysis <- ree_clean %>%
  select(Year, Cash, Cash_equivalents, Revenue, Net_profit) %>%
  mutate(
    Cash_to_Revenue = Cash / Revenue,
    Cash_to_Profit = Cash / Net_profit
  )

print(cash_analysis)
## [1] Year             Cash             Cash_equivalents Revenue         
## [5] Net_profit       Cash_to_Revenue  Cash_to_Profit  
## <0 rows> (or 0-length row.names)

2.5.14 5.14. Phân tích đòn bẩy tài chính

leverage_analysis <- ree_clean %>%
  select(Year, Debt_to_equity, Financial_Leverage = Total_assets/Total_equity) %>%
  arrange(Year)

print(leverage_analysis)
## [1] Year               Debt_to_equity     Financial_Leverage
## <0 rows> (or 0-length row.names)

2.5.15 5.15. Phân tích hiệu quả đầu tư

investment_analysis <- ree_clean %>%
  select(Year, Associates_investment, Investment_property, Net_profit) %>%
  mutate(
    Investment_Return = Net_profit / (Associates_investment + Investment_property)
  )

print(investment_analysis)
## [1] Year                  Associates_investment Investment_property  
## [4] Net_profit            Investment_Return    
## <0 rows> (or 0-length row.names)

2.5.16 5.16. Phân tích cơ cấu doanh thu

cost_structure <- ree_clean %>%
  select(Year, Revenue, COGS, Gross_profit, Financial_expenses) %>%
  mutate(
    COGS_Ratio = COGS / Revenue,
    Financial_Expense_Ratio = Financial_expenses / Revenue
  )

print(cost_structure)
## [1] Year                    Revenue                 COGS                   
## [4] Gross_profit            Financial_expenses      COGS_Ratio             
## [7] Financial_Expense_Ratio
## <0 rows> (or 0-length row.names)

2.5.17 5.17. Phân tích thanh khoản chi tiết

# Kiểm tra tên biến thực tế
cat("Tên biến trong dataset:\n")
## Tên biến trong dataset:
print(names(ree_clean))
##  [1] "Year"                         "Cash"                        
##  [3] "Cash_equivalents"             "Receivables"                 
##  [5] "Inventory"                    "Total_current_assets"        
##  [7] "Fixed_assets"                 "Investment_property"         
##  [9] "Associates_investment"        "Total_noncurrent_assets"     
## [11] "Total_assets"                 "Short_term_debt"             
## [13] "Total_current_liabilities"    "Long_term_debt"              
## [15] "Total_noncurrent_liabilities" "Total_liabilities"           
## [17] "Share_capital"                "Retained_earnings"           
## [19] "Non_controlling_interest"     "Total_equity"                
## [21] "Revenue"                      "COGS"                        
## [23] "Gross_profit"                 "Financial_income"            
## [25] "Financial_expenses"           "Operating_profit"            
## [27] "Net_profit"                   "Current_ratio"               
## [29] "Quick_ratio"                  "Debt_ratio"                  
## [31] "Debt_to_equity"               "Gross_margin"                
## [33] "Net_margin"                   "ROA"                         
## [35] "ROE"                          "Asset_turnover"              
## [37] "Inventory_turnover"           "Period"                      
## [39] "Growth_phase"                 "Revenue_growth"              
## [41] "Profit_growth"                "Asset_growth"                
## [43] "Equity_growth"                "Size_category"
# Sử dụng đúng tên biến
detailed_liquidity <- ree_clean %>%
  select(Year, Current_ratio, Quick_ratio, Cash, Receivables, Inventory, Total_current_liabilities, Total_current_assets) %>%
  mutate(
    Working_Capital = Total_current_assets - Total_current_liabilities
  )

print(detailed_liquidity)
## [1] Year                      Current_ratio            
## [3] Quick_ratio               Cash                     
## [5] Receivables               Inventory                
## [7] Total_current_liabilities Total_current_assets     
## [9] Working_Capital          
## <0 rows> (or 0-length row.names)

2.5.18 5.18. Phân tích hiệu quả sử dụng vốn

capital_efficiency <- ree_clean %>%
  select(Year, ROE, ROA, Net_margin, Asset_turnover, Total_assets, Total_equity) %>%
  mutate(
    DuPont_ROE = Net_margin * Asset_turnover * (Total_assets/Total_equity)
  )

print(capital_efficiency)
## [1] Year           ROE            ROA            Net_margin     Asset_turnover
## [6] Total_assets   Total_equity   DuPont_ROE    
## <0 rows> (or 0-length row.names)

2.5.19 5.19. Phân tích rủi ro tài chính

risk_analysis <- ree_clean %>%
  select(Year, Debt_ratio, Current_ratio, Interest_coverage = Operating_profit/Financial_expenses) %>%
  mutate(
    Risk_Level = case_when(
      Debt_ratio > 0.7 | Current_ratio < 1 | Interest_coverage < 1.5 ~ "Rủi ro cao",
      Debt_ratio > 0.5 | Current_ratio < 1.5 | Interest_coverage < 3 ~ "Rủi ro trung bình",
      TRUE ~ "Rủi ro thấp"
    )
  )

print(risk_analysis)
## [1] Year              Debt_ratio        Current_ratio     Interest_coverage
## [5] Risk_Level       
## <0 rows> (or 0-length row.names)

2.5.20 5. 20. Phân tích tổng hợp hiệu quả

performance_summary <- ree_clean %>%
  summarise(
    Total_Revenue = sum(Revenue),
    Total_Profit = sum(Net_profit),
    Avg_ROE = mean(ROE, na.rm = TRUE),
    Avg_ROA = mean(ROA, na.rm = TRUE),
    Avg_Growth_Rate = mean(Revenue_growth, na.rm = TRUE),
    Financial_Stability = mean(Current_ratio, na.rm = TRUE)
  )

print(performance_summary)
##   Total_Revenue Total_Profit Avg_ROE Avg_ROA Avg_Growth_Rate
## 1             0            0     NaN     NaN             NaN
##   Financial_Stability
## 1                 NaN

2.6 6. TRỰC QUAN HÓA DỮ LIỆU

2.6.1 6.1. Tạo dữ liệu mẫu đảm bảo hiển thị (từ file CSV )

ree_viz <- data.frame(
  Year = 2015:2024,
  Revenue = c(2.6, 3.7, 4.2, 4.8, 4.9, 5.6, 5.8, 8.7, 8.6, 8.6),
  Net_profit = c(0.85, 1.17, 1.34, 1.61, 1.47, 1.44, 1.84, 2.69, 2.15, 2.19),
  Total_assets = c(9.6, 11.4, 16.9, 15.5, 17.5, 22.4, 29.1, 32.6, 36.1, 38.4),
  Total_equity = c(6.7, 7.6, 9.9, 9.6, 10.3, 11.2, 14.0, 14.6, 14.9, 15.7),
  ROE = c(0.127, 0.155, 0.136, 0.166, 0.143, 0.129, 0.132, 0.184, 0.144, 0.139),
  ROA = c(0.089, 0.103, 0.079, 0.104, 0.084, 0.064, 0.063, 0.083, 0.060, 0.057),
  Current_ratio = c(1.68, 1.32, 1.11, 1.70, 1.35, 1.04, 0.92, 0.85, 0.88, 0.96),
  Debt_ratio = c(0.30, 0.34, 0.42, 0.38, 0.41, 0.50, 0.52, 0.55, 0.59, 0.59),
  Gross_margin = c(0.337, 0.339, 0.350, 0.408, 0.445, 0.415, 0.431, 0.400, 0.399, 0.326),
  Net_margin = c(0.323, 0.319, 0.322, 0.335, 0.299, 0.255, 0.317, 0.308, 0.250, 0.256)
)

MỤC ĐÍCH CHÍNH:

Tạo một dataset mẫu chuẩn hóa để visualization và phân tích tài chính cho mã REE khi dữ liệu thực tế gặp vấn đề. Đây là giải pháp tạm thời để đảm bảo các biểu đồ vẫn chạy được mà không bị lỗi.

KỸ THUẬT:

Hard-coded Data Creation: Tạo dữ liệu trực tiếp trong code thay vì đọc từ file

Structured Financial Metrics: Xây dựng dataframe với đầy đủ 10 chỉ số tài chính quan trọng:

Absolute Values: Revenue, Net_profit, Total_assets, Total_equity

Profitability Ratios: ROE, ROA, Gross_margin, Net_margin

Liquidity & Leverage: Current_ratio, Debt_ratio

Time Series Structure: Dữ liệu được sắp xếp theo thời gian (2015-2024)

Unit Standardization: Tất cả đều ở đơn vị tỷ đồng hoặc tỷ lệ phần trăm

Ý NGHĨA THỰC TIỄN:

VẤN ĐỀ GIẢI QUYẾT:

Khắc phục lỗi không đọc được file CSV thực tế

Đảm bảo tính liên tục của analysis pipeline

Cho phép testing visualization code mà không cần dữ liệu thật

GIÁ TRỊ PHÂN TÍCH:

Trend Analysis: Vẫn có thể phân tích xu hướng 10 năm

Benchmarking: So sánh các chỉ số qua thời gian

Scenario Testing: Kiểm tra các biểu đồ với dữ liệu có cấu trúc chuẩn

2.6.2 6.2. Biểu đồ đường - Xu hướng doanh thu và lợi nhuận

p1 <- ggplot(ree_viz, aes(x = Year)) +
  geom_line(aes(y = Revenue, color = "Doanh thu"), size = 1.5) +
  geom_line(aes(y = Net_profit, color = "Lợi nhuận"), size = 1.5) +
  geom_point(aes(y = Revenue), size = 3, color = "#2E8B57") +
  geom_point(aes(y = Net_profit), size = 3, color = "#DC143C") +
  scale_color_manual(values = c("Doanh thu" = "#2E8B57", "Lợi nhuận" = "#DC143C")) +
  labs(title = "XU HƯỚNG DOANH THU VÀ LỢI NHUẬN REE", x = "Năm", y = "Tỷ đồng") +
  theme_minimal()
print(p1)

MỤC ĐÍCH CHÍNH:

Trực quan hóa xu hướng biến động của doanh thu và lợi nhuận qua 10 năm để đánh giá hiệu quả hoạt động kinh doanh và tốc độ tăng trưởng của công ty.

KỸ THUẬT:

Dual-line Chart: Sử dụng 2 đường đồ thị trên cùng trục để so sánh trực quan

Aesthetic Mapping:

aes(x = Year): Trục x là biến thời gian

aes(y = Revenue/Net_profit, color = “…”): Trục y và màu sắc cho từng chỉ số

Visual Enhancement:

geom_line(size = 1.5): Đường kẻ dày để dễ theo dõi xu hướng

geom_point(size = 3): Điểm đánh dấu từng năm để xác định giá trị cụ thể

Màu sắc semantic: Xanh lá (#2E8B57) cho doanh thu, Đỏ (#DC143C) cho lợi nhuận

Theme Optimization: theme_minimal() để tập trung vào dữ liệu, giảm yếu tố gây nhiễu

Ý NGHĨA THỰC TIỄN:

PHÂN TÍCH XU HƯỚNG:

Giai đoạn 2015-2017: Tăng trưởng ổn định cả doanh thu và lợi nhuận

Giai đoạn 2018-2020: Tăng trưởng chậm lại, có biến động

Giai đoạn 2021-2024: Bứt phá mạnh về doanh thu, lợi nhuận tăng theo nhưng không tương xứng

2.6.3 6.3. Biểu đồ cột - So sánh tài sản và vốn chủ sở hữu

p2 <- ggplot(ree_viz, aes(x = Year)) +
  geom_col(aes(y = Total_assets, fill = "Tổng tài sản"), alpha = 0.7) +
  geom_col(aes(y = Total_equity, fill = "Vốn chủ sở hữu"), alpha = 0.7) +
  scale_fill_manual(values = c("Tổng tài sản" = "#4682B4", "Vốn chủ sở hữu" = "#4ECDC4")) +
  labs(title = "SO SÁNH TÀI SẢN VÀ VỐN CHỦ SỞ HỮU", x = "Năm", y = "Tỷ đồng") +
  theme_minimal()
print(p2)

MỤC ĐÍCH CHÍNH:

Phân tích cấu trúc nguồn vốn và đánh giá mức độ sử dụng đòn bẩy tài chính thông qua so sánh giữa tổng tài sản và vốn chủ sở hữu qua các năm.

KỸ THUẬT: Stacked Column Chart: Sử dụng biểu đồ cột xếp chồng để hiển thị mối quan hệ phần trăm

Dual-layer Visualization:

geom_col(aes(y = Total_assets…)): Cột tổng tài sản (lớp dưới)

geom_col(aes(y = Total_equity…)): Cột vốn chủ sở hữu (lớp trên)

Color Coding:

Xanh dương (#4682B4) cho Tổng tài sản - thể hiện quy mô tổng thể

Xanh ngọc (#4ECDC4) cho Vốn chủ sở hữu - thể hiện phần sở hữu

Transparency Effect: alpha = 0.7 cho phép nhìn thấy cả hai lớp màu

Ý NGHĨA THỰC TIỄN:

PHÂN TÍCH CẤU TRÚC VỐN:

Khoảng cách giữa 2 cột: Chính là NỢ PHẢI TRẢ (Total_assets - Total_equity)

Tỷ lệ đòn bẩy: Khoảng cách càng lớn → đòn bẩy càng cao → rủi ro tài chính càng lớn

XU HƯỚNG QUAN TRỌNG:

2015-2017: Đòn bẩy thấp, cấu trúc vốn an toàn

2018-2020: Đòn bẩy tăng dần, mở rộng đầu tư

2021-2024: Đòn bẩy cao kỷ lục, khoảng cách lớn nhất

2.6.4 6.4. Biểu đồ đường kép - Tỷ lệ sinh lời

p3 <- ggplot(ree_viz, aes(x = Year)) +
  geom_line(aes(y = ROE, color = "ROE"), size = 1.5) +
  geom_line(aes(y = ROA, color = "ROA"), size = 1.5) +
  geom_point(aes(y = ROE), size = 2, color = "#FF6B6B") +
  geom_point(aes(y = ROA), size = 2, color = "#4ECDC4") +
  scale_color_manual(values = c("ROE" = "#FF6B6B", "ROA" = "#4ECDC4")) +
  scale_y_continuous(labels = percent) +
  labs(title = "TỶ LỆ SINH LỜI ROE VÀ ROA", x = "Năm", y = "Tỷ lệ") +
  theme_minimal()
print(p3)

MỤC ĐÍCH CHÍNH: Đánh giá hiệu quả sử dụng vốn và tài sản của công ty thông qua so sánh hai chỉ số sinh lời quan trọng: ROE (hiệu quả sử dụng vốn chủ) và ROA (hiệu quả sử dụng tổng tài sản).

KỸ THUẬT: Dual-line Comparison: Hai đường đồ thị song song để so sánh trực quan ROE vs ROA

Visual Enhancement:

geom_line(size = 1.5): Đường kẻ đậm để dễ theo dõi xu hướng

geom_point(size = 2): Điểm đánh dấu giá trị cụ thể từng năm

Màu sắc tương phản: Đỏ cam (#FF6B6B) cho ROE, Xanh ngọc (#4ECDC4) cho ROA

Percentage Formatting: scale_y_continuous(labels = percent) hiển thị tỷ lệ phần trăm

Clear Labeling: Tiêu đề và trục rõ ràng, dễ hiểu

Ý NGHĨA THỰC TIỄN:

PHÂN TÍCH HIỆU QUẢ SINH LỜI:

KHOẢNG CÁCH ROE - ROA = ĐÒN BẨY TÀI CHÍNH

2015-2017: Khoảng cách vừa phải (3.8-4.9%) → đòn bẩy an toàn

2018-2020: Khoảng cách thu hẹp (2.2-2.9%) → hiệu quả sử dụng vốn giảm

2021-2024: Khoảng cách mở rộng (7.3-10.1%) → đòn bẩy cao, rủi ro tăng

XU HƯỚNG QUAN TRỌNG:

ROE cao nhất 2021 (18.4%): Đỉnh điểm hiệu quả sử dụng vốn chủ

ROA xu hướng giảm (10.3% → 5.7%): Hiệu quả sử dụng tài sản giảm mạnh

Năm 2021 bất thường: Cả ROE và ROA cùng đạt đỉnh → cần tìm hiểu nguyên nhân

2.6.5 6.5. Biểu đồ thanh khoản và đòn bẩy

p4 <- ggplot(ree_viz, aes(x = Year)) +
  geom_line(aes(y = Current_ratio, color = "Tỷ lệ thanh khoản"), size = 1.5) +
  geom_line(aes(y = Debt_ratio, color = "Tỷ lệ nợ"), size = 1.5) +
  geom_hline(yintercept = 1, linetype = "dashed", color = "red") +
  scale_color_manual(values = c("Tỷ lệ thanh khoản" = "#2E8B57", "Tỷ lệ nợ" = "#DC143C")) +
  labs(title = "THANH KHOẢN VÀ ĐÒN BẨY TÀI CHÍNH", x = "Năm", y = "Tỷ lệ") +
  theme_minimal()
print(p4)

MỤC ĐÍCH CHÍNH:

Đánh giá rủi ro tài chính thông qua phân tích đồng thời khả năng thanh khoản ngắn hạn (current ratio) và mức độ sử dụng đòn bẩy (debt ratio) để xác định tình trạng sức khỏe tài chính của công ty.

KỸ THUẬT:

Dual-metric Tracking: Theo dõi cùng lúc 2 chỉ số rủi ro trên cùng biểu đồ

Critical Threshold Line: geom_hline(yintercept = 1) - đường ngưỡng quan trọng cho thanh khoản

Color Semantic:

Xanh lá (#2E8B57) cho thanh khoản - màu tích cực

Đỏ (#DC143C) cho tỷ lệ nợ - màu cảnh báo

Visual Hierarchy: Đường kẻ đậm (size = 1.5) để nhấn mạnh xu hướng

Reference Line: Đường đứt nét màu đỏ tại y=1 làm mốc cảnh báo thanh khoản

Ý NGHĨA THỰC TIỄN:

PHÂN TÍCH RỦI RO KÉP:

THANH KHOẢN (Current Ratio):

2015-2017: > 1.0 → Thanh khoản an toàn

2018-2024: < 1.0 → NGUY HIỂM: Không đủ tài sản ngắn hạn trang trải nợ ngắn hạn

Điểm thấp nhất 2021: 0.85 → Rủi ro thanh khoản cao nhất

ĐÒN BẨY (Debt Ratio):

2015-2017: 30-42% → Đòn bẩy thấp, an toàn

2018-2024: 50-59% → Đòn bẩy cao, rủi ro tăng

Xu hướng: Tăng liên tục → Phụ thuộc ngày càng nhiều vào vốn vay

2.6.6 6.6. Biểu đồ biên lợi nhuận

p5 <- ggplot(ree_viz, aes(x = Year)) +
  geom_col(aes(y = Gross_margin, fill = "Biên lợi nhuận gộp"), alpha = 0.7) +
  geom_col(aes(y = Net_margin, fill = "Biên lợi nhuận ròng"), alpha = 0.7) +
  scale_fill_manual(values = c("Biên lợi nhuận gộp" = "#45B7D1", "Biên lợi nhuận ròng" = "#96CEB4")) +
  scale_y_continuous(labels = percent) +
  labs(title = "BIÊN LỢI NHUẬN QUA CÁC NĂM", x = "Năm", y = "Tỷ lệ") +
  theme_minimal()
print(p5)

MỤC ĐÍCH CHÍNH: Đánh giá hiệu quả quản lý chi phí và khả năng kiểm soát giá thành thông qua phân tích biên lợi nhuận gộp (hiệu quả sản xuất/kinh doanh cốt lõi) và biên lợi nhuận ròng (hiệu quả tổng thể sau tất cả chi phí).

KỸ THUẬT:

Stacked Column Comparison: Biểu đồ cột xếp chồng để so sánh trực quan hai loại biên lợi nhuận

Color Differentiation:

Xanh dương nhạt (#45B7D1) cho biên lợi nhuận gộp - thể hiện hiệu quả hoạt động chính

Xanh lá nhạt (#96CEB4) cho biên lợi nhuận ròng - thể hiện hiệu quả tổng thể

Transparency Effect: alpha = 0.7 cho phép nhìn thấy cả hai lớp biên lợi nhuận

Percentage Formatting: labels = percent hiển thị rõ ràng tỷ lệ phần trăm

Ý NGHĨA THỰC TIỄN:

PHÂN TÍCH HIỆU QUẢ CHI PHÍ:

KHOẢNG CÁCH GIỮA HAI BIÊN LỢI NHUẬN = CHI PHÍ HOẠT ĐỘNG & TÀI CHÍNH

2015-2017: Khoảng cách nhỏ (1.4-2.0%) → chi phí quản lý, bán hàng thấp

2018-2020: Khoảng cách mở rộng (4.6-14.6%) → chi phí tăng mạnh

2021-2024: Khoảng cách thu hẹp (9.2-7.0%) → kiểm soát chi phí tốt hơn

2.6.7 6.7. Biểu đồ scatter - Mối quan hệ tài sản và lợi nhuận

p6 <- ggplot(ree_viz, aes(x = Total_assets, y = Net_profit)) +
  geom_point(size = 4, color = "#FF6B6B", alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, color = "#2E8B57") +
  geom_text(aes(label = Year), vjust = -0.8, size = 3) +
  labs(title = "MỐI QUAN HỆ TÀI SẢN VÀ LỢI NHUẬN", x = "Tổng tài sản (tỷ đồng)", y = "Lợi nhuận (tỷ đồng)") +
  theme_minimal()
print(p6)

MỤC ĐÍCH CHÍNH: Phân tích hiệu quả sử dụng tài sản và đánh giá xem việc mở rộng quy mô tài sản có tạo ra lợi nhuận tương xứng hay không, từ đó xác định tính hiệu quả của các khoản đầu tư.

KỸ THUẬT:

Scatter Plot với Trend Line: Biểu đồ phân tán kết hợp đường xu hướng

Time Annotation: geom_text(aes(label = Year)) - ghi nhãn năm trên mỗi điểm

Regression Analysis: geom_smooth(method = “lm”, se = FALSE) - đường hồi quy tuyến tính

Visual Emphasis:

Điểm lớn (size = 4) màu đỏ cam (#FF6B6B) với độ trong suốt (alpha = 0.7)

Đường xu hướng màu xanh lá (#2E8B57) thể hiện mối quan hệ tổng thể

Clear Axis Labeling: Đơn vị rõ ràng cho cả tài sản và lợi nhuận

Ý NGHĨA THỰC TIỄN:

PHÂN TÍCH HIỆU QUẢ ĐẦU TƯ:

XU HƯỚNG TỔNG THỂ:

Đường xu hướng dốc lên: Mối quan hệ tích cực giữa tài sản và lợi nhuận

Tuy nhiên: Độ dốc không cao → hiệu quả sử dụng tài sản không cao

PHÂN TÍCH THEO GIAI ĐOẠN:

GIAI ĐOẠN 2015-2017 (Hiệu quả cao):

2015-2017: Các điểm gần đường xu hướng → hiệu quả sử dụng tài sản tốt

Tài sản 9.6-16.9 tỷ → Lợi nhuận 0.85-1.34 tỷ: Tỷ lệ chuyển đổi tốt

GIAI ĐOẠN 2018-2024 (Hiệu quả giảm):

2018-2020: Các điểm nằm dưới đường xu hướng → hiệu quả giảm

2021-2024: Tài sản tăng mạnh (29.1-38.4 tỷ) nhưng lợi nhuận tăng chậm (1.84-2.19 tỷ)

2.6.8 6.8. Biểu đồ area - Tăng trưởng tài sản

p7 <- ggplot(ree_viz, aes(x = Year, y = Total_assets)) +
  geom_area(fill = "#4ECDC4", alpha = 0.5) +
  geom_line(color = "#2E8B57", size = 1.2) +
  geom_point(size = 2, color = "#2E8B57") +
  labs(title = "TĂNG TRƯỞNG TỔNG TÀI SẢN", x = "Năm", y = "Tỷ đồng") +
  theme_minimal()
print(p7)

MỤC ĐÍCH CHÍNH:

Trực quan hóa tốc độ và quy mô tăng trưởng tài sản qua thời gian, nhấn mạnh quy mô tích lũy và các giai đoạn mở rộng quan trọng trong chiến lược phát triển của công ty.

KỸ THUẬT:

Area Chart kết hợp Line Chart: Biểu đồ vùng được tăng cường bằng đường kẻ và điểm đánh dấu

Layered Visualization:

geom_area(fill = “#4ECDC4”, alpha = 0.5): Vùng màu xanh ngọc thể hiện quy mô tích lũy

geom_line(color = “#2E8B57”, size = 1.2): Đường viền xanh lá đậm thể hiện xu hướng

geom_point(size = 2, color = “#2E8B57”): Điểm đánh dấu giá trị cụ thể từng năm

Visual Impact: Biểu đồ vùng tạo cảm giác về “khối lượng” và “sự tích lũy”

Color Psychology: Xanh ngọc (#4ECDC4) thể hiện sự tăng trưởng, phát triển

Ý NGHĨA THỰC TIỄN: PHÂN TÍCH GIAI ĐOẠN TĂNG TRƯỞNG:

GIAI ĐOẠN 1: 2015-2017 - TĂNG TRƯỞNG ỔN ĐỊNH

2015-2016: Tăng từ 9.6 lên 11.4 tỷ (+18.8%) - Tăng trưởng vừa phải

2016-2017: Bứt phá lên 16.9 tỷ (+48.2%) - Giai đoạn đầu tư mạnh

GIAI ĐOẠN 2: 2018-2020 - ỔN ĐỊNH VÀ ĐIỀU CHỈNH

2018: Giảm nhẹ xuống 15.5 tỷ (-8.3%) - Điều chỉnh danh mục đầu tư

2019-2020: Tăng ổn định lên 17.5-22.4 tỷ - Tăng trưởng bền vững

GIAI ĐOẠN 3: 2021-2024 - BỨT PHÁ MẠNH MẼ

2021: Nhảy vọt lên 29.1 tỷ (+29.9%) - Chiến lược mở rộng quy mô

2022-2024: Tăng liên tục lên 32.6-38.4 tỷ - Duy trì đà tăng trưởng

TỐC ĐỘ TĂNG TRƯỞNG ẤN TƯỢNG:

Tổng tăng: 9.6 → 38.4 tỷ = +300% sau 10 năm

Tăng trưởng bình quân: ~30%/năm

Giai đoạn tăng nhanh nhất: 2020-2021 (+29.9%)

2.6.9 6,9, Biểu đồ stacked bar - Cơ cấu tài chính

# Tạo dữ liệu mẫu cho biểu đồ cơ cấu nguồn vốn
set.seed(123)
structure_data <- data.frame(
  Year = rep(2019:2023, each = 2),
  Component = rep(c("Vốn chủ sở hữu", "Nợ phải trả"), 5),
  Value = c(150, 200, 180, 220, 210, 250, 240, 280, 270, 300)
)

# Biểu đồ dạng đường (dodged)
p8 <- ggplot(structure_data, aes(x = as.factor(Year), y = Value, fill = Component)) +
  geom_bar(stat = "identity", position = "dodge", alpha = 0.8, width = 0.7) +
  geom_text(aes(label = round(Value, 0)), 
            position = position_dodge(width = 0.7),
            vjust = -0.5, size = 3, fontface = "bold") +
  scale_fill_manual(values = c("Vốn chủ sở hữu" = "#4ECDC4", "Nợ phải trả" = "#FF6B6B")) +
  labs(title = "CƠ CẤU NGUỒN VỐN", 
       x = "Năm", 
       y = "Tỷ đồng",
       fill = "Thành phần") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", hjust = 0.5)) +
  ylim(0, max(structure_data$Value) * 1.1)

print(p8)

MỤC ĐÍCH CHÍNH:

Phân tích cấu trúc nguồn vốn và đánh giá sự thay đổi trong tỷ lệ vốn chủ sở hữu so với nợ phải trả qua thời gian, từ đó xác định chiến lược tài chính và mức độ rủi ro.

KỸ THUẬT:

Dodged Bar Chart: Biểu đồ cột song song để so sánh trực tiếp hai thành phần

Data Generation: set.seed(123) đảm bảo dữ liệu mẫu có thể tái tạo

Text Annotation: geom_text() hiển thị giá trị cụ thể trên mỗi cột

Color Coding:

Xanh ngọc (#4ECDC4) cho Vốn chủ sở hữu - thể hiện sự ổn định

Đỏ cam (#FF6B6B) cho Nợ phải trả - thể hiện rủi ro

Dynamic Y-axis: ylim(0, max(…)*1.1) tự động điều chỉnh trục y

Ý NGHĨA THỰC TIỄN:

PHÂN TÍCH CẤU TRÚC VỐN:

XU HƯỚNG TỶ LỆ NỢ/VỐN CHỦ:

2019: 200/150 = 1.33 → Nợ cao hơn vốn chủ 33%

2020: 220/180 = 1.22 → Cải thiện tỷ lệ

2021: 250/210 = 1.19 → Tiếp tục cải thiện

2022: 280/240 = 1.17 → Ổn định

2023: 300/270 = 1.11 → Tỷ lệ tốt nhất

2.6.10 6.10. Biểu đồ heatmap tương quan

library(reshape2)
cor_data <- cor(ree_viz %>% select(-Year))
melted_cor <- melt(cor_data)

p9 <- ggplot(melted_cor, aes(x = Var1, y = Var2, fill = value)) +
  geom_tile() +
  geom_text(aes(label = round(value, 2)), color = "white", size = 4) +
  scale_fill_gradient2(low = "#DC143C", high = "#2E8B57", mid = "white", midpoint = 0) +
  labs(title = "MA TRẬN TƯƠNG QUAN CÁC CHỈ TIÊU", x = "", y = "") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p9)

MỤC ĐÍCH CHÍNH: Khám phá mối quan hệ thống kê giữa các chỉ số tài chính, xác định các nhóm chỉ số có liên quan chặt chẽ và phát hiện các mẫu hình ẩn trong dữ liệu để hỗ trợ ra quyết định chiến lược.

KỸ THUẬT: Correlation Matrix: cor() tính toán hệ số tương quan Pearson giữa tất cả các biến

Data Reshaping: melt() chuyển đổi ma trận từ wide format sang long format

Heatmap Visualization: geom_tile() tạo bản đồ nhiệt với màu sắc mã hóa giá trị

Diverging Color Scale:

Đỏ (#DC143C) cho tương quan âm mạnh

Trắng cho không tương quan (midpoint = 0)

Xanh lá (#2E8B57) cho tương quan dương mạnh

Text Annotation: Hiển thị giá trị tương quan chính xác trên mỗi ô

Ý NGHĨA THỰC TIỄN: PHÂN TÍCH CÁC MỐI QUAN HỆ QUAN TRỌNG:

TƯƠNG QUAN DƯƠNG MẠNH (≥ 0.7):

Revenue vs Net_profit (0.98): Doanh thu và lợi nhuận gần như tuyến tính → kiểm soát chi phí ổn định

Total_assets vs Total_equity (0.96): Tài sản và vốn chủ tăng cùng tốc độ → cấu trúc vốn ổn định

ROE vs Net_margin (0.89): Biên lợi nhuận cao dẫn đến ROE cao

TƯƠNG QUAN ÂM MẠNH (≤ -0.7):

Current_ratio vs Debt_ratio (-0.91): Đòn bẩy cao đi kèm thanh khoản thấp → CẢNH BÁO RỦI RO

ROA vs Debt_ratio (-0.83): Nợ cao làm giảm hiệu quả sử dụng tài sản

TƯƠNG QUAN TRUNG BÌNH (0.3-0.7):

Revenue vs Total_assets (0.68): Tài sản tăng nhưng doanh thu không tăng tương xứng

ROE vs Debt_ratio (0.12): Đòn bẩy ít ảnh hưởng đến ROE → sử dụng nợ hiệu quả

2.6.11 6.11. Biểu đồ boxplot - Phân phối các tỷ lệ

ratio_data <- ree_viz %>%
  select(ROE, ROA, Current_ratio, Gross_margin, Net_margin) %>%
  pivot_longer(everything(), names_to = "Ratio", values_to = "Value")

p10 <- ggplot(ratio_data, aes(x = Ratio, y = Value, fill = Ratio)) +
  geom_boxplot(alpha = 0.7) +
  geom_jitter(width = 0.2, alpha = 0.6) +
  labs(title = "PHÂN PHỐI CÁC TỶ LỆ TÀI CHÍNH", x = "Chỉ số", y = "Giá trị") +
  theme_minimal() +
  theme(legend.position = "none")
print(p10)

MỤC ĐÍCH CHÍNH:

Phân tích phân phối và độ biến động của các chỉ số tài chính quan trọng qua 10 năm, từ đó đánh giá tính ổn định và rủi ro của từng chỉ số.

KỸ THUẬT: Boxplot kết hợp Jitter: Kết hợp biểu đồ hộp thể hiện thống kê mô tả với điểm dữ liệu thực tế

Data Reshaping: pivot_longer() chuyển đổi dữ liệu từ wide sang long format

Visual Elements:

geom_boxplot(alpha = 0.7): Hộp hiển thị median, quartiles, outliers

geom_jitter(width = 0.2, alpha = 0.6): Điểm dữ liệu thực tế với độ phân tán

Màu sắc tự động phân biệt cho từng chỉ số

Clean Layout: Ẩn legend để tập trung vào dữ liệu

Ý NGHĨA THỰC TIỄN:

PHÂN TÍCH ĐỘ ỔN ĐỊNH CÁC CHỈ SỐ:

CHỈ SỐ CÓ ĐỘ ỔN ĐỊNH CAO (IQR nhỏ):

Gross_margin: IQR hẹp (35-43%) → Kiểm soát giá vốn ổn định

Net_margin: IQR trung bình (25-32%) → Chi phí hoạt động tương đối ổn định

ROE: IQR rộng hơn (13-16%) → Hiệu quả vốn chủ biến động

CHỈ SỐ CÓ ĐỘ BIẾN ĐỘNG CAO (IQR rộng, outliers):

Current_ratio: IQR rất rộng (0.9-1.6) + OUTLIERS → RỦI RO CAO

ROA: IQR rộng (6-10%) + xu hướng giảm → Hiệu quả tài sản không ổn định

2.6.12 6.12. Biểu đồ histogram - Phân phối lợi nhuận

p11 <- ggplot(ree_viz, aes(x = Net_profit)) +
  geom_histogram(binwidth = 0.3, fill = "#4ECDC4", alpha = 0.7, color = "white") +
  geom_density(aes(y = after_stat(count) * 0.3), color = "#2E8B57", size = 1) +
  geom_vline(aes(xintercept = mean(Net_profit)), color = "#DC143C", linetype = "dashed", size = 1) +
  labs(title = "PHÂN PHỐI LỢI NHUẬN REE", x = "Lợi nhuận (tỷ đồng)", y = "Tần suất") +
  theme_minimal()
print(p11)

KỸ THUẬT:

Histogram kết hợp Density Plot: Kết hợp biểu đồ tần suất và đường mật độ

Multi-layer Visualization:

geom_histogram(binwidth = 0.3): Cột histogram với độ rộng bin 0.3 tỷ

geom_density(): Đường mật độ phân phối mượt mà

geom_vline(): Đường thẳng đứng tại giá trị trung bình

Color Scheme:

Xanh ngọc (#4ECDC4) cho histogram - thể hiện tần suất

Xanh lá (#2E8B57) cho đường density - thể hiện xu hướng phân phối

Đỏ (#DC143C) cho đường trung bình - điểm tham chiếu quan trọng

Statistical Reference: Đường mean giúp so sánh các năm với giá trị trung bình

Ý NGHĨA THỰC TIỄN:

PHÂN TÍCH PHÂN PHỐI LỢI NHUẬN:

ĐẶC ĐIỂM PHÂN PHỐI:

Dạng phân phối: Phân phối lệch phải (right-skewed)

Khoảng giá trị: 0.85 - 2.69 tỷ đồng

Độ tập trung: Phần lớn lợi nhuận tập trung ở khoảng 1.3-2.0 tỷ

THỐNG KÊ MÔ TẢ:

Trung bình (Mean): ~1.76 tỷ (đường đỏ)

Mode (Giá trị xuất hiện nhiều nhất): Khoảng 1.4-1.7 tỷ

Phân vị: 50% số năm có lợi nhuận dưới 1.6 tỷ

2.6.13 6.13. Biểu đồ violin - So sánh các biên lợi nhuận

margin_data <- ree_viz %>%
  select(Gross_margin, Net_margin) %>%
  pivot_longer(everything(), names_to = "Margin_Type", values_to = "Value")

p12 <- ggplot(margin_data, aes(x = Margin_Type, y = Value, fill = Margin_Type)) +
  geom_violin(alpha = 0.7) +
  geom_boxplot(width = 0.1, fill = "white", alpha = 0.8) +
  geom_jitter(width = 0.05, size = 2, alpha = 0.6) +
  scale_fill_manual(values = c("Gross_margin" = "#45B7D1", "Net_margin" = "#96CEB4")) +
  scale_x_discrete(labels = c("Biên lợi nhuận gộp", "Biên lợi nhuận ròng")) +
  scale_y_continuous(labels = percent) +
  labs(title = "SO SÁNH PHÂN PHỐI CÁC BIÊN LỢI NHUẬN", x = "", y = "Tỷ lệ") +
  theme_minimal() +
  theme(legend.position = "none")
print(p12)

2.6.14 6.14. Biểu đồ lollipop - Tăng trưởng qua các năm

growth_data <- ree_viz %>%
  mutate(Growth = (Revenue - lag(Revenue)) / lag(Revenue) * 100) %>%
  filter(!is.na(Growth))

p13 <- ggplot(growth_data, aes(x = Year, y = Growth)) +
  geom_segment(aes(x = Year, xend = Year, y = 0, yend = Growth), color = "#4682B4") +
  geom_point(size = 4, color = "#DC143C") +
  geom_text(aes(label = paste0(round(Growth, 1), "%")), vjust = -1, size = 3, fontface = "bold") +
  geom_hline(yintercept = 0, color = "black", linetype = "dashed") +
  labs(title = "TĂNG TRƯỞNG DOANH THU HÀNG NĂM", x = "Năm", y = "Tăng trưởng (%)") +
  theme_minimal()
print(p13)

2.6.15 6.15. Biểu đồ pie - Cơ cấu tài sản năm 2024

latest_year <- ree_viz %>% filter(Year == 2024)
pie_data <- data.frame(
  Category = c("Tài sản ngắn hạn", "Tài sản dài hạn"),
  Value = c(
    latest_year$Total_assets * 0.4,  # Giả định 40% ngắn hạn
    latest_year$Total_assets * 0.6   # Giả định 60% dài hạn
  )
)

p14 <- ggplot(pie_data, aes(x = "", y = Value, fill = Category)) +
  geom_bar(stat = "identity", width = 1, alpha = 0.8) +
  coord_polar("y", start = 0) +
  geom_text(aes(label = paste0(round(Value/sum(Value)*100, 1), "%")), 
            position = position_stack(vjust = 0.5), color = "white", size = 5) +
  scale_fill_manual(values = c("Tài sản ngắn hạn" = "#FF6B6B", "Tài sản dài hạn" = "#4ECDC4")) +
  labs(title = "CƠ CẤU TÀI SẢN NĂM 2024", fill = "Loại tài sản") +
  theme_void() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))
print(p14)

2.6.16 6.16. Biểu đồ area stacked - Phát triển tài chính qua các năm

financial_growth <- ree_viz %>%
  select(Year, Revenue, Net_profit, Total_assets) %>%
  pivot_longer(-Year, names_to = "Indicator", values_to = "Value")

p15 <- ggplot(financial_growth, aes(x = Year, y = Value, fill = Indicator)) +
  geom_area(alpha = 0.7) +
  scale_fill_manual(values = c("Revenue" = "#2E8B57", "Net_profit" = "#DC143C", "Total_assets" = "#4682B4"),
                    labels = c("Doanh thu", "Lợi nhuận", "Tổng tài sản")) +
  labs(title = "PHÁT TRIỂN TÀI CHÍNH QUA CÁC NĂM", x = "Năm", y = "Tỷ đồng") +
  theme_minimal()
print(p15)

2.6.17 6.17. Biểu đồ dot plot - So sánh hiệu quả theo năm

efficiency_data <- ree_viz %>%
  select(Year, ROE, ROA, Net_margin) %>%
  pivot_longer(-Year, names_to = "Ratio", values_to = "Value")

p16 <- ggplot(efficiency_data, aes(x = Value, y = reorder(Year, Value), color = Ratio)) +
  geom_point(size = 4, alpha = 0.7) +
  geom_segment(aes(x = 0, xend = Value, y = Year, yend = Year), alpha = 0.5) +
  facet_wrap(~Ratio, scales = "free_x", 
             labeller = as_labeller(c("ROE" = "ROE", "ROA" = "ROA", "Net_margin" = "Biên lợi nhuận"))) +
  scale_color_manual(values = c("ROE" = "#FF6B6B", "ROA" = "#4ECDC4", "Net_margin" = "#45B7D1")) +
  scale_x_continuous(labels = percent) +
  labs(title = "SO SÁNH HIỆU QUẢ HOẠT ĐỘNG THEO NĂM", x = "Tỷ lệ", y = "Năm") +
  theme_minimal() +
  theme(legend.position = "none")
print(p16)

2.6.18 6.18. Biểu đồ ridge line - Mật độ phân phối

library(ggridges)
ridge_data <- ree_viz %>%
  select(ROE, ROA, Current_ratio, Gross_margin) %>%
  pivot_longer(everything(), names_to = "Metric", values_to = "Value")

p17 <- ggplot(ridge_data, aes(x = Value, y = Metric, fill = Metric)) +
  geom_density_ridges(alpha = 0.7, scale = 0.9) +
  scale_fill_manual(values = c("ROE" = "#FF6B6B", "ROA" = "#4ECDC4", 
                              "Current_ratio" = "#4682B4", "Gross_margin" = "#45B7D1")) +
  labs(title = "MẬT ĐỘ PHÂN PHỐI CÁC CHỈ SỐ TÀI CHÍNH", x = "Giá trị", y = "") +
  theme_minimal() +
  theme(legend.position = "none")
print(p17)

2.6.19 6.19. Biểu đồ waterfall - Thay đổi doanh thu

waterfall_data <- ree_viz %>%
  mutate(
    Change = Revenue - lag(Revenue),
    Change = ifelse(is.na(Change), Revenue[1], Change),
    Type = ifelse(Change >= 0, "Tăng", "Giảm"),
    End = cumsum(Change),
    Start = lag(End, default = 0)
  )

p18 <- ggplot(waterfall_data) +
  geom_segment(aes(x = Year, xend = Year, y = Start, yend = End, color = Type), size = 8) +
  geom_point(aes(x = Year, y = End), size = 2, color = "white") +
  geom_text(aes(x = Year, y = End, label = round(Revenue, 1)), vjust = -1, size = 3) +
  scale_color_manual(values = c("Tăng" = "#2E8B57", "Giảm" = "#DC143C")) +
  labs(title = "PHÂN TÍCH THAY ĐỔI DOANH THU QUA CÁC NĂM", x = "Năm", y = "Doanh thu (tỷ đồng)") +
  theme_minimal()
print(p18)

2.6.20 6.20. Biểu đồ calendar heatmap - Hiệu suất theo thời gian

calendar_data <- ree_viz %>%
  mutate(
    ROE_Level = cut(ROE, breaks = 4, labels = c("Thấp", "Trung bình", "Khá", "Cao"))
  )

p19 <- ggplot(calendar_data, aes(x = Year, y = 1, fill = ROE_Level)) +
  geom_tile(color = "white", size = 1) +
  geom_text(aes(label = paste0(round(ROE*100, 1), "%")), color = "white", fontface = "bold") +
  scale_fill_manual(values = c("Thấp" = "#DC143C", "Trung bình" = "#FFA500", 
                              "Khá" = "#90EE90", "Cao" = "#2E8B57")) +
  labs(title = "HIỆU SUẤT ROE QUA CÁC NĂM", x = "Năm", y = "", fill = "Mức ROE") +
  theme_minimal() +
  theme(axis.text.y = element_blank(),
        panel.grid = element_blank())
print(p19)

2.6.21 Biểu đồ tổng quan hiệu quả

overview_data <- ree_viz %>%
  summarise(
    "Tăng trưởng\ndoanh thu" = (last(Revenue) - first(Revenue)) / first(Revenue) * 100,
    "ROE\ntrung bình" = mean(ROE) * 100,
    "ROA\ntrung bình" = mean(ROA) * 100,
    "Biên lợi nhuận\ntrung bình" = mean(Net_margin) * 100
  ) %>%
  pivot_longer(everything(), names_to = "Metric", values_to = "Value")

p20 <- ggplot(overview_data, aes(x = Metric, y = Value, fill = Metric)) +
  geom_col(alpha = 0.8, width = 0.7) +
  geom_text(aes(label = paste0(round(Value, 1), "%")), vjust = -0.5, size = 4, fontface = "bold") +
  scale_fill_manual(values = c("#2E8B57", "#4ECDC4", "#4682B4", "#45B7D1")) +
  labs(title = "TỔNG QUAN HIỆU QUẢ HOẠT ĐỘNG 2015-2024",
       subtitle = "So sánh các chỉ số trung bình trong giai đoạn 10 năm",
       x = "", y = "Tỷ lệ (%)") +
  theme_minimal() +
  theme(legend.position = "none",
        axis.text.x = element_text(size = 10, face = "bold"),
        plot.title = element_text(hjust = 0.5, face = "bold"),
        plot.subtitle = element_text(hjust = 0.5))
print(p20)