TIỂU LUẬN

Ngôn ngữ lập trình trong phân tích dữ liệu

Nhóm 10 : Phan Văn Hồng Nguyên, Trần Xuân Phát

Giảng viên hướng dẫn: ThS. Trần Mạnh Tường

10/11/2025




Phần 1: Bộ dữ liệu GiveMeSomeCredit

1 Đề tài dộ dữ liệu

1.1 Tính cấp thiết của đề tài:

Trong bối cảnh ngành Tài chính - ngân hàng ngày càng coi trọng công tác quản trị rủi ro tín dụng, việc dự báo chính xác khả năng trả nợ của khách hàng trở thành yếu tố then chốt quyết định đến hiệu quả hoạt động cho vay. Song hành với đó, sự phát triển của khoa học dữ liệu đã mang đến những phương pháp phân tích định lượng hiện đại, cho phép các tổ chức tín dụng chuyển đổi từ đánh giá chủ quan sang các mô hình dự báo khách quan dựa trên dữ liệu thứ cấp được thu thập.

Bộ dữ liệu GiveMeSomeCredit.csv là một bộ dữ liệu công khai nổi tiếng, xuất phát từ một cuộc thi trên nền tảng khoa học dữ liệu Kaggle được tổ chức vào năm 2011. Mục tiêu của phân tích là đánh giá khả năng rủi ro tín dụng dựa trên đặc điểm nhân khẩu học và lịch sử tài chính của từng hồ sơ của khác hàng cá nhân. Bộ dữ liệu thô ban đầu gồm 150000 quan sát với 11 biến biến

1.1.1 Nạp các thư viện cần thiết:

Hàm library() là một hàm cơ bản trong R, được sử dụng để nạp các gói thư viện (packages) cần thiết cho quá trình phân tích dữ liệu. Trong phần này, nhóm dùng lệnh library(tidyverse)library(knitr) với các gói mà hàm library() tác động lên là: tidyverseknitr. Với:

Gói tidyversebộ công cụ toàn diện giúp : Nhập và làm sạch dữ liệu; Biến đổi và tổng hợp dữ liệu; Trực quan hóa bằng ggplot2. Nó giúp công việc phân tích dữ liệu trở nên gọn gàng, nhất quán và dễ đọc.

Gói knitr dùng để chuyển file R Markdown (.Rmd) thành báo cáo hoàn chỉnh (Word, PDF, HTML…).Nó kết hợp code, kết quả và lời giải thích trong cùng một tài liệu thông qua nút lệnh bấm nút Knit trong R Markdown.

library(tidyverse)
library(knitr)

Các thư viện đã được nạp thành công vào môi trường R, cung cấp các công cụ cần thiết cho việc xử lý dữ liệu và tạo báo cáo trong các bước phân tích tiếp theo.

1.1.2 Kiểm tra đường dẫn hiện tại trước khi tải file lên

Hàm getwd() là một hàm cơ bản trong R, được sử dụng để trả về đường dẫn làm việc hiện tại \((current working directory)\) của môi trường là ngôn ngữ R. Trong phần này, nhóm dùng lệnh getwd() để xác định thư mục làm việc hiện tại mà R đang thao tác, hỗ trợ cho việc truy xuất file dữ liệu đầu vào. Nếu file dữ liệu không nằm trong thư mục làm việc mặc định, nhóm sẽ di chuyển file vào đây để thuận tiện hơn cho quá trình gọi nguồn dữ liệu.

getwd()
## [1] "C:/Users/Admin/Downloads/tieuluan2"

Kết quả trả về đường dẫn C:/Users/Admin/Downloads/tieuluan2 đậy chính là dường dẫn mặc định của R cầ cần di chuyển file dữ liệu đầu vào vào thư mục làm việc mặc định này hoặc thay đổi thư mục làm việc mặc định để có thể truy xuất file dữ liệu một cách trực tiếp. Điều này đảm bảo việc đọc và ghi file sẽ diễn ra đúng vị trí mong muốn trong quá trình phân tích dữ liệu.

1.1.3 Đọc dữ liệu đầu vào.

Hàm read.csv() là một hàm cơ bản trong R, được sử dụng để đọc tệp dữ liệu có định dạng CSV (Comma-Separated Values). Lệnh credit <- read.csv('Givemesomecredit.csv') với đối tượng mà hàm read.csv() tác động lên là tệp dữ liệu: Givemesomecredit.csv.

credit <- read.csv('GiveMeSomeCredit.csv')

Do tệp GiveMeSomeCredit.csv đã nằm trong thư mục làm việc mặc định của R được xác định từ bước kiểm tra đường dẫn trước đó, việc đọc dữ liệu được thực hiện trực tiếp mà không cần thay đổi thư mục làm việc. Dữ liệu đầu vào đã được nhập thành công và gán vào đối tượngcredit dưới dạngdata frame, sẵn sàng cho các bước phân tích tiếp theo.

1.1.4 Giới thiệu sơ qua về các biến có trong bộ dữ liệu

Hàm names() là một hàm cơ bản trong R, được sử dụng để trả về tên các biến $(variable names)$ của một đối tượng dữ liệu có cấu trúc, phổ biến nhất là data frame. Trong thao tác này, nhóm dùng lệnh names(credit) với đối tượng mà hàm names() tác động lên là data frame: credit.

names(credit)
##  [1] "SeriousDlqin2yrs"                    
##  [2] "RevolvingUtilizationOfUnsecuredLines"
##  [3] "age"                                 
##  [4] "NumberOfTime30.59DaysPastDueNotWorse"
##  [5] "DebtRatio"                           
##  [6] "MonthlyIncome"                       
##  [7] "NumberOfOpenCreditLinesAndLoans"     
##  [8] "NumberOfTimes90DaysLate"             
##  [9] "NumberRealEstateLoansOrLines"        
## [10] "NumberOfTime60.89DaysPastDueNotWorse"
## [11] "NumberOfDependents"

Bộ dữ liệu có 11 biến được liệt kê như trên. Ý nghĩa của từng biến được mô tả trong bảng sau:

Table 1.1: Mô tả các biến trong bộ dữ liệu
Tên.biến Ý.nghĩa
SeriousDlqin2yrs 1 nếu khách hàng nợ xấu 2 năm qua, 0 nếu không
RevolvingUtilizationOfUnsecuredLines Tỷ lệ sử dụng tín dụng quay vòng trên hạn mức
age Tuổi của người vay
NumberOfTime30-59DaysPastDueNotWorse Số lần trễ hạn 30–59 ngày
DebtRatio Tỷ lệ nợ/thu nhập hàng tháng
MonthlyIncome Thu nhập hàng tháng (USD)
NumberOfOpenCreditLinesAndLoans Số tài khoản tín dụng/ khoản vay mở
NumberOfTimes90DaysLate Số lần trễ hạn ≥ 90 ngày
NumberRealEstateLoansOrLines Số khoản vay thế chấp bất động sản
NumberOfTime60-89DaysPastDueNotWorse Số lần trễ hạn 60–89 ngày
NumberOfDependents Số người phụ thuộc tài chính

1.1.5 Xem số lượng quan sát và biến của bộ dữ liệu trước khi kiểm tra.

Hàm dim() là một hàm cơ bản trong R, được sử dụng để trả về kích thước \((dimension)\) của một đối tượng dữ liệu có cấu trúc, phổ biến nhất là data frame. ở nghiên cứu này nhóm dùng lệnh dim(credit) với đối tượng mà hàm dim() tác động lên là data frame : credit.

dim(credit)
## [1] 150000     11

Dữ liệu thô của nghiên cứu có 150000 quan sát11 biến được thể hiện thông qua Rscript.

1.1.6 Xem dữ liệu thông qua các quan sát đầu tiên:

Hàm head() là một hàm cơ bản trong R, được sử dụng để xem nhanh một số quan sát đầu tiên \((first observations)\) của một đối tượng dữ liệu có cấu trúc, phổ biến nhất là data frame. Trong thao tác này, nhóm dùng lệnh head(credit) với đối tượng mà hàm head() tác động lên là data frame:credit .

head(credit)

Kết quả hiển thị 6 quan sát đầu tiên của bộ dữ liệu, cho phép kiểm tra cấu trúc dữ liệu, xác nhận việc đọc dữ liệu thành công và nhận diện sơ bộ các giá trị thiếu hoặc bất thường. Đây là bước kiểm tra nhanh quan trọng trước khi tiến hành phân tích sâu.

Table 1.2: Các giá trị đầu tiên của các biến trong bộ dữ liệu
Tên.biến Các.quan.sát.đầu.tiên
SeriousDlqin2yrs 1, 0, 0, 0, 0, 0
RevolvingUtilizationOfUnsecuredLines 0.7661, 0.9572, 0.6582, 0.2338, 0.9072, 0.2132
age 45, 40, 38, 30, 49, 74
NumberOfTime30_59DaysPastDueNotWorse 2, 0, 1, 0, 1, 0
DebtRatio 0.8030, 0.1219, 0.0851, 0.0360, 0.0249, 0.3756
MonthlyIncome 9.200, 2.600, 3.042, 3.300, 6.3588, 3.500
NumberOfOpenCreditLinesAndLoans 13, 4, 2, 5, 7, 3
NumberOfTimes90DaysLate 0, 0, 1, 0, 0, 0
NumberRealEstateLoansOrLines 6, 0, 0, 0, 1, 1
NumberOfTime60_89DaysPastDueNotWorse 0, 0, 0, 0, 0, 0
NumberOfDependents 2, 1, 0, 0, 0, 1

1.1.7 Xem các hàng cuối của bộ dữ liệu

Hàm tail() là một hàm cơ bản trong R, được sử dụng để xem nhanh một số quan sát cuối cùng \((last observations)\) của một đối tượng dữ liệu có cấu trúc, phổ biến nhất là data frame. Do có công dụng hơi ngược với hàm head() nên thao tác này là 1 thao tác bổ xung có tình tương quan với quan sát trướng đó. Trong thao tác này, nhóm dùng lệnh tail(credit) với đối tượng mà hàm tail() tác động lên là data frame: credit.

tail(credit)
SeriousDlqin2yrs RevolvingUtilizationOfUnsecuredLines age NumberOfTime30.59DaysPastDueNotWorse DebtRatio MonthlyIncome NumberOfOpenCreditLinesAndLoans NumberOfTimes90DaysLate NumberRealEstateLoansOrLines NumberOfTime60.89DaysPastDueNotWorse NumberOfDependents
149995 0 0.39 50 0 0.40 3,400 7 0 0 0 0
149996 0 0.04 74 0 0.23 2,100 4 0 1 0 0
149997 0 0.30 44 0 0.72 5,584 4 0 1 0 2
149998 0 0.25 58 0 3,870.00 NA 18 0 1 0 0
149999 0 0.00 30 0 0.00 5,716 4 0 0 0 0
150000 0 0.85 64 0 0.25 8,158 8 0 2 0 0

Kết quả hiển thị 6 quan sát cuối cùng của bộ dữ liệu, cho phép kiểm tra tính toàn vẹn của dữ liệu ở phần kết thúc dataset, xác nhận không có sự bất thường hay lỗi trong quá trình nhập liệu ở những bản ghi cuối cùng. Đây là bước kiểm tra đối xứng với việc xem các quan sát đầu tiên, đảm bảo tính nhất quán trong toàn bộ tập dữ liệu trước khi tiến hành phân tích sâu.

Table 1.3: Các quan sát cuối cùng (mẫu) của các biến trong bộ dữ liệu
Tên.biến Các.quan.sát.cuối..mẫu.
SeriousDlqin2yrs 0, 0, 0, 0, 0, 0
RevolvingUtilizationOfUnsecuredLines 0.3857, 0.0407, 0.2997, 0.2460, 0.0000, 0.8503
age 50, 74, 44, 58, 30, 64
NumberOfTime30_59DaysPastDueNotWorse 0, 0, 0, 0, 0, 0
DebtRatio 0.4043, 0.2251, 0.7166, 3870.0000, 0.0000, 0.2499
MonthlyIncome 3.400, 2.100, 5.584, NA, 5.716, 8.158
NumberOfOpenCreditLinesAndLoans 7, 4, 4, 18, 4, 8
NumberOfTimes90DaysLate 0, 0, 0, 0, 0, 0
NumberRealEstateLoansOrLines 0, 1, 1, 1, 0, 2
NumberOfTime60_89DaysPastDueNotWorse 0, 0, 0, 0, 0, 0
NumberOfDependents 0, 0, 2, 0, 0, 0

1.1.8 Xem kiểu dữ liệu của các biến

Hàm sapply() (viết tắt của “simplify apply”) thuộc họ hàm apply, có chức năng áp dụng một phép tính cụ thể lên tất cả các phần tử của một data frame hoặc vector; và trả về kết quả dưới dạng đơn giản hóa

Hàm class() là hàm cơ bản dùng để xác định kiểu dữ liệu (data type) của một đối tượng trong R

Khi kết hợp sapply(credit, class), chúng ta đang thực hiện: áp dụng hàm class lên từng biến (cột) trong data frame credit, từ đó trả về một vector chứa thông tin về kiểu dữ liệu của tất cả các biến. Cách tiếp cận này cho phép xác định chính xác và nhanh chóng kiểu dữ liệu cơ bản của từng cột.

sapply(credit, class)

Kết quả thực thi lệnh cho thấy:

  • Biến SeriousDlqin2yrs thuộc kiểu “integer” số thực đã dược mã hóa 0/1 .

  • Biến RevolvingUtilizationOfUnsecuredLines , và DebtRatiothuộc kiểu số thực “numeric”

  • Đa số các biến còn lại như : age , NumberOfTime30-59DaysPastDueNotWorse, MonthlyIncome, NumberOfOpenCreditLinesAndLoans… đều thuộc kiểu “integer” là dạng số nguyên

  • Biến thuộc kiểu “numeric”

1.1.9 Xem số lượng quan sát và kiểu dữ liệu một cách chi tiết của từng biến của bộ dữ liệu trước khi kiểm tra.

Sử dụng hàm str() (viết tắt của “structure”) là công cụ mạnh mẽ để kiểm tra cấu trúc nội tại của một đối tượng. Kết quả từ str() là phiên bản nâng cấp từ hàm dim() và hàm head(); cụ thể kết quả của str() cho ta biết số lượng quan sát, cấu trúc dữ liệu của từng đối tượng và các quan sát đầu tiên của đối tượng đó. Ở phần này nhóm sử dụng hàm str() để xem các quan sát đầu tiên và kiểu dự liệu của các biến trong bộ dữ liệucủa data frame credit.

str(credit)  

Kết quả kiểm tra cấu trúc dữ liệu bằng hàm str(credit) cho thấy bộ dữ liệu Give Me Some Credit được lưu trữ dưới dạng data.frame gồm 150.000 quan sát11 biến.
Các biến trong tập dữ liệu chủ yếu thuộc kiểu số nguyên (integer)số thực (numeric), phù hợp cho các phép tính thống kê và mô hình hóa. Do trong những quan sát đầu xuất hiện những khuyết thiếu nên nhóm sẽ chỉ giới thiệu sơ về nội dung bộ dữ liệu ở phần này và tập trung phân tích sâu hơn từng biến ở các phần sau.

Table 1.4: Cấu trục bộ dữ liệu
Tên.biến các.giá.trị.đầu..mẫu.
SeriousDlqin2yrs 1; 0; 0; 0; 0; 0
RevolvingUtilizationOfUnsecuredLines 0,766; 0,957; 0,658; 0,234; 0,907; 0,213
age 45; 40; 38; 30; 49; 74
NumberOfTime30,59DaysPastDueNotWorse 2; 0; 1; 0; 1; 0
DebtRatio 0,803; 0,1219; 0,0851; 0,036; 0,0249; 0,3756
MonthlyIncome 9.120; 2.600; 3.042; 3.300; 63.588; 3.500
NumberOfOpenCreditLinesAndLoans 13; 4; 2; 5; 7; 3
NumberOfTimes90DaysLate 0; 0; 1; 0; 0; 0
NumberRealEstateLoansOrLines 6; 0; 0; 0; 1; 1
NumberOfTime60,89DaysPastDueNotWorse 0; 0; 0; 0; 0; 0
NumberOfDependents 2; 1; 0; 0; 0; 1

Kết quả kiểm tra cấu trúc dữ liệu bằng hàm str(credit) cho thấy bộ dữ liệu Give Me Some Credit được lưu trữ dưới dạng data.frame gồm 150.000 quan sát11 biến. Các biến trong tập dữ liệu chủ yếu thuộc kiểu số nguyên (integer)số thực (numeric), phù hợp cho các phép tính thống kê và mô hình hóa. Do trong những quan sát đầu xuất hiện những khuyết thiếu nên nhóm sẽ chỉ giới thiệu sơ về nội dung bộ dữ liệu ở phần này và tập trung phân tích sâu hơn từng biến ở các phần sau.

1.1.10 Kiểm tra dữ liệu trùng lặp

Hàm duplicated() là một hàm cơ bản trong R, được sử dụng để xác định các hàng trùng lặp \((duplicate rows)\) trong một đối tượng dữ liệu có cấu trúc. Trong thao tác này, nhóm dùng lệnh sum(duplicated(credit)) với đối tượng mà hàm duplicated()tác động lên là data frame tên redit. Với: Hàm duplicated() trả về một vector logic (TRUE/FALSE) cho biết dòng nào trong bảng bị trùng với dòng trước đó, trong đó TRUE dòng bị trùng và FALSE dòng là duy nhất.

Hàm sum() khi áp dụng cho giá trị logic sẽ đếm số lượng TRUE, tức là đếm số dòng trùng lặp trong biến credit.

sum(duplicated(credit))
## [1] 609

Kết quả cho thấy bộ dữ liệu có 609 quan sát trùng lặp, tương đương khoảng 0,4% tổng số 150.000 bản ghi. Nguyên nhân có thể đến từ việc bộ dữ liệu trên không nhắc đến các yếu tố như tên, giới tính, mã định danh cá nhân ,… nên việc có 0.4% trùng lặp khác là hợp lý và không có gì bất thường.

1.1.11 Kiểm tra giá trị thiếu

Hàm is.na()colSums() là các hàm cơ bản trong R, được sử dụng để kiểm tra và đếm số lượng giá trị thiếu \((missing values)\) trong từng biến của một đối tượng dữ liệu có cấu trúc. Trong thao tác này, nhóm dùng lệnh colSums(is.na(credit)) với đối tượng mà các hàm này tác động lên đối tượng credit. Với:

Hàm is.na() trả về một ma trận logic (TRUE/FALSE) cùng kích thước với dữ liệu gốc, trong đó TRUE các ô dữ liệu bị thiếu (NA) và FALSE ô dữ liệu có giá trị.

Hàm colSums() tính tổng số giá trị TRUE theo từng cột, tức là đếm số lượng giá trị thiếu cho mỗi biến.

colSums(is.na(credit))

Kết quả:

Tên.biến Giá.trị
SeriousDlqin2yrs 0
RevolvingUtilizationOfUnsecuredLines 0
age 0
NumberOfTime30.59DaysPastDueNotWorse 0
DebtRatio 0
MonthlyIncome 29,731
NumberOfOpenCreditLinesAndLoans 0
NumberOfTimes90DaysLate 0
NumberRealEstateLoansOrLines 0
NumberOfTime60.89DaysPastDueNotWorse 0
NumberOfDependents 3,924

Kết quả kiểm tra cho thấy bộ dữ liệu có hai biến chứa giá trị thiếu: MonthlyIncome (29,731 giá trị thiếu, xấp xỉ 19.8% tổng quan sát) và NumberOfDependents (3,924 giá trị thiếu, xấp xỉ 2.6% tổng quan sát). Trong bối cảnh phân tích tín dụng, việc thiếu thông tin thu nhập hàng tháng là khá phổ biến do nhiều khách hàng không tiết lộ hoặc không ổn định về thu nhập. Thông tin về số người phụ thuộc thiếu có thể hợp lý với các nhóm khách hàng trẻ tuổi, độc thân, người lớn tuổi có con tự lập, hoặc người đã ly hôn không có quyền nuôi con. Tỷ lệ thiếu này cần được xử lý thích hợp để đảm bảo chất lượng mô hình dự báo rủi ro tín dụng.

1.1.12 KẾT LUẬN :

Những phát hiện ban đầu này cung cấp nền tảng quan trọng cho việc tiến hành làm sạch dữ liệu, phân tích chuyên sâu và xây dựng mô hình dự báo rủi ro tín dụng trong các chương tiếp theo. Bộ dữ liệu đã chứng minh tính phù hợp cho mục tiêu nghiên cứu là đánh giá khả năng trả nợ của khách hàng dựa trên các chỉ số tài chính và nhân khẩu học.

1.2 Xử lý dữ liệu thô

Trong chương này, chúng tôi tiến hành làm sạch và chuẩn bị dữ liệu cho quá trình phân tích. Các bước xử lý bao gồm: đổi tên biến, xử lý giá trị thiếu, loại bỏ dữ liệu trùng lặp, xử lý giá trị ngoại lai và ép kiểu dữ liệu. Mục tiêu là có được một bộ dữ liệu sạch, nhất quán và phù hợp cho các phân tích tiếp theo.

1.2.1 Đổi tên biến cho dễ thao tác

Để thuận tiện cho việc thao tác và phân tích, chúng tôi tiến hành đổi tên các biến trong bộ dữ liệu từ tên gốc (tiếng Anh, có thể dài và phức tạp) sang tên mới ngắn gọn, dễ hiểu và dễ sử dụng trong các lệnh code.

Tôi sẽ Sử dụng hàm rename() từ gói dplyr để đổi tên biến. Cú pháp: rename(new_name = old_name) VỚI CODE:

credit_clean <- credit %>%
  rename(
    Target = SeriousDlqin2yrs,
    Util = RevolvingUtilizationOfUnsecuredLines,
    Age = age,
    Due30_59 = NumberOfTime30.59DaysPastDueNotWorse,
    Due60_89 = NumberOfTime60.89DaysPastDueNotWorse,
    Due90 = NumberOfTimes90DaysLate,
    Income = MonthlyIncome,
    Debts = NumberOfOpenCreditLinesAndLoans,
    Dependents = NumberOfDependents
  )

# Xem tên cột mới
names(credit_clean)

Giải thích code:

  • Dóng 1 tạo ra data.frame mới tên credit_clean thay data.frame cũ credit thông quan toán tử gán :‘<-’

  • Từ dòng 2 đến dòng 12 là tên các biến của data.frame credit_clean được lấy ra từ các biến của dataframe credit thống qua toán tử pie ‘%>%’ dẫn thẳng biến từ data.frame credit sang là đối tượng cho thao tác đổi tên và tạo biến cũa credit_clean tên được đổi đổi vê sao cho ngắn gọn vẫn giữ nguyên ý nghĩa Ví dụ như:

  • Chúng ta đổi tên biến mục tiêu SeriousDlqin2yrs thành Target để ngắn gọn và dễ tham chiếu.

  • Các biến khác cũng được đổi tên tương tự để dễ sử dụng, ví dụ:RevolvingUtilizationOfUnsecuredLines thành Util, age thành Age, v.v.

Kết quả: Các biến đã được đổi tên đúng như trong code của hàm rename. Việc đổi tên biến không làm thay đổi dữ liệu nhưng giúp việc thao tác và viết code trở nên dễ dàng và ít lỗi hơn; tên biến ngắn gọn, rõ ràng giúp các bên liên quan (nhà phân tích, quản lý) dễ dàng nhận diện và thảo luận về các biến trong mô hình.

1.2.2 Xử lý giá trị thiếu của biến số người phụ thuộc tài chính

Biến Dependents (số người phụ thuộc) có một số giá trị thiếu (NA). Chúng tôi quyết định thay thế các giá trị thiếu này bằng 0, dựa trên giả định rằng nếu không có thông tin về người phụ thuộc, có thể coi như khách hàng không có người phụ thuộc.

Kỹ thuật và hàm sử dụng:

Sử dụng hàm coalesce() từ gói dplyr để thay thế giá trị NA bằng 0. Với cấu trúc:coalesce(x, y) trả về giá trị của x nếu x không phảilà giá trị bị thiếu (NA), ngược lại trả về y.

Code:

# Thay thế NA trong Dependents bằng median của số người phụ thuộc tài chính
credit_clean$Dependents <- coalesce(credit_clean$Dependents,0)

Giải thích code: dòng code thứ 2 sau chú thích chính là thực hiện trên dối tượng là biến Người phụ thuộc (Dependents) trong data.frame credit_clean ( credit_clean$Dependents ). bằng hàm coalesce(credit_clean$Dependents,0) nếu các giá trị của biến số người phụ thuộc tài chính Dependents bị khuyết thiếu sẽ thay giá trị thiếu bằng 0 còn nếu không bị thiếu thì giữ nguyên giá trị.

Thay thế bằng 0 (Dùng coalesce): Giả sử “không có người phụ thuộc” (Dependents) có thể được điền là 0

Kết luận: Giả định này hợp lý vì trong hồ sơ vay, nếu không khai báo người phụ thuộc, có thể khách hàng không có người phụ thuộc Giúp giảm số lượng giá trị thiếu, đảm bảo dữ liệu đầy đủ cho phân tích chuyên sâu. Tôi sẽ kiểm tra lại tất cả các khuyết thiếu sau khi xử lý các khuyết thiếu trên biến còn lại.

1.2.3 Xử lý giá trị thiếu ở biến thu nhập

Biến thu nhập hàng tháng (Income) có một số giá trị thiếu. Chúng tôi thay thế các giá trị thiếu bằng giá trị trung vị của thu nhập để bảo toàn phân phối của dữ liệu. Kỹ thuật và hàm sử dụng: Sử dụng median(..., na.rm = TRUE) để tính trung vị, bỏ qua giá trị NA; và Sử dụng coalesce() tương tự như thao tác vối biến số người phụ thuộc tài chính trước đó để thay thế NA bằng trung vị.

Code:

# Tính trung vị Income (bỏ qua NA)
median_income <- median(credit_clean$Income, na.rm = TRUE)

# Thay thế NA trong Income bằng giá trị trung vị
credit_clean$Income <-  coalesce(credit_clean$Income, median_income)

# Kiểm tra lại:
colSums(is.na(credit_clean))

Giải thích code Dóng code thứ 2 sau chú thích dùng để tính trung vị của biến thu nhapp65 (Income) có loại bỏ các khuyết thiếu (NA) thông qua na.rm viết tắt của (Not Available remove: loại bỏ những giá trị bị thiếu)
Dòng thứ 5 Thực hiện thao tác trên biến thu nhập của data.frame creadit_clean (creadit_clean$Income) dùng hàm coalesce(credit_clean$Income, median_income) thay thế những phần tử có giá trị bị thiếu trong biến thu nhập (Income) thành trung vị của chính biến thu nhập, nu61 phần tử không bị thiếu sẽ được giữ nguyên. Dòng 8 là sử dụng hàm colSum kết hợp với is.na giống như ở chương 1 để tính tổng số quan sát bị thieuu61 của từng biến cột trong data.frame : creadit_clean.

Trung vị được chọn vì nó ít bị ảnh hưởng bởi giá trị ngoại lai so với trung bình sau đó dùng colSum() để kiểm tra lại coi còn giá trị khuyết thiếu nào trong bộ dữ liệu không. Thay thế bằng trung vị giúp duy trì mức thu nhập điển hình của tập dữ liệu, tránh làm lệch phân phối; đảm bảo không có giá trị thiếu trong biến thu nhậ và tất cả các biến còn lại, giúp phân tích không bị gián đoạn

1.2.4 Xử lý giá trị trùng lặp

Dữ liệu trùng lặp có thể làm sai lệch kết quả phân tích. Chúng tôi đã kiểm tra ở chương 1 và phát hiện các quan sát trùng lặp tuy có ý nghĩa về nmat85 kinh tế nhưng để tránh làm ảnh hưởng về thống kê phân tích và mô hình hóa tôi sẽ loại bỏ các quan sát trùng lặp.Kỹ thuật và hàm sử dụng: Sử dụng hàm distinct() từ gói dplyr để loại bỏ các dòng trùng lặp.

## loại bỏ trùng lặp trong dplyr "distinct()"
 
credit_clean <- credit_clean %>% distinct()

Giải thích code : Hàm distinct() giữ lại các dòng duy nhất, loại bỏ các bản sao.

Ý nghĩa: Giúp đảm bảo mỗi quan sát là duy nhất, tránh việc một số khách hàng bị tính nhiều lần. Tránh làm sai lệch các ước lượng và dự báo do dữ liệu trùng lặp.

Sau đó chúng ta lại sử dụng lặp lại hàm sum kết hợp với duplicated để kiểm tra lại 1 lần nữa và không thấy giá trị khuyết thiếu nữa:

# Kiểm tra lại:
sum(duplicated(credit_clean))

1.2.5 Ép kiểu dữ liệu biến mục tiêu

Biến Target trong bộ dữ liệu thể hiện tình trạng vỡ nợ của khách hàng trong vòng 2 năm (1 = có vỡ nợ, 0 = không). Đây là biến đóng vai trò biến mục tiêu trong mô hình phân tích và dự báo rủi ro tín dụng. Tuy nhiên, trong dữ liệu gốc, biến này đang được lưu ở dạng số (numeric), có thể gây nhầm lẫn khi trực quan hóa và xây dựng mô hình phân loại. Do đó, cần ép kiểu dữ liệu của biến Target sang dạng factor (biến phân loại) để phản ánh đúng bản chất dữ liệu và hỗ trợ các thao tác thống kê mô tả, trực quan hóa và mô hình hóa sau này. Kỹ thuật và hàm sử dụng:

Sử dụng hàm as.factor() để chuyển đổi kiểu dữ liệu

credit_clean$Target <- as.factor(credit_clean$Target)
class(credit_clean$Target)
## [1] "factor"

Giải thích chi tiết: Dòng 1 Biến mục tiêu là biến phân loại (0: không vỡ nợ, 1: vỡ nợ) nên cần được xử lý như factor; Dòng code 2 dùng hàm class kiểm tra lại biến Target triong data.frame creadit_clean xem kết quả của dòng code trước đó. KẾT QUẢ: Biến mục tiêu đã được ép kiểu đúng tính chất của biến là kiểu factor nhằm Chuẩn bị dữ liệu phù hợp cho các bước tiếp theo như thống kê mô tả và phân tích đánh giá sự tương quan giữa các biến khác với biến mục tiêu

1.2.6 Xử lý những giá trị bất hợp lý

Bộ dữ liệu credit_clean không có lỗi dữ liệu không nhất quán (kiểu “Nam” vs “nam”). Nó đã sạch ở bước này. Tôi tiến hàn kiểm tra các biến và các giá trị không có ý nghĩa hay các giá trị có giá trị bất thường đột biến.

1.2.6.1 Tuổi

Biến Tuổi (Age) là một chỉ số cơ bản để đánh giá khả năng ổn định tài chính và kinh nghiệm quản lý nợ của khách hàng. Trong thực tế, các công ty tín dụng thường chỉ chấp nhận khách hàng trong một phạm vi tuổi nhất định (ví dụ từ 18 đến 70 tuổi),

sum(credit_clean$Age < 18)
## [1] 1

Giải thích Code : Sủ dụng hàm sum() lên đối tượng là biến tuổi tác của data.frame credit_clean cho thấy tổng các quan sát có giá trị dưới 18 Kết quả: phát hiện 1 quan sát có số tuổi dưới 18 tuổi vi phạm quy định phát luật về độ tuổi tối thiểu của người đứng tên 1 khoản và không đảm bào khả năng trả nợ khi dứng tên khoản vay tín dụng. . Xử lý: Code

credit_clean <- credit_clean%>%filter(Age>18)
sum(credit_clean$Age < 18)
## [1] 0

Giải nghĩa code: - Dòng 1: thông qua toán tử đường ống pie %>%” để lọc các biến độ tuổi (Age) chỉtrực tiếp biến tuổi người vay trên dataframe credit_clean làm đối tượng để hàm filter() lọc những biến tuổi lớn hơn 18 và loại bỏ quan sát có biến tuổi < 18 bất hợp lý - Dòng 2 kiểm tra lại các quan sát số tuổi xem thỏa mãn độ tuổi theo quy định có thể vay tín dụng là trên 18 chưa . Kết quả không còn quan sát hay hồ sơ vay nào có số tuổi sai quy định, đồng thời khẳng định sự hiệu quả dòng code thứ 1.

Ý nghĩa: Giúp loại bỏ biến tuổi bất hợp lý theo quy định về tín dụng và độ tuổi khách hàng có thể vay tín dung nhằm làm sạch bộ dữ liệu có ý nghĩa thống kê và cả ý nghĩa kinh tế, tài chính.

1.2.6.2 Thu nhập

Biến thu nhập hàng tháng phản ánh khả năng chi trả của khách hàng trong hoạt động vay vốn. Tuy nhiên, trong dữ liệu xuất hiện một số giá trị thu nhập quá cao so với mặt bằng chung, có thể do lỗi nhập liệu hoặc thuộc nhóm trường hợp cá biệt không đại diện. Tính đến tháng 6 năm 2024 người có thu nhập 100.000 USD/tháng tương đương 1,2 triệu USD/năm, và đây là mức rất cao, chỉ nằm trong nhóm 1% người có thu nhập cao nhất tại Mỹ (theo Vneconomy) . Những giá trị này được xem là ngoại lai, có thể làm sai lệch phân tích và mô hình dự báo. Vì vậy, cần tiến hành kiểm tra và xử lý các giá trị thu nhập bất thường để đảm bảo dữ liệu hợp lý và tin cậy.

Sử dụng summary() để có cái nhìn tổng quan về phân phối

Sử dụng filter() với điều kiện để loại bỏ ngoại lai

#phát hiện ngoại lai thông qua sumary 1 cách cơ bản
summary(credit_clean$Income)
print(count <- sum(credit_clean$Income > 100000))

Giải thích chi tiết: dòng code 2 sử dụng hàm summary nhằm xem các đặc điểm thogn61 kê cơ bản như giá trị bé nhất lớn nhất của thu nhập giúp đánh giá xem biến có phân phối như thế nào và có khả năng có ngoại lai không. dòng 3 dùng hàm sum() giúp tính tổng các quan sát trong biến thu nhập(Income) từ data.frame credit_clean xem có bao nhiêu quan sát hồ sơ vay có thu nhập lớn hơn 100000 USD và gán giá trị đó vào biến counti sau đó dùng hàm print in biến “counti” ra.

Kết quả :

Từ kết quả chạy ra ta có thông tin biến thu nhập(Income) có giá trị nhỏ nhất là 0 và giá trị lớn nhất là 3.008.75 usd có xác xuất rất cao có giá trị bất thường; Về giá trị nhỏ nhất là 0 có thể do các hồ sơ vay thế chấp tài sản của những người trẻ thất nghiệp, như người già mất khả năng lao động người cao tuổi,.. còn giá trị lớn nhất lớn hơn rất nhiều so với 1% thu nhập cao nhất nước mỹ và kết quả ở [1] cho thấy có 70 quan sát có thu nhập thuộc top 1% thu nhập cần loại bỏ tránh ảnh hưởn đến phân phối, thống kê và trực quan. Xử Lý Code:

# Loại bỏ NA 
credit_clean <- credit_clean %>%
  filter(Income <= 100000)
# kiểm tra lại 
sum(credit_clean$Income > 100000)

Giải nghĩa code: - dòng 2 thao tác trên chính data.frame: creadit_clean dùng hàm filter() lọc các giá trị biến thu nhập (Income) lớn hơn 100.000 usd - dòng 5 thao tác dùm hàm sum() lên biến thu nhập(Income) của đối tượng creadit_clean nhằm kiểm tra coi còn quan sát nào của bioen16 thu nhập có giá trị lớn hơn 100.00 không

Kết quả không còn quan sát nào thuộc biến thu nhập có thu nhập lớn hơn 100000 usd/ tháng nũa. Thao tác này giúp giảm ảnh hưởng của các giá trị cực đoan lên các ước lượng thống kê, tập trung vào nhóm khách hàng phổ biến, tránh làm sai lệch đánh giá rủi ro tín dụng.

1.2.6.3 Số người phụ thuộc tài chính

Biến Số người phụ thuộc (Dependents) phản ánh khối lượng trách nhiệm gia đình mà khách hàng phải gánh vác, một yếu tố quan trọng ảnh hưởng đến khả năng tiết kiệm và thanh toán nợ. ố người phụ thuộc càng nhiều thường đồng nghĩa với chi phí cố định hàng tháng cao hơn và khả năng dự phòng tài chính thấp hơn, từ đó làm tăng rủi ro vỡ nợ. Trong thực tế, số người phụ thuộc tài chính của một cá nhân thường nằm trong khoảng 0–5 người (gia đình hạt nhân + ông bà trong một số trường hợp) đông nhất là 10 người nếu > 10 trong dữ liệu là không hợp lý và có khả năng là trường hợp cá biệt cần loại bỏ tránh ảnh hưởng đến ý nghĩa thống kê

Kỹ thuật và hàm sử dụng: Sử dụng kết hợp summary(), sum() và filter() để phát hiện và xử lý Code : Phát hiện ngoại lai

summary(credit_clean$Dependents)
print(countdepen <- sum(credit_clean$Dependents > 10))

Giải nghĩa code: dòng 1 tính toán thống kê cơ bản của biến số người phụ thuc65 tài chính trên data.frame : creadit_clean xem phân phối đánh giá khả năng có ngọa lai dòng 2 tạo 1 phần tử tên:“countdepen” gán từ hàm um tính tổng sối quan sát vi phạm (biến Dependent > 10) sau đó dùng ham print() để in phần tử “countdepen” ra

Kết quả Thống kê cơ bản chú ý vào giá trị lớn nhất là 20 nghĩa là số người phụ thuộc tài chính tận 20 người rất phi hợp lý có thể là các trường hợp đặc biệt cần loại bỏ. Dòng kết quả [1] cho ta thấy tổng số ngoại lai là 2 cần loại bỏ theo giả thiết ban đầu.

Loại bỏ ngoại lai

credit_clean <- credit_clean %>%
  filter(Dependents <= 10)

# kiểm tra lại
sum(credit_clean$Dependents > 10)

Giải thích chi tiết: dòng 1 trên đối tuộng creadit_clean thực hiện tao tác lọc thông qua hàm filter như ở các thao tác trước lọc các quan sát có số người phụ thuộc tài chính lớn hơn 10 dòng 5 tương tự như phần xử lý biến trước đó tính tồng số quan sát có số người phụ thuộc tài chính lớn hơn 10 nhằm đánh giá lại hiệu quả dòng code đầu

Sau khi lọc bỏ và kiểm tra phát hiện không còn ngoại lai theo giả thiết đã đặt ra; kết quả này giúp tạo ra bộ dữ liệu “sạch” hơn, giảm nhiễu trong quá trình phân tích, giúp tăng độ tin cậy của các kết quả phân tích, hỗ trợ ra quyết định chính xác hơn

1.2.6.4 Khoản vay có thế chấp

Biến NumberRealEstateLoansOrLines phản ánh số lượng khoản vay thế chấp mà khách hàng đang sở hữu. Trong thực tế, hầu hết khách hàng chỉ có từ 0–3 khoản vay, và số lượng vượt quá 10 là rất hiếm là những người có số lượng bất động sản ,.. thế chấp nhiều hơn 10 là các trường hợp khác thường, cố lượng tài sản nhiều không như các hồ sơ vay thông thường và cần phải loại bỏ tránh ảnh hưởng đến thống kê đánh giá các biến với nhau code : phát hiện ngoại lai

sum(credit_clean$NumberRealEstateLoansOrLines > 10)

Giải nghĩa: dùng hàm sum() trực tiếp tính tổng các quan sát biến NumberRealEstateLoansOrLines là số khoản vay thế chấp trong data.frame creadit_clean . Kết quả trả ra dòng [1] :số lượng quan sát vi phạm giả thiết là 92 quan sát cần loại bỏ đảm bảo dac859diem639 thống kê tránh tác động bỏi ngoại lai

Loại bỏ ngoại lai

credit_clean <- credit_clean %>%
  filter(!(NumberRealEstateLoansOrLines > 10 ))
sum(credit_clean$NumberRealEstateLoansOrLines > 10)
## [1] 0

Giải nghĩa:

  • dòng 1 tương tự như các biến trước dùng hàm filter() 1 cách trực tiếp lên biến NumberRealEstateLoansOrLines của data.frame creadit_clean thông qua sự dẫn đường toán tử ống pie”%>%” nhằm lọc bỏ các quan sát có giá trị lớn hơn 10 là vi phạm giải thiết cần loại bỏ
  • dòng 3 dùng hàm sum () tương tự ở cacac1 biến kahc1 chii3 đổi đối tượng biến NumberRealEstateLoansOrLines nhằm kiểm tra kết quả dòng code đầu

Kết quả: Kết quả cho thấy không còn giá trị ngoại lai theo giả thiết là các quan sát có giá trị biến số khoản vay thế chấp NumberRealEstateLoansOrLines lớn hơn 10 thương là các người đại điện cho công ty, người làm ăn kinh doanh lớn ,.. khá đặc biệt cần loại bỏ tránh ảnh hưởng thống kê của tổng thể

1.2.6.5 Tỷ lệ sử dụng tín dụng quay vòng so với tổng hạn mức

Biến Util thể hiện tỷ lệ sử dụng các khoản tín dụng quay vòng so với tổng hạn mức được cấp. Đây là một chỉ số quan trọng phản ánh mức độ phụ thuộc vào nợ tín dụng không có tài sản đảm bảo của khách hàng. Tỷ lệ cao có thể cho thấy khách hàng đang sử dụng gần hết hạn mức tín dụng, từ đó làm tăng nguy cơ vỡ nợ. Trong dữ liệu thực tế, biến này đôi khi xuất hiện các giá trị bất hợp lý (ví dụ âm, vượt quá 1 hoặc 100% nếu tính theo tỷ lệ) cần loại bỏ tránh ảnh hương phân tích đánh giá tổng thể Kỹ thuật và hàm sử dụng:

Sử dụng hàm sum() để đếm số lượng giá trị ngoại lai

Sử dụng hàm filter() với điều kiện logic để loại bỏ các giá trị bất hợp lý

Code

##biến mục tiêu Util Tỷ lệ sử dụng tín dụng quay vòng so với tổng hạn mức
min(credit_clean$Util)
sum(credit_clean$Util > 1)

Giải nghĩa dòng code 1 tính toán giá trị bé nhất của biến tỷ lệ tín dụng xoay vòng so với tổng hạn mức hằm xác định giá trị bé nhất coi biến có bị âm không đòng 2 giống như các biến khac 1 dùng hàm sum() tính toán tổng các quan sát có giá trị biến tỷ lệ tín dụng xoay vòng so với tổng hạn mức trong creadit_clean lonm71 hớn 1 vi phạm giả thiết

Kết quả không có quan sát nào âm và có 3220 quan sát có giá trị lớn hơn 1 cần loại bỏ để tránh ảnh hưởng phân tích đánh giá tương quan và thống kê.

Xử lý:

credit_clean <- credit_clean %>%
  filter(!(Util>1)) ## xóa do dữ liệu này sai r >1 rất khó
sum(credit_clean$Util > 1) ## Kiểm tra lại
## [1] 0

Giải nghĩa dòng 1 giống các bước xử lý các biến trước lọc bỏ các quan sat1 có giá trị biến Util lớn hơn 1 dòng 3 tương tự các biến trước nhằm dánh giá kết quả code đầu tiên

Kết quả sau khi lọc bỏ và kiểm tra thì không còn phát hione65 ngoại lai theo giả thiết đặt ra giúp biến tỷ lệ tín dụng xoay vòng so với tổng hạn mức về lý thuyết không thể vượt quá 100% (giá trị 1); Việc loại bỏ các giá trị này giúp đảm bảo tính hợp lý của dữ liệu cho phân tích và là yếu tố quan trọng trong việc xác định rủi ro tín dụng và điều chỉnh hạn mức cho vay

1.2.6.6 Tỷ lệ nợ trên thu nhập

Biến thể hiện tỷ lệ giữa tổng nợ và thu nhập hàng tháng (DebtRatio) của khách hàng. Đây là chỉ số quan trọng phản ánh mức độ đòn bẩy tài chính và khả năng quản lý nợ so với thu nhập. Tỷ lệ cao cho thấy khách hàng đang chịu gánh nặng nợ lớn so với khả năng tài chính, làm tăng nguy cơ mất khả năng thanh toán. Trong dữ liệu thực tế, biến này xuất hiện các giá trị bất hợp lý (lớn hơn 10) cần được xử lý để đảm bảo tính chính xác cho phân tích.

Kỹ thuật và hàm sử dụng: Sử dụng hàm sum() để xác định số lượng quan sát có giá trị ngoại lai Sử dụng hàm filter() với toán tử logic để loại bỏ các giá trị không hợp lý

Code:

##biến tỷ lệ nợ trên thu nhập 
sum(credit_clean$DebtRatio > 10)

Giải nghĩa: Dòng code sử dụng hàm sum() để tính toán tổng số quan sát có giá trị biến tỷ lệ nợ trên thu nhâp: “DebtRatio” lớn hơn 10, nhằm xác định số lượng giá trị ngoại lai vi phạm giả định về tính hợp lý của tỷ lệ nợ trên thu nhập.

Kết quả: Có 28,282 quan sát có giá trị lớn hơn 10 cần được loại bỏ để tránh ảnh hưởng đến phân tích thống kê và đánh giá tương quan.

Kiểm tra DebtRatio Kết quả
Giá trị > 10 (số quan sát cần loại) 28282

Xử LÝ:

credit_clean <- credit_clean %>%
  filter(!(DebtRatio > 10)) ## xóa loại bỏ do bất hợp lý
sum(credit_clean$DebtRatio > 10) ## Kiểm tra lại

Giải nghĩa Dòng đầu tiên sử dụng hàm filter() để lọc và loại bỏ tất cả quan sát có giá trị DebtRatio lớn hơn 10. Dòng cuối cùng kiểm tra lại để đảm bảo không còn tồn tại giá trị ngoại lai nào trong dataset

Kết quả: Sau khi lọc bỏ và kiểm tra, kết quả trả về 0, chứng tỏ không còn quan sát nào có giá trị DebtRatio lớn hơn 10. Việc loại bỏ các giá trị này giúp đảm bảo tính hợp lý của dữ liệu, do trong thực tế tỷ lệ nợ trên thu nhập lớn hơn 10 (tổng nợ gấp hơn 10 lần thu nhập) là tình trạng rất bất thường và khó duy trì. Ngoài ra, còn tập trung vào nhóm khách hàng có tỷ lệ nợ/thu nhập trong phạm vi hợp lý, giúp ngân hàng đánh giá chính xác hơn khả năng trả nợ và mức độ rủi ro của từng khách hàng

1.2.6.7 Ngoại lai của số lần trẽ hạn thanh toán của 3 cấp độ

Các biến Due30_59, Due60_89 và Due90 lần lượt thể hiện số lần trễ hạn thanh toán trong các khoảng 30-59 ngày, 60-89 ngày và từ 90 ngày trở lên. Đây là những chỉ số quan trọng phản ánh lịch sử tín dụng và ý thức trả nợ của khách hàng. Trong dữ liệu thực tế, các biến này xuất hiện những giá trị đặc biệt (98 và 96) tại cùng một thời điểm trên cả 3 cấp độ, cho thấy đây có thể là mã lỗi hệ thống hoặc giá trị đại diện cho trường hợp không xác định.

Kỹ thuật và hàm sử dụng: Tiếp tục sử dụng hàm summary() và hàm filter() lần lượ để kiểm tra phân phối và phát hiện và loại bỏ các giá trị đặc biệt

summary(data.frame(
  Due90 = credit_clean$Due90,
  Due60_89 = credit_clean$Due60_89,
  Due30_59 = credit_clean$Due30_59
))
##      Due90           Due60_89         Due30_59   
##  Min.   : 0.000   Min.   : 0.000   Min.   : 0.0  
##  1st Qu.: 0.000   1st Qu.: 0.000   1st Qu.: 0.0  
##  Median : 0.000   Median : 0.000   Median : 0.0  
##  Mean   : 0.239   Mean   : 0.218   Mean   : 0.4  
##  3rd Qu.: 0.000   3rd Qu.: 0.000   3rd Qu.: 0.0  
##  Max.   :98.000   Max.   :98.000   Max.   :98.0
sum(credit_clean$Due60_89 == 98 &
       credit_clean$Due30_59 == 98 &
       credit_clean$Due90 == 98)
## [1] 187
sum(credit_clean$Due60_89 == 96 &
       credit_clean$Due30_59 == 96 &
       credit_clean$Due90 == 96)
## [1] 5

Giải nghĩa: Đoạn code đầu sử dụng hàm summary() ở dòng 1 trên data frame chứa cả 3 biến số lần trễ hạn thanh toá trải dài từ dòng code số 2 đến 4, nhằm quan sát phân phối và phát hiện các giá trị bất thường trong tập dữ liệu. Hai đoạn code thứ 2 và thứ 3 lần lượt từ dòng số 6 đến số 8 và 10 đến 12 đếu dùng sử dụng hàm sum() kết hợp với toán tử logic & để đếm số lượng quan sát có giá trị 98 và 96 xuất hiện đồng thời trên cả 3 biến trễ hạn.

Nhóm dựa vào đoạn code đầu có thể thấy kết quả về số lần vỡ nợ lớn nhất của cả 3 cấp độ là bằng nhau rất đáng ngờ, sau 2 đoạn code còn lại phát hiện ra các ngoại lai của các biến quá hạn thanh tóa 1-2 tháng, 2-3 tháng , 3 tháng trở lên đều có cùng giá trị 98 hoặc 96 trên cùng các quan sát. Đây là tình huống bất thường vì trong thực tế khó có khách hàng nào có số lần trễ hạn giống hệt nhau ở cả 3 cấp độ.

Loại bỏ ngoại lai:

credit_clean <- credit_clean %>%
  filter(!(Due60_89 == 98 & Due30_59 == 98 & Due90 == 98))

credit_clean <- credit_clean %>%
  filter(!(Due60_89 == 96 & Due30_59 == 96 & Due90 == 96))
#kiểm tra
sum(credit_clean$Due60_89 == 98 &
       credit_clean$Due30_59 == 98 &
       credit_clean$Due90 == 98)
## [1] 0
sum(credit_clean$Due60_89 == 96 &
       credit_clean$Due30_59 == 96 &
       credit_clean$Due90 == 96)
## [1] 0

Giải nghĩa cụm code 1 và 2 có số dòng lần lượt là 1 đến 2 và từ 4 đến 5 sử dụng hàm filter() với toán tử phủ định ! kết hợp toán tử & để loại bỏ các quan sát đặc biệt. Cụ thể :dòng 1 và 2 sẽ loại bỏ các quan sát có sự trùng lặp và giữ lại tất cả các quan sát KHÔNG thuộc nhóm có cùng giá trị 98 trên cả 3 biến, đoạn code từ dòng 4 đến dòng 5 thìtiến hành tượng tự với giá trị trùng lặp 3 biến là 96 2 cụm code cuối có chức năng tương tự phần phát hiện giá trị bất thưởng biến trễ hạn thanh toán 3 cấp độ trong chính phần nàynhằm kiểm tra lại kết quả 2 cụm doạn code trước đó . Kết quả: Sau khi thực hiện lọc bỏ, kết quả kiểm tra cho thấy dataset đã được làm sạch khỏi các quan sát chứa giá trị đặc biệt. Việc loại bỏ này giúp đảm bảo tính hợp lý của dữ liệu, do các giá trị 98 và 96 có khả năng là mã đặc biệt của hệ thống thay vì phản ánh tình trạng trễ hạn thực tế của khách hàng.

1.2.7 Kết luận chương 2

Qua quá trình xử lý dữ liệu thô, chúng tôi đã xây dựng được bộ dữ liệu credit_clean sạch và chất lượng cao. Các bước xử lý bao gồm đổi tên biến, xử lý giá trị thiếu, loại bỏ trùng lặp, xử lý ngoại lai và ép kiểu dữ liệu đã được thực hiện bài bản. Bộ dữ liệu này sẵn sàng cho các phân tích thống kê mô tả và xây dựng mô hình dự báo trong các chương tiếp theo.

1.3 Thống kê và Trực quan

1.3.1 Thống kê cơ bản và Trực quan hóa

1.3.1.1 Chọn biến mục tiêu và các biến ảnh hưởng

a) Biến Mục tiêu của nghiên cứu:

  • Target (Tình trạng vỡ nợ): Biến nhị phân thể hiện sự kiện khách hàng có rơi vào tình trạng nợ xấu trong vòng 2 năm hay không. Biến nhận giá trị 1 nếu có và 0 nếu không. Đây là biến mục tiêu chính trong mô hình dự báo rủi ro tín dụng.

b) Các biến độc lập

  • Util (Tỷ lệ sử dụng hạn mức tín dụng)**: Tỷ lệ này phản ánh mức độ sử dụng các khoản tín dụng quay vòng so với tổng hạn mức được cấp. Một tỷ lệ cao cho thấy khách hàng đang phụ thuộc nhiều vào nợ không có tài sản đảm bảo.

  • DebtRatio (Tỷ lệ nợ): Tỷ lệ này đo lường gánh nặng nợ và khả năng chi trả của người đi vay. Một tỷ lệ cao cho thấy phần lớn thu nhập của khách hàng đã được dùng để trả nợ

  • Income (Thu nhập hàng tháng): Đây là chỉ số cơ bản thể hiện năng lực tài chính và khả năng trả nợ của khách hàng. Thu nhập càng cao thường đi kèm với sự ổn định tài chính tốt hơn.

  • Age (Tuổi): Tuổi tác phản ánh kinh nghiệm sống và sự ổn định trong sự nghiệp. Nhóm người vay trẻ tuổi thường có thu nhập chưa ổn định và có thể chưa có kỹ năng quản lý nợ hiệu quả.

  • Dependents: Số người phụ thuộc tài chính phản ánh gánh nặng tài chính và trách nhiệm gia đình của người vay. Những khách hàng có nhiều người phụ thuộc thường phải đối mặt với áp lực chỉ tiêu cao hơn và khả năng dự phòng tài chính thấp hơn.

1.3.2 Thống kê cơ bản

xem lại số quan sát sau khi xử lý hàm str

## 'data.frame':    117274 obs. of  11 variables:
##  $ Target                      : Factor w/ 2 levels "0","1": 2 1 1 1 1 1 1 1 1 1 ...
##  $ Util                        : num  0.766 0.957 0.658 0.234 0.907 ...
##  $ Age                         : int  45 40 38 30 49 74 39 57 30 51 ...
##  $ Due30_59                    : int  2 0 1 0 1 0 0 0 0 0 ...
##  $ DebtRatio                   : num  0.803 0.1219 0.0851 0.036 0.0249 ...
##  $ Income                      : int  9120 2600 3042 3300 63588 3500 3500 23684 2500 6501 ...
##  $ Debts                       : int  13 4 2 5 7 3 8 9 5 7 ...
##  $ Due90                       : int  0 0 1 0 0 0 0 0 0 0 ...
##  $ NumberRealEstateLoansOrLines: int  6 0 0 0 1 1 0 4 0 2 ...
##  $ Due60_89                    : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ Dependents                  : num  2 1 0 0 0 1 0 2 0 2 ...

Chúng ta sử dụng hàm str() như ở các phần trước xem lại cấu trúc dữ liệu cho toàn bộ bộ dữ liệu sau khi xử lý thô ta thấy được kết quả : Kết quả cho thấy sau khi xử lý thô, bộ dữ liệucredit_clean còn lại 117274quan sát (dòng) và 11 biến. Trong đó, biến mục tiêu Target là biến nhân tố (factor) gồm hai mức giá trị 0 và 1 (tương ứng với khách hàng tốt và nợ xấu). Các biến còn lại chủ yếu thuộc kiểu số (numeric hoặc integer), phản ánh các đặc điểm tài chính và nhân khẩu của khách hàng như tuổi (Age), tỷ lệ sử dụng tín dụng (Util), thu nhập (Income), số khoản nợ quá hạn (Due30_59, Due60_89, Due90), tỷ lệ nợ trên thu nhập (DebtRatio), số bất động sản thế chấp (NumberRealEstateLoansOrLines) và số người phụ thuộc (Dependents). Cấu trúc này cho thấy dữ liệu đã được làm sạch và sẵn sàng cho các bước phân tích thống kê và mô hình hóa tiếp theo.

1.3.2.1 Thống kê mô tả Biến mục tiêu

biến mục tiêu có

  • Thống kê: sử dụng hàm summary() nhằm xem đặc điểm thống kê biến đặc trưng
summary(credit_clean$Target)
##      0      1 
## 110037   7237

h

# kiem trea ngoai lai
total_obs <- nrow(credit_clean)

Phân tích thống kê: Tổng số quan sát là 117.274 khách hàng.

Trong đó:

  • 110.037 người (93.8%) thuộc nhóm Target = 0 → khách hàng trả nợ đúng hạn.
  • 7.237 người (6.2%) thuộc nhóm Target = 1 → khách hàng bị vỡ nợ.

Phân tích thống kê: Tổng số quan sát là 117.274 khách hàng.

Trong đó:

  • 110.037 người (93.8%) thuộc nhóm Target = 0 → khách hàng trả nợ đúng hạn.
  • 7.237 người (6.2%) thuộc nhóm Target = 1 → khách hàng bị vỡ nợ.

Như vậy, dữ liệu bị mất cân bằng khá mạnh giữa hai nhóm, nhóm trả nợ đúng hạn chiếm tỷ lệ áp đảo.

Tỷ lệ vỡ nợ thấp cho thấy đây là tập dữ liệu tín dụng an toàn, nhưng cũng đồng nghĩa việc xây dựng mô hình dự đoán cần chú ý hiện tượng mất cân bằng lớp (class imbalance).

Phân tích kinh tế: Tỷ lệ vỡ nợ chỉ 6.2% phản ánh rằng phần lớn khách hàng có khả năng trả nợ tốt, hệ thống tín dụng hoặc quy trình xét duyệt vay vốn hiện tại đang hiệu quả.

Tuy nhiên, một bộ phận nhỏ (~6%) vẫn vỡ nợ, đây là nhóm rủi ro cần được phân tích sâu hơn (về tuổi, thu nhập, số người phụ thuộc, lịch sử vay,…).

Từ góc nhìn quản trị rủi ro, việc kiểm soát tốt nhóm nhỏ này có thể giảm tổn thất tín dụng và cải thiện chất lượng danh mục cho vay.

Ngoài ra, vì dữ liệu nghiêng về nhóm “trả đúng hạn”, nên khi mô hình hóa cần cân bằng dữ liệu (dùng SMOTE, class_weight, hoặc lấy mẫu lại) để tránh mô hình thiên lệch về nhóm đa số.

Trực quan :

Tạo bảng thể hiện phần trăm tần số sử dụng gruop_by() cụ thể ở đây là hàm group_by(Target) %>% nhằm nhóm (phân loại) tất cả các dòng trong credit_clean dựa trên các giá trị duy nhất của cột Target. Ví dụ: Nếu cột Target có hai giá trị là “0” và “1”, thì dữ liệu sẽ được chia thành hai nhóm: một nhóm cho tất cả các dòng có Target == “0” và một nhóm cho Target == “1”.

# 1. Tạo bảng tần số và tính phần trăm
df_target_pie <- credit_clean %>%
  group_by(Target) %>%
  summarise(Count = n(), .groups = "drop") %>%
  rename(Số_lượng = Count) %>%
  mutate(
    "Phần trăm" = round(Số_lượng / sum(Số_lượng) * 100, 2)
  )

# Xem dữ liệu
knitr::kable(df_target_pie)
Target Số_lượng Phần trăm
0 110037 93.8
1 7237 6.2

vẽ:

p_pie_basic <- ggplot(df_target_pie, aes(x = "", y = Số_lượng, fill = as.factor(Target))) +
  geom_bar(stat = "identity", width = 1, color = "white") +
  coord_polar("y", start = 0) +
  geom_text(aes(label = paste0(`Phần trăm`, "%")),
            position = position_stack(vjust = 0.5),
            size = 5, fontface = "bold", color = "white") +
  scale_fill_manual(values = c("0" = "#4CAF50", "1" = "#F44336"),
                    labels = c("Trả đúng hạn", "Vỡ nợ")) +
  labs(title = "Phân bố biến Target",
       subtitle = "0 = Trả đúng hạn, 1 = Vỡ nợ",
       fill = "Trạng thái") +
  theme_void() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 16),
    plot.subtitle = element_text(hjust = 0.5, size = 12),
    legend.title = element_text(face = "bold", size = 12),
    legend.text = element_text(size = 11)
  )

print(p_pie_basic)

1.3.2.2 Thống kê mô tả các biến được chọn phân tích và trực quan hóa:

1.3.2.2.1 Biến độ tuổi người vay

Thống kê

Biến Age thể hiện độ tuổi của người vay, là yếu tố nhân khẩu học quan trọng trong đánh giá rủi ro tín dụng. Tuổi tác phản ánh kinh nghiệm sống, sự ổn định nghề nghiệp và khả năng chi trả của khách hàng. Phân tích thống kê mô tả giúp hiểu rõ phân phối và đặc điểm của biến này trong tập dữ liệu.

Kỹ thuật và hàm sử dụng:

Sử dụng gói e1071 để tính toán các chỉ số thống kê nâng cao như skewness và kurtosis.

Xây dựng hàm tùy chỉnh phat() để tổng hợp đầy đủ các chỉ số thống kê mô tả. CODE:

library(e1071)
phat <- function(data, var_name) {
  x <- data[[var_name]]
  mode_val <- as.numeric(names(sort(table(x), decreasing = TRUE)[1]))
  
  result <- list(
    Min = min(x),
    Q1 = as.numeric(quantile(x, 0.25)),  
    Mean = mean(x),
    Median = median(x),
    Mode = mode_val,
    Q3 = as.numeric(quantile(x, 0.75)),  
    Max = max(x),
    SD = sd(x),
    Skewness = skewness(x),
    Kurtosis = kurtosis(x)
  )
  return(invisible(result))
}
summary_Age <- phat(credit_clean, "Age")

Giải thích chi tiết code:

  • Dòng 1 : gọi thư viện gói e1071 để tính toán các chỉ số thống kê nâng cao như skewness và kurtosis.
  • Dòng 2 và 3 : Tạo một hàm mới tên là phat, và hàm này sẽ nhận 2 giá trị đầu vào được đặt tên tạm là data và var_name; với dữ liệu của cột được chỉ định (bằng var_name) từ data và lưu vào một vector tên là x. Dấu ngoặc kép [[…]] cho phép ta truy cập cột bằng tên biến.
  • Dòng 4: Đây là một cách phổ biến trong R để tìm Mode (Yếu vị): Tạo một bảng tần suất (đếm số lần xuất hiện của mỗi giá trị):“table(x):”; sau đó Sắp xếp bảng tần suất đó theo thứ tự giảm dần bằng hàm sort(…, decreasing = TRUE), Chọn phần tử đầu tiên (phần tử có tần suất cao nhất) bằng [1] ; cuối cùng lấy tên của phần tử đó (chính là giá trị Mode) bằng names(…), và chuyển đổi phần tử của biến mode đó sang dạng số bằng hàm numeric(…).
  • Cụm code từ dòng 6 đến dòng 17 tạo một danh sách (list) tên là result để lưu trữ tất cả các kết quả thống kê :
    • theo thứ tự lần lượt là từ dòng 7 đến dòng thứ 14 lần lượt là giá trị bé nhất, Tứ phân vị thứ nhất( 25%), giá trị trung bình, giá trị trung vị (tứ phân vị thứ 2), giá trị mode, Tứ phân vị thứ ba , Độ lệch chuẩn được tính bằng các hàm R cơ bản.
    • dòng thứ 15 và 16 lần lượt là: Độ xiên( Skewness) và Độ nhọn (Kurtosis ): Được tính bằng các hàm từ thư viện e1071.
    • dòng 19 dùng trả về giá trị kết quả result, nhưng đừng tự động in nó ra màn hình. Chỉ khi nào người dùng chủ động gán nó vào một biến (như summary_Age <-phat(data,biến) …) hoặc dùng lệnh print() thì mới cho họ thấy.
  • dòng 21 sẽ tạo thống kê mô tả biến tuổi Age thông qua hàm phat

KẾT QUẢ:

KẾT QUẢ: Biến Age dao động trong khoảng từ 21 đến 105, thể hiện sự đa dạng về độ tuổi trong tập dữ liệu. Mode là 49, nhỏ hơn median là 51và nhỏ hơn giá trị trung bình là 51.8 và ta thấy hình của phân phối chủ yếu ở trung tâm nhưng có lệch phải nhẹ. Độ lệch chuẩn(14.6) ở mức vừa phải, Skewness (0.24) > 0 phân phi61 dữ liệu bị lệch phải nhẹ và Kurtosis (-0.46) < 0 xác nhận là (phân phối hơi bẹt hơn chuẩn)cũng xác nhận dữ liệu không quá lệch và phân tán hợp lý quanh trung tâm.

Phân bố tập trung chủ yếu trong khoảng tứ phân vị từ 41đến 62, với trung vị ở 51 tuổi, phản ánh nhóm khách hàng chủ yếu ở độ tuổi trung niên.

Trực quan Để trực quan hóa dữ liệu biến tuổi, chúng ta sử dụng gói ggplot2, là một trong những gói đồ họa mạnh mẽ và linh hoạt nhất trong R. Hàm ggplot() được xây dựng theo nguyên tắc “ngữ pháp đồ họa” (grammar of graphics), cho phép tạo ra các biểu đồ chất lượng cao với đầy đủ các thành phần tùy chỉnh. Các thành phần chính trong code: - ggplot(credit_clean, aes(x = "", y = Age)): Khởi tạo đồ thị với dữ liệu và aesthetic mapping - geom_boxplot(): Vẽ boxplot với các tham số tùy chỉnh màu sắc - geom_point(): Thêm điểm để đánh dấu mean và mode - coord_flip(): Đảo trục để boxplot nằm ngang - labs()theme_minimal(): Tuỳ chỉnh nhãn và tiêu đề

code trực quan hóa thống kê cơ bản của biếnAge :

#Tối ưu code tạo hàm vẽ cho các biến
ve_boxplot <- function(data, var_name, stat_result = NULL, title = NULL) {
  library(ggplot2)

  # Lấy Mean và Mode từ kết quả phat
  mean_val <- stat_result$Mean
  mode_val <- stat_result$Mode
  
  # Tạo tiêu đề tự động nếu không có
  if (is.null(title)) {
    title <- paste("Boxplot của biến", var_name, "(có Mean & Mode)")
  }
  
  # Vẽ boxplot
  p <- ggplot(data, aes(x = "", y = .data[[var_name]])) +
    geom_boxplot(fill = "skyblue", color = "darkblue", notch = TRUE) +
    geom_point(aes(y = mean_val), color = "red", size = 3, shape = 18) +      
    geom_point(aes(y = mode_val), color = "orange", size = 3, shape = 18) +  
    coord_flip() +
    labs(title = title,
         y = paste("Giá trị", var_name),
         x = "") +
    theme_minimal() +
    annotate("text", x = 1.35, y = mean_val, 
             label = paste("Mean =", round(mean_val, 2)), 
             color = "red", size = 3.5, hjust = 0) +
    annotate("text", x = 1.25, y = mode_val, 
             label = paste("Mode =", round(mode_val, 2)), 
             color = "orange", size = 3.5, hjust = 0)
  
  return(p)
}
# Vẽ
ve_boxplot(credit_clean, "Age", summary_Age)

giải nghĩa code :

  • Dòng 2: Tạo một hàm mới có tên là ve_boxplot. Hàm này được thiết kế để nhận vào tối đa 4 giá trị đầu vào, bao gồm: data (bộ dữ liệu), var_name (tên của cột/biến cần vẽ), stat_result (một danh sách chứa các kết quả thống kê đã tính toán trước đó), và title (tiêu đề cho biểu đồ, đây là giá trị không bắt buộc).

  • Dòng 3: Gọi thư viện ggplot2, đây là một gói rất mạnh trong R dùng để vẽ đồ thị một cách linh hoạt và đẹp mắt. Lệnh này đảm bảo các chức năng vẽ của ggplot2 có sẵn để sử dụng trong hàm.

  • Dòng 6 và 7: Trích xuất hai giá trị cụ thể từ danh sách stat_result đã được cung cấp khi gọi hàm. Dòng 6 lấy giá trị Trung bình (Mean) và lưu vào biến mean_val. Dòng 7 lấy giá trị trung vị vị (Mode) và lưu vào biến mode_val.

  • Cụm code từ dòng 10 đến 12: Đây là một khối lệnh điều kiện. Nó kiểm tra xem người dùng có cung cấp tiêu đề (title) khi gọi hàm hay không. Nếu người dùng không cung cấp (giá trị là NULL), hàm sẽ tự động tạo một tiêu đề mặc định bằng cách ghép chuỗi “Boxplot của biến” với tên biến var_name được truyền vào.

  • Cụm code từ dòng 15 đến 33: Đây là phần chính để tạo ra biểu đồ, sử dụng cú pháp của ggplot2. Mỗi dòng bắt đầu bằng dấu + sẽ thêm một lớp hoặc một tùy chỉnh mới vào biểu đồ.

    • Dòng 15: Khởi tạo một đối tượng đồ thị. ggplot(data, aes(x = ““, y = .data[[var_name]])) tạo ra một khung đồ thị trống, sử dụng bộ dữ liệu data được cung cấp. Phần aes là để thực hiện”ánh xạ (mapping)” dữ liệu vào các thuộc tính hình ảnh của biểu đồ. Ở đây, x = “” có nghĩa là chúng ta không vẽ theo một biến cụ thể nào trên trục hoành (để tạo ra một boxplot duy nhất), và y = .data[[var_name]] chỉ định rằng dữ liệu từ cột có tên trong var_name sẽ được biểu diễn trên trục tung.
    • Dòng 16: Thêm lớp biểu đồ hộp (boxplot) vào khung đồ thị. fill = “skyblue” tô màu xanh da trời cho phần thân hộp, color = “darkblue” đặt màu xanh đậm cho đường viền, và notch = TRUE tạo một vết lõm ở hai bên hộp để thể hiện khoảng tin cậy cho Trung vị (Median).
    • Dòng 17 và 18: Thêm hai điểm riêng biệt lên biểu đồ. Dòng 17 vẽ một điểm đại diện cho giá trị Trung bình (mean_val) với màu đỏ, kích thước là 3 và có hình dạng là viên kim cương (shape = 18). Dòng 18 làm tương tự để vẽ một điểm đại diện cho giá trị Yếu vị (mode_val) với màu cam.
    • Dòng 19: Lệnh coord_flip() đảo ngược trục tọa độ, làm cho biểu đồ hộp nằm ngang thay vì thẳng đứng.
  • Cụm code từ dòng 20 đến 22: Đặt các nhãn cho biểu đồ. dùng title = title đặt tiêu đề, y = paste(…) đặt nhãn cho trục tung là Giá Trị sau khi lật), và trục hoành để trống x = “” để ẩn nhãn của trục hoành (bây giờ là trục dọc).

  • Dòng 23: Áp dụng một giao diện tối giản (theme_minimal()) cho biểu đồ, giúp loại bỏ nền xám và các chi tiết không cần thiết, làm cho biểu đồ trông sạch sẽ hơn.

  • Cụm code từ dòng 24 đến 30: Sử dụng hàm annotate() để thêm các chú thích văn bản trực tiếp lên biểu đồ:

    • Hai dòng đầu tiên (24 đến 26) thêm chú thích cho giá trị Trung bình. Nó đặt văn bản tại một vị trí cụ thể trên biểu đồ (x = 1.35, y = mean_val), nội dung văn bản là “Mean =” ghép với giá trị trung bình đã được làm tròn đến 2 chữ số thập phân, với màu đỏ và kích thước chữ là 3.5.
    • Hai dòng tiếp theo (27 đến 29) làm điều tương tự để thêm chú thích cho giá trị trung vị, nhưng với màu cam và ở một vị trí khác một chút (x = 1.25) để tránh bị chồng chéo.
  • Dòng 31: Trả về đối tượng đồ thị p đã hoàn chỉnh. Điều này cho phép người dùng có thể hiển thị, lưu hoặc chỉnh sửa thêm biểu đồ sau khi gọi hàm.

  • Dòng 35: Đây là dòng lệnh thực thi hàm. Nó gọi hàm ve_boxplot vừa tạo, truyền vào bộ dữ liệu credit_clean, tên cột cần vẽ là “Age”, và đối tượng summary_Age (được tạo từ hàm phat ở đoạn code trước) chứa các giá trị thống kê cần thiết (như Mean và Mode) để vẽ lên biểu đồ. Kết quả là một biểu đồ hộp của biến “Age” sẽ được tạo ra và hiển thị.

Kết quả : biểu đồ box plot giúp chúng ta dễ nhìn thấy được khoản dao động biến độ tuổi trong khoảng từ 21 đến 105 sự lệch phải nhẹ của biểu đồ box-plot này với hộp lệch phải nhẹ so với trung tâm thể hiện chủ yếu các phần tử biến tuổi biến độ tuổi khẳng định kết quả thống kê mô tả cụ thể là chỉ số Skewness độ lệch của phân phối là lệch nhe sang phải ý nghĩa kinh tế : Ok, gọn và tập trung ý nghĩa kinh tế:

Biến Age có giá trị trung bình khoảng 52 tuổi, phần lớn khách hàng nằm trong nhóm trung niên (41–62 tuổi). Đây là giai đoạn mà thu nhập và nghề nghiệp thường ổn định hơn, do đó rủi ro tín dụng nhìn chung thấp hơn so với nhóm khách hàng quá trẻ hoặc quá lớn tuổi. Điều này cho thấy cơ cấu tuổi của khách hàng trong mẫu khá phù hợp và có khả năng trả nợ tương đối tốt.

Phân tích biến Age giúp ngân hàng hoặc công ty tài chính hiểu cấutrúc độ tuổi của khách hàng, từ đó điều chỉnh chính sách tín dụng:

  1. Tập trung vào nhóm tuổi có tỷ lệ trả nợ tốt.

  2. Kiểm soát rủi ro cao hơn ở nhóm quá trẻ hoặc quá già.

  3. Làm cơ sở xây dựng mô hình dự báo khả năng vỡ nợ (credit scoring), nơi “tuổi” là biến giải thích quan trọng.

1.3.2.2.2 Tỷ lệ sử dụng hạn mức tín dụng:

Thống kê: Để thực hiện phân tích thống kê cho biến tỷ lệ sử dụng hạn mức tín dụng, chúng ta tiếp tục sử dụng gói e1071 để tính toán các chỉ số thống kê nâng cao. Hàm summary tùy chỉnh sẽ cung cấp đầy đủ các thông số mô tả quan trọng cho biến này.

THỐNG KÊ

summary_Util <- phat(credit_clean, "Util")

dùng hàm phat đã được tạo từ biến trước gán và tạo 1 đối tượng là biến summary_Utill thông qua thống kê mô tả biến Tỷ lệ sử dụng hạn mức tín dụng (Util) từ data.frame: creadit_clean.

KẾT QUẢ :

Ý NGHĨA KẾT QUẢ: Phân tích tỷ lệ sử dụng hạn mức (Util) cho thấy hành vi khách hàng phân hóa rõ rệt. Con số này có ý nghĩa quan trọng khi giá trị trung vị (Median) chỉ ở mức 16,16%, thấp hơn nhiều so với giá trị trung bình (Mean) là 31,2%. Sự chênh lệch này cho thấy phần lớn khách hàng sử dụng rất ít hạn mức, trong khi một nhóm nhỏ sử dụng rất cao, kéo giá trị trung bình lên. Điều này được khẳng định bởi hệ số bất đối xứng Skewness= 0,903 >0 là minh chứng cho một phân phối lệch phải. Hệ quả là dữ liệu có độ phân tán hệ số Standard Deviatio (SD) =0,3363 và phân phối có dạng bẹt hơn chuẩn do hệ số Kurtosis = -0,6046 <0 phản ánh sự đa dạng trong hành vi sử dụng sản phẩm tín dụng. Ý NGHĨa KINH TẾ : Biến Util có giá trị trung bình khoảng 0.31 và trung vị khoảng 0.16, cho thấy đa số khách hàng chỉ sử dụng một phần hạn mức tín dụng được cấp. Tuy nhiên, vẫn có một nhóm khách hàng có mức sử dụng hạn mức cao (Q3 ≈ 0.54 và tối đa = 1), thể hiện mức độ phụ thuộc vào tín dụng lớn hơn và tiềm ẩn rủi ro vỡ nợ cao hơn. Điều này gợi ý rằng việc theo dõi tỷ lệ sử dụng hạn mức là rất quan trọng trong đánh giá sức khỏe tài chính và khả năng trả nợ của khách hàng.

TRỰC QUAN

ve_boxplot(credit_clean, "Util", summary_Util)

dùng hàm ve_boxplot đã dược tạo từ trước nhằm quan sát dặc trưng phân phối thống kê biến

Kết quả: Biểu đồ box plot của biến Util cho thấy phần lớn khách hàng có tỷ lệ sử dụng hạn mức tín dụng thấp, khi hộp (box) nằm nghiêng về phía trái với trung vị Median = 0.16 thấp hơn đáng kể so với trung bình Mean = 0.31, trong khi phần đuôi bên phải kéo dài cho thấy có nhóm nhỏ khách hàng sử dụng hạn mức rất cao; điều này trực quan hóa rõ ràng sự lệch phải của phân phối ( hê số Skewness = 0.903 > 0) và độ nhọn lớn hơn so với phân phối chuẩn chuẩn (Kurtosis = -0.6046 < 0), đồng thời củng cố kết quả thống kê mô tả rằng dữ liệu phân tán tương đối lớn ( thể hiện thông qua SD = 0.3363) và hành vi sử dụng tín dụng giữa các nhóm khách hàng là rất khác biệt. Ngoài ra cho thấy rõ ràng hơn trực quan hơn các ý nghĩa kinh tế.

1.3.2.2.3 Tỷ lệ nợ trên thu nhập

THỐNG KÊ

summary_DebtRatio <- phat(credit_clean, "DebtRatio")

dùng hàm phat đã được tạo từ biến trước gán và tạo 1 đối tượng là biến summary_DebtRatio thông qua thống kê mô tả biến Tỷ lệ nợ trên thu nhập(DebtRatio)) từ data.frame: creadit_clean.

KẾT QUẢ

Ý NGHĨA KẾT QUẢ: Phân tích biến Tỷ lệ nợ trên thu nhập (DebtRatio) cho thấy hành vi khách hàng có sự phân hóa cực độ. Con số này có ý nghĩa đặc biệt quan trọng khi giá trị trung vị (Median) chỉ ở mức 0.292, thấp hơn rất nhiều so với giá trị trung bình (Mean) là 0.421. Sự chênh lệch lớn này cho thấy đa phần khách hàng có mức sử dụng rất thấp, trong khi một số ít cá nhân có giá trị sử dụng cực cao, làm kéo giá trị trung bình lên đáng kể. Điều này được khẳng định rõ rệt bởi hệ số bất đối xứng Skewness = 7.769 > 0, là minh chứng cho một phân phối lệch phải cực mạnh. Hệ quả là dữ liệu có độ phân tán rất lớn với hệ số Standard Deviation (SD) = 0.740 và phân phối có đỉnh nhọn cực hẹp với đuôi dài do hệ số Kurtosis = 76.564 > 0, phản ánh sự chênh lệch khổng lồ trong hành vi sử dụng thực tế.

Ý NGHĨA KINH TẾ: Khoảng 75% khách hàng có tỷ lệ nợ trên thu nhập dưới 0.50 thuộc nhóm khách hàng an toàn, sử dụng tín dụng cơ bản; 50% khách hàng có tỷ lệ nợ từ 0.20 đến 0.50 thuộc nhóm trung lưu, nợ ổn định; 25% khách hàng có tỷ lệ nợ lớn hơn 0.50 thuộc nhóm nhóm rủi ro cao; khoảng 5% khách hàng có tỷ lệ nợ trên thu nhập lớn hơn 1.0 là nhóm ngoại lai cần quản lý rủi ro đặc biệt. Sự chênh lệch 0.129 giữa trung bình và trung vị phản ánh phân hóa rõ rệt trong hành vi sử dụng nợ của khách hàng.

ve_boxplot(credit_clean, "DebtRatio", summary_DebtRatio)

Dùng hàm dã tạo ve_boxplot tên cùng data.frmae khác biến là tỷ lệ nợ trên thu nập và DebtRatio, mẫu các thống kê mô tả từ đối tượng summary_DebtRatio chứa thống kê mô tả từ hàm phat tao thogn16 kê mô tả cho biến DebtRatio từ trước đó . Kết quả: Biểu đồ box plot giúp chúng ta dễ dàng quan sát thấy khoảng dao động của biến DebtRatio từ giá trị nhỏ nhất là 0 đến giá trị lớn nhất là 10. Sự lệch phải cực mạnh của biểu đồ này, với hộp (box) co cực ngắn và nằm sát phía dưới trong khi phần đuôi trên kéo dài một cách bất thường, đã trực quan hóa và khẳng định chắc chắn kết quả từ thống kê mô tả. Cụ thể, nó minh họa rõ nét cho hệ số Skewness = 7.769 > 0 cực lớn chứng tỏ phân phối của dữ liệu bị lệch phải cực kỳ nghiêm trọng. Đồng thời, hệ số Kurtosis = 76.564 > 0 cực cao cho thấy phân phối có một đỉnh nhọn và đuôi nặng, tập trung rất nhiều điểm ngoại lai (outlier) ở phía trên, là nguyên nhân kéo giá trị trung bình (Mean = 0.42) lệch xa so với giá trị trung vị (Median = 0.292). Tóm lại phần lớn khách hàng sử dụng hạn mức ở mức vừa phải, nhưng nhóm sử dụng hạn mức cao cần được chú ý vì rủi ro tín dụng lớn

1.3.2.2.4 Thu nhập hàng tháng:

THỐNG KÊ

summary_Income <- phat(credit_clean, "Income")

sử dụng hàm phat đã dược tạo từ phần trước nhằm tạo đối tượng mói tên summary_Income lấy từ data.frame : credit_clean và biến được chọn là biến thu nhập (Income)

KẾT QUẢ

Ý NGHÃI KẾT QUẢ: Phân tích biến Thu nhập hàng tháng (Income) cho thấy đặc điểm của khách hàng có sự phân hóa cực độ. Con số này có ý nghĩa đặc biệt quan trọng khi giá trị trung vị (Median) chỉ ở mức 5416, thấp hơn rất nhiều so với giá trị trung bình (Mean) là 6605.54. Sự chênh lệch lớn này cho thấy đa phần khách hàng có giá trị biến số rất thấp, trong khi một số ít cá nhân có giá trị cực cao (lên đến 100000), làm kéo giá trị trung bình lên đáng kể. Điều này được khẳng định rõ rệt bởi hệ số bất đối xứng Skewness = 5.024 > 0 có ý nghĩa là minh chứng cho một phân phối lệch phải cực mạnh. Hệ quả là dữ liệu có độ phân tán rất lớn với hệ số Standard Deviation (SD) = 5308.75 và phân phối có đỉnh nhọn cực hẹp với đuôi dài do hệ số Kurtosis = 51.651 > 0, phản ánh sự chênh lệch khổng lồ trong giá trị thực tế, với nhiều điểm ngoại lai ở phía trên. Ý Nghĩa kinh tế: có khoảng 75% khách hàng có thu nhập dưới 8.291, thuộc nhóm đại chúng cần sản phẩm tín dụng cơ bản; 50% có thu nhập từ 3.540 đến 8.291, là nhóm trung lưu với nhu cầu tín dụng ổn định; có khoảng 25% trên 8.291 là khách hàng cao cấp, tiềm năng cho sản phẩm đặc biệt, trong khi khoảng 5% có thu nhập trên 20.000 là nhóm siêu cao cấp cần quản lý rủi ro đặc biệt. Sự chênh lệch 1.189,54 giữa trung bình và trung vị cho thấy mức độ phân hóa giàu nghèo sâu sắc trong tập khách hàng.

TRỰC QUAN

ve_boxplot(credit_clean, "Income", summary_Income)

sử dụng hàm ve_boxplot đã dược tạo từ biến trước để vẽ biểu dồ box-plot của biến thu nhập (Incone) từ 1 đối tượng cũ creadit_clean và biến là thu nhập (Income) thông tin các chỉ số củ thogn16 kê mô tả lấy từ summary_Income Ý NGHĨA:Kết quả: Biểu đồ box plot giúp chúng ta dễ dàng quan sát thấy khoảng dao động của biến thu nhập người vay (Income) từ giá trị nhỏ nhất là 0 đến giá trị lớn nhất là 100000. Sự lệch phải cực mạnh của biểu đồ này, với hộp (box) co cực ngắn và nằm sát phía dưới bên trái trong khi phần đuôi trên kéo dài một cách bất thường, đã trực quan hóa và khẳng định chắc chắn kết quả từ thống kê mô tả. Cụ thể, nó minh họa rõ nét cho hệ số Skewness = 5.024 > 0 cực lớn chứng tỏ phân phối của dữ liệu bị lệch phải cực kỳ nghiêm trọng. Đồng thời, hệ số Kurtosis = 51.651 > 0 cực cao cho thấy phân phối có một đỉnh nhọn và đuôi dày, tập trung rất nhiều điểm ngoại lai (outlier) ở phía trên, là nguyên nhân kéo giá trị trung bình (Mean = 6605.54) lệch xa so với giá trị trung vị (Median = 5416). Ngoài ra cũng đã thể hiện ý nghĩa kinh tế là phần lớn khách hàng có thu nhập ở mức trung bình thấp, phù hợp với nhóm khách hàng đại chúng, trong khi tồn tại một nhóm nhỏ khách hàng có thu nhập rất cao, đòi hỏi các chiến lược kinh doanh và quản lý rủi ro phù hợp cho từng phân khúc.

1.3.2.2.5 Số người phụ thuộc tài chính

THỐNG KÊ

summary_Dependents <- phat(credit_clean, "Dependents")
sử dụng hàm phat tạo 1 đối tượng tên summary_Dependents chứa các thông tin thống kê mô tả của dataframe creadit_clean và biến là số người phụ thuộc tài chính (Depentdents)

KẾT QUẢ Phân tích thống kê mô tả biến số người phụ thuộc tài chính với giá trị trung vị (Median = 0) chỉ ở mức , thấp hơn rất nhiều so với giá trị trung bình (Mean = 0.834). Sự chênh lệch lớn này cho thấy đa phần khách hàng không có người phụ thuộc tài chính lớn cho thấy hồ sơ vay hầu hết là người dộc than hoặc đã có con cái trưởng thành không cân nuôi dưỡng, trong khi một số ít cá nhân có số người phụ thuộc tài chính cực cao lên đến 10 người , làm kéo giá trị trung bình lên đáng kể. Điều này được khẳng định rõ rệt bởi hệ số bất đối xứng Skewness = 1.418 > 0 có ý nghĩa là minh chứng cho một phân phối lệch phải mạnh. Hệ quả là dữ liệu có độ phân tán rất lớn với hệ số Standard Deviation (SD) = 1.139 và phân phối có đỉnh nhọn với đuôi dài do hệ số Kurtosis = 4.906 > 0, phản ánh sự chênh lệch khá lớn trong giá trị thực tế, với nhiều điểm ngoại lai ở phía trên. Kinh tế :Phần lớn khách hàng có ít hoặc không có người phụ thuộc, phù hợp với nhóm trẻ độc thân hoặc các cặp vợ chồng có con trưởng thành, phản ánh xu hướng nhân khẩu học hiện đại. Nhóm ít người phụ thuộc có khả năng tài chính linh hoạt, trong khi nhóm nhiều người phụ thuộc (≥10) tiềm ẩn rủi ro tín dụng cao. Do đó, sản phẩm tín dụng và quản lý danh mục cần phân khúc rõ ràng, thẩm định kỹ khả năng tài chính và theo dõi định kỳ nhóm khách hàng có nhiều người phụ thuộc.

TRỰC QUAN

ve_boxplot(credit_clean, "Dependents", summary_Dependents)

sử dụng hàm ve_boxplot đã đựợc tạo từ biến trước để vẽ biểu dồ box-plot của biến số người phụ thuộc tài chính (Depentdents) từ 1 đối tượng cũ creadit_clean và lấy các thông tin các chỉ số của thống kê mô tả lấy từ summary_Dependents. Kết quả: Biểu đồ box plot giúp chúng ta dễ dàng quan sát thấy khoảng dao động của biến số người phụ thuộc từ giá trị nhỏ nhất là 0 đến giá trị lớn nhất là 10. Sự lệch phải mạnh của biểu đồ này, với hộp (box) co ngắn và nằm sát phía dưới trong khi phần đuôi trên kéo dài một cách bất thường, đã trực quan hóa và khẳng định chắc chắn kết quả từ thống kê mô tả. Cụ thể, nó minh họa rõ nét cho chứng tỏ phân phối của dữ liệu bị lệch phải mạnh và cho thấy phân phối có một đỉnh nhọn, đuôi dài thể hiện qua hệ số Skewness = 1.418 > 0 và hệ số Kurtosis = 4.906 > 0 . Ngoài ra cũng đã thể hiện ý nghĩa kinh tế là Phần lớn khách hàng có ít hoặc không có người phụ thuộc, phù hợp với nhóm trẻ độc thân hoặc các cặp vợ chồng có con trưởng thành, phản ánh xu hướng nhân khẩu học hiện đại. Nhóm ít người phụ thuộc có khả năng tài chính linh hoạt số lượng người có gia đình gia đình dông con đi vay khá ít.

1.3.3 Thống kê theo cặp

1.3.3.1 Biến mục tiêu với biến tuổi tác

THỐNG KÊ

phat1 <- function(data, var_name) {
  
  # Kiểm tra biến Target có tồn tại không
  if (!"Target" %in% names(data)) {
    stop("Dữ liệu phải có cột 'Target'!")
  }
  
  # Tính toán thống kê cho từng nhóm Target
  result <- data %>%
    group_by(Target) %>%
    summarise(
      Min = min(.data[[var_name]]),
      Q1 = as.numeric(quantile(.data[[var_name]], 0.25)),
      Mean = mean(.data[[var_name]]),
      Median = median(.data[[var_name]]),
      Mode = as.numeric(names(sort(table(.data[[var_name]]), decreasing = TRUE)[1])),
      Q3 = as.numeric(quantile(.data[[var_name]], 0.75)),
      Max = max(.data[[var_name]]),
      SD = sd(.data[[var_name]]),
      Skewness = skewness(.data[[var_name]]),
      Kurtosis = kurtosis(.data[[var_name]]),
      .groups = 'drop'
    )
  
  return(result)
}

summary_Age_by_Target <- phat1(credit_clean, "Age")

Giải nghãi code:

  • Dòng 1: Tạo một hàm mới có tên là phat1, hàm này sẽ nhận hai giá trị đầu vào là một bộ dữ liệu (data) và tên của một cột trong bộ dữ liệu đó (var_name).

  • Cụm code từ dòng 3 đến 5: Đây là một bước kiểm tra an toàn. nếu vượt qua qua cụm code tiếp theo

    • Dòng 4: Lệnh này kiểm tra xem trong bộ dữ liệu được cung cấp có tồn tại một cột tên là “Target” hay không. Cụ thể, names(data) lấy ra tên của tất cả các cột, … %in% … là phép toán kiểm tra sự tồn tại, và dấu ! ở đầu có nghĩa là “phủ định”. Vậy cả dòng có nghĩa là “nếu không có cột ‘Target’ trong dữ liệu thì tiếp tục sẽ đến với code ở dòng 5”.
    • Dòng 5: Nếu điều kiện ở dòng 4 là đúng (tức là không tìm thấy cột “Target”), hàm sẽ dừng lại ngay lập tức và hiển thị thông báo lỗi “Dữ liệu phải có cột ‘Target’!”. Ngược lại nếu vi phạm điều kiện dòng 4 sẽ bỏ qua dòng 5 qua các bước tiếp theo.
  • Cụm code từ dòng 8 đến 22: Đây là phần xử lý chính của hàm, sử dụng chuỗi các thao tác liền mạch thông qua toán tử %>% (đọc là “pipe” hay “đường ống” giúp dẫn nguồn trực tiếp các biến trong các đối tượng nhằm thao tác).

    • Dòng 9: gán kết quả result thông qua việc lấy bộ dữ liệu data và chuyển nó làm đầu vào cho lệnh tiếp theo thông qua toán tử pie .

    • Dòng 10: Lệnh group_by(Target) sẽ phân chia toàn bộ dữ liệu thành các nhóm nhỏ dựa trên các giá trị duy nhất có trong cột Target. Ví dụ, nếu cột Target có hai giá trị là 0 và 1, thì dữ liệu sẽ được chia thành hai nhóm: một nhóm gồm tất cả các dòng có Target bằng 0, và một nhóm gồm tất cả các dòng có Target bằng 1. Mọi tính toán sau bước này sẽ được thực hiện riêng biệt trên từng nhóm này.

    • Cụm code từ Dòng 11 đến 23 dùng Lệnh summarise (trong dòng 11) được dùng để tạo ra một bảng tóm tắt những tính toan thống kê cho . Mỗi dòng trong bảng này sẽ tương ứng với một nhóm đã được tạo ở bước trên nhóm theo biến mục tiêu(Target), và các cột sẽ là các chỉ số thống kê được tính toán.:

      • Dòng 12, 14, 15, 18, 19: Lần lượt tính giá trị nhỏ nhất (Min), trung bình (Mean), trung vị (Median), giá trị lớn nhất (Max), và độ lệch chuẩn (SD) bằng các hàm R cơ bản. Cú pháp .data[[var_name]] là cách để truy cập vào dữ liệu của cột được chỉ định bởi biến var_name trong mỗi nhóm.
      • Dòng 13 và 17: Tính Tứ phân vị thứ nhất (Q1) và Tứ phân vị thứ ba (Q3). Hàm as.numeric(…) được dùng để chuyển kết quả về dạng số và loại bỏ đi phần tên chú thích (như “25%”) mà hàm quantile thường tạo ra.
      • Dòng 16: Tính toán giá trị trung vị (Mode) theo cách tương tự như hàm phat trước đó: tạo bảng tần suất (table), sắp xếp giảm dần (sort), lấy tên của giá trị có tần suất cao nhất (names(…)[1]), và chuyển nó thành dạng số (as.numeric).
      • Dòng 20 và 21: Tính Độ xiên (Skewness) và Độ nhọn (Kurtosis) bằng các hàm từ thư viện gói e1071.
      • Dòng 22: Tùy chọn .groups = ‘drop’ có nghĩa là sau khi hàm thống kê mô tả summarise hoàn thành, cấu trúc nhóm sẽ được gỡ bỏ. Kết quả trả về sẽ là một bảng dữ liệu thông thường.
  • Dòng 25: Hàm sẽ trả về bảng kết quả result vừa được tạo ra thông qua hàm return().

  • Dòng 27: Đây là dòng lệnh gọi để thực thi hàm phat1. Nó truyền vào bộ dữ liệu credit_clean và yêu cầu tính toán các chỉ số thống kê cho cột “Age”, được thực hiện riêng cho từng nhóm trong cột vỡ nợ “Target”. Kết quả (là một bảng tóm tắt) sẽ được lưu vào một biến mới có tên là summary_Age_by_Target.

KẾT QUẢ
Table 1.5: Table 1.6: Thống kê mô tả biến Age theo Target
Target Min Q1 Mean Median Mode Q3 Max SD Skewness Kurtosis
0 21 41 52 52 49 62 105 15 0.22 -0.48
1 21 37 46 46 49 54 101 13 0.45 0.03
Note:
Target 0: Không vỡ nợ | Target 1: Vỡ nợ

Giải nghĩa kết quả:

Thống kê:

  • Ở nhóm không vỡ nợ (Target = 0), tuổi trung bình là 52.15, độ lệch chuẩn 14.65, cho thấy độ phân tán tuổi khá lớn. Phân phối hơi lệch phải nhẹ (Skewness = 0.2156), tức là có một số cá nhân lớn tuổi kéo trung bình lên. Độ nhọn âm (Kurtosis =-0.4751< 0) cho thấy phân phối khá dẹt là dữ liệu phân tán rộng, ít giá trị tập trung quanh trung bình, các đuôi phân phối mỏng hơn so với phân phối chuẩn, ít tập trung quanh trung vị.
  • Ở nhóm vỡ nợ (Target = 1), tuổi trung bình thấp hơn ở nhóm vỡ nợ là 46.29, độ lệch chuẩn nhỏ hơn ở nhóm không vỡ nợ (SD= 12.81), chứng tỏ nhóm này có độ đồng đều cao hơn (do SD càng nhỏ, dữ liệu càng đồng đều hay là gần trung bình hơn ). Phân phối cũng lệch phải nhẹ hơn so với phân phối chuẩn (Skewness = 0.4506), tức vẫn có người lớn tuổi trong nhóm này nhưng không nhiều. Trung vị và mode của cả hai đều quanh 46 và 49 tuổi, cho thấy phần lớn người vỡ nợ tập trung ở độ tuổi trung niên.

Kinh tế: Nhóm vỡ nợ có xu hướng trẻ hơn so với nhóm không vỡ nợ. Điều này gợi ý rằng người trẻ tuổi có khả năng quản lý tài chính và trả nợ yếu hơn hoặc chưa tích lũy đủ kinh nghiệm và tài sản dự phòng. Ngược lại, nhóm lớn tuổi hơn (trên 50) ít vỡ nợ hơn, có thể do thu nhập ổn định, kinh nghiệm tài chính tốt, hoặc có tài sản đảm bảo.

Kết quả này phù hợp với xu hướng chung là độ tuổi càng cao, mức độ rủi ro tín dụng càng giảm. TRỰC QUAN

plot_box_by_Target <- function(data, var_name) {
  ggplot(data, aes(x = factor(Target), y = .data[[var_name]], fill = factor(Target))) +
    geom_boxplot(alpha = 0.6, outlier.color = "red") +
    scale_fill_manual(values = c("#56B4E9", "#E69F00")) +
    labs(
      x = "Target",
      y = var_name,
      title = paste("Boxplot của", var_name, "theo Target"),
      fill = "Target"
    ) +
    theme_minimal(base_size = 12)
}
plot_box_by_Target(credit_clean, "Age")

Giải nghĩa code:

  • Dòng 1: Tạo một hàm mới có tên là plot_box_by_Target. Hàm này nhận hai giá trị đầu vào là một bộ dữ liệu (data) và tên của một cột (var_name) trong bộ dữ liệu đó nhằm vẽ box plot trực quan cho các phần kết quả ở trên.

  • Dòng 2: Đây là dòng lệnh khởi tạo đồ thị bằng gói ggplot2. Với ggplot(data, …): Bắt đầu tạo một đồ thị sử dụng bộ dữ liệu được truyền vào qua biến data. Hàm aes(…): Phần này dùng để “ánh xạ (mapping)”, tức là gán các cột dữ liệu cho các thuộc tính hình ảnh của đồ thị. x = factor(Target): Gán cột Target cho trục hoành (trục X). Hàm factor() được dùng để đảm bảo R hiểu rằng cột Target là một biến phân loại (gồm các nhóm riêng biệt như 0 và 1) chứ không phải là một dãy số liên tục. Điều này sẽ tạo ra một biểu đồ hộp riêng cho mỗi giá trị của Target. y = .data[[var_name]]: Gán cột được chỉ định bởi var_name (ví dụ: cột “Age”) cho trục tung (trục Y). fill = factor(Target): Gán cột Target cho thuộc tính fill (màu tô). Điều này có nghĩa là màu của mỗi hộp trong biểu đồ sẽ phụ thuộc vào giá trị Target tương ứng (ví dụ: hộp của nhóm Target=0 sẽ có một màu, và hộp của nhóm Target=1 sẽ có màu khác).

  • Dòng 3: Thêm một lớp hình học vào đồ thị. geom_boxplot(…): Lệnh này chỉ định rằng chúng ta muốn vẽ biểu đồ hộp (boxplot). alpha = 0.6: Thiết lập độ trong suốt của màu tô là 60%. Điều này làm cho màu sắc của các hộp trông nhạt hơn một chút.outlier.color = “red”: Quy định rằng bất kỳ điểm dữ liệu nào được xác định là ngoại lệ (outlier) sẽ được tô màu đỏ để dễ nhận biết.

  • Dòng 4: Tùy chỉnh màu sắc được sử dụng cho việc tô màu các hộp. scale_fill_manual(…): Cho phép người dùng tự định nghĩa một bảng màu cụ thể thay vì sử dụng màu mặc định. values = c(“#56B4E9”, “#E69F00”): Cung cấp một danh sách các mã màu sẽ được sử dụng. Theo thứ tự, nhóm đầu tiên của biến mục tiêu là nhóm không vỡ nợ ứng với Target = 0 sẽ được tô màu xanh lam ( mã màu #56B4E9), và nhóm còn lại là nhóm vỡ nợ sẽ được tô màu cam ( mã màu #E69F00).

  • Cụm code từ dòng 5 đến 10: Đặt các nhãn và tiêu đề cho đồ thị với :

    • Dòng 5 hàm labs(…): Là hàm để tùy chỉnh các nhãn.
    • Dòng 6 x = “Target”: Đặt tên cho trục hoành là “Target”.
    • Dòng 7 dùng y = var_name: Đặt tên cho trục tung là tên của biến được vẽ (được lấy từ var_name).
    • Dòng 8 hàm title = paste(…): Tạo một tiêu đề động bằng cách ghép chuỗi “Boxplot của” với tên biến và chuỗi “theo Target”. (nhằm vẽ được lặp lại nhiều hình thể hiện tác động biến được chọn đến biến mục tiêu)
    • Dòng 9 hàm fill = “Target”: Đặt tiêu đề cho phần chú giải (legend) của màu sắc là biến vỡ nợ “Target”.
    • Dòng 10 thêm 1 lớp bằng dấu “+” không ghi thêm gì tránh tràn code khi trình bày.
  • Dòng 11 : Áp dụng một giao diện (theme) cho đồ thị. dùng hàm theme_minimal(…): Chọn một giao diện tối giản với nền trắng, giúp đồ thị trông gọn gàng và hiện đại. với Đặt kích thước chữ cơ bản cho tất cả các văn bản trên đồ thị (tiêu đề, nhãn trục,…) là 12 (base_size = 12). cuối cùng kết thúc phần tạo hàm plot_box_by_Target ở dòng thứ 12 bằng “}”

  • Dòng 13: Đây là dòng lệnh thực thi hàm vừa được tạo. Nó gọi hàm plot_box_by_Target với bộ dữ liệu là credit_clean và yêu cầu vẽ biểu đồ cho biến độ tuổi “Age”. Kết quả là một biểu đồ gồm hai hộp, trực quan hóa sự phân bổ của biến Age cho một nhóm Target khác nhau.

Giải nghĩa kết quả:

  • Về thống kê: Hộp màu xanh (Target = 0) nằm cao hơn thể hiện đúng, nhóm này lớn tuổi hơn, hai đường trung vị phản ánh chênh lệch rõ ràng .Hộp màu xanh (Target = 0) rộng hơn thể hiện chính xác độ phân tán lớn hơn. Biểu đồ có nhiều điểm ngoại lai (chấm đỏ) ở phía trên thê hiện đúng với đặc điểm “đuôi phải dài”(Skewness > 0).
  • Về Kinh tế: Nhóm không vỡ nợ (màu xanh) lớn tuổi hơn và phân tán hơn , nghĩa là người trung niên và cao tuổi đa dạng hơn về độ tuổi nhưng nhìn chung có khả năng trả nợ tốt hơn. Các điểm ngoạilai trong biến tuổi (tuổi cao > 80) là nhóm rất ít nhưng vẫn tồn tại trong cả hai nhóm, có thể là những cá nhân đặc biệt (người cao tuổi vẫn có hồ sơ tín dụng). Nhóm vỡ nợ trẻ hơn, ít biến động hơn, còn nhóm không vỡ nợ vừa lớn tuổi vừa đa dạng về độ tuổi hơn dúng cới đặc điểm nhân khẩu học cơ bản.

1.3.3.2 Biến mục tiêu với biến Tỷ lệ sử dụng hạn mức tín dụng (Util)

THỐNG KÊ

summary_Util <- phat1(credit_clean, "Util")

Giải nghãi code: Sử dụng hàm phat1 đã dược tạo từ bước trước đó nhằm tạo thống kê mô tả biến Tỷ lệ sử dụng hạn mức tín dụng (Util) theo các nhóm của biến mục tiêu dạng vỡ nợ hoặc không (Target = 1 và 0) trong data.frame creadit_clean

KẾT QUẢ
Table 1.7: Table 1.8: Thống kê mô tả biến Util theo Target
Target Min Q1 Mean Median Mode Q3 Max SD Skewness Kurtosis
0 0 0.03 0.29 0.14 0 0.48 1 0.32 1.0 -0.32
1 0 0.31 0.63 0.73 1 0.97 1 0.35 -0.5 -1.23
Note:
Target 0: Không vỡ nợ | Target 1: Vỡ nợ

Giải nghĩa kết quả Thống Kê:

  • Ở nhóm không vỡ nợ (Target = 0): Tỷ lệ sử dụng hạn mức tín dụng (Util) trung bình là 0.29, trung vị 0.14, độ lệch chuẩn 0.32 ; thể hiện phần lớn khách hàng chỉ sử dụng một phần nhỏ hạn mức tín dụng của họ. Có chỉ số Skewness = 1.0175 > 0 thể hiện phân phối lệch phải mạnh, tức có một số người sử dụng gần hết hạn mức (Util ≈ 1), kéo trung bình lên cao. Hệ số Kurtosis = -0.3213 < 0 phân phối dẹt (dữ liệu rải rộng, ít tập trung), các giá trị trải khá rộng, không tập trung quanh trung vị.
  • Ở nhóm vỡ nợ (Target = 1): Giá trị trung bình 0.6253 và trung vị 0.7253 cao hơn hẳn, nhằm cho thấy đa phần nhóm này sử dụng gần hết hoặc vượt hạn mức tín dụng. Độ lệch chuẩn ( SD= 0.35>0) tương đương nhóm 0, nhưng hệ số Skewness =-0.4987<0 âm nhẹ thể hiện phân phối lệch trái, tức phần lớn giá trị nằm ở mức cao, chỉ có ít người dùng ít tín dụng. Hệ số Kurtosis = -1.2260 thể hiện phân phối rất dẹt giống như ở nhóm không vỡ nợ , thể hiện sự biến động mạnh, ít tập trung.

Kinh tế: Nhóm vỡ nợ có tỷ lệ sử dụng tín dụng (Util) cao hơn rõ rệt , nghĩa là họ thường vay hoặc chi tiêu vượt quá khả năng, rủi ro tín dụng cao. Nhóm không vỡ nợ duy trì mức sử dụng tín dụng thấp do đó có thể thấy sự quản lý tài chính tốt hơn, ít phụ thuộc vào vay nợ. Đặc điểm lệch phải và lệch trái giữa hai nhóm thể hiện rõ hành vi khác nhau: người không vỡ nợ chủ yếu dùng ít, chỉ một số ít sử dụng tối đa ; ngược lại , người vỡ nợ phần lớn đang “cạn hạn mức”, tức khả năng trả nợ và quản lý chi tiêu yếu.

TRỰC QUAN

plot_box_by_Target(credit_clean, "Util")

Giải nghĩa code: Sử dụng hàm plot_box_by_Target đã dược tạo ở biến trước đó vẽ các đặc diểm thogn16 kê của biến Tỷ lệ sử dụng hạn mức tín dụng (Util) theo nhóm của biến mục tiêu Target

Giải nghĩa kết quả :

– Về thống kê: Hộp màu vàng (Target = 1) nằm cao hơn thể hiện đúng, nhóm này có tỷ lệ sử dụng hạn mức tín dụng (Util) lớn hơn rõ rệt; hai đường trung vị phản ánh chênh lệch rất rõ giữa hai nhóm. Hộp màu vàng (Target = 1) cũng rộng tương đương hộp xanh, thể hiện mức độ phân tán lớn. Ngoài ra, hộp màu xanh (Target = 0) xuất hiện giá trị râu trên dài hơn và có một số điểm lệch trên biểu thị trạng thái lệch phải (Skewness > 0), phù hợp với việc một số khách hàng sử dụng tín dụng gần tối đa, kéo phân phối lên cao.

– Về kinh tế: Nhóm vỡ nợ (màu vàng) có mức sử dụng tín dụng cao hơn, tức họ thường chi tiêu vượt khả năng và dựa nhiều vào tín dụng, làm tăng rủi ro không trả được nợ. Nhóm không vỡ nợ (màu xanh) có mức sử dụng tín dụng thấp hơn, thể hiện hành vi quản lý tài chính tốt hơn, ít phụ thuộc vào hạn mức. Các điểm ngoại lai trong nhóm không vỡ nợ cho thấy vẫn tồn tại một nhóm nhỏ khách hàng sử dụng tín dụng cao nhưng vẫn duy trì trạng thái không vỡ nợ có thể thuộc nhóm có khả năng tài chính tốt hơn. Nhìn chung, nhóm vỡ nợ chủ yếu đang sử dụng tín dụng ở mức cao và tập trung hơn, còn nhóm không vỡ nợ có xu hướng sử dụng thấp và phân tán hơn, phản ánh hành vi tài chính chắc chắn hơn.

1.3.3.3 Biến mục tiêu với Tỷ lệ nợ trên thu nhập (DebtRatio)

THỐNG KÊ

summary_DebtRatio <- phat1(credit_clean, "DebtRatio")

Giải nghãi code: Tiếp tục sử dụng hàm phat1 đã dược tạo từ bước trước đó nhằm tạo thống kê mô tả biến Tỷ lệ nợ trên thu nhập (DebtRatio) theo các nhóm của biến mục tiêu dạng vỡ nợ hoặc không (Target = 1 và 0) trong data.frame creadit_clean

KẾT QUẢ
Table 1.9: Table 1.10: Thống kê mô tả biến DebtRatio theo Target
Target Min Q1 Mean Median Mode Q3 Max SD Skewness Kurtosis
0 0 0.14 0.42 0.29 0 0.47 10 0.75 7.8 76
1 0 0.17 0.48 0.36 0 0.59 10 0.65 7.1 75
Note:
Target 0: Không vỡ nợ | Target 1: Vỡ nợ

Giải nghĩa kết quả: Thống kê:

  • Ở nhóm không vỡ nợ (Target = 0): Tỷ lệ nợ trên thu nhập (DebtRatio) trung bình là 0.4174, trung vị 0.2889, cho thấy đa số khách hàng chỉ sử dụng một phần tương đối nhỏ thu nhập của họ để trang trải nghĩa vụ nợ. Độ lệch chuẩn SD = 0.7452 cho thấy mức biến động khá lớn giữa các khách hàng. Chỉ số Skewness = 7.7970 > 0 phản ánh phân phối lệch phải rất mạnh: đa số khách hàng có DebtRatio thấp, song tồn tại một số ít khách hàng có tỷ lệ nợ cực lớn (DebtRatio gần 10), kéo trung bình lên cao. Hệ số Kurtosis = 76.4491 >> 0 cho thấy phân phối rất nhọn (đỉnh cao), tập trung mạnh quanh các giá trị nhỏ và có nhiều giá trị ngoại lai lớn thể hiện đặc trưng kiểu phân phối có “đuôi phải rất dài”.

  • Ở nhóm vỡ nợ (Target = 1): Giá trị trung bình 0.4816 và trung vị 0.3619 cao hơn so với nhóm không vỡ nợ, thể hiện đa phần khách hàng trong nhóm này dành tỷ trọng thu nhập cho nghĩa vụ nợ nhiều hơn. Độ lệch chuẩn SD = 0.6476 cũng cho thấy mức độ phân tán tương đối lớn, tuy hơi thấp hơn nhóm 0. Chỉ số Skewness = 7.0643 > 0 vẫn cho thấy phân phối lệch phải mạnh, nghĩa là phần lớn khách hàng có tỷ lệ nợ trên thu nhập (DebtRatio) thấp nhưng tồn tại một số khách hàng có tỷ lệ nợ trên thu nhập rất cao (DebtRatio ≈ 1000%). Hệ số Kurtosis = 75.3977 > 0 phản ánh phân phối rất nhọn, tương tự nhóm không vỡ nợ, cho thấy dữ liệu tập trung quanh giá trị thấp và có nhiều ngoại lai cực lớn.

Kinh tế: Nhìn chung, nhóm vỡ nợ (Target = 1) có mức tỷ lệ nợ trên thu nhập (DebtRatio ) cao hơn so với nhóm không vỡ nợ, cho thấy họ dùng phần lớn thu nhập để trả nợ, dẫn đến áp lực tài chính và rủi ro vỡ nợ cao hơn. Trong khi đó, nhóm không vỡ nợ (Target = 0) có tỷ lệ nợ trên thu nhập ( DebtRatio) thấp hơn, phản ánh khả năng quản lý tài chính ổn định hơn, ít phụ thuộc vào vay nợ để đáp ứng nhu cầu chi tiêu.

Cả hai nhóm đều có đặc điểm là chỉ số Skewness rất lớn và dương (≫ 0) kèm theo là chỉ số Kurtosis cực lớn, cho thấy phân phối biến tỷ lệ nợ trên thu nhập ( DebtRatio ) tập trung chính ở mức thấp đuôi trái dày nhưng vẫn tồn tại một số trường hợp có tỷ lệ nợ trên thu nhập cực cao (DebtRatio ~10). Đây là những cá nhân mang đặc điểm tài chính bất thường, có thể gây rủi ro tín dụng.

Tóm lại, xu hướng DebtRatio cao hơn ở nhóm vỡ nợ thể hiện rằng việc dành phần lớn thu nhập để chi trả nợ làm giảm khả năng thanh toán các nghĩa vụ khác, dẫn đến nguy cơ vỡ nợ. Ngược lại, những người duy trì DebtRatio thấp có sức khỏe tài chính tốt hơn, quản lý nợ an toàn và ổn định hơn.

TRỰC QUAN

plot_box_by_Target(credit_clean, "DebtRatio")

giải nghĩa code: Tiếp tục giống biến trước đó Sử dụng hàm plot_box_by_Target đã dược tạo ở biến trước đó vẽ các đặc diểm thống kê của biến Tỷ lệ sử dụng hạn mức tín dụng (Util) theo nhóm của biến mục tiêu Target

Giải nghĩa kết quả:Biểu đồ boxplot phản ánh đúng tinh thần của phần thống kê mô tả: Cụ thể: Hộp màu vàng (Target = 1) nằm cao hơn hộp màu xanh (Target = 0) , phù hợp việc nhóm vỡ nợ có Tỷ lệ nợ trên thu nhập (DebtRatio) trung bình và trung vị cao hơn. Cả hai nhóm đều có nhiều điểm ngoại lai (điểm đỏ) ở phía trên đã dược nêu ra kết luận thống kê mô tả về đặc điểm phân phối lệch phải rất mạnh (Skewness >> 0) và Kurtosis lớn, cho thấy có một số khách hàng có DebtRatio cực cao.

Thân hộp của hai nhóm đều thấp sát đáy, trong khi phần ngoại lai kéo dài lên trê điều này thể hiện sự tập trung mạnh của phần lớn dữ liệu ở mức DebtRatio thấp, và có hiện tượng đuôi phải rất dài dã nêu ở mô tả thống kê.

Biểu đồ boxplot minh họa trực quan một cách rõ ràng và nhất quán các đặc trưng đã nêu trong thống kê mô tả: Nhóm vỡ nợ có DebtRatio cao hơn, phân phối lệch phải rất mạnh, nhiều ngoại lai ở vùng giá trị cao Nhằm nhấn mạnh rằng rủi ro vỡ nợ gia tăng với mức tỷ lệ nợ trên thu nhập cao. => Kết luận trực quan HOÀN TOÀN phù hợp với kết quả thống kê mô tả

1.3.3.4 Biến mục tiêu với Thu nhập hàng tháng (Income)

THỐNG KÊ

summary_Income <- phat1(credit_clean, "Income")

Giải nghãi code Tiếp tục sủ dụng hàm phat nhằm tính các chỉ số thống kê cơ bản biến thu nhập theo các nhóm biến mục tiêu

KẾT QUẢ
Table 1.11: Table 1.12: Thống kê mô tả biến Income theo Target
Target Min Q1 Mean Median Mode Q3 Max SD Skewness Kurtosis
0 0 3600 6663 5494 5000 8333 100000 5331 5.0 51
1 0 3000 5737 4697 3000 7000 81000 4879 5.5 57
Note:
Target 0: Không vỡ nợ | Target 1: Vỡ nợ

Giải nghĩa kết quả:

Về mặt thống kê:

  • Ở nhóm không vỡ nợ (Target = 0): Thu nhập trung bình là 6,662.70, trung vị 5,494, và độ lệch chuẩn 5,330.86 phản ánh thu nhập giữa các cá nhân chênh lệch khá lớn. hệ số Skewness = 5.0059 > 0 cho thấy phân phối lệch phải rất mạnh nghĩa là đa số người vay có thu nhập trung bình đến thấp, chỉ một số ít có thu nhập cực cao (kéo trung bình tăng mạnh). Chỉ số Kurtosis = 51.4718 > 0 có nghĩa là phân phối rất nhọn, đuôi dày, có nhiều giá trị ngoại lệ ở mức thu nhập cao bất thường.

  • Ở nhóm vỡ nợ (Target = 1): Thu nhập trung bình thấp hơn (5,736.54), trung vị 4,697 → nhìn chung nhóm này kiếm được ít tiền hơn. Độ lệch chuẩn SD = 4,878.98 >0 cũng cho thấy thu nhập phân tán rộng của phân phối biến thu nhập nhưng thấp hơn nhóm không vỡ nợ. Chỉ số Skewness = 5.4960 và Kurtosis = 57.0128 thể hiện mức lệch phải và độ nhọn còn cao hơn không vỡ nợ có một số ít cá nhân thu nhập rất cao trong nhóm vỡ nợ có thể là các chủ doanh nghiệp có thu nhập cao nhưng làm ăn thua lỗ dẫn đến vỡ nợ , song phần lớn lại thu nhập thấp

Về mặt kinh tế, tài chính: Người không vỡ nợ có thu nhập trung bình và trung vị cao hơn, chứng tỏ họ có khả năng trả nợ tốt và quản lý tài chính ổn định hơn. Người vỡ nợ có thu nhập thấp hơn, dễ rơi vào tình trạng thiếu thanh khoản hoặc chi tiêu vượt khả năng. Tuy nhiên,các chỉ số Skewness và Kurtosis cực cao ở cả hai nhóm cho thấy dữ liệu rất không đồng đều, tồn tại ít người thu nhập cực cao trong cả hai nhóm thể hiện những hồ sơ vay đặc biệt (ví dụ, người có thu nhập cao nhưng vay nhiều, hoặc có nợ tín dụng rủi ro).

TRỰC QUAN:

plot_box_by_Target(credit_clean, "Income")

Giải nghĩa code: Tiếp tục giống biến trước đó Sử dụng hàm plot_box_by_Target đã dược tạo ở biến trước đó vẽ các đặc diểm thống kê của biến thu nhập (Income) theo nhóm của biến mục tiêu Target

Giải nghĩa kết quả: Biểu đồ boxplot đã phản ánh đúng tinh thần các kết luận thống kê mô tả và ý nghĩa kinh tế dã nêu trước đó, nhìn vào boxplot, có thể thấy nhóm không vỡ nợ (Target = 0) có thu nhập cao hơn đáng kể so với nhóm vỡ nợ (Target = 1), thể hiện qua vị trí hộp và trung vị nằm cao hơn. Điều này phù hợp với thống kê mô tả cho thấy nhóm không vỡ nợ có thu nhập trung bình và trung vị lớn hơn, phản ánh khả năng tài chính tốt hơn và ít rủi ro hơn. Ngoài ra, cả hai nhóm đều có nhiều ngoại lai thu nhập rất cao, nhưng điều này không làm thay đổi xu hướng chung: nhằm kết luận rằng nhóm thu nhập cao chủ yếu thuộc nhóm không vỡ nợ, trong khi nhóm vỡ nợ tập trung ở mức thu nhập thấp hơn.

1.3.3.5 Biến mục tiêu với Số người phụ thuộc tài chính (Depentdents)

THỐNG KÊ

summary_Dependents <- phat1(credit_clean, "Dependents")

Giải nghãi code sử dụng hàm phat1 để tạo thống kê mô tả biến số người phụ thuộc tài chính theo 2 nhóm khogn6 vỡ nợ và vỡ nợ của biến mục tiêu .

KẾT QUẢ
Table 1.13: Table 1.14: Thống kê mô tả biến Dependents theo Target
Target Min Q1 Mean Median Mode Q3 Max SD Skewness Kurtosis
0 0 0 0.82 0 0 1 10 1.1 1.4 1.99
1 0 0 1.03 1 0 2 8 1.2 1.1 0.88
Note:
Target 0: Không vỡ nợ | Target 1: Vỡ nợ

Giải nghĩa kết quả:

Thống kê:

Ở nhóm không vỡ nợ (Target = 0): Số người phụ thuộc trung bình là 0.82, trung vị = 0, độ lệch chuẩn = 1.13 thể hiện rằng đa phần người vay không có hoặc chỉ có 1 người phụ thuộc, độ biến động vừa phải. Hệ số Skewness = 1.4382 > 0 hàm ý rằng phân phối lệch phải, có một số người có rất nhiều người phụ thuộc (tối đa 10), kéo trung bình tăng lên. cùng với Kurtosis = 1.9949 > 0 mang ý nghĩa phân phối hơi nhọn tức là có một nhóm nhỏ giá trị cực trị ở phía cao ( nghĩa là có nhiều người phụ thuộc tài chính ).

Ở nhóm vỡ nợ (Target = 1): Số người phụ thuộc trung bình cao hơn (1.03), trung vị = 1, và độ lệch chuẩn = 1.23 thể hiện rõ biến động lớn hơn một chút so với nhóm không vỡ nợ hay có thể nói nhóm này có xu hướng có nhiều người phụ thuộc hơn. chỉ số Skewness = 1.1349 và Kurtosis = 0.8764 phân phối của biến số người phụ thuộc tài chính trong nhóm vỡ nợ cũng lệch phải, nhưng nhẹ hơn nhóm không vỡ nợ, tức là phần lớn vẫn tập trung ở mức thấp (0 đế 2 người phụ thuộc).

Kinh tế : Người có nhiều người phụ thuộc thường gánh nặng tài chính cao hơn, chi tiêu cố định lớn, ít khả năng tích lũy hoặc ứng phó rủi ro. Do đó, nhóm vỡ nợ có trung bình số người phụ thuộc cao hơn ,diều này là hợp lý về mặt kinh tế: càng nhiều người phụ thuộc, khả năng vỡ nợ càng lớn do áp lực chi tiêu và thu nhập khả dụng giảm.

Tuy nhiên, vì phân phối lệch phải và giá trị trung vị thấp, phần lớn người vay vẫn chỉ có ít người phụ thuộc; chỉ một nhóm nhỏ có số lượng cao bất thường .

TRỰC QUAN:

plot_box_by_Target(credit_clean, "Dependents")

Giải nghĩa code: sử dạng lại hàm plot_box_by_Target đã tạo trước đó nhằm mô hình hóa đặc điểm thống kê biến số người phụ thuộc tài chính trên 2 nhóm vỡ nợ hoặc không .

Giải nghĩa kết quả: Biểu đồ boxplot phản ánh đúng tinh thần của phần thống kê mô tả và ý nghĩa kinh tế đã nêu trước đó. Quan sát cho thấy nhóm vỡ nợ (Target = 1) có số người phụ thuộc cao hơn so với nhóm không vỡ nợ (Target = 0). Điều này thể hiện rõ qua việc vị trí hộp và trung vị của Target = 1 cao hơn Target = 0, phù hợp với thống kê mô tả rằng nhóm vỡ nợ có trung bình (1.03) và trung vị (1) cao hơn so với nhóm không vỡ nợ (mean = 0.82, median = 0). Ngoài ra, cả hai nhóm đều có nhiều điểm ngoại lai ở vùng giá trị cao (nhiều người phụ thuộc), đúng với đặc điểm phân phối lệch phải (Skewness > 0) và có một nhóm nhỏ giá trị cực lớn như thống kê ghi nhận. Tuy nhiên, phần lớn giá trị vẫn tập trung gần 0–2 người phụ thuộc và điều này được thể hiện qua độ rộng của hộp nằm thấp.

1.3.4 Thống kê phân tổ

Trong thống kê trong kinh tế kinh donah thống kê các hci3 số nhằm phân tổ dữ liệu thường dùng công thức tính số tổ là \(\sqrt{2x(Số quan sát)}\) nhưng trong bộ dữ liệu này số quan sát rất lớn lên đến trăm ngàn quan sát ảnh hưởng đến phân tổ kết quả số tổ cần phân lên đến 900 hay 1000 nên tôi sẽ giải định nhằm phân tổ theo giả định và thống kê chúng phục vụ cho phân tíchvới biến mục tiêu.

1.3.4.1 Biến Tuổi

Biến Tuổi thể hiện độ tuổi của các cá nhân trong bộ dữ liệu. Nhóm tuổi theo giai đoạn thăng tiến sự nghiệp rất quan trọng trong việc đánh giá năng lực, kinh nghiệm và khả năng tài chính cần phân tổ nhằm đánh giá khả năng trả nợ tín dụng.

Phân tổ

biến tuổi được phân thành 4 tổ: khởi đầu (21–41), phát triển (41–51), ổn định (51–62),về hưu à truyền đạt kionh nghiệm (62–105). | Tổ | Khoảng tuổi | Tên tổ | Giai đoạn sự nghiệp | | —- | ———– | ——————————- | ———————— | | Tổ 1 | 21 – 41 | Khởi đầu sự nghiệp |Giai đoạn khởi đầu | | Tổ 2 | 41 – 51 | Thăng tiến | Giai đoạn phát triển | | Tổ 3 | 51 – 62 | Ổn định sự nghiệp | Giai đoạn ổn định | | Tổ 4 | 62 – 105 | Nghỉ hưu | Giai đoạn dẫn đầu |

code:

credit_clean$giai_doan_su_nghiep <- cut(credit_clean$Age,
                    breaks = c(20, 41, 51, 62, 105),
                    labels = c("Khởi đầu sự nghiệp ",
                              "Thăng tiến ",
                              "Ổn định sự nghiệp ",
                              "Nghỉ hưu "),
                    include.lowest = TRUE,
                    right = TRUE)

Giải nghĩa code:

  • Dòng 1: Phần này có nghĩa là tạo ra một cột mới có tên là giai_doan_su_nghiep bên trong bảng dữ liệu credit_clean. Toán tử <- là lệnh gán, nó sẽ lấy toàn bộ kết quả từ hàm cut ở vế bên phải và lưu vào cột mới này. Cụm code từ cuối dòng 1 đến dòng 8: Đây là hàm cut, một hàm rất hữu ích trong R dùng để chia một biến số liên tục (như tuổi) thành các khoảng (hay các nhóm) rời rạc. cuối dòng 1 (tham số đầu tiên): Sử dụng hàm cut, với dữ liệu đầu vào cụ thể là cột Age từ bảng credit_clean. Hàm sẽ xem xét từng giá trị tuổi trong cột này để tiến hành phân loại.
  • Dòng 2: Tham số breaks xác định các điểm chia để tạo ra các khoảng tuổi. Với các điểm chia này, R sẽ tạo ra 4 khoảng tuổi. Cụm code từ dòng 3 đến 6: Tham số labels dùng để đặt tên (hay nhãn) cho các khoảng đã được tạo ra ở trên. Các nhãn này sẽ được gán theo đúng thứ tự của các khoảng. cụ thể :
    • Khoảng 1: Tuổi từ 20 đến và bao gồm 41 ([20, 41]). Những người trong khoảng tuổi này sẽ được gán nhãn là “Khởi đầu sự nghiệp”
    • Khoảng 2: Tuổi lớn hơn 41 cho đến và bao gồm 51 ((41, 51]). Những người trong khoảng tuổi này sẽ được gán nhãn là “Thăng tiến”
    • Khoảng 3: Tuổi lớn hơn 51 cho đến và bao gồm 62 ((51, 62]). Những người trong khoảng tuổi này sẽ được gán nhãn là “Ổn định sự nghiệp”
    • Khoảng 4: Tuổi lớn hơn 62 cho đến và bao gồm 105 ((62, 105]). Những người trong khoảng tuổi này sẽ được gán nhãn là “Nghỉ hưu”
  • Dòng 7: Tham số này có nghĩa là giá trị nhỏ nhất trong breaks (tức là số 20) sẽ được bao gồm trong khoảng đầu tiên.
  • Dòng 8:Tham số này quy định rằng các khoảng tuổi sẽ được tính bao gồm cả giá trị bên phải của khoảng đó.

Ý nghĩa: Về thống kê phân tổ giúp dễ dang phân tích các bộ dữ liệu có số quan sát lớn về kinh tế nhóm tuổi theo giai đoạn thăng tiến sự nghiệp rất quan trọng trong việc đánh giá năng lực, kinh nghiệm và khả năng tài chính cần phân tổ nhằm đánh giá khả năng trả nợ tín dụng

Kết quả sử dạng hàm tính tần số các tổ

bang_ket_qua_Age <- credit_clean %>%
  count(giai_doan_su_nghiep, name = "Tần số") %>%
  mutate(`Tần suất` = round((`Tần số` / sum(`Tần số`)) * 100, 2)) %>%
  rename(`Tên tổ` = giai_doan_su_nghiep)
(print(bang_ket_qua_Age))

Giải nghĩa :

  • Dòng 1: Lệnh này bắt đầu bằng việc tạo một biến mới có tên là bang_ket_qua_Age để lưu kết quả cuối cùng. Nó lấy toàn bộ bảng dữ liệu credit_clean và sử dụng toán tử %>% (được gọi là “pipe” hay “đường ống”). Toán tử này sẽ “đẩy” kết quả của vế bên trái vào làm đầu vào cho hàm ở vế bên phải, tạo thành một chuỗi xử lý liền mạch, dễ đọc từ trên xuống dưới.

  • Dòng 2: Dữ liệu từ credit_clean được chuyển vào hàm count. Hàm count() thực hiện việc đếm số lần xuất hiện (số dòng) cho mỗi giá trị duy nhất trong cột được chỉ định, ở đây là cột giai_doan_su_nghiep. Tham số name = “Tần số” chỉ định rằng cột mới chứa kết quả đếm sẽ được đặt tên là “Tần số” (thay vì tên mặc định là n). Kết quả của bước này là một bảng mới có 2 cột: giai_doan_su_nghiep và Tần số. Bảng này sau đó lại được “đẩy” qua toán tử %>% để xử lý ở bước tiếp theo.

  • Dòng 3: Cột tiếp theo sau cột Tên tổ sẽ tạo thông qua Hàm mutate() dùng để tạo ra một cột mới hoặc chỉnh sửa một cột đã có. Ở đây, nó tạo ra một cột mới tên là Tần suất. dùng dấu `` được dùng để bao quanh tên cột vì nó có chứa khoảng trắng. Giá trị của cột mới này được tính bằng một công thức: Lấy tần số của từng nhóm chia cho tổng số quan sát để tính ra tỷ lệ (hay tần suất tương đối). Nhân tỷ lệ với 100 để chuyển nó thành dạng phần trăm. Sau đó làm tròn giá trị phần trăm vừa tính được đến 2 chữ số thập phân. Kết quả của bước này là một bảng có 3 cột: giai_doan_su_nghiep, Tần số, và Tần suất. Bảng này lại tiếp tục được “đẩy” đi.

  • Dòng 4: bảng vừa tạo có cột giai_doan_su_nghiep được chuyển vào hàm rename để đổi tên một cột. Cú pháp tên_mới = tên_cũ có nghĩa là đổi tên cột giai_doan_su_nghiep thành Tên tổ. Đây là bước cuối cùng trong chuỗi xử lý. Toàn bộ bảng kết quả cuối cùng (gồm 3 cột Tên tổ, Tần số, Tần suất) sẽ được gán vào biến bang_ket_qua_Age.

  • Dòng 5: Lệnh này đơn giản là in (hiển thị) nội dung của bảng bang_ket_qua_Age vừa được tạo ra lên màn hình .

Đọc kết quả: Nhóm tuổi trong bộ dữ liệu phân theo giai đoạn sự nghiệp khá cân bằng, với Khởi đầu sự nghiệp chiếm 26,37%, Thăng tiến 24,53%, Ổn định 25,28% và Nghỉ hưu 23,82%. Điều này phản ánh lực lượng lao động trẻ và trung niên chiếm ưu thế, đồng thời có lượng kinh nghiệm đáng kể từ nhóm ổn định và nghỉ hưu chuẩn bị dữ liệu đánh giá phân tích với kah3 năng trả nợ.

1.3.4.1.1 Trực quan hóa kết quản phân tổ biến đơn
visualize_group <- function(df, title = NULL) {
  if (is.null(title)) {
    title <- "Biểu đồ tần số nhóm tuổi"
  }
    ggplot(df, aes(x = `Tên tổ`, y = `Tần số`, fill = `Tên tổ`)) +
    geom_bar(stat = "identity") +
    geom_text(aes(label = `Tần số`), vjust = -0.5) +
    labs(x = "Tên tổ", y = "Tần số", title = title) +
    theme_minimal()+
    theme(axis.text.x = element_text(angle = 45, hjust = 1))}
visualize_group(bang_ket_qua_Age)

Giải nghĩa code:

  • Dòng 1: Tạo một hàm mới có tên là visualize_group giúp tối ưu hóa code vẽ nhiều hình tương tự nhau Hàm này sẽ nhận hai giá trị đầu vào: df (là một bảng dữ liệu) và title (là tiêu đề cho biểu đồ). Với title = NULL có nghĩa là tham số title là không bắt buộc. Nếu người dùng không cung cấp giá trị cho title khi gọi hàm, nó sẽ mặc định là rỗng (NULL). Cụm code từ dòng 2 đến 4: Đây là một khối lệnh điều kiện để xử lý tiêu đề một cách linh hoạt Giúp thay thế tên biểu đồ nếu vẽ cac biến tiếp theo.

  • Dòng 2: thực hiện một phép kiểm tra: “Có phải người dùng đã không cung cấp tiêu đề không?”.

  • Dòng 3: tNếu câu trả lời cho câu hỏi trên là “Đúng”, thì dòng lệnh này sẽ tự động gán một tiêu đề mặc định vào biến title có giá trị là “Biểu đồ tần số nhóm tuổi”. Điều này đảm bảo biểu đồ sẽ luôn có một tiêu đề, ngay cả khi người dùng quên nhập.

  • Cụm code từ dòng 5 đến 10: Đây là phần chính để xây dựng biểu đồ cột bằng gói ggplot2. Mỗi dòng bắt đầu bằng dấu + sẽ thêm một lớp hoặc một tùy chỉnh mới vào biểu đồ.

    • Dòng 5: Lớp đầu tiên tạo khung biểu đồ và ánh xạ dữ liệu: “Tên tổ” lên trục X, “Tần số” lên trục Y và đồng thời dùng “Tên tổ” để tô màu các cột.
    • Dòng 6: Lớp thứ hai thêm biểu đồ cột với geom_bar, trong đó stat=“identity” chỉ định lấy chiều cao cột trực tiếp từ giá trị Tần số thay vì để ggplot tự đếm.
    • Dòng 7: Lớp geom_text dùng để hiển thị giá trị Tần số lên trên mỗi cột, và vjust = -0.5 giúp đẩy chữ lên một chút để nằm rõ ràng phía trên đỉnh cột.
    • Dòng 8: Lớp này dùng hàm labs để thiết lập các nhãn cho biểu đồ, bao gồm nhãn cho trục x, trục y, và tiêu đề chính của biểu đồ (lấy giá trị từ biến title đã được xử lý ở trên).
    • Dòng 9: Thêm lớp áp dụng một giao diện (theme) có sẵn tên là minimal. Giao diện này có nền trắng và các đường lưới mờ, giúp biểu đồ trông sạch sẽ, hiện đại và dễ đọc hơn.
    • Dòng 10 Dòng này xoay chữ ở trục X 45° và căn lại cho dễ đọc:
  • Dòng 11: Lệnh này gọi hàm visualize_group với dữ liệu bang_ket_qua_Age. Vì không cung cấp tiêu đề, hàm sẽ dùng tiêu đề mặc định “Biểu đồ tần số nhóm tuổi”.

Kết quả là một biểu đồ cột sẽ được tạo ra và hiển thị, minh họa trực quan tần số của các nhóm tuổi đã được thống kê trong bảng bang_ket_qua_Age. Việc trực quan hóa đã tể hiện rõ tân suất xuất hiện các tổ với tổ cao nhất là Khởi đầu sự nghiệp thấp nhất là tổ nghỉ hưu phản ánh đáng tính chất đời thường hay thấy nhất là người lập nghiệp người trẻ vay tín dung nhiều hơn người lớn tuổi và người đã ổn định

1.3.4.1.2 Tần số các tổ trong biến mục tiêu

Phân bổ tần suất từng tổ biến độ tuổi hai nhóm của biến mục tiêu là gì và tổ nào sẽ có khả năng vỡ nợ theo tỷ lệ lớn nhất là các câu hỏi đáng suy xet đánh giá và sẽ làm rõ trong phần này. ta tiến hành thống kê tần số các nhóm biến tuổi theo nbien16 mục tiêu: Code

bang_tan_so_Age_theo_Target <- credit_clean %>%
  group_by(giai_doan_su_nghiep, Target) %>%
  summarise(`Tần số` = n(), .groups = "drop") %>%
  group_by(giai_doan_su_nghiep) %>%
  mutate(`Tần suất` = round(`Tần số` / sum(`Tần số`) * 100, 2)) %>%
  rename(`Tên tổ` = giai_doan_su_nghiep)
print(bang_tan_so_Age_theo_Target)

Giải nghĩa code: sử dụng các hàm giống như tạo bảng tần số các tổ của biến tuổi người vay chỉ them hàm gruop_bygiu1p tạo bảng tần số tần suất từng tổ theo 2 giái trị của biến mục tiêu trạng thái nợ xấu (Target)

Kết Quả

Kết quả : Phần lớn các cá nhân trong tất cả các giai đoạn sự nghiệp đều có tỷ lệ không bị vỡ nợ (Target = 0 ), với tỷ lệ cao nhất là 97,32% ở nhóm Nghỉ hưu và thấp nhất 91,14% ở nhóm Khởi đầu sự nghiệp. Điều này cho thấy nhóm Khởi đầu và Thăng tiến có tỷ lệ vỡ nợ (Target = 1) cao hơn, phản ánh nguy cơ/đặc điểm nhất định tập trung ở lực lượng lao động trẻ và trung niên.

Trực quan

visualize_group_pie <- function(df, title = NULL) {
  if (is.null(title)) title <- "Biểu đồ tần số nhóm tuổi"
  df <- df %>%
    mutate(`Tên tổ` = factor(`Tên tổ`, levels = unique(`Tên tổ`))) %>%
    mutate(.label = ifelse(`Tần suất` >= 1, paste0(`Tần suất`, "%"), ""))
  
  p <- ggplot(df, aes(x = "", y = `Tần suất`, fill = factor(Target))) +
    geom_col(width = 1) +
    coord_polar(theta = "y") +
    facet_wrap(~ `Tên tổ`, ncol = 2) +
    geom_text(aes(label = .label), position = position_stack(vjust = 0.5), size = 3) +
    labs(title = title, fill = "Target") +
    theme_void() +
    theme(plot.title = element_text(hjust = 0.5, size = 13),
          strip.text = element_text(size = 10))
  p}
visualize_group_pie(bang_tan_so_Age_theo_Target)

Giải nghĩa code:

  • Dòng 1: Định nghĩa hàm visualize_group_pie để vẽ biểu đồ tần số cho nhiều biến, nhận hai tham số: df (bảng dữ liệu) và title (tiêu đề, không bắt buộc, mặc định NULL).
  • Dòng 2: Kiểm tra xem người dùng có cung cấp tiêu đề (title) hay không. Nếu không, gán tiêu đề mặc định “Biểu đồ tần số nhóm tuổi”, giúp hàm linh hoạt và biểu đồ luôn có tiêu đề.
  • Cụm code từ dòng 3 đến 5: : Xử lý dữ liệu bằng chuỗi toán tử dường ống %>% dẫn thẳng dữ liệu đến dể thực hiện thao tác : Dòng 3 chức năng lấy bảng dữ liệu df làm đầu vào cho các bước tiếp theo, kết quả cuối cùng gán lại cho df; Dòng 4 sẽ chuyển cột Tên tổ thành kiểu factor và giữ nguyên thứ tự xuất hiện ban đầu, tránh R tự sắp xếp theo chữ cái. Cuố cùng dòng 5 là tạo cột .labelchứa nhãn phần trăm. Nếu giá trị ≥ 1, ghép số với %; nếu < 1, để chuỗi rỗng, tránh hiển thị nhãn quá nhỏ gây rối biểu đồ
  • Dòng 7: Bắt đầu quá trình vẽ biểu đồ và lưu kết quả vào biến p. Sử dụng bảng dữ liệu df đã được xử lý(ggplot(df, …)) aes(…): “Ánh xạ (mapping)” các cột dữ liệu vào thuộc tính hình ảnh. Cột trục hoành trống là một kỹ thuật để tạo biểu đồ tròn. Nó tạo ra một biểu đồ cột xếp chồng duy nhất. Chiều cao của các phần trong cột đó (sẽ trở thành các phần trong hình tròn) được quyết định bởi giá trị Tần suất (y = Tần suất); Màu tô của mỗi miảng hình tròn sẽ phụ thuộc vào giá trị của cột Target (0 hoặc 1) (fill = factor(Target))
  • Dòng 8 : Vẽ biểu đồ cột (geom_col). width = 1 làm cho cột chiếm toàn bộ không gian, tạo ra một hình tròn không có lỗ hổng ở giữa sau khi biến đổi.
  • Dòng 9: Lớp Đây là lệnh biến biểu đồ cột thành biểu đồ tròn. Nó lấy biểu đồ cột và “uốn cong” nó thành một vòng tròn, trong đó góc của mỗi miếng bánh (theta) được xác định bởi giá trị trên trục y (chính là Tần suất).
  • Dòng 10 :Nó chia dữ liệu theo các giá trị trong cột Tên tổ và vẽ một biểu đồ tròn riêng biệt cho mỗi nhóm tuổi, sau đó sắp xếp chúng thành một lưới có 2 cột (ncol = 2).
  • Dòng 11:Thêm nhãn phần trăm lên trên các miảng hình tròn ; Nội dung văn bản được lấy từ cột .label đã tạo ở bước trên (aes(label = .label)); Một kỹ thuật để đặt nhãn số nằm ngay ngắn ở chính giữa mỗi mảng hình tròn (position = position_stack(vjust = 0.5))
  • Dòng 12: Đặt tiêu đề chính cho toàn bộ cụm biểu đồ và đặt tên cho phần chú giải màu sắc.
  • Dòng 13: Áp dụng một giao diện trống, loại bỏ tất cả các trục, đường lưới và nền, rất phù hợp cho biểu đồ tròn.
  • Cụm code từ dòng 14 đến 15: Tinh chỉnh thêm giao diện: dòng 14 căn giữa và đặt kích thước cho tiêu đề chính, dòng 15 đặt kích thước chữ cho tiêu đề của từng biểu đồ nhỏ (ví dụ: “Khởi đầu sự nghiệp”, “Thăng tiến”, v.v.).
  • Dòng 16: trả về kết quả đối tượng biểu đồ p đã hoàn chỉnh.
  • Dòng 17 :Đây là dòng lệnh thực thi hàm. Nó gọi hàm visualize_group_pie và truyền vào bảng dữ liệu bang_tan_so_Age_theo_Target để bắt đầu toàn bộ quá trình vẽ và hiển thị biểu đồ. Kết quả : thông quan kết quả hình trực quan ta có nhận xét phần kết luận trên đã đúng và việc trực quan hóa giúp chúng ta xác nhận Tỷ lệ không vỡ nợ Target = 0 ở bốn nhóm đều trên 90%. Nhóm Nghỉ hưu cao nhất khoảng 97.3%. Nhóm Khởi đầu sự nghiệp thấp nhất khoảng 91.1%. Vì vậy hai nhóm Khởi đầu và Thăng tiến có tỷ lệ vỡ nợ (Target = 1) cao hơn các nhóm còn lại.

1.3.4.2 Biến Util (Tỷ lệ sử dụng hạn mức tín dụng)

Biến Util phản ánh mức độ sử dụng các khoản tín dụng quay vòng so với tổng hạn mức được cấp. Một tỷ lệ cao cho thấy khách hàng đang phụ thuộc nhiều vào nợ không có tài sản đảm bảo, có thể là dấu hiệu của áp lực tài chính hoặc quản lý nợ kém, làm tăng rủi ro vỡ nợ. Việc phân tổ nhằm đánh giá mức độ rủi ro theo từng nhóm sử dụng hạn mức.

Phân tổ

Biến Util được phân thành 4 tổ dựa trên mức độ sử dụng hạn mức và rủi ro tiềm ẩn: Rất thấp (0-0.2), Thấp (0.2-0.5), Cao (0.5-0.8) và Rất cao (0.8-1).

Tổ Khoảng Util Tên tổ Mức độ rủi ro
Tổ 1 0 – 0.2 Sử dụng thấp Rủi ro thấp
Tổ 2 0.2 – 0.5 Sử dụng trung bình Rủi ro trung bình
Tổ 3 0.5 – 0.8 Sử dụng cao Rủi ro cao
Tổ 4 0.8 – 1 Sử dụng rất cao Rủi ro rất cao

Code:

credit_clean$muc_do_su_dung_hm <- cut(credit_clean$Util,
                    breaks = c(-0.01, 0.2, 0.5, 0.8, 1),
                    labels = c("Sử dụng thấp",
                              "Sử dụng trung bình",
                              "Sử dụng cao",
                              "Sử dụng rất cao"),
                    include.lowest = TRUE,
                    right = TRUE)

Giải nghĩa code:

  • Dòng 1: Tạo một cột mới tên muc_do_su_dung_hm trong bảng credit_clean. Toán tử <- gán kết quả từ hàm cut vào cột mới này.
  • Dòng 2: Tham số breaks xác định các điểm chia để tạo ra 4 khoảng giá trị cho Util. Giá trị -0.01 được thêm vào để đảm bảo giá trị 0 được bao gồm trong khoảng đầu tiên.
  • Cụm code từ dòng 3 đến 6: Tham số labels gán nhãn cho các khoảng đã tạo, tương ứng với mức độ sử dụng hạn mức.
  • Dòng 7: include.lowest = TRUE đảm bảo giá trị nhỏ nhất (-0.01) được bao gồm trong khoảng đầu tiên.
  • Dòng 8: right = TRUE xác định mỗi khoảng bao gồm giá trị bên phải (ví dụ: khoảng (0.2, 0.5] bao gồm 0.5 nhưng không bao gồm 0.2).

Ý nghĩa: Phân tổ giúp định lượng rủi ro tín dụng một cách trực quan. Khách hàng sử dụng hạn mức càng cao thường có khả năng trả nợ thấp hơn do phụ thuộc nhiều vào nợ quay vòng và có ít dư địa tài chính để ứng phó với các cú sốc.

Kết quả sử dụng hàm tính tần số các tổ

bang_ket_qua_Util <- credit_clean %>%
  count(muc_do_su_dung_hm, name = "Tần số") %>%
  mutate(`Tần suất` = round((`Tần số` / sum(`Tần số`)) * 100, 2)) %>%
  rename(`Tên tổ` = muc_do_su_dung_hm)
print(bang_ket_qua_Util)

Giải nghĩa:

  • Dòng 1: Tạo biến bang_ket_qua_Util và sử dụng pipe %>% để chuyển dữ liệu từ credit_clean đến các hàm xử lý tiếp theo.
  • Dòng 2: Hàm count đếm số lượng quan sát cho mỗi nhóm duy nhất trong cột muc_do_su_dung_hm và lưu kết quả vào cột “Tần số”.
  • Dòng 3: Hàm mutate tạo cột mới “Tần suất” bằng cách lấy tần số của từng nhóm chia cho tổng số quan sát và nhân 100, sau đó làm tròn đến 2 chữ số thập phân.
  • Dòng 4: Hàm rename đổi tên cột muc_do_su_dung_hm thành “Tên tổ” cho rõ nghĩa.
  • Dòng 5: In bảng kết quả ra màn hình.

Kết qủa:

Đọc kết quả:Kết quả cho thấy phần lớn khách hàng thuộc nhóm “sử dụng thấp” chiếm 53.86%, tức hơn một nửa tổng số mẫu. Nhóm “sử dụng trung bình” chiếm 19.38%, trong khi “sử dụng cao” và “rất cao” lần lượt chiếm 11.92% và 14.84%. Kết luận: Nhìn chung, mức sử dụng tín dụng của khách hàng còn khá thận trọng, tập trung ở mức thấp và trung bình. Chỉ một tỷ lệ nhỏ có xu hướng sử dụng hạn mức cao hoặc rất cao, cho thấy rủi ro tín dụng tập trung ở nhóm nhỏ nhưng có khả năng tác động mạnh nếu họ mất khả năng trả nợ.

1.3.4.2.1 Trực quan hóa kết quả phân tổ biến đơn
visualize_group(bang_ket_qua_Util, title = "Biểu đồ tần số theo mức độ sử dụng hạn mức")

Giải nghĩa code: Hàm visualize_group được tái sử dụng từ phần trước, vẽ biểu đồ cột thể hiện tần số của các nhóm Util. Tham số title được tùy chỉnh để phù hợp với ngữ cảnh.

Kết quả: Biểu đồ cột giúp hình dung rõ ràng sự phân bố của khách hàng ở biến tỷ lệ nợ trên htu nhập các mức độ sử dụng hạn mức. Nhóm Sử dụng thấp nghĩa là Tỷ lệ sử dụng tín dụng trên hạn mức dưới 20% cá tần số xuất hiện cao nhất, ngược lại nhóm Sử dụng rất cáo và Sử dụng cao có tần số thấp nhất và thấp thứ 2 nhưng lại là nhóm cần được giám sát chặt chẽ nhất, qua đó cũng thể hiện được kết quả của bảng tần số phía trên.

1.3.4.2.2 Tần số các tổ trong biến mục tiêu

Phân tích này nhằm trả lời câu hỏi: Tỷ lệ vỡ nợ (Target=1) ở nhóm sử dụng hạn mức nào là cao nhất?

bang_tan_so_Util_theo_Target <- credit_clean %>%
  group_by(muc_do_su_dung_hm, Target) %>%
  summarise(`Tần số` = n(), .groups = "drop") %>%
  group_by(muc_do_su_dung_hm) %>%
  mutate(`Tần suất` = round(`Tần số` / sum(`Tần số`) * 100, 2)) %>%
  rename(`Tên tổ` = muc_do_su_dung_hm)
print(bang_tan_so_Util_theo_Target)

Giải nghĩa code: Code tương tự như với biến Age, sử dụng group_by lồng nhau: đầu tiên theo nhóm sử dụng hạn mức và trạng thái vỡ nợ (Target), sau đó theo từng nhóm sử dụng hạn mức để tính tần suất phần trăm trong từng nhóm.

Kết luận: Tỷ lệ khách hàng vỡ nợ (Target = 1) tăng dần theo mức độ sử dụng tín dụng: Sử dụng thấp cố tỷ lệ thấp nhất chỉ 2.21% , Sử dụng cao và Sử dụng rất cao: chiếm tỉ lệ cao nhất lần lượt là 10.83% và 18.30% Kết luận: Mức sử dụng tín dụng càng cao thì khả năng vỡ nợ càng lớn, cho thấy mối quan hệ tỷ lệ thuận giữa rủi ro tín dụng và mức độ sử dụng hạn mức. Nhóm “Sử dụng rất cao” là đối tượng rủi ro trọng tâm, cần được theo dõi kỹ và có biện pháp quản lý tín dụng chặt chẽ hơn.

Trực quan

visualize_group_pie(bang_tan_so_Util_theo_Target, title = "Tỷ lệ vỡ nợ theo mức độ sử dụng hạn mức")

Giải nghĩa code: Hàm visualize_group_pie được tái sử dụng để vẽ một loạt biểu đồ tròn, mỗi biểu đồ tương ứng với một nhóm Util, cho thấy tỷ lệ % vỡ nợ và không vỡ nợ trong nội bộ nhóm đó.

Kết quả: Trực quan hóa bằng biểu đồ tròn khẳng định mạnh mẽ kết luận từ bảng số liệu. Màu đỏ (Targe=0) trong biểu đồ tròn của nhóm “Sử dụng rất cao” sẽ chiếm diện nhỏ lớn hơn rõ rệt so với các nhóm còn lại, minh họa trực quan cho rủi ro cao. ngược lai phần màu đỏ thể hiện không bị nợ xấu cao nhất ở nhóm sủ dụng thấp đúng với thực tế rằng càn ít sử dụng thẻ tín dụng nguy cơ nợ xấu càng ít.

1.3.4.3 Biến DebtRatio (Tỷ lệ nợ)

Biến DebtRatio đo lường tỷ lệ giữa các khoản nợ hàng tháng so với tổng thu nhập. Một tỷ lệ cao cho thấy phần lớn thu nhập của khách hàng đã được dùng để trả nợ, khiến họ dễ bị tổn thương trước các biến động tài chính và làm giảm khả năng trả nợ các khoản tín dụng mới. Việc phân tổ nhằm đánh giá mức độ rủi ro theo từng nhóm gánh nặng nợ.

Phân tổ

Biến DebtRatio được phân thành 4 tổ dựa trên mức độ gánh nặng nợ: Thấp (0-0.3), Trung bình (0.3-0.6), Cao (0.6-0.9) và Rất cao (0.9-10).

Tổ Khoảng DebtRatio Tên tổ Mức độ gánh nặng nợ
Tổ 1 0 – 0.3 Gánh nặng nợ thấp Rủi ro thấp
Tổ 2 0.3 – 0.6 Gánh nặng nợ trung bình Rủi ro trung bình
Tổ 3 0.6 – 0.9 Gánh nặng nợ cao Rủi ro cao
Tổ 4 0.9 – 10 Gánh nặng nợ rất cao Rủi ro rất cao

Code:

credit_clean$muc_do_ganh_nang_no <- cut(credit_clean$DebtRatio,
                    breaks = c(-0.01, 0.3, 0.6, 0.9, 10),
                    labels = c("Gánh nặng nợ thấp",
                              "Gánh nặng nợ trung bình",
                              "Gánh nặng nợ cao",
                              "Gánh nặng nợ rất cao"),
                    include.lowest = TRUE,
                    right = TRUE)

Giải nghĩa code: (Tương tự biến Util):

  • Cấu trúc hàm cut và các tham số giống hệt với biến Util
  • Điểm khác biệt duy nhất: giá trị breaks cuối cùng là 10 (thay vì 1) để phù hợp với phạm vi thực tế của biến DebtRatio

Ý nghĩa: Phân tổ giúp định lượng rủi ro tín dụng theo nhóm dựa trên gánh nặng nợ hiện tại. Khách hàng có tỷ lệ nợ trên thu nhập DebtRatio càng cao thường có khả năng trả nợ thấp hơn do thu nhập còn lại sau khi trả nợ không đủ để trang trải chi phí sinh hoạt và tích lũy.

Kết quả sử dụng hàm tính tần số các tổ

bang_ket_qua_DebtRatio <- credit_clean %>%
  count(muc_do_ganh_nang_no, name = "Tần số") %>%
  mutate(`Tần suất` = round((`Tần số` / sum(`Tần số`)) * 100, 2)) %>%
  rename(`Tên tổ` = muc_do_ganh_nang_no)
print(bang_ket_qua_DebtRatio)

Giải nghĩa: (Giống hệt giải nghĩa biến Util)

  • Chuỗi xử lý sử dụng các hàm count, mutaterename hoàn toàn tương tự

Đọc kết quả: Kết quả cho thấy phần lớn khách hàng thuộc nhóm “Gánh nặng nợ thấp” chiếm 51.31%, tức hơn một nửa tổng số mẫu. Nhóm “Gánh nặng nợ trung bình” chiếm 32.97%, trong khi “Gánh nặng nợ cao” và “rất cao” lần lượt chiếm 9.10% và 6.62%.

Kết luận: Nhìn chung, đa số khách hàng có mức gánh nặng nợ ở mức chấp nhận được (thấp và trung bình). Tuy nhiên, vẫn tồn tại khoảng 15.72% khách hàng có gánh nặng nợ từ cao đến rất cao, đây là nhóm có rủi ro tín dụng tiềm ẩn cần được theo dõi sát sao.

1.3.4.3.1 Trực quan hóa kết quả phân tổ biến đơn
visualize_group(bang_ket_qua_DebtRatio, title = "Biểu đồ tần số theo mức độ gánh nặng nợ")

Giải nghĩa code: (Giống hệt biến Util) - Hàm visualize_group được tái sử dụng hoàn toàn, chỉ thay đổi tiêu đề cho phù hợp

Kết quả: Biểu đồ cột giúp hình dung rõ ràng sự phân bố của khách hàng across các mức độ gánh nặng nợ. Nhóm “Gánh nặng nợ thấp” có tần số xuất hiện cao nhất, ngược lại nhóm “Gánh nặng nợ rất cao” và “Gánh nặng nợ cao” có tần số thấp hơn nhưng lại là nhóm cần được giám sát chặt chẽ nhất, qua đó cũng thể hiện được kết quả của bảng tần số phía trên.

1.3.4.3.2 Tần số các tổ trong biến mục tiêu

Phân tích này nhằm trả lời câu hỏi: Tỷ lệ vỡ nợ (Target=1) ở nhóm gánh nặng nợ nào là cao nhất?

bang_tan_so_DebtRatio_theo_Target <- credit_clean %>%
  group_by(muc_do_ganh_nang_no, Target) %>%
  summarise(`Tần số` = n(), .groups = "drop") %>%
  group_by(muc_do_ganh_nang_no) %>%
  mutate(`Tần suất` = round(`Tần số` / sum(`Tần số`) * 100, 2)) %>%
  rename(`Tên tổ` = muc_do_ganh_nang_no)
print(bang_tan_so_DebtRatio_theo_Target)

Giải nghĩa code: (Giống hệt biến Util) - Sử dụng group_by lồng nhau hoàn toàn tương tự: đầu tiên theo nhóm gánh nặng nợ và trạng thái vỡ nợ, sau đó theo từng nhóm để tính tần suất phần trăm

Kết luận: Tỷ lệ khách hàng vỡ nợ (Target = 1) tăng dần theo mức độ gánh nặng nợ: Gánh nặng nợ thấp có tỷ lệ thấp nhất chỉ 5.08%, Gánh nặng nợ trung bình 6.23%, Gánh nặng nợ cao 9.38% và Gánh nặng nợ rất cao có tỷ lệ cao nhất là 9.97%.

Kết luận: Mức gánh nặng nợ càng cao thì khả năng vỡ nợ càng lớn, cho thấy mối quan hệ tỷ lệ thuận giữa rủi ro tín dụng và tỷ lệ nợ trên thu nhập. Nhóm “Gánh nặng nợ rất cao” là đối tượng rủi ro trọng tâm với tỷ lệ vỡ nợ gần 10%, cần được đánh giá kỹ lưỡng về khả năng trả nợ trước khi phê duyệt khoản vay mới.

Trực quan

visualize_group_pie(bang_tan_so_DebtRatio_theo_Target, title = "Tỷ lệ vỡ nợ theo mức độ gánh nặng nợ")

Giải nghĩa code: (Giống hệt biến Util): - Hàm visualize_group_pie được tái sử dụng hoàn toàn để vẽ biểu đồ tròn phân tầng

Kết quả: Trực quan hóa bằng biểu đồ tròn khẳng định mạnh mẽ kết luận từ bảng số liệu. Màu đỏ (Target=1) trong biểu đồ tròn của nhóm “Gánh nặng nợ rất cao” chiếm diện tích lớn hơn rõ rệt so với các nhóm còn lại, minh họa trực quan cho rủi ro cao. Ngược lại, phần màu xanh thể hiện không bị nợ xấu cao nhất ở nhóm gánh nặng nợ thấp, đúng với thực tế rằng khách hàng có ít nợ hiện tại thì nguy cơ nợ xấu càng thấp.

1.3.4.4 Biến Income (Thu nhập hàng tháng)

Thu nhập là chỉ số cơ bản thể hiện năng lực tài chính và khả năng trả nợ. Thu nhập càng cao thường đi kèm với sự ổn định tài chính tốt hơn và khả năng chịu đựng các khoản nợ cao hơn.

phân tổ

biến income được phân thành 4 tổ dựa trên mức thu nhập: thấp (0-30000), trung bình (30000-60000), khá (60000-90000) và cao (90000-trở lên).

tổ khoảng income tên tổ mức độ thu nhập
tổ 1 0 – 30000 thu nhập thấp khả năng tài chính hạn chế
tổ 2 30000 – 60000 thu nhập trung bình khả năng tài chính ổn định
tổ 3 60000 – 90000 thu nhập khá khả năng tài chính tốt
tổ 4 90000 – 100000 thu nhập cao khả năng tài chính rất tốt

code:

credit_clean$muc_thu_nhap <- cut(credit_clean$Income,
                    breaks = c(-1, 30000, 60000, 90000, 100000),
                    labels = c("thu nhập thấp",
                              "thu nhập trung bình",
                              "thu nhập khá",
                              "thu nhập cao"),
                    include.lowest = TRUE,
                    right = TRUE)

Giải nghĩa code: (tương tự biến debtratio)

  • Cấu trúc hàm cut và các tham số giống hệt với biến debtratio
  • Khác biệt: sử dụng các điểm breaks phù hợp với phạm vi thu nhập và giá trị cuối cùng là 100000 để đảm bảo bao trọn phạm vi dữ liệu

Ý nghĩa: Phân tổ giúp đánh giá rủi ro tín dụng dựa trên năng lực tài chính. khách hàng có thu nhập càng cao thường có khả năng trả nợ tốt hơn do có nhiều nguồn lực tài chính để đáp ứng các nghĩa vụ nợ.

Kết quả sử dụng hàm tính tần số các tổ

bang_ket_qua_Income <- credit_clean %>%
  count(muc_thu_nhap, name = "Tần số") %>%
  mutate(`Tần suất` = round((`Tần số` / sum(`Tần số`)) * 100, 2)) %>%
  rename(`Tên tổ` = muc_thu_nhap)
print(bang_ket_qua_Income)

Giải nghĩa: (giống hệt giải nghĩa biến debtratio)

  • Chuỗi xử lý sử dụng các hàm count, mutaterename hoàn toàn tương tự

Đọc kết quả: Kết quả cho thấy tuyệt đại đa số khách hàng (99.41%) thuộc nhóm “thu nhập thấp”. các nhóm còn lại chiếm tỷ lệ rất nhỏ: “thu nhập trung bình” 0.47%, “thu nhập khá” 0.11% và “thu nhập cao” chỉ 0.01%.

Kết luận: Phân phối thu nhập trong tập dữ liệu cực kỳ lệch, với gần như toàn bộ khách hàng thuộc nhóm thu nhập thấp. điều này cho thấy đối tượng khách hàng trong tập dữ liệu chủ yếu là những người có thu nhập khiêm tốn, có thể ảnh hưởng đến đánh giá rủi ro tín dụng tổng thể.

1.3.4.4.1 Trực quan hóa kết quả phân tổ biến đơn
visualize_group(bang_ket_qua_Income, title = "Biểu đồ tần số theo mức thu nhập")

Giải nghĩa code: (giống hệt biến debtratio) dùng hàm visualize_group được tái sử dụng hoàn toàn, chỉ thay đổi tiêu đề cho phù hợp

Kết quả: Biểu đồ cột cho thấy sự chênh lệch cực lớn giữa nhóm “thu nhập thấp” so với các nhóm còn lại. cột của nhóm thu nhập thấp chiếm gần như toàn bộ biểu đồ, trong khi các nhóm thu nhập khác có tần số rất thấp, gần như không thể quan sát rõ trên biểu đồ.

1.3.4.4.2 Tần số các tổ trong biến mục tiêu

Phân tích này nhằm trả lời câu hỏi: tỷ lệ vỡ nợ (target=1) ở nhóm thu nhập nào là cao nhất?

bang_tan_so_income_theo_target <- credit_clean %>%
  group_by(muc_thu_nhap, Target) %>%
  summarise(`Tần số` = n(), .groups = "drop") %>%
  group_by(muc_thu_nhap) %>%
  mutate(`Tần suất` = round(`Tần số` / sum(`Tần số`) * 100, 2)) %>%
  rename(`Tên tổ` = muc_thu_nhap)
print(bang_tan_so_income_theo_target)

Giải nghĩa code: (giống hệt biến Debtratio)

  • Sử dụng group_by lồng nhau hoàn toàn tương tự: đầu tiên theo nhóm thu nhập và trạng thái vỡ nợ, sau đó theo từng nhóm để tính tần suất phần trăm

Kết lquả: Tỷ lệ vỡ nợ giữa các nhóm thu nhập có sự khác biệt: nhóm “Thu nhập thấp” có tỷ lệ vỡ nợ 6.18%, trong khi các nhóm “Thu nhập trung bình” và “Thu nhập khá” lần lượt là 4.93% và 5.26%. đặc biệt, nhóm “thu nhập cao” không có trường hợp vỡ nợ nào 2%.

Kết luận: Mặc dù số lượng mẫu ở các nhóm thu nhập cao rất ít, nhưng xu hướng chung cho thấy khách hàng thu nhập thấp có tỷ lệ vỡ nợ cao hơn. Nhóm thu nhập cao với 0% vỡ nợ cho thấy thu nhập thực sự là yếu tố quan trọng trong đánh giá rủi ro tín dụng, tuy nhiên cần thận trọng do kích thước mẫu quá nhỏ ở các nhóm thu nhập cao.

Trực quan:

visualize_group_pie(bang_tan_so_income_theo_target, title = "Tỷ lệ vỡ nợ theo mức thu nhập")

Giải nghĩa code: Giống hệt biến trước đó dùng hàm đã tạo visualize_group_pie được tái sử dụng hoàn toàn để vẽ biểu đồ tròn phân tầng Kết quả: Trực quan hóa bằng biểu đồ tròn cho thấy rõ sự chiếm ưu thế của nhóm thu nhập thấp trong toàn bộ tập dữ liệu. ở nhóm thu nhập thấp, màu xanh vỡ nợ (Target=1) chiếm tỷ lệ nhỏ nhưng vẫn hiện diện, trong khi ở nhóm thu nhập cao hoàn toàn không có màu đỏ. các nhóm thu nhập trung bình và khá có tỷ lệ vỡ nợ tương đối thấp và ổn định.

1.3.4.5 Biến Dependents (Số người phụ thuộc)

Số người phụ thuộc phản ánh gánh nặng tài chính và trách nhiệm gia đình. những khách hàng có nhiều người phụ thuộc thường phải đối mặt với áp lực chi tiêu cao hơn, dẫn đến khả năng dự phòng tài chính thấp hơn và có thể ảnh hưởng đến khả năng trả nợ.

Phân tổ:

Biến số người phụ thuộc tài chính (Dependents) là biến rời rạc, nên chúng ta phân tổ trực tiếp theo số lượng người phụ thuộc.

tổ số người phụ thuộc tên tổ mức độ gánh nặng tài chính
tổ 1 0 không có người phụ thuộc gánh nặng thấp
tổ 2 1 một người phụ thuộc gánh nặng trung bình
tổ 3 2 hai người phụ thuộc gánh nặng khá cao
tổ 4 > 3 từ ba người phụ thuộc trở lên gánh nặng cao

Code:

credit_clean$nhom_nguoi_phu_thuoc <- cut(credit_clean$Dependents,
                    breaks = c(-0.1, 0.1, 1.1, 2.1, max(credit_clean$Dependents)),
                    labels = c("Không có người phụ thuộc",
                              "Một người phụ thuộc",
                              "Hai người phụ thuộc",
                              "Từ ba người phụ thuộc trở lên"),
                    include.lowest = TRUE,
                    right = FALSE)

Giải nghĩa code: (Tương tự biến income):

  • cấu trúc hàm cut phân tổ giống với các biến trước
  • Điểm khác biệt: sử dụng right = FALSE để các khoảng bao gồm giá trị bên trái, phù hợp với việc phân nhóm các số nguyên
  • Sử dụng max(credit_clean$dependents) để tự động xác định giá trị lớn nhất của biến số người phụ thuco56 tài chính

Ý nghĩa: phân tổ giúp đánh giá rủi ro tín dụng dựa trên gánh nặng gia đình. khách hàng có càng nhiều người phụ thuộc thường có áp lực tài chính cao hơn, ảnh hưởng đến khả năng trả nợ.

Kết quả sử dụng hàm tính tần số các tổ:

bang_ket_qua_dependents <- credit_clean %>%
  count(nhom_nguoi_phu_thuoc, name = "Tần số") %>%
  mutate(`Tần suất` = round((`Tần số` / sum(`Tần số`)) * 100, 2)) %>%
  rename(`Tên tổ` = nhom_nguoi_phu_thuoc)
print(bang_ket_qua_dependents)

Giải nghĩa: (Giống hệt giải nghĩa biến income) Chuỗi xử lý sử dụng các hàm count, mutaterename hoàn toàn tương tự. Kết quả:

Kết quả: kết quả cho thấy đa số khách hàng không có người phụ thuộc (55.23%), nhóm có một người phụ thuộc chiếm 20.08%, hai người phụ thuộc chiếm 14.71%, và từ ba người phụ thuộc trở lên chiếm 9.98%.

Kết luận: hơn một nửa khách hàng (55.23%) không có người phụ thuộc, cho thấy khả năng tài chính linh hoạt hơn. các nhóm có người phụ thuộc phân bố giảm dần theo số lượng, với khoảng 45% khách hàng có ít nhất một người phụ thuộc.

1.3.4.5.1 Trực quan hóa kết quả phân tổ biến đơn
visualize_group(bang_ket_qua_dependents, title = "Biểu đồ tần số theo số người phụ thuộc")

Giải nghĩa code: (giống hệt biến trước đó ) dùng hàm visualize_group được tái sử dụng hoàn toàn, chỉ thay đổi tiêu đề cho phù hợp

Kết quả: Biểu đồ cột giúp hình dung rõ ràng sự phân bố của khách hàng theo số người phụ thuộc. nhóm “Không có người phụ thuộc” có tần số cao nhất (64,774), trong khi nhóm “Từ ba người phụ thuộc trở lên” có tần số thấp nhất (11,707), phản ánh xu hướng giảm dần khi số người phụ thuộc tăng.

1.3.4.5.2 Tần số các tổ trong biến mục tiêu

phân tích này nhằm trả lời câu hỏi: tỷ lệ vỡ nợ (target=1) ở nhóm số người phụ thuộc nào là cao nhất?

bang_tan_so_dependents_theo_target <- credit_clean %>%
  group_by(nhom_nguoi_phu_thuoc, Target) %>%
  summarise(`Tần số` = n(), .groups = "drop") %>%
  group_by(nhom_nguoi_phu_thuoc) %>%
  mutate(`Tần suất` = round(`Tần số` / sum(`Tần số`) * 100, 2)) %>%
  rename(`Tên tổ` = nhom_nguoi_phu_thuoc)
print(bang_tan_so_dependents_theo_target)

Giải nghĩa code: (giống hệt việc tạo bảng tần số với biến mục tiêu các phần trước ) Dùng group_by lồng nhau hoàn toàn tương tự: đầu tiên theo nhóm người phụ thuộc tài chính và trạng thái vỡ nợ, sau đó theo từng nhóm để tính tần suất phần trăm

Kết luận: Tỷ lệ khách hàng vỡ nợ (Target = 1) tăng dần theo số người phụ thuộc: không có người phụ thuộc 5.28%, một người phụ thuộc 6.63%, hai người phụ thuộc 7.33%, và từ ba người phụ thuộc trở lên có tỷ lệ cao nhất 8.45%.

Kết luận: Số người phụ thuộc càng cao thì khả năng vỡ nợ càng lớn, cho thấy mối quan hệ tỷ lệ thuận rõ rệt giữa rủi ro tín dụng và gánh nặng gia đình. nhóm “từ ba người phụ thuộc trở lên” là đối tượng rủi ro trọng tâm với tỷ lệ vỡ nợ cao hơn 60% so với nhóm không có người phụ thuộc.

Trực quan :

visualize_group_pie(bang_tan_so_dependents_theo_target, title = "Tỷ lệ vỡ nợ theo số người phụ thuộc")

Giải nghĩa code: Giống hệt việc trực quan hóa biến trước đó theo biến mục tiêu dùng hàm tự tạo visualize_group_pie được tái sử dụng hoàn toàn để vẽ biểu đồ tròn phân tầng

Kết quả: Trực quan hóa bằng biểu đồ tròn khẳng định mạnh mẽ kết luận từ bảng số liệu. màu xanh (Target=1) trong biểu đồ tròn của nhóm “Từ ba người phụ thuộc trở lên” chiếm diện tích lớn hơn rõ rệt so với các nhóm còn lại, minh họa trực quan cho rủi ro cao. Ngược lại, phần màu đỏ thể hiện không bị nợ xấu giảm dần khi số người phụ thuộc tăng, đúng với thực tế rằng khách hàng có ít người phụ thuộc thì nguy cơ nợ xấu càng thấp.

1.3.5 KẾT LUẬN

Qua quá trình phân tích thống kê và trực quan hóa dữ liệu, nghiên cứu đã rút ra được những kết luận quan trọng về hồ sơ khách hàng và các yếu tố ảnh hưởng đến rủi ro vỡ nợ:

  1. Đặc điểm chung của tập dữ liệu: Tập dữ liệu có sự mất cân bằng lớp (class imbalance) rõ rệt , với đại đa số khách hàng (93.8%) thuộc nhóm trả nợ đúng hạn (Target = 0) và chỉ một tỷ lệ nhỏ (6.2%) thuộc nhóm vỡ nợ (Target = 1). Điều này đặt ra yêu cầu cần xử lý cân bằng dữ liệu khi xây dựng mô hình dự báo. Các biến liên tục như DebtRatio, IncomeUtil đều có phân phối lệch phải mạnh, cho thấy phần lớn khách hàng có giá trị ở mức thấp, nhưng tồn tại một nhóm nhỏ có giá trị cực cao (các điểm ngoại lai), kéo giá trị trung bình lên. Đây là những đối tượng tiềm ẩn rủi ro cần được quan tâm đặc biệt.

  2. Mối quan hệ giữa các biến độc lập và biến mục tiêu:

    • Tuổi (Age): Có mối tương quan nghịch với rủi ro vỡ nợ. Nhóm khách hàng trẻ tuổi (Khởi đầu sự nghiệp) có tỷ lệ vỡ nợ cao nhất (~8.9%), trong khi nhóm lớn tuổi (Nghỉ hưu) có tỷ lệ thấp nhất (~2.7%). Điều này phản ánh sự ổn định về tài chính và kinh nghiệm quản lý nợ tốt hơn ở nhóm khách hàng trung niên và cao tuổi.
    • Tỷ lệ sử dụng hạn mức (Util): Có mối tương quan thuận rất mạnh với rủi ro vỡ nợ. Khách hàng sử dụng càng nhiều hạn mức tín dụng thì nguy cơ vỡ nợ càng cao. Đặc biệt, nhóm “Sử dụng rất cao” (Util > 0.8) có tỷ lệ vỡ nợ lên đến 18.3%, gấp hơn 8 lần so với nhóm “Sử dụng thấp”.
    • Tỷ lệ nợ trên thu nhập (DebtRatio): Có mối tương quan thuận với rủi ro vỡ nợ. Khách hàng có gánh nặng nợ càng lớn thì khả năng trả nợ càng giảm. Nhóm “Gánh nặng nợ rất cao” có tỷ lệ vỡ nợ (~10%) cao gần gấp đôi so với nhóm “Gánh nặng nợ thấp”.
    • Thu nhập (Income): Có mối tương quan nghịch với rủi ro vỡ nợ. Khách hàng có thu nhập thấp có tỷ lệ vỡ nợ cao hơn. Tuy nhiên, cần thận trọng với kết luận này do số lượng mẫu ở nhóm thu nhập cao quá ít.
    • Số người phụ thuộc (Dependents): Có mối tương quan thuận với rủi ro vỡ nợ. Số người phụ thuộc càng nhiều, áp lực tài chính càng lớn, dẫn đến tỷ lệ vỡ nợ cao hơn. Nhóm có từ 3 người phụ thuộc trở lên có tỷ lệ vỡ nợ lên đến 8.45%.

1.4 Kết luận tổng quan cho toàn bộ đề tài

Dựa trên toàn bộ quá trình phân tích, đề tài đã đạt được những mục tiêu chính sau:

  1. Xác định được hồ sơ khách hàng rủi ro: Nghiên cứu đã vẽ nên chân dung điển hình của một khách hàng có nguy cơ vỡ nợ cao: Người trẻ tuổi, có thu nhập thấp, sử dụng gần hết hoặc vượt hạn mức tín dụng, có tỷ lệ nợ trên thu nhập cao và có nhiều người phụ thuộc về tài chính.

  2. Cung cấp cơ sở thực tiễn cho quản trị rủi ro: Các phát hiện từ phân tích thống kê cung cấp những hàm ý quan trọng cho các ngân hàng và tổ chức tín dụng:

    • Thẩm định chặt chẽ: Cần siết chặt việc thẩm định đối với các hồ sơ có đặc điểm thuộc nhóm rủi ro cao (đặc biệt là các khách hàng có UtilDebtRatio ở mức cao).
    • Giám sát chủ động: Thiết lập cơ chế cảnh báo sớm để theo dõi những khách hàng có sự gia tăng đột biến về tỷ lệ sử dụng hạn mức hoặc tỷ lệ nợ.
    • Định hướng sản phẩm: Phát triển các sản phẩm tín dụng phù hợp, các chương trình tư vấn tài chính cho từng phân khúc khách hàng (ví dụ: nhóm trẻ tuổi cần được hướng dẫn về quản lý nợ).
    • Phân bổ nguồn lực: Tập trung nguồn lực để quản lý và giám sát hiệu quả nhóm khách hàng rủi ro cao, từ đó tối ưu hóa chi phí và giảm thiểu tổn thất.
  3. Tạo nền tảng cho mô hình dự báo: Toàn bộ kết quả phân tích thống kê, đặc biệt là việc xác định các biến có tương quan mạnh với biến mục tiêu, là cơ sở vững chắc cho bước tiếp theo như việc Xây dựng và lựa chọn mô hình Machine Learning để dự báo khả năng vỡ nợ một cách chính xác và tự động. Các biến như Util, Age, DebtRatioDependents chắc chắn sẽ là những biến đầu vào quan trọng cho mô hình.

Hướng phát triển tiếp theo: Kết quả của chương này mở đường cho việc áp dụng các kỹ thuật xử lý dữ liệu (như xử lý ngoại lai, cân bằng dữ liệu bằng SMOTE) và tiến hành xây dựng các mô hình dự báo như Logistic Regression, Decision Tree, Random Forest, XGBoost… để không chỉ hiểu rõ mà còn có khả năng dự đoán chính xác rủi ro tín dụng, từ đó hỗ trợ ra quyết định trong hoạt động kinh doanh của các tổ chức tài chính.

Phần 2: Bộ dữ liệu mã chứng khoán BVH

2 BỘ DỮ LIỆU BÁO CÁO TÀI CHÍNH

Phần 2 của tiểu luận này trình bày phân tích chi tiết về dữ liệu tài chính của Tập đoàn Bảo Việt (mã chứng khoán: BVH) từ quý 1/2023 đến quý 2/2025, bao gồm 10 biến tài chính chính từ báo cáo kết quả kinh doanh.

2.1 GIỚI THIỆU

2.1.1 ĐỌC DỮ LIỆU TỪ FILE EXCEL

Lý do thực hiện: Đây là bước đầu tiên và quan trọng nhất trong quy trình phân tích dữ liệu. Việc đọc dữ liệu chính xác từ nguồn (file Excel) đảm bảo tất cả các phân tích tiếp theo được xây dựng trên nền tảng dữ liệu đáng tin cậy.

# KỸ THUẬT 1: ĐỌC DỮ LIỆU TỪ FILE EXCEL
# ----------------------------------------
# Sử dụng hàm read_excel() từ package readxl
# Tham số sheet: chỉ định tên sheet cần đọc
# Ưu điểm: Xử lý tốt file Excel, tự động detect kiểu dữ liệu

library(readxl)
library(dplyr)
library(tidyr)
library(ggplot2)
library(gridExtra)
library(knitr)

# Thiết lập thư mục làm việc - QUAN TRỌNG: đảm bảo đường dẫn đúng
setwd("C:\\Users\\Admin\\Documents\\tuhoc\\txp")

# Đọc 3 báo cáo tài chính quan trọng nhất
bcdt <- read_excel("BVH.xlsx", sheet = "Balance Sheet")      # Bảng Cân đối kế toán
kqkd <- read_excel("BVH.xlsx", sheet = "Income Statement")   # Báo cáo Kết quả kinh doanh  
lctt <- read_excel("BVH.xlsx", sheet = "Cash Flow")          # Báo cáo Lưu chuyển tiền tệ

Kỹ thuật: Sử dụng hàm read_excel() từ package readxl với tham số sheet để đọc từng bảng tính riêng biệt trong file Excel. với : library(readxl): Nạp (kích hoạt) gói thư viện readxl. Gói này cung cấp hàm read_excel() mà bạn sẽ dùng ở dưới, chuyên để đọc dữ liệu từ các tệp Excel (đuôi .xlsx hoặc .xls).

library(dplyr): Nạp gói dplyr. Đây là một gói cực kỳ mạnh mẽ và phổ biến để thao tác và biến đổi dữ liệu (ví dụ: lọc hàng, chọn cột, tạo cột mới, nhóm dữ liệu…).

library(tidyr): Nạp gói tidyr. Gói này dùng để “dọn dẹp” và tái cấu trúc dữ liệu, đặc biệt là chuyển đổi qua lại giữa định dạng dữ liệu “rộng” (wide) và “dài” (long) bằng các hàm như pivot_longer()pivot_wider()giúp ích chuẩn hóa bảng cho việc vẽ biểu đồ .

library(ggplot2) :Nạp gói ggplot2. Đây là gói thư viện tiêu chuẩn vàng của R để vẽ các biểu đồ thống kê phức tạp và đẹp mắt, dựa trên “Ngữ pháp của Đồ họa” (Grammar of Graphics) giúp ích việc vẽ biểu đồ các buốc sau.

library(gridExtra) Nạp gói gridExtra. Gói này cung cấp các công cụ hữu ích để sắp xếp, bố trí nhiều biểu đồ (thường là biểu đồ ggplot) vào chung một lưới (grid) hoặc một trang duy nhất.

library(knitr) Nạp gói knitr. Đây là công cụ chính để tạo báo cáo động (dynamic reports) trong R, ví dụ như trong R Markdown. Nó xuất (knit) code R, văn bản, và kết quả (bảng biểu, đồ thị) lại với nhau để xuất ra file báo cáo HTML, PDF, hoặc Word.

setwd("C:\\Users\\Admin\\Documents\\tuhoc\\txp") Đây là lệnh set working directory (Thiết lập Thư mục Làm việc). Nó ra lệnh cho R: "Kể từ bây giờ, hãy coi thư mục C:\Users\Admin\Documents\tuhoc\txp là vị trí làm việc mặc định".

bcdt <- read_excel(“BVH.xlsx”, sheet = “BalanceSheet”) # Bảng Cân đối kế toán

read_excel(...): Đây là hàm (từ gói readxl) thực hiện việc đọc file Excel.

"BVH.xlsx": Là tên file Excel bạn muốn đọc. R sẽ tìm file này trong thư mục làm việc đã setwd ở trên.

sheet = "BalanceSheet": Chỉ định cụ thể rằng R chỉ đọc dữ liệu từ sheet có tên chính xác là "BalanceSheet" bên trong file Excel "BVH.xlsx"

bcdt <- ...: Dấu <- là "toán tử gán". Nó lấy toàn bộ kết quả (dữ liệu) đọc được từ bên phải và lưu vào một biến (data frame là bcdt) ở bên trái.

-> Tóm lại: Dòng này đọc sheet "BalanceSheet" từ file "BVH.xlsx" và lưu toàn bộ bảng dữ liệu đó vào một biến tên là bcdt.

kqkd <- read_excel("BVH.xlsx", sheet = "IncomeStatement") # Báo cáo Kết quả kinh doanh: Tương tự như trên, dòng này đọc sheet có tên “IncomeStatement” từ cùng file “BVH.xlsx” và lưu dữ liệu vào biến tên là “kqkd”.

lctt <- read_excel("BVH.xlsx", sheet = "CashFlow") # Báo cáo Lưu chuyển tiền tệ: Tương tự, dòng này đọc sheet “CashFlow” từ file BVH.xlsx và lưu dữ liệu vào biến tên là lctt.

Giá trị kỹ thuật: Cho phép tái hiện toàn bộ phân tích khi có dữ liệu mới, tự động hóa quá trình nhập liệu và đảm bảo tính minh bạch của nguồn dữ liệu.

Kết luận : Qua bước này, chúng ta đã thành công trong việc nạp 3 báo cáo tài chính quan trọng vào môi trường R. Điều này giúp hiểu được cấu trúc cơ bản của dữ liệu tài chính doanh nghiệp và chuẩn bị cho các bước làm sạch, biến đổi dữ liệu tiếp theo.

2.1.2 KIỂM TRA KÍCH THƯỚC DỮ LIỆU

Lý do thực hiện: Đây là bước kiểm tra quan trọng ngay sau khi đọc dữ liệu, nhằm xác định chính xác quy mô và phạm vi của bộ dữ liệu. Việc này giúp đảm bảo không có sự thiếu hụt hoặc sai sót trong quá trình nhập liệu, đồng thời cung cấp cái nhìn tổng quan về cấu trúc dữ liệu trước khi tiến hành các phân tích chuyên sâu.

# KỸ THUẬT 2: KIỂM TRA KÍCH THƯỚC DỮ LIỆU
# -----------------------------------------
# Hàm dim() trả về vector [số_dòng, số_cột]
# Mỗi dòng: một chỉ tiêu tài chính
# Mỗi cột: một kỳ báo cáo (quý) + cột tên chỉ tiêu

cat("KÍCH THƯỚC BẢNG CÂN ĐỐI KẾ TOÁN:\n")
## KÍCH THƯỚC BẢNG CÂN ĐỐI KẾ TOÁN:
dim_bcdt <- dim(bcdt)
print(dim_bcdt)
## [1] 152  11
cat("\nKÍCH THƯỚC BÁO CÁO KẾT QUẢ KINH DOANH:\n")  
## 
## KÍCH THƯỚC BÁO CÁO KẾT QUẢ KINH DOANH:
dim_kqkd <- dim(kqkd)
print(dim_kqkd)
## [1] 84 11
cat("\nKÍCH THƯỚC BÁO CÁO LƯU CHUYỂN TIỀN TỆ:\n")
## 
## KÍCH THƯỚC BÁO CÁO LƯU CHUYỂN TIỀN TỆ:
dim_lctt <- dim(lctt)
print(dim_lctt)
## [1] 49 11
# GIẢI THÍCH KỸ THUẬT CHO THẦY:
# ------------------------------
# - dim() là hàm cơ bản trong R để kiểm tra kích thước dataframe
# - Kết quả trả về: [số dòng, số cột] 
# - Ứng dụng: Kiểm tra nhanh số lượng chỉ tiêu (dòng) và số kỳ báo cáo (cột)
# - Phát hiện lỗi: Nếu kích thước khác mong đợi → cần kiểm tra lại dữ liệu gốc

Kỹ thuật: Sử dụng hàm dim() để lấy kích thước của từng dataframe, kết hợp với hàm cat()print() để hiển thị kết quả một cách rõ ràng và có cấu trúc.

Với: - cat("KÍCH THƯỚC BẢNG CÂN ĐỐI KẾ TOÁN:\n"): Hàm cat() (viết tắt của concatenate) dùng để in thông báo văn bản ra màn hình. Ký tự \n tạo dòng mới, giúp định dạng đầu ra dễ đọc hơn.

  • dim(bcdt): Hàm dim() (dimensions) trả về một vector số gồm 2 giá trị: [số_dòng, số_cột] của dataframe. Đối với dữ liệu tài chính, mỗi dòng đại diện cho một chỉ tiêu tài chính, mỗi cột đại diện cho một kỳ báo cáo.

  • print(dim_bcdt): Hàm print() hiển thị giá trị của biến dim_bcdt ra console, cho phép người dùng trực tiếp quan sát kích thước của từng báo cáo tài chính.

Giá trị kỹ thuật: Cung cấp thông tin nhanh và chính xác về số lượng biến và quan sát trong mỗi báo cáo tài chính. Trong môi trường R Markdown, kỹ thuật này đảm bảo tính minh bạch của quy trình xử lý dữ liệu và cho phép người đọc dễ dàng hình dung được quy mô tổng thể của bộ dữ liệu trước khi đi sâu vào phân tích chi tiết.

Kết luận: Qua bước này, chúng ta đã xác minh thành công kích thước cụ thể của từng báo cáo tài chính, bao gồm Bảng cân đối kế toán, Báo cáo kết quả kinh doanh và Báo cáo lưu chuyển tiền tệ. Việc kiểm tra này không chỉ đảm bảo tính toàn vẹn của dữ liệu mà còn cung cấp nền tảng quan trọng để đánh giá mức độ chi tiết và độ tin cậy của thông tin tài chính mà doanh nghiệp công bố, từ đó tạo cơ sở vững chắc cho các bước phân tích tiếp theo.

2.1.3 KHẢO SÁT CẤU TRÚC DỮ LIỆU

Lý do thực hiện: Đây là bước khảo sát quan trọng nhằm hiểu rõ cấu trúc nội tại của dữ liệu trước khi tiến hành phân tích. Việc nắm bắt được kiểu dữ liệu, định dạng và giá trị mẫu giúp phát hiện sớm các vấn đề tiềm ẩn và lập kế hoạch xử lý dữ liệu phù hợp.

# KỸ THUẬT 3: KHẢO SÁT CẤU TRÚC DỮ LIỆU
# ---------------------------------------
# Hàm str(): Hiển thị cấu trúc internal của dataframe
# Hàm head(): Hiển thị 5 dòng đầu tiên

cat("CẤU TRÚC BÁO CÁO KẾT QUẢ KINH DOANH:\n")
## CẤU TRÚC BÁO CÁO KẾT QUẢ KINH DOANH:
str(kqkd)
## tibble [84 × 11] (S3: tbl_df/tbl/data.frame)
##  $ ...1   : chr [1:84] "Doanh thu từ phí bảo hiểm" "Thu phí bảo hiểm gốc" "Thu phí nhận tái bảo hiểm" "Tăng/(giảm) dư phòng phí bảo hiểm chưa được hưởng" ...
##  $ Q1 2023: num [1:84] 10498304763879 10584182384873 43957654998 -129835275992 -830932465110 ...
##  $ Q2 2023: num [1:84] 10538407611787 10293552198878 31819591595 213035821314 -810984911298 ...
##  $ Q3 2023: num [1:84] 10391709658069 10488841325514 65686318426 -162817985871 -828168908111 ...
##  $ Q4 2023: num [1:84] 11114691927996 11274879368561 71000939533 -231188380098 -831876412668 ...
##  $ Q1 2024: num [1:84] 10322671994713 10405763064606 41276495023 -124367564916 -874006536739 ...
##  $ Q2 2024: num [1:84] 10708089813599 10430938017626 60367957122 216783838851 -885774761191 ...
##  $ Q3 2024: num [1:84] 10473575370025 10608409899942 51123448452 -185957978369 -900818164203 ...
##  $ Q4 2024: num [1:84] 11165344381246 11146664997677 64803201619 -46123818050 -882898418406 ...
##  $ Q1 2025: num [1:84] 10675751900634 10751532426661 47432589766 -123213115793 -890516512505 ...
##  $ Q2 2025: num [1:84] 11364907796139 11226449607269 36044343695 102413845175 -898456165634 ...
cat("\n5 DÒNG ĐẦU TIÊN CỦA DỮ LIỆU:\n")
## 
## 5 DÒNG ĐẦU TIÊN CỦA DỮ LIỆU:
head(kqkd, 5)
…1 Q1 2023 Q2 2023 Q3 2023 Q4 2023 Q1 2024 Q2 2024 Q3 2024 Q4 2024 Q1 2025 Q2 2025
Doanh thu từ phí bảo hiểm 10,498,304,763,879 10,538,407,611,787 10,391,709,658,069 11,114,691,927,996 10,322,671,994,713 10,708,089,813,599 10,473,575,370,025 11,165,344,381,246 10,675,751,900,634 11,364,907,796,139
Thu phí bảo hiểm gốc 10,584,182,384,873 10,293,552,198,878 10,488,841,325,514 11,274,879,368,561 10,405,763,064,606 10,430,938,017,626 10,608,409,899,942 11,146,664,997,677 10,751,532,426,661 11,226,449,607,269
Thu phí nhận tái bảo hiểm 43,957,654,998 31,819,591,595 65,686,318,426 71,000,939,533 41,276,495,023 60,367,957,122 51,123,448,452 64,803,201,619 47,432,589,766 36,044,343,695
Tăng/(giảm) dư phòng phí bảo hiểm chưa được hưởng -129,835,275,992 213,035,821,314 -162,817,985,871 -231,188,380,098 -124,367,564,916 216,783,838,851 -185,957,978,369 -46,123,818,050 -123,213,115,793 102,413,845,175
Các khoản giảm trừ doanh thu -830,932,465,110 -810,984,911,298 -828,168,908,111 -831,876,412,668 -874,006,536,739 -885,774,761,191 -900,818,164,203 -882,898,418,406 -890,516,512,505 -898,456,165,634

Kỹ thuật: Sử dụng kết hợp hàm str() để phân tích cấu trúc và hàm head() để xem mẫu dữ liệu thực tế, cung cấp cái nhìn toàn diện về đặc điểm của bộ dữ liệu.

Với: - str(kqkd): Hàm str() (structure) cung cấp thông tin chi tiết về cấu trúc của dataframe kqkd. Hàm này hiển thị kiểu dữ liệu của từng cột (ví dụ: chr cho ký tự, num cho số), số lượng quan sát, số lượng biến, và ví dụ về giá trị trong mỗi cột.

  • head(kqkd, 5): Hàm head() trả về 5 dòng đầu tiên của dataframe kqkd. Tham số thứ hai (5) xác định số dòng cần hiển thị, cho phép người dùng trực tiếp quan sát dữ liệu thực tế, bao gồm tên các chỉ tiêu tài chính và giá trị tại các kỳ báo cáo khác nhau.

Giá trị kỹ thuật: Trong môi trường R Markdown, kỹ thuật này cung cấp cái nhìn tổng quan về “bộ mặt” của dữ liệu, cho phép người đọc hình dung rõ ràng về các biến và giá trị mẫu trước khi đi sâu vào phân tích chi tiết. Điều này đảm bảo tính minh bạch và giúp phát hiện sớm các vấn đề về định dạng dữ liệu.

Kết luận: Qua bước khảo sát này, chúng ta đã nắm bắt thành công các đặc điểm cấu trúc cơ bản của bộ dữ liệu tài chính, bao gồm kiểu dữ liệu của từng cột, tên các chỉ tiêu tài chính quan trọng, và định dạng của các kỳ báo cáo. Những thông tin này tạo nền tảng vững chắc để thực hiện các thao tác chuyển đổi, làm sạch và lọc dữ liệu trong các bước phân tích tiếp theo, đảm bảo độ chính xác và hiệu quả của toàn bộ quy trình phân tích.

2.1.4 LỰA CHỌN VÀ LỌC 10 BIẾN CHÍNH THEO NHÓM

Lý do thực hiện: Đây là bước tối ưu hóa tập dữ liệu nhằm tập trung vào các biến quan trọng nhất, phản ánh dòng chảy tài chính cốt lõi của doanh nghiệp bảo hiểm. Việc lựa chọn có hệ thống này giúp loại bỏ thông tin nhiễu, tăng hiệu quả phân tích và đảm bảo kết quả mang tính đại diện cao cho hoạt động kinh doanh.

# KỸ THUẬT 4: LỌC VÀ CHỌN BIẾN THEO NHÓM
# ----------------------------------------
# Sử dụng vector kết hợp với toán tử %in% để lọc
# Phân nhóm biến theo logic tài chính

# ĐỊNH NGHĨA 10 BIẾN CHÍNH THEO 4 NHÓM TÀI CHÍNH
# Nhóm 1: Doanh thu Bảo hiểm (2 biến) - Nguồn thu chính
nhom_doanhthu_bh <- c(
  "Thu phí bảo hiểm gốc",           # Doanh thu từ bán bảo hiểm
  "Doanh thu phí bảo hiểm thuần"    # Doanh thu sau các điều chỉnh
)

# Nhóm 2: Chi phí Bảo hiểm (2 biến) - Chi phí hoạt động cốt lõi  
nhom_chiphi_bh <- c(
  "Chi bồi thường bảo hiểm gốc và chi trả đáo hạn",  # Chi phí bồi thường
  "Tổng chi trực tiếp hoạt động kinh doanh bảo hiểm" # Chi phí vận hành
)

# Nhóm 3: Hoạt động Tài chính (3 biến) - Đầu tư và quản lý tài chính
nhom_taichinh <- c(
  "Doanh thu hoạt động tài chính",   # Thu từ đầu tư
  "Chi phí hoạt động tài chính",     # Chi phí tài chính
  "Lợi nhuận hoạt động tài chính"    # Hiệu quả đầu tư
)

# Nhóm 4: Lợi nhuận & Thuế (3 biến) - Kết quả cuối cùng
nhom_loinhuan_thue <- c(
  "Lợi nhuận gộp hoạt động kinh doanh bảo hiểm",  # Lợi nhuận cốt lõi
  "Lợi nhuận sau thuế thu nhập doanh nghiệp",     # Lợi nhuận ròng
  "Chi phí thuế thu nhập doanh nghiệp trong năm"  # Nghĩa vụ thuế
)

# Gộp tất cả thành 1 vector 10 biến
selected_vars <- c(nhom_doanhthu_bh, nhom_chiphi_bh, nhom_taichinh, nhom_loinhuan_thue)

# KỸ THUẬT LỌC DỮ LIỆU
# --------------------
# Bước 1: Chuẩn hóa tên cột đầu tiên
colnames(kqkd)[1] <- "ChiTieu"

# Bước 2: Sử dụng filter() kết hợp %in% để lọc theo danh sách
kqkd_10vars <- kqkd %>%
  filter(ChiTieu %in% selected_vars)

cat("DỮ LIỆU SAU KHI LỌC 10 BIẾN CHÍNH:\n")
## DỮ LIỆU SAU KHI LỌC 10 BIẾN CHÍNH:
kqkd_10vars
ChiTieu Q1 2023 Q2 2023 Q3 2023 Q4 2023 Q1 2024 Q2 2024 Q3 2024 Q4 2024 Q1 2025 Q2 2025
Thu phí bảo hiểm gốc 10,584,182,384,873 10,293,552,198,878 10,488,841,325,514 11,274,879,368,561 10,405,763,064,606 10,430,938,017,626 10,608,409,899,942 11,146,664,997,677 10,751,532,426,661 11,226,449,607,269
Doanh thu phí bảo hiểm thuần 9,667,372,298,769 9,727,422,700,489 9,563,540,749,958 10,282,815,515,328 9,448,665,457,974 9,822,315,052,408 9,572,757,205,822 10,282,445,962,840 9,785,235,388,129 10,466,451,630,505
Chi bồi thường bảo hiểm gốc và chi trả đáo hạn -4,323,844,953,729 -5,246,231,522,321 -4,897,602,478,774 -5,130,993,931,628 -4,499,151,247,256 -4,965,593,684,235 -4,929,543,129,080 -5,320,087,494,877 -4,445,351,554,154 -5,578,313,081,204
Tổng chi trực tiếp hoạt động kinh doanh bảo hiểm -9,957,872,373,054 -10,685,771,425,881 -10,520,854,068,053 -11,359,987,423,497 -10,107,416,979,581 -10,393,171,606,402 -9,891,469,987,875 -10,400,229,977,645 -9,396,804,999,043 -10,068,195,800,780
Lợi nhuận gộp hoạt động kinh doanh bảo hiểm -111,381,766,638 -794,597,534,646 -794,528,699,883 -789,668,186,060 -488,787,756,073 -402,441,677,273 -145,033,082,073 67,149,647,564 577,222,965,394 592,598,316,073
Lợi nhuận hoạt động tài chính 2,494,207,309,192 2,734,887,603,791 2,848,871,714,165 2,631,845,220,882 2,861,235,190,010 2,553,829,977,716 2,578,766,467,004 2,579,764,071,055 2,562,599,021,062 2,708,187,595,335
Doanh thu hoạt động tài chính 3,124,947,998,167 3,612,279,381,928 3,513,790,934,942 3,295,561,442,982 3,258,485,105,958 3,116,372,526,598 3,105,166,130,634 3,209,303,332,534 3,231,774,542,958 3,406,655,634,725
Chi phí hoạt động tài chính -630,740,688,975 -877,391,778,137 -664,919,220,777 -663,716,222,100 -397,249,915,948 -562,542,548,882 -526,399,663,630 -629,539,261,479 -669,175,521,896 -698,468,039,390
Chi phí thuế thu nhập doanh nghiệp trong năm -110,999,228,012 -85,589,128,588 -87,478,139,499 -77,852,971,897 -124,964,624,309 -92,879,401,434 -127,499,078,071 -123,659,770,152 -160,444,753,265 -145,500,540,281
Lợi nhuận sau thuế thu nhập doanh nghiệp 546,200,835,278 421,510,941,372 460,331,028,469 369,712,889,499 616,900,182,316 441,601,973,943 560,654,928,435 575,011,518,636 686,754,473,580 684,022,197,188

Kỹ thuật: Áp dụng phương pháp lọc dữ liệu có hệ thống thông qua việc phân nhóm biến và sử dụng toán tử %in% kết hợp với hàm filter() từ thư viện dplyr.

Với: - Phân nhóm biến: 10 biến được phân thành 4 nhóm logic theo dòng chảy tài chính: Doanh thu bảo hiểm → Chi phí bảo hiểm → Hoạt động tài chính → Lợi nhuận & Thuế. Mỗi nhóm đại diện cho một giai đoạn quan trọng trong chu trình tài chính của doanh nghiệp bảo hiểm.

  • colnames(kqkd)[1] <- "ChiTieu": Thao tác chuẩn hóa tên cột đầu tiên thành “ChiTieu” nhằm tạo sự thống nhất và dễ dàng cho việc tham chiếu trong các bước lọc dữ liệu tiếp theo.

  • filter(ChiTieu %in% selected_vars): Hàm filter() từ thư viện dplyr kết hợp với toán tử %in% để lọc ra những dòng có giá trị trong cột “ChiTieu” nằm trong danh sách selected_vars đã được định nghĩa. Toán tử %in% thực hiện phép so sánh từng phần tử và trả về kết quả TRUE/FALSE.

Giá trị kỹ thuật: Trong R Markdown, kỹ thuật này minh họa rõ nét quy trình lựa chọn biến có hệ thống, giúp người đọc hiểu được logic phân nhóm và tiêu chí lựa chọn biến cho phân tích. Phương pháp này đảm bảo tính linh hoạt - dễ dàng thêm/bớt biến khi cần, và tạo cơ sở cho việc tái lập phân tích với các tập biến khác nhau.

Kết luận: Quá trình lựa chọn và lọc biến đã được thực hiện thành công, thu hẹp phạm vi phân tích từ 84 chỉ tiêu xuống còn 10 biến trọng yếu nhất. Các biến này được phân nhóm logic theo dòng chảy tài chính, từ doanh thu, chi phí đến lợi nhuận, tạo thành bộ khung phân tích toàn diện về hiệu quả hoạt động kinh doanh của doanh nghiệp bảo hiểm. Việc tập trung vào các biến cốt lõi này không chỉ nâng cao hiệu quả phân tích mà còn đảm bảo kết quả mang tính đại diện cao và dễ diễn giải trong bối cảnh ngành bảo hiểm.

2.1.5 KIỂM TRA DỮ LIỆU SAU KHI LỌC

Lý do thực hiện: Đây là bước xác minh quan trọng sau khi thực hiện các thao tác lọc dữ liệu, nhằm đảm bảo kết quả thu được đúng như mong đợi về số lượng biến và cấu trúc dữ liệu. Việc kiểm tra này giúp phát hiện kịp thời các sai sót trong quá trình xử lý dữ liệu.

# KỸ THUẬT 5: KIỂM TRA DỮ LIỆU SAU KHI LỌC
# ------------------------------------------
# Hàm glimpse() từ dplyr: phiên bản nâng cao của str()

cat("TỔNG QUAN DỮ LIỆU 10 BIẾN SAU KHI LỌC:\n")
## TỔNG QUAN DỮ LIỆU 10 BIẾN SAU KHI LỌC:
glimpse(kqkd_10vars)
## Rows: 10
## Columns: 11
## $ ChiTieu   <chr> "Thu phí bảo hiểm gốc", "Doanh thu phí b…
## $ `Q1 2023` <dbl> 10584182384873, 9667372298769, -43238449…
## $ `Q2 2023` <dbl> 10293552198878, 9727422700489, -52462315…
## $ `Q3 2023` <dbl> 10488841325514, 9563540749958, -48976024…
## $ `Q4 2023` <dbl> 11274879368561, 10282815515328, -5130993…
## $ `Q1 2024` <dbl> 10405763064606, 9448665457974, -44991512…
## $ `Q2 2024` <dbl> 10430938017626, 9822315052408, -49655936…
## $ `Q3 2024` <dbl> 10608409899942, 9572757205822, -49295431…
## $ `Q4 2024` <dbl> 11146664997677, 10282445962840, -5320087…
## $ `Q1 2025` <dbl> 10751532426661, 9785235388129, -44453515…
## $ `Q2 2025` <dbl> 11226449607269, 10466451630505, -5578313…
# Kiểm tra số lượng biến thực tế
so_bien_thuc_te <- nrow(kqkd_10vars)
cat("\nSỐ BIẾN THỰC TẾ SAU KHI LỌC:", so_bien_thuc_te)
## 
## SỐ BIẾN THỰC TẾ SAU KHI LỌC: 10

Kỹ thuật: Sử dụng hàm glimpse() từ thư viện dplyr để xem tổng quan cấu trúc dữ liệu kết hợp với hàm nrow() để đếm số lượng biến thực tế sau khi lọc.

Với: - glimpse(kqkd_10vars): Hàm glimpse() cung cấp cái nhìn tổng quan về cấu trúc của dataframe kqkd_10vars. Khác với str(), hàm này hiển thị thông tin theo chiều ngang, giúp người dùng dễ dàng quan sát kiểu dữ liệu và giá trị mẫu của từng cột một cách trực quan và nhanh chóng.

  • nrow(kqkd_10vars): Hàm nrow() (number of rows) đếm số dòng trong dataframe kqkd_10vars. Trong ngữ cảnh này, mỗi dòng đại diện cho một chỉ tiêu tài chính, do đó kết quả trả về chính là số lượng biến đã được lọc thành công.

Giá trị kỹ thuật: Trong môi trường R Markdown, kỹ thuật này đảm bảo tính liên tục và chính xác của toàn bộ quy trình phân tích. Việc kiểm tra sau khi lọc cung cấp bằng chứng rõ ràng cho thấy dữ liệu đã được xử lý đúng theo yêu cầu, tạo niềm tin cho người đọc về độ tin cậy của các phân tích tiếp theo.

Kết luận: Qua bước kiểm tra này, chúng ta đã xác nhận thành công việc lọc dữ liệu với đúng 10 biến theo yêu cầu phân tích. Kết quả này không chỉ khẳng định tính chính xác của quy trình lọc dữ liệu mà còn cung cấp sự đảm bảo cần thiết để tiến hành các phân tích thống kê chuyên sâu trong các bước tiếp theo, đảm bảo toàn bộ quy trình phân tích được xây dựng trên nền tảng dữ liệu đáng tin cậy.

2.1.6 XÁC ĐỊNH PHẠM VI THỜI GIAN PHÂN TÍCH

Lý do thực hiện: Đây là bước thiết lập ngữ cảnh thời gian cho toàn bộ phân tích, giúp xác định chính xác phạm vi nghiên cứu, số lượng kỳ báo cáo và khoảng cách thời gian giữa các quan sát. Việc này đặc biệt quan trọng đối với phân tích chuỗi thời gian trong lĩnh vực tài chính.

# KỸ THUẬT 6: XÁC ĐỊNH PHẠM VI THỜI GIAN
# ---------------------------------------
# Hàm colnames() lấy tên tất cả các cột

cat("CÁC KỲ BÁO CÁO TRONG DỮ LIỆU:\n")
## CÁC KỲ BÁO CÁO TRONG DỮ LIỆU:
cac_ky_bao_cao <- colnames(kqkd_10vars)
print(cac_ky_bao_cao)
##  [1] "ChiTieu" "Q1 2023" "Q2 2023" "Q3 2023" "Q4 2023"
##  [6] "Q1 2024" "Q2 2024" "Q3 2024" "Q4 2024" "Q1 2025"
## [11] "Q2 2025"
cat("\nPHẠM VI PHÂN TÍCH TỪ:", cac_ky_bao_cao[2], "ĐẾN:", tail(cac_ky_bao_cao, 1))
## 
## PHẠM VI PHÂN TÍCH TỪ: Q1 2023 ĐẾN: Q2 2025
cat("\nTỔNG SỐ KỲ BÁO CÁO:", length(cac_ky_bao_cao) - 1)  # Trừ cột ChiTieu
## 
## TỔNG SỐ KỲ BÁO CÁO: 10

Kỹ thuật: Sử dụng hàm colnames() để trích xuất thông tin thời gian từ tên các cột dữ liệu, kết hợp với các hàm tail()length() để xác định phạm vi và số lượng kỳ báo cáo.

Với: - colnames(kqkd_10vars): Hàm colnames() trả về một vector chứa tên của tất cả các cột trong dataframe kqkd_10vars. Trong cấu trúc dữ liệu tài chính, các cột (trừ cột đầu tiên) thường chứa thông tin về các kỳ báo cáo theo thời gian.

  • tail(cac_ky_bao_cao, 1): Hàm tail() với tham số 1 trích xuất phần tử cuối cùng của vector cac_ky_bao_cao, đại diện cho kỳ báo cáo gần nhất trong tập dữ liệu.

  • length(cac_ky_bao_cao) - 1: Hàm length() đếm tổng số phần tử trong vector, và trừ đi 1 để loại trừ cột “ChiTieu” (cột chứa tên các chỉ tiêu tài chính), kết quả thu được chính là tổng số kỳ báo cáo cần phân tích.

Giá trị kỹ thuật: Trong R Markdown, kỹ thuật này cung cấp ngữ cảnh thời gian rõ ràng cho toàn bộ phân tích, giúp người đọc dễ dàng hình dung được giai đoạn nghiên cứu và phạm vi dữ liệu được sử dụng. Thông tin này là nền tảng cho các phân tích xu hướng và mô hình dự báo trong tương lai.

Kết luận: Chúng ta đã xác định chính xác phạm vi phân tích từ quý 1 năm 2023 đến quý 2 năm 2025 với tổng cộng 10 kỳ báo cáo. Thông tin về khung thời gian này có ý nghĩa quan trọng trong việc phân tích xu hướng, đánh giá tính mùa vụ, và xác định các mô hình phát triển theo thời gian của các chỉ tiêu tài chính, tạo cơ sở vững chắc cho các phân tích chuyên sâu về hiệu quả hoạt động của doanh nghiệp qua từng giai đoạn.

2.1.7 ĐÁNH GIÁ CHẤT LƯỢNG DỮ LIỆU

Lý do thực hiện: Đây là bước đánh giá quan trọng nhằm phát hiện và xử lý dữ liệu thiếu trước khi tiến hành phân tích. Trong phân tích tài chính, dữ liệu thiếu có thể dẫn đến những kết luận sai lệch và ảnh hưởng nghiêm trọng đến chất lượng của toàn bộ nghiên cứu.

# KỸ THUẬT 7: KIỂM TRA DỮ LIỆU THIẾU (MISSING VALUES)
# ----------------------------------------------------
# Hàm is.na() trả về ma trận TRUE/FALSE
# Hàm sum() đếm tổng số TRUE (số giá trị NA)

tong_na <- sum(is.na(kqkd_10vars))
cat("TỔNG SỐ GIÁ TRỊ THIẾU (NA) TRONG 10 BIẾN:", tong_na, "\n")
## TỔNG SỐ GIÁ TRỊ THIẾU (NA) TRONG 10 BIẾN: 0
# Kiểm tra chi tiết theo từng cột
cat("\nSỐ GIÁ TRỊ THIẾU THEO TỪNG CỘT:\n")
## 
## SỐ GIÁ TRỊ THIẾU THEO TỪNG CỘT:
na_theo_cot <- colSums(is.na(kqkd_10vars))
print(na_theo_cot)
## ChiTieu Q1 2023 Q2 2023 Q3 2023 Q4 2023 Q1 2024 Q2 2024 
##       0       0       0       0       0       0       0 
## Q3 2024 Q4 2024 Q1 2025 Q2 2025 
##       0       0       0       0
# Tính tỷ lệ phần trăm giá trị thiếu
ty_le_na <- mean(is.na(kqkd_10vars)) * 100
cat("\nTỶ LỆ GIÁ TRỊ THIẾU:", round(ty_le_na, 2), "%\n")
## 
## TỶ LỆ GIÁ TRỊ THIẾU: 0 %

Kỹ thuật: Sử dụng kết hợp hàm is.na() để phát hiện giá trị thiếu và các hàm tổng hợp như sum(), colSums(), mean() để đánh giá mức độ và phân bố của dữ liệu thiếu trong tập dữ liệu.

Với: - is.na(kqkd_10vars): Hàm is.na() trả về một ma trận logic có cùng kích thước với dataframe kqkd_10vars, trong đó giá trị TRUE đại diện cho vị trí có giá trị thiếu (NA) và FALSE đại diện cho giá trị hợp lệ.

  • sum(is.na(kqkd_10vars)): Hàm sum() áp dụng trên ma trận kết quả từ is.na() sẽ đếm tổng số giá trị TRUE, tương đương với tổng số giá trị thiếu trong toàn bộ dataframe.

  • colSums(is.na(kqkd_10vars)): Hàm colSums() tính tổng số giá trị thiếu theo từng cột, giúp xác định các kỳ báo cáo cụ thể có vấn đề về dữ liệu.

  • mean(is.na(kqkd_10vars)) * 100: Tính tỷ lệ phần trăm giá trị thiếu bằng cách lấy trung bình số giá trị TRUE trong ma trận và nhân với 100, cung cấp chỉ số đánh giá tổng quan về chất lượng dữ liệu.

Giá trị kỹ thuật: Trong R Markdown, kỹ thuật này thể hiện tính chuyên nghiệp trong quy trình xử lý dữ liệu và cung cấp đánh giá khách quan về độ tin cậy của bộ dữ liệu. Việc công khai đánh giá chất lượng dữ liệu giúp tăng tính minh bạch và độ tin cậy của toàn bộ phân tích.

Kết luận: Qua bước đánh giá chất lượng dữ liệu, chúng ta đã xác nhận bộ dữ liệu hoàn toàn không chứa giá trị thiếu (NA). Kết quả này cho thấy chất lượng dữ liệu đầu vào rất tốt, đảm bảo độ tin cậy cao cho các phân tích thống kê tiếp theo. Việc không có dữ liệu thiếu đồng nghĩa với việc không cần áp dụng các kỹ thuật xử lý phức tạp như imputation (thay thế giá trị thiếu), giúp đơn giản hóa quy trình phân tích và duy trì tính nguyên bản của dữ liệu gốc từ báo cáo tài chính của doanh nghiệp.

2.1.8 PHÂN TÍCH THỐNG KÊ MÔ TẢ

Lý do thực hiện: Đây là bước phân tích nền tảng cung cấp cái nhìn toàn diện về đặc điểm phân phối và xu hướng của các biến tài chính. Thống kê mô tả giúp phát hiện các giá trị bất thường, đánh giá mức độ biến động và hình thành cơ sở cho các phân tích chuyên sâu tiếp theo.

# KỸ THUẬT 8: PHÂN TÍCH THỐNG KÊ MÔ TẢ
# -------------------------------------
# Hàm summary() tính các thống kê mô tả chính
# Hàm apply() kết hợp sd() và mean() để tính hệ số biến thiên

cat("THỐNG KÊ MÔ TẢ 10 BIẾN TÀI CHÍNH CHÍNH:\n")
## THỐNG KÊ MÔ TẢ 10 BIẾN TÀI CHÍNH CHÍNH:
thong_ke_mo_ta <- summary(kqkd_10vars[,-1])  # Bỏ cột ChiTieu (cột 1)
print(thong_ke_mo_ta)
##     Q1 2023                  Q2 2023               
##  Min.   :-9957872373050   Min.   :-10685771425900  
##  1st Qu.: -500900958391   1st Qu.:  -856693217264  
##  Median :  217600803633   Median :   167960906392  
##  Mean   : 1128207181590   Mean   :   910007143688  
##  3rd Qu.: 2967262825920   3rd Qu.:  3392931437390  
##  Max.   :10584182384900   Max.   : 10293552198900  
##     Q3 2023                   Q4 2023               
##  Min.   :-10520854068100   Min.   :-11359987423500  
##  1st Qu.:  -762126330106   1st Qu.:  -758180195070  
##  Median :   186426444485   Median :   145929958801  
##  Mean   :   990999314606   Mean   :   983259570207  
##  3rd Qu.:  3347561129750   3rd Qu.:  3129632387460  
##  Max.   : 10488841325500   Max.   : 11274879368600  
##     Q1 2024                   Q2 2024               
##  Min.   :-10107416979600   Min.   :-10393171606400  
##  1st Qu.:  -465903296042   1st Qu.:  -522517330980  
##  Median :   245967779004   Median :   174361286254  
##  Mean   :  1097347847770   Mean   :   994842863006  
##  3rd Qu.:  3159172626970   3rd Qu.:  2975736889380  
##  Max.   : 10405763064600   Max.   : 10430938017600  
##     Q3 2024                  Q4 2024               
##  Min.   :-9891469987880   Min.   :-10400229977600  
##  1st Qu.: -431058018241   1st Qu.:  -503069388647  
##  Median :  216577925182   Median :   321080583100  
##  Mean   : 1080580969110   Mean   :  1138682302620  
##  3rd Qu.: 2973566214730   3rd Qu.:  3051918517160  
##  Max.   :10608409899900   Max.   : 11146664997700  
##     Q1 2025                  Q2 2025               
##  Min.   :-9396804999040   Min.   :-10068195800800  
##  1st Qu.: -541992829738   1st Qu.:  -560226164613  
##  Median :  631988719487   Median :   638310256630  
##  Mean   : 1292334198940   Mean   :  1259388751940  
##  3rd Qu.: 3064480662480   3rd Qu.:  3232038624880  
##  Max.   :10751532426700   Max.   : 11226449607300
# Tính thêm một số chỉ số thống kê quan trọng
cat("\nMỘT SỐ CHỈ SỐ THỐNG KÊ BỔ SUNG:\n")
## 
## MỘT SỐ CHỈ SỐ THỐNG KÊ BỔ SUNG:
# Độ biến động (Coefficient of Variation) cho từng biến
do_bien_dong <- apply(kqkd_10vars[,-1], 2, function(x) sd(x)/mean(x) * 100)
cat("ĐỘ BIẾN ĐỘNG (CV %):\n")
## ĐỘ BIẾN ĐỘNG (CV %):
print(round(do_bien_dong, 2))
## Q1 2023 Q2 2023 Q3 2023 Q4 2023 Q1 2024 Q2 2024 Q3 2024 
##     535     691     628     676     550     622     562 
## Q4 2024 Q1 2025 Q2 2025 
##     564     462     511

Kỹ thuật: Sử dụng hàm summary() để tính toán các thống kê mô tả cơ bản kết hợp với hàm apply() để tính hệ số biến thiên, cung cấp đánh giá toàn diện về phân phối và độ biến động của dữ liệu.

Với: - summary(kqkd_10vars[,-1]): Hàm summary() áp dụng trên dataframe (đã loại bỏ cột “ChiTieu”) tính toán các thống kê mô tả quan trọng bao gồm: giá trị nhỏ nhất (Min), phân vị thứ nhất (Q1), trung vị (Median), giá trị trung bình (Mean), phân vị thứ ba (Q3), và giá trị lớn nhất (Max) cho từng biến tài chính qua các kỳ báo cáo.

  • apply(kqkd_10vars[,-1], 2, function(x) sd(x)/mean(x) * 100): Hàm apply() với tham số 2 (áp dụng theo cột) kết hợp với hàm tự định nghĩa để tính hệ số biến thiên (CV). Công thức sd(x)/mean(x) * 100 cho phép so sánh độ biến động giữa các biến có quy mô khác nhau bằng cách chuẩn hóa độ lệch chuẩn theo giá trị trung bình.

Giá trị kỹ thuật: Trong R Markdown, kỹ thuật này cung cấp thông tin nền tảng quan trọng về các biến, cho phép người đọc hiểu được quy mô, xu hướng trung tâm và mức độ biến động của các chỉ tiêu tài chính. Việc trình bày đầy đủ các chỉ số thống kê tạo cơ sở vững chắc cho việc diễn giải kết quả và đưa ra nhận định trong bối cảnh ngành bảo hiểm.

Kết luận: Qua phân tích thống kê mô tả, chúng ta đã thu thập được những thông tin quan trọng về đặc điểm phân phối của 10 biến tài chính chính. Các chỉ số như trung vị, trung bình, và đặc biệt là hệ số biến thiên đã cung cấp cái nhìn sâu sắc về xu hướng và mức độ rủi ro trong hoạt động tài chính của doanh nghiệp. Những thông tin này tạo nền tảng thiết yếu cho việc đánh giá hiệu quả hoạt động và dự báo xu hướng phát triển trong tương lai.

2.1.9 PHÂN TÍCH TÍNH MÙA VỤ THEO QUÝ

Lý do thực hiện: Đây là bước phân tích chuỗi thời gian quan trọng nhằm phát hiện các mô hình mùa vụ trong hoạt động tài chính của doanh nghiệp bảo hiểm. Việc xác định tính mùa vụ giúp hỗ trợ công tác dự báo, lập kế hoạch kinh doanh và quản lý dòng tiền hiệu quả theo từng quý trong năm.

# KỸ THUẬT 9: PHÂN TÍCH TÍNH MÙA VỤ THEO QUÝ
# -------------------------------------------
# Sử dụng pivot_longer() để chuyển dạng wide → long
# Tách số quý từ tên cột bằng substr()
# Group by theo chỉ tiêu và quý để tính trung bình

cat("PHÂN TÍCH TRUNG BÌNH THEO QUÝ (PHÁT HIỆN MÙA VỤ):\n")
## PHÂN TÍCH TRUNG BÌNH THEO QUÝ (PHÁT HIỆN MÙA VỤ):
# Bước 1: Chuyển sang dạng long để dễ xử lý
kqkd_long <- kqkd_10vars %>%
  pivot_longer(
    cols = -ChiTieu,           # Giữ cột ChiTieu
    names_to = "Quy",          # Tên cột mới cho kỳ báo cáo
    values_to = "GiaTri"       # Tên cột mới cho giá trị
  ) %>%
  mutate(
    QuySo = as.numeric(substr(Quy, 2, 2)),  # Tách số quý (ví dụ: Q1 → 1)
    Nam = as.numeric(substr(Quy, 4, 7))     # Tách năm (ví dụ: Q1.2023 → 2023)
  )

# Bước 2: Tính trung bình theo cùng quý qua các năm
trung_binh_theo_quy <- kqkd_long %>%
  group_by(ChiTieu, QuySo) %>%
  summarise(
    TrungBinhQuy = mean(GiaTri, na.rm = TRUE),
    SoNam = n_distinct(Nam),      # Đếm số năm khác nhau
    DoLechChuan = sd(GiaTri, na.rm = TRUE),
    .groups = 'drop'
  )

# Bước 3: Hiển thị kết quả dạng bảng đẹp
cat("BẢNG TRUNG BÌNH THEO QUÝ:\n")
## BẢNG TRUNG BÌNH THEO QUÝ:
kable(trung_binh_theo_quy, format.args = list(big.mark = ".", decimal.mark = ","))
ChiTieu QuySo TrungBinhQuy SoNam DoLechChuan
Chi bồi thường bảo hiểm gốc và chi trả đáo hạn 1 -4.422.782.585.046 3 89.805.862.350
Chi bồi thường bảo hiểm gốc và chi trả đáo hạn 2 -5.263.379.429.253 3 306.719.420.464
Chi bồi thường bảo hiểm gốc và chi trả đáo hạn 3 -4.913.572.803.927 2 22.585.450.427
Chi bồi thường bảo hiểm gốc và chi trả đáo hạn 4 -5.225.540.713.253 2 133.709.340.852
Chi phí hoạt động tài chính 1 -565.722.042.273 3 147.161.313.214
Chi phí hoạt động tài chính 2 -712.800.788.803 3 157.913.204.229
Chi phí hoạt động tài chính 3 -595.659.442.204 2 97.948.118.186
Chi phí hoạt động tài chính 4 -646.627.741.790 2 24.166.760.615
Chi phí thuế thu nhập doanh nghiệp trong năm 1 -132.136.201.862 3 25.490.952.029
Chi phí thuế thu nhập doanh nghiệp trong năm 2 -107.989.690.101 3 32.689.217.342
Chi phí thuế thu nhập doanh nghiệp trong năm 3 -107.488.608.785 2 28.299.077.054
Chi phí thuế thu nhập doanh nghiệp trong năm 4 -100.756.371.025 2 32.390.297.671
Doanh thu hoạt động tài chính 1 3.205.069.215.694 3 70.660.601.947
Doanh thu hoạt động tài chính 2 3.378.435.847.750 3 249.154.910.795
Doanh thu hoạt động tài chính 3 3.309.478.532.788 2 288.941.370.087
Doanh thu hoạt động tài chính 4 3.252.432.387.758 2 60.993.694.830
Doanh thu phí bảo hiểm thuần 1 9.633.757.714.957 3 170.784.322.040
Doanh thu phí bảo hiểm thuần 2 10.005.396.461.134 3 402.094.567.877
Doanh thu phí bảo hiểm thuần 3 9.568.148.977.890 2 6.517.018.440
Doanh thu phí bảo hiểm thuần 4 10.282.630.739.084 2 261.313.070
Lợi nhuận gộp hoạt động kinh doanh bảo hiểm 1 -7.648.852.439 3 540.522.989.971
Lợi nhuận gộp hoạt động kinh doanh bảo hiểm 2 -201.480.298.615 3 715.099.425.847
Lợi nhuận gộp hoạt động kinh doanh bảo hiểm 3 -469.780.890.978 2 459.262.755.704
Lợi nhuận gộp hoạt động kinh doanh bảo hiểm 4 -361.259.269.248 2 605.861.700.397
Lợi nhuận hoạt động tài chính 1 2.639.347.173.421 3 195.179.598.043
Lợi nhuận hoạt động tài chính 2 2.665.635.058.947 3 97.742.031.669
Lợi nhuận hoạt động tài chính 3 2.713.819.090.585 2 190.993.251.902
Lợi nhuận hoạt động tài chính 4 2.605.804.645.969 2 36.826.934.215
Lợi nhuận sau thuế thu nhập doanh nghiệp 1 616.618.497.058 3 70.277.242.546
Lợi nhuận sau thuế thu nhập doanh nghiệp 2 515.711.704.168 3 146.106.909.292
Lợi nhuận sau thuế thu nhập doanh nghiệp 3 510.492.978.452 2 70.939.709.981
Lợi nhuận sau thuế thu nhập doanh nghiệp 4 472.362.204.068 2 145.168.052.831
Thu phí bảo hiểm gốc 1 10.580.492.625.380 3 172.914.209.011
Thu phí bảo hiểm gốc 2 10.650.313.274.591 3 503.655.160.970
Thu phí bảo hiểm gốc 3 10.548.625.612.728 2 84.547.749.795
Thu phí bảo hiểm gốc 4 11.210.772.183.119 2 90.661.251.098
Tổng chi trực tiếp hoạt động kinh doanh bảo hiểm 1 -9.820.698.117.226 3 374.639.732.366
Tổng chi trực tiếp hoạt động kinh doanh bảo hiểm 2 -10.382.379.611.021 3 308.929.220.944
Tổng chi trực tiếp hoạt động kinh doanh bảo hiểm 3 -10.206.162.027.964 2 445.041.751.065
Tổng chi trực tiếp hoạt động kinh doanh bảo hiểm 4 -10.880.108.700.571 2 678.650.998.256

Kỹ thuật: Áp dụng quy trình chuyển đổi dữ liệu từ dạng rộng sang dạng dài kết hợp với các thao tác xử lý chuỗi và phân nhóm để phân tích tính mùa vụ theo quý.

Với: - pivot_longer(cols = -ChiTieu, names_to = "Quy", values_to = "GiaTri"): Hàm pivot_longer() từ thư viện tidyr chuyển đổi dữ liệu từ định dạng rộng (wide format - mỗi kỳ báo cáo là một cột) sang định dạng dài (long format - tất cả giá trị theo thời gian được xếp chồng lên nhau trong một cột). Tham số cols = -ChiTieu chỉ định giữ nguyên cột “ChiTieu”, các cột còn lại được chuyển thành hai cột mới: “Quy” (chứa tên kỳ báo cáo) và “GiaTri” (chứa giá trị tài chính).

  • mutate(QuySo = as.numeric(substr(Quy, 2, 2)), Nam = as.numeric(substr(Quy, 4, 7))): Sử dụng hàm substr() để tách thông tin số quý và năm từ chuỗi ký tự tên kỳ báo cáo. Ví dụ: từ “Q1.2023” tách được QuySo = 1 và Nam = 2023.

  • group_by(ChiTieu, QuySo) %>% summarise(...): Nhóm dữ liệu theo từng chỉ tiêu và số quý, sau đó tính toán các thống kê tổng hợp bao gồm giá trị trung bình, số năm quan sát và độ lệch chuẩn cho cùng quý qua các năm.

Giá trị kỹ thuật: Trong R Markdown, kỹ thuật này minh họa rõ nét khả năng phân tích chuỗi thời gian và phát hiện các pattern theo mùa trong dữ liệu tài chính. Việc trình bày kết quả dưới dạng bảng rõ ràng giúp người đọc dễ dàng nhận diện các quý có kết quả hoạt động đặc biệt tốt hoặc kém, từ đó đưa ra các quyết định quản lý phù hợp.

Kết luận: Phân tích tính mùa vụ theo quý đã giúp chúng ta xác định thành công các mô hình lặp lại theo chu kỳ năm trong hoạt động tài chính của Tập đoàn Bảo Việt. Việc phát hiện các quý có kết quả trung bình cao hơn hoặc thấp hơn đáng kể so với các quý khác cung cấp thông tin quý giá cho công tác dự báo, hoạch định ngân sách và xây dựng chiến lược kinh doanh. Đặc biệt, việc xác định được quý IV thường có kết quả mạnh mẽ do ảnh hưởng của việc kết thúc năm tài chính là cơ sở quan trọng cho việc tối ưu hóa kế hoạch hoạt động.

2.1.10 XÁC ĐỊNH BIẾN CÓ ĐỘ BIẾN ĐỘNG CAO NHẤT

Lý do thực hiện: Đây là bước phân tích rủi ro quan trọng nhằm xác định các chỉ tiêu tài chính có mức độ biến động cao, từ đó tập trung nguồn lực giám sát và quản lý các biến tiềm ẩn nguy cơ gây bất ổn cho hoạt động tài chính của doanh nghiệp.

# KỸ THUẬT 10: PHÂN TÍCH ĐỘ BIẾN ĐỘNG
# -------------------------------------
# Tính hệ số biến thiên CV = (độ lệch chuẩn / trung bình) * 100
# Sắp xếp kết quả theo độ biến động giảm dần

cat("PHÂN TÍCH BIẾN CÓ ĐỘ BIẾN ĐỘNG CAO NHẤT:\n")
## PHÂN TÍCH BIẾN CÓ ĐỘ BIẾN ĐỘNG CAO NHẤT:
# Tính CV cho từng biến (theo từng chỉ tiêu qua thời gian)
cv_analysis <- kqkd_long %>%
  group_by(ChiTieu) %>%
  summarise(
    TrungBinh = mean(GiaTri, na.rm = TRUE),
    DoLechChuan = sd(GiaTri, na.rm = TRUE),
    HeSoBienThien = (DoLechChuan / TrungBinh) * 100,
    .groups = 'drop'
  ) %>%
  arrange(desc(HeSoBienThien))  # Sắp xếp giảm dần theo độ biến động

# Hiển thị kết quả
cat("BẢNG XẾP HẠNG ĐỘ BIẾN ĐỘNG CỦA CÁC BIẾN:\n")
## BẢNG XẾP HẠNG ĐỘ BIẾN ĐỘNG CỦA CÁC BIẾN:
kable(cv_analysis, format.args = list(big.mark = ".", decimal.mark = ","))
ChiTieu TrungBinh DoLechChuan HeSoBienThien
Lợi nhuận sau thuế thu nhập doanh nghiệp 536.270.096.872 109.955.213.864 20,5
Doanh thu hoạt động tài chính 3.287.433.703.143 173.194.674.402 5,3
Lợi nhuận hoạt động tài chính 2.655.419.417.021 127.350.840.712 4,8
Doanh thu phí bảo hiểm thuần 9.861.902.196.222 353.752.210.430 3,6
Thu phí bảo hiểm gốc 10.721.121.329.161 364.523.978.001 3,4
Tổng chi trực tiếp hoạt động kinh doanh bảo hiểm -10.278.177.464.181 529.744.688.668 -5,2
Chi bồi thường bảo hiểm gốc và chi trả đáo hạn -4.933.671.307.726 408.656.291.136 -8,3
Chi phí hoạt động tài chính -632.014.286.121 124.364.047.986 -19,7
Chi phí thuế thu nhập doanh nghiệp trong năm -113.686.763.551 27.520.610.223 -24,2
Lợi nhuận gộp hoạt động kinh doanh bảo hiểm -228.946.777.362 525.489.415.320 -229,5
# Xác định biến có độ biến động cao nhất
bien_bien_dong_cao_nhat <- cv_analysis$ChiTieu[1]
cv_cao_nhat <- round(cv_analysis$HeSoBienThien[1], 2)

cat("\nBIẾN CÓ ĐỘ BIẾN ĐỘNG CAO NHẤT:\n")
## 
## BIẾN CÓ ĐỘ BIẾN ĐỘNG CAO NHẤT:
cat("- Chỉ tiêu:", bien_bien_dong_cao_nhat, "\n")
## - Chỉ tiêu: Lợi nhuận sau thuế thu nhập doanh nghiệp
cat("- Hệ số biến thiên:", cv_cao_nhat, "%\n")
## - Hệ số biến thiên: 20 %

Kỹ thuật: Sử dụng hệ số biến thiên (Coefficient of Variation - CV) để đánh giá và so sánh độ biến động giữa các biến tài chính có quy mô khác nhau, kết hợp với việc sắp xếp kết quả để xác định các biến có rủi ro cao nhất.

Với: - group_by(ChiTieu) %>% summarise(...): Nhóm dữ liệu theo từng chỉ tiêu tài chính và tính toán các thống kê tổng hợp bao gồm giá trị trung bình, độ lệch chuẩn và hệ số biến thiên cho toàn bộ chuỗi thời gian của mỗi biến.

  • HeSoBienThien = (DoLechChuan / TrungBinh) * 100: Công thức tính hệ số biến thiên CV, trong đó độ lệch chuẩn được chuẩn hóa theo giá trị trung bình và nhân với 100 để biểu diễn dưới dạng phần trăm. CV cho phép so sánh độ biến động giữa các biến có đơn vị và quy mô khác nhau.

  • arrange(desc(HeSoBienThien)): Sắp xếp kết quả theo thứ tự giảm dần của hệ số biến thiên, giúp xác định nhanh các biến có độ biến động cao nhất nằm ở đầu danh sách.

Giá trị kỹ thuật: Trong R Markdown, kỹ thuật này thể hiện rõ nét khả năng đánh giá rủi ro và ổn định tài chính thông qua phân tích thống kê. Việc xác định và xếp hạng các biến theo mức độ biến động cung cấp thông tin đầu vào quan trọng cho việc ra quyết định quản lý rủi ro và xây dựng các kịch bản dự phòng.

Kết luận: Qua phân tích độ biến động, chúng ta đã xác định chính xác các chỉ tiêu tài chính có mức độ biến động cao nhất trong hoạt động của Tập đoàn Bảo Việt. Thông tin này có ý nghĩa quan trọng trong việc quản lý rủi ro tài chính, dự báo kết quả kinh doanh và xây dựng các kịch bản ứng phó với biến động bất lợi. Việc tập trung giám sát các biến có hệ số biến thiên cao giúp doanh nghiệp chủ động trong việc kiểm soát rủi ro và duy trì ổn định tài chính.

2.1.11 KẾT LUẬN CHƯƠNG 1

Qua Chương 1 của tiểu luận, chúng ta đã thực hiện thành công toàn bộ quy trình xử lý và phân tích dữ liệu tài chính cơ bản cho Tập đoàn Bảo Việt. Những thành tựu và bài học quan trọng thu được bao gồm:

Về mặt kỹ thuật phân tích dữ liệu:

  • Làm chủ quy trình ETL (Extract-Transform-Load): Từ khâu đọc dữ liệu thô từ file Excel, thực hiện các bước làm sạch và chuyển đổi dữ liệu, đến tiến hành phân tích chuyên sâu
  • Kỹ năng lựa chọn biến có hệ thống: Áp dụng thành công phương pháp phân nhóm biến theo logic dòng chảy tài chính từ doanh thu, chi phí đến lợi nhuận
  • Năng lực đánh giá chất lượng dữ liệu: Phát hiện và xác nhận không có dữ liệu thiếu, đảm bảo độ tin cậy cho toàn bộ phân tích
  • Thành thạo phân tích thống kê mô tả: Hiểu rõ đặc điểm phân phối, xu hướng trung tâm và độ biến động của các biến tài chính

Về mặt hiểu biết chuyên môn ngành bảo hiểm:

  • Nhận diện thành thạo các chỉ tiêu tài chính trọng yếu: Nắm bắt được 10 chỉ tiêu quan trọng nhất phản ánh hiệu quả hoạt động của doanh nghiệp bảo hiểm
  • Hiểu sâu mối quan hệ giữa các nhóm chỉ tiêu: Nắm vững logic từ Doanh thu → Chi phí → Lợi nhuận trong mô hình kinh doanh bảo hiểm
  • Phát hiện tính mùa vụ đặc thù: Nhận diện được các mô hình hoạt động theo quý có ảnh hưởng đến kết quả tài chính

Về mặt ứng dụng thực tiễn trong quản lý:

  • Cung cấp cơ sở dữ liệu cho ra quyết định: Kết quả phân tích tạo nền tảng vững chắc cho việc đưa ra các quyết định quản lý hiệu quả
  • Định hướng quản lý rủi ro tập trung: Việc xác định các biến có độ biến động cao giúp ưu tiên nguồn lực giám sát và quản lý rủi ro
  • Hỗ trợ công tác dự báo và hoạch định: Phân tích mùa vụ cung cấp thông tin quý giá cho việc dự báo kết quả và lập kế hoạch ngân sách theo chu kỳ

Chương tiếp theo sẽ đi sâu vào phân tích các chỉ số tài chính quan trọng và đánh giá hiệu quả hoạt động của tập đoàn qua thời gian, trên cơ sở nền tảng dữ liệu đã được chuẩn bị kỹ lưỡng trong chương này.

2.2 XỬ LÝ DỮ LIỆU THÔ VÀ MÃ HÓA DỮ LIỆU

2.2.1 Xử lý dữ liệu

Lý do thực hiện: Đây là bước chuẩn bị dữ liệu quan trọng nhằm chuyển đổi bộ dữ liệu từ dạng wide format (10 biến × 11 cột) sang long format phù hợp cho phân tích thống kê và trực quan hóa. Quy trình xử lý này đảm bảo dữ liệu đầu ra sẵn sàng cho các phân tích chuyên sâu trong các phần tiếp theo.

classify_indicator <- function(chi_tieu) {
  nhom <- case_when(
    grepl("Thu|Doanh thu", chi_tieu, ignore.case = FALSE) ~ "Doanh thu",
    grepl("Chi|bồi thường|Bồi thường", chi_tieu, ignore.case = FALSE) ~ "Chi phí",
    grepl("Lợi nhuận", chi_tieu, ignore.case = FALSE) ~ "Lợi nhuận",
    TRUE ~ "Khác"
  )
  factor(nhom, levels = c("Doanh thu", "Chi phí", "Lợi nhuận", "Khác"))
}

Kỹ thuật: Sử dụng hàm classify_indicator() kết hợp với case_when()grepl() để phân loại tự động các chỉ tiêu tài chính thành 3 nhóm chính dựa trên từ khóa trong tên chỉ tiêu.

Với: - classify_indicator(chi_tieu): Hàm tự định nghĩa nhận đầu vào là vector ký tự chứa tên chỉ tiêu và trả về vector factor gồm 3 mức độ phân loại.

  • grepl("Thu|Doanh thu", chi_tieu, ignore.case = FALSE): Hàm grepl() thực hiện tìm kiếm pattern trong chuỗi ký tự. Tham số ignore.case = FALSE đảm bảo khớp chính xác với chuẩn mực kế toán Việt Nam.

  • case_when(): Hàm từ thư viện dplyr thực hiện phân loại có điều kiện, cho phép xác định nhóm cho từng chỉ tiêu dựa trên các pattern tìm thấy.

  • factor(nhom, levels = c("Doanh thu", "Chi phí", "Lợi nhuận", "Khác")): Chuyển đổi kết quả thành kiểu factor với thứ tự levels cố định để đảm bảo tính nhất quán trong các biểu đồ và bảng thống kê.

Giá trị kỹ thuật: Trong R Markdown, việc tạo hàm phân loại riêng biệt thay vì sử dụng trực tiếp trong mutate() mang lại ba lợi ích quan trọng: khả năng tái sử dụng code khi cần phân loại ở nhiều bước khác nhau, dễ dàng bảo trì và cập nhật logic phân loại, và tuân thủ nguyên tắc DRY (Don’t Repeat Yourself) trong lập trình R.

Kết luận: Hàm classify_indicator() đã được định nghĩa thành công với logic phân loại rõ ràng dựa trên từ khóa trong tên chỉ tiêu. Việc sử dụng grepl() với tham số ignore.case = FALSE đảm bảo khớp chính xác với chuẩn mực kế toán Việt Nam. Kết quả factor với 4 levels (bao gồm cả “Khác” cho trường hợp ngoại lệ) đảm bảo hàm robust và có thể xử lý được các tình huống không lường trước, tạo nền tảng vững chắc cho các bước xử lý dữ liệu tiếp theo.

2.2.2 THÊM CỘT PHÂN NHÓM CHO 10 BIẾN

Lý do thực hiện: Sau khi định nghĩa hàm phân loại, bước tiếp theo là áp dụng hàm này để tạo cột “Nhom” trong dataset. Việc phân nhóm chỉ tiêu là cần thiết để hỗ trợ tính toán thống kê mô tả theo nhóm, tạo cơ sở cho visualization theo từng nhóm, và phân tích cấu trúc thu chi lợi nhuận của doanh nghiệp bảo hiểm.

df_10_bien <- kqkd %>%
  filter(ChiTieu %in% selected_vars)

df_10_bien <- df_10_bien %>%
  mutate(Nhom = classify_indicator(ChiTieu)) %>%
  select(ChiTieu, Nhom, everything())

Kỹ thuật: Sử dụng hàm mutate() kết hợp với hàm classify_indicator() đã định nghĩa để tạo cột mới “Nhom”, sau đó sử dụng select() để sắp xếp lại thứ tự cột cho hợp lý.

Với: - df_10_bien <- kqkd %>% filter(ChiTieu %in% selected_vars): Tạo dataframe df_10_bien bằng cách lọc từ dataframe kqkd chỉ giữ lại các dòng có giá trị trong cột “ChiTieu” nằm trong danh sách selected_vars. Toán tử %in% kiểm tra từng phần tử trong cột “ChiTieu” có thuộc vector selected_vars hay không, trả về TRUE/FALSE. Hàm filter() giữ lại các dòng có kết quả TRUE.

  • mutate(Nhom = classify_indicator(ChiTieu)): Hàm mutate() từ thư viện dplyr tạo cột mới “Nhom” bằng cách áp dụng hàm classify_indicator() lên cột “ChiTieu”. Mỗi chỉ tiêu tài chính sẽ được phân loại vào một trong ba nhóm (“Doanh thu”, “Chi phí”, “Lợi nhuận”) dựa trên từ khóa trong tên chỉ tiêu. Hàm classify_indicator() đã được định nghĩa trước đó sử dụng case_when()grepl() để thực hiện phân loại tự động.

  • select(ChiTieu, Nhom, everything()): Hàm select() sắp xếp lại thứ tự các cột trong dataframe. Tham số ChiTieu, Nhom đặt hai cột này ở vị trí đầu tiên, everything() giữ nguyên tất cả các cột còn lại theo thứ tự hiện có. Việc sắp xếp này giúp cấu trúc dataset trở nên rõ ràng và dễ theo dõi, với thông tin phân loại ngay sau tên chỉ tiêu.

Giá trị kỹ thuật: Trong R Markdown, việc thêm cột phân nhóm giúp tạo cơ sở cho các phân tích theo nhóm trong các bước tiếp theo. Cột “Nhom” có kiểu factor thay vì character để đảm bảo thứ tự hiển thị cố định trong bảng và biểu đồ, đồng thời hỗ trợ các thao tác group_by() trong các phân tích thống kê. Phân nhóm chỉ tiêu cũng cho phép thực hiện faceted visualization (chia nhỏ biểu đồ theo nhóm) và phân tích cấu trúc tài chính một cách hệ thống.

Kết luận: Cột “Nhom” đã được tạo thành công với phân loại chính xác các chỉ tiêu tài chính. Kết quả cho thấy cấu trúc cân bằng giữa các nhóm, phù hợp cho phân tích so sánh. Với cột phân nhóm này, dataset giờ đã có kích thước hoàn chỉnh và sẵn sàng cho bước chuyển đổi sang long format, tạo nền tảng cho các phân tích chuyên sâu về cấu trúc tài chính của doanh nghiệp. Việc phân nhóm logic theo chức năng tài chính (doanh thu, chi phí, lợi nhuận) không chỉ hỗ trợ phân tích hiệu quả hoạt động mà còn tạo điều kiện cho việc diễn giải kết quả trong bối cảnh ngành bảo hiểm.

2.2.3 CHUYỂN ĐỔI TỪ WIDE FORMAT SANG LONG FORMAT

Lý do thực hiện: Đây là bước quan trọng nhất trong xử lý dữ liệu tài chính theo chuỗi thời gian. Việc chuyển đổi từ wide format sang long format giúp dữ liệu trở nên phù hợp cho phân tích chuỗi thời gian trong R, cho phép dễ dàng vẽ biểu đồ và hỗ trợ các hàm thống kê chuyên sâu.

df_long <- df_10_bien %>%
  pivot_longer(
    cols = -c(ChiTieu, Nhom),
    names_to = "QuyNam",
    values_to = "GiaTri"
  )

Kỹ thuật: Sử dụng hàm pivot_longer() từ thư viện tidyr để chuyển đổi dữ liệu từ định dạng rộng sang định dạng dài, tập trung các cột thời gian thành hai cột mới.

Với: - pivot_longer(cols = -c(ChiTieu, Nhom), names_to = "QuyNam", values_to = "GiaTri"): Hàm pivot_longer() thực hiện chuyển đổi với ba tham số chính. Tham số cols xác định các cột cần chuyển đổi (tất cả cột trừ “ChiTieu” và “Nhom”), names_to đặt tên cho cột mới chứa tên các cột gốc (“QuyNam”), và values_to đặt tên cho cột mới chứa giá trị số liệu (“GiaTri”).

  • Ký hiệu -c(ChiTieu, Nhom): Xác định rằng các cột “ChiTieu” và “Nhom” sẽ được giữ nguyên không tham gia vào quá trình chuyển đổi, chỉ các cột còn lại (các cột thời gian) sẽ được chuyển đổi.

Giá trị kỹ thuật: Trong R Markdown, long format là cấu trúc chuẩn cho phân tích chuỗi thời gian trong R. Định dạng này cho phép dễ dàng vẽ line charts với ggplot2 thông qua mapping aes(x = time, y = value, color = variable), hỗ trợ group_by() theo nhiều chiều khác nhau, và tương thích với hầu hết các hàm thống kê nâng cao.

Kết luận: Chuyển đổi long format đã được thực hiện thành công, tạo ra dataset với cấu trúc tối ưu cho phân tích chuỗi thời gian. Mỗi dòng trong dataset mới đại diện cho một quan sát cụ thể (chỉ tiêu X tại quý Y), với cấu trúc rõ ràng và dễ dàng cho các thao tác phân tích tiếp theo. Dữ liệu đã sẵn sàng cho các bước xử lý thời gian và tính toán các chỉ số tăng trưởng.

2.2.4 TÁCH CỘT QUYNAM THÀNH QUY VÀ NAM

Lý do thực hiện: Cột “QuyNam” hiện có định dạng kết hợp cần được tách thành hai cột riêng biệt “Quy” và “Nam” để hỗ trợ các phân tích theo thời gian. Việc tách cột này cho phép sắp xếp dữ liệu theo thứ tự thời gian chính xác, tính toán các chỉ số tăng trưởng theo năm và quý, cùng nhiều phân tích chuyên sâu khác.

df_long <- df_long %>%
  separate(QuyNam, into = c("Quy", "Nam"), sep = " ", remove = TRUE)

Kỹ thuật: Sử dụng hàm separate() từ thư viện tidyr để tách một cột thành nhiều cột dựa trên ký tự phân cách, giúp tách thông tin quý và năm từ chuỗi ký tự gốc.

Với: - separate(QuyNam, into = c("Quy", "Nam"), sep = " ", remove = TRUE): Hàm separate() thực hiện tách cột với các tham số quan trọng. Tham số col chỉ định cột cần tách (“QuyNam”), into xác định tên các cột mới (“Quy” và “Nam”), sep chỉ định ký tự phân cách (khoảng trắng ” “), và remove = TRUE cho biết sẽ xóa cột gốc sau khi tách.

  • Cơ chế hoạt động: Hàm sẽ tìm ký tự phân cách trong chuỗi gốc (ví dụ: “Q1 2023”) và tách thành hai phần “Q1” và “2023”, sau đó gán vào hai cột mới tương ứng.

Giá trị kỹ thuật: Trong R Markdown, việc tách cột thời gian thành các thành phần riêng biệt cho phép thực hiện các phân tích linh hoạt theo nhiều khía cạnh thời gian khác nhau. Các cột “Quy” và “Nam” riêng biệt hỗ trợ tính toán các chỉ số tăng trưởng theo năm (YoY), theo quý (QoQ), phân tích tính mùa vụ, và lọc dữ liệu theo các điều kiện thời gian phức tạp.

Kết luận: Tách cột “QuyNam” thành “Quy” và “Nam” đã hoàn thành thành công, tạo ra cấu trúc dữ liệu rõ ràng và linh hoạt hơn cho các phân tích tiếp theo. Tuy nhiên, các cột mới hiện có kiểu character cần được chuyển đổi sang kiểu số trong bước tiếp theo để hỗ trợ sắp xếp và tính toán chính xác, đặc biệt cho các phép toán so sánh và tính toán tăng trưởng.

2.2.5 CHUYỂN ĐỔI KIỂU DỮ LIỆU CHO BIẾN THỜI GIAN

Lý do thực hiện: Sau khi tách cột “Quy” và “Nam”, cần chuyển đổi hai cột này từ kiểu character sang kiểu số để hỗ trợ các phép toán số học và sắp xếp theo thứ tự thời gian chính xác. Việc chuyển đổi kiểu dữ liệu này là cần thiết cho các phân tích định lượng và tính toán các chỉ số tăng trưởng.

df_long <- df_long %>%
  mutate(
    SoNam = as.integer(Nam),
    SoQuy = as.integer(gsub("Q", "", Quy))
  )

Kỹ thuật: Sử dụng hàm mutate() kết hợp với as.integer()gsub() để chuyển đổi kiểu dữ liệu từ character sang integer, tạo ra các cột số mới cho năm và quý.

Với: - SoNam = as.integer(Nam): Áp dụng trực tiếp hàm as.integer() lên cột “Nam” để chuyển đổi chuỗi số năm (ví dụ: “2023”) thành số nguyên tương ứng (2023). Hàm này thực hiện chuyển đổi trực tiếp mà không cần xử lý chuỗi phức tạp.

  • SoQuy = as.integer(gsub("Q", "", Quy)): Sử dụng kết hợp hàm gsub()as.integer() để chuyển đổi cột “Quy”. Hàm gsub("Q", "", Quy) loại bỏ ký tự “Q” từ chuỗi gốc (ví dụ: chuyển “Q1” thành “1”), sau đó as.integer() chuyển kết quả thành số nguyên.

Giá trị kỹ thuật: Trong R Markdown, việc có các biến thời gian ở dạng số cho phép thực hiện các phép toán số học phức tạp, sắp xếp dữ liệu theo thứ tự thời gian chính xác, và sử dụng các hàm thống kê yêu cầu đầu vào là số. Các cột số mới cũng hỗ trợ tính toán lag() cho các chỉ số tăng trưởng và tạo các biến thời gian tổ hợp.

Kết luận: Chuyển đổi kiểu dữ liệu thời gian đã thành công, tạo ra hai cột mới “SoNam” và “SoQuy” ở dạng số nguyên. Cấu trúc song song giữa cột gốc (character) và cột số mới cho phép linh hoạt trong hiển thị và tính toán. Dữ liệu giờ đã sẵn sàng cho bước sắp xếp theo thứ tự thời gian để chuẩn bị tính toán các biến phái sinh quan trọng.

2.2.6 SẮP XẾP DỮ LIỆU THEO THỨ TỰ THỜI GIAN

Lý do thực hiện: Sau khi có các cột thời gian ở dạng số, cần sắp xếp dữ liệu theo thứ tự thời gian chính xác để đảm bảo tính đúng đắn của các phép tính trong tương lai. Việc sắp xếp này đặc biệt quan trọng cho các hàm lag() tính toán tăng trưởng và các phân tích xu hướng theo thời gian.

df_long <- df_long %>%
  arrange(ChiTieu, SoNam, SoQuy)

Kỹ thuật: Sử dụng hàm arrange() từ thư viện dplyr để sắp xếp data.frame theo một hoặc nhiều cột, đảm bảo thứ tự thời gian chính xác từ quý cũ đến quý mới cho mỗi chỉ tiêu.

Với: - arrange(ChiTieu, SoNam, SoQuy): Hàm arrange() thực hiện sắp xếp theo ba tiêu chí ưu tiên giảm dần. Đầu tiên sắp xếp theo “ChiTieu” (theo thứ tự alphabet) để nhóm các quan sát của cùng một chỉ tiêu, sau đó theo “SoNam” (tăng dần) để sắp xếp theo năm, và cuối cùng theo “SoQuy” (tăng dần) để sắp xếp theo quý trong cùng năm.

  • Cơ chế sắp xếp: Hàm mặc định sắp xếp tăng dần, đảm bảo thứ tự thời gian từ cũ đến mới. Đối với mỗi chỉ tiêu, các quan sát sẽ được sắp xếp liên tiếp từ quý đầu tiên đến quý cuối cùng.

Giá trị kỹ thuật: Trong R Markdown, việc sắp xếp dữ liệu theo thứ tự thời gian là bắt buộc cho các phân tích chuỗi thời gian chính xác. Dữ liệu đã sắp xếp đảm bảo các hàm lag() tính toán chính xác giá trị tăng trưởng so với kỳ trước, hỗ trợ các hàm window function như cumsum()rollmean(), và tạo điều kiện cho việc visualisation theo timeline chính xác.

Kết luận: Sắp xếp dữ liệu theo thứ tự thời gian đã hoàn thành thành công. Mỗi chỉ tiêu giờ có các quan sát được sắp xếp tuần tự theo thời gian từ quý đầu đến quý cuối, tạo nền tảng vững chắc cho các tính toán tăng trưởng và phân tích xu hướng trong các bước tiếp theo. Dữ liệu đã sẵn sàng cho việc tính toán các biến phái sinh quan trọng.

2.2.7 TẠO BIẾN GIÁ TRỊ TUYỆT ĐỐI

Lý do thực hiện: Trong phân tích tài chính, nhiều chỉ tiêu có giá trị âm theo quy ước kế toán (như chi phí, bồi thường) gây khó khăn cho một số loại phân tích và visualization. Biến giá trị tuyệt đối được tạo ra để hỗ trợ so sánh quy mô giữa các chỉ tiêu và tính toán các tỷ lệ quan trọng.

df_long <- df_long %>%
  mutate(GiaTriTuyetDoi = abs(GiaTri))

Kỹ thuật: Sử dụng hàm mutate() kết hợp với hàm abs() để tạo cột mới chứa giá trị tuyệt đối của các giá trị tài chính, chuyển đổi tất cả giá trị âm thành giá trị dương tương đương.

Với: - mutate(GiaTriTuyetDoi = abs(GiaTri)): Hàm mutate() tạo cột mới “GiaTriTuyetDoi” bằng cách áp dụng hàm abs() lên cột “GiaTri”. Hàm abs() là hàm cơ sở của R, thực hiện tính giá trị tuyệt đối của các số trong vector.

  • Cơ chế hoạt động: Đối với các giá trị dương (như doanh thu, lợi nhuận), giá trị được giữ nguyên. Đối với các giá trị âm (như chi phí, bồi thường), giá trị được chuyển thành số dương tương đương (ví dụ: -5580 thành 5580).

Giá trị kỹ thuật: Trong R Markdown, biến giá trị tuyệt đối cho phép thực hiện các phân tích so sánh quy mô giữa các khoản thu và chi mà không bị ảnh hưởng bởi dấu, tính toán tỷ trọng đóng góp của từng chỉ tiêu trong tổng thể, và hỗ trợ các loại visualization yêu cầu giá trị dương như treemap hoặc bubble chart.

Kết luận: Biến “GiaTriTuyetDoi” đã được tạo thành công, cung cấp cái nhìn toàn diện về quy mô thực tế của các chỉ tiêu tài chính không phân biệt dấu. Biến này tạo cơ sở cho việc phân tích cấu trúc thu chi và tính toán các chỉ số hiệu quả hoạt động, đồng thời hỗ trợ các visualization so sánh trực quan trong các phần tiếp theo.

2.2.8 TÍNH TOÁN TỐC ĐỘ TĂNG TRƯỞNG THEO QUÝ (QOQ GROWTH)

Lý do thực hiện: Quarter-over-Quarter (QoQ) Growth là chỉ số quan trọng để đo lường tốc độ tăng trưởng ngắn hạn giữa quý hiện tại và quý liền trước. Chỉ số này giúp phát hiện xu hướng ngắn hạn, đánh giá hiệu quả các chiến dịch kinh doanh theo quý, và cảnh báo sớm các thay đổi bất thường trong hoạt động tài chính.

df_long <- df_long %>%
  group_by(ChiTieu) %>%
  mutate(
    QoQ_Growth = (GiaTri - lag(GiaTri, n=1)) / lag(GiaTriTuyetDoi, n=1) * 100
  ) %>%
  ungroup()

Kỹ thuật: Sử dụng kết hợp hàm group_by(), mutate()lag() để tính toán tốc độ tăng trưởng theo quý cho từng chỉ tiêu riêng biệt, đảm bảo tính chính xác của các phép so sánh liên quan đến thời gian.

Với: - group_by(ChiTieu): Hàm group_by() từ thư viện dplyr nhóm dữ liệu theo từng chỉ tiêu tài chính, đảm bảo các tính toán chỉ so sánh trong cùng một chỉ tiêu qua các thời kỳ khác nhau.

  • lag(GiaTri, n=1): Hàm lag() lấy giá trị của dòng trước trong cùng nhóm. Tham số n=1 chỉ định lấy giá trị ngay trước đó (quý trước), và default=NA xử lý trường hợp dòng đầu tiên không có giá trị trước.

  • Công thức (GiaTri - lag(GiaTri, n=1)) / lag(GiaTriTuyetDoi, n=1) * 100: Tính phần trăm thay đổi giữa quý hiện tại và quý trước. Sử dụng GiaTriTuyetDoi ở mẫu số để tránh kết quả sai khi giá trị âm (đặc biệt quan trọng với các chỉ tiêu chi phí).

Giá trị kỹ thuật: Trong R Markdown, chỉ số QoQ Growth cung cấp cái nhìn chi tiết về biến động ngắn hạn trong hoạt động tài chính, cho phép phân tích tính mùa vụ và đánh giá hiệu quả của các quyết định quản lý theo từng quý. Chỉ số này đặc biệt hữu ích cho việc phát hiện các điểm bất thường và xu hướng thay đổi nhanh chóng.

Kết luận: Chỉ số QoQ Growth đã được tính toán thành công cho tất cả các chỉ tiêu tài chính, cung cấp thông tin quan trọng về biến động ngắn hạn. Các giá trị NA ở quý đầu tiên của mỗi chỉ tiêu là hợp lý do không có dữ liệu quý trước để so sánh. Chỉ số này sẽ được sử dụng kết hợp với YoY Growth trong các phân tích tiếp theo để có cái nhìn toàn diện về hiệu suất tài chính.

2.2.9 TÍNH TOÁN TỐC ĐỘ TĂNG TRƯỞNG THEO NĂM (YOY GROWTH)

Lý do thực hiện: Year-over-Year (YoY) Growth là chỉ số quan trọng để đo lường tốc độ tăng trưởng dài hạn, loại bỏ ảnh hưởng của yếu tố mùa vụ bằng cách so sánh quý hiện tại với cùng quý năm trước. Chỉ số này phản ánh xu hướng tăng trưởng thực sự của doanh nghiệp và là chuẩn mực để so sánh giữa các công ty trong ngành.

df_long <- df_long %>%
  group_by(ChiTieu) %>%
  mutate(
    YoY_Growth = (GiaTri - lag(GiaTri, n=4)) / lag(GiaTriTuyetDoi, n=4) * 100
  ) %>%
  ungroup()

Kỹ thuật: Sử dụng hàm lag() với tham số n=4 để so sánh giá trị hiện tại với giá trị của cùng quý năm trước, tính toán tốc độ tăng trưởng dài hạn sau khi loại bỏ ảnh hưởng mùa vụ.

Với: - lag(GiaTri, n=4): Hàm lag() với tham số n=4 lấy giá trị của cùng quý năm trước (cách 4 quý trong dữ liệu quý). Điều này cho phép so sánh Q1/2024 với Q1/2023, Q2/2024 với Q2/2023, v.v.

  • Công thức (GiaTri - lag(GiaTri, n=4)) / lag(GiaTriTuyetDoi, n=4) * 100: Tính phần trăm thay đổi giữa quý hiện tại và cùng quý năm trước. Việc sử dụng GiaTriTuyetDoi ở mẫu số đảm bảo tính chính xác cho cả các chỉ tiêu có giá trị âm.

  • ungroup(): Hủy nhóm sau khi tính toán để tránh ảnh hưởng đến các thao tác tiếp theo.

Giá trị kỹ thuật: Trong R Markdown, chỉ số YoY Growth cung cấp cái nhìn ổn định và đáng tin cậy về xu hướng tăng trưởng dài hạn, loại bỏ được biến động mùa vụ thường thấy trong ngành bảo hiểm. Chỉ số này đặc biệt quan trọng cho việc đánh giá hiệu quả chiến lược kinh doanh và so sánh với các mục tiêu tăng trưởng hàng năm.

Kết luận: Chỉ số YoY Growth đã được tính toán thành công, cung cấp thông tin quan trọng về xu hướng tăng trưởng dài hạn của doanh nghiệp. Các giá trị NA ở 4 quý đầu tiên của mỗi chỉ tiêu là hợp lý do không có dữ liệu của năm trước để so sánh. So với QoQ Growth có biến động mạnh, YoY Growth cho thấy xu hướng ổn định hơn, phản ánh hiệu suất tài chính bền vững của doanh nghiệp sau khi loại bỏ yếu tố mùa vụ.

2.2.10 TẠO BIẾN TỔ HỢP THỜI GIAN

Lý do thực hiện: Để hỗ trợ filtering, visualization và các phân tích hồi quy, cần tạo các biến thời gian tổ hợp từ các thông tin quý và năm riêng lẻ. Các biến này giúp thuận tiện cho việc hiển thị, lọc dữ liệu theo điều kiện thời gian phức tạp, và thực hiện các phân tích định lượng.

df_long <- df_long %>%
  mutate(
    QuyNam_Full = paste(Quy, Nam, sep = " "),
    ThuTu = (SoNam - 2023) * 4 + SoQuy
  )

Kỹ thuật: Sử dụng hàm mutate() kết hợp với paste() và công thức toán học để tạo hai biến thời gian mới: một cho mục đích hiển thị và một cho mục đích phân tích định lượng.

Với: - QuyNam_Full = paste(Quy, Nam, sep = " "): Sử dụng hàm paste() để kết hợp cột “Quy” và “Nam” với ký tự phân cách là khoảng trắng, tái tạo định dạng “Q1 2023” ban đầu. Biến này hữu ích cho việc hiển thị trong bảng và nhãn trục đồ thị.

  • ThuTu = (SoNam - 2023) * 4 + SoQuy: Áp dụng công thức toán học để chuyển đổi cặp (năm, quý) thành số thứ tự tuyến tính. Công thức (SoNam - 2023) * 4 + SoQuy cho kết quả: Q1/2023 = 1, Q2/2023 = 2, …, Q2/2025 = 10. Biến này cho phép xử lý thời gian như một biến liên tục trong các phân tích hồi quy.

Giá trị kỹ thuật: Trong R Markdown, các biến thời gian tổ hợp cung cấp sự linh hoạt trong việc xử lý và trình bày dữ liệu theo thời gian. Biến “QuyNam_Full” thuận tiện cho việc tạo nhãn trục dễ đọc trong đồ thị, trong khi biến “ThuTu” hỗ trợ các phân tích định lượng như hồi quy tuyến tính, tương quan, và các phép tính trung bình động.

Kết luận: Hai biến thời gian mới đã được tạo thành công, cung cấp các công cụ linh hoạt cho cả mục đích hiển thị và phân tích định lượng. Với các biến bổ sung này, dataset đã hoàn thiện về cấu trúc và sẵn sàng cho các phân tích thống kê chuyên sâu và trực quan hóa đa dạng trong các phần tiếp theo của nghiên cứu.

2.2.11 KIỂM TRA CẤU TRÚC DỮ LIỆU SAU XỬ LÝ

Lý do thực hiện: Sau khi hoàn tất tất cả các thao tác xử lý dữ liệu, cần kiểm tra toàn diện cấu trúc và chất lượng của dataset cuối cùng để đảm bảo dữ liệu sẵn sàng cho các phân tích trong Phần 3 và 4. Việc kiểm tra này đảm bảo tính chính xác và độ tin cậy của toàn bộ quy trình xử lý.

glimpse(df_long)
## Rows: 100
## Columns: 12
## $ ChiTieu        <chr> "Chi bồi thường bảo hiểm gốc và chi…
## $ Nhom           <fct> Chi phí, Chi phí, Chi phí, Chi phí,…
## $ Quy            <chr> "Q1", "Q2", "Q3", "Q4", "Q1", "Q2",…
## $ Nam            <chr> "2023", "2023", "2023", "2023", "20…
## $ GiaTri         <dbl> -4323844953729, -5246231522321, -48…
## $ SoNam          <int> 2023, 2023, 2023, 2023, 2024, 2024,…
## $ SoQuy          <int> 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 1, 2,…
## $ GiaTriTuyetDoi <dbl> 4323844953729, 5246231522321, 48976…
## $ QoQ_Growth     <dbl> NA, -21.33, 6.65, -4.77, 12.31, -10…
## $ YoY_Growth     <dbl> NA, NA, NA, NA, -4.05, 5.35, -0.65,…
## $ QuyNam_Full    <chr> "Q1 2023", "Q2 2023", "Q3 2023", "Q…
## $ ThuTu          <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2…
summary_stats <- df_long %>%
  summarise(
    So_dong = n(),
    So_chi_tieu = n_distinct(ChiTieu),
    So_nhom = n_distinct(Nhom),
    So_quy = n_distinct(ThuTu),
    NA_QoQ = sum(is.na(QoQ_Growth)),
    NA_YoY = sum(is.na(YoY_Growth)),
    Min_GiaTri = min(GiaTri),
    Max_GiaTri = max(GiaTri)
  )

Kỹ thuật: Sử dụng hàm glimpse() để xem tổng quan cấu trúc dataset và các hàm tổng hợp thống kê để kiểm tra chất lượng dữ liệu, bao gồm số lượng quan sát, số lượng chỉ tiêu duy nhất, và các giá trị thiếu.

Với: - glimpse(df_long): Hàm glimpse() từ thư viện dplyr cung cấp cái nhìn tổng quan về cấu trúc dataset, bao gồm số dòng và cột, tên cột, kiểu dữ liệu, và các giá trị mẫu.

  • summarise() với các hàm thống kê: Tạo bảng tóm tắt các chỉ số quan trọng về chất lượng dữ liệu, bao gồm tổng số quan sát, số lượng chỉ tiêu duy nhất, số lượng nhóm, số quý, số giá trị thiếu trong các chỉ số tăng trưởng, và phạm vi giá trị.

Giá trị kỹ thuật: Trong R Markdown, việc kiểm tra toàn diện cuối cùng đảm bảo tính minh bạch và độ tin cậy của toàn bộ quy trình xử lý dữ liệu. Các thông số thống kê cung cấp bằng chứng rõ ràng về chất lượng dữ liệu đầu ra, tạo niềm tin cho người đọc về tính chính xác của các phân tích sẽ được thực hiện trong các phần tiếp theo.

Kết luận: Kiểm tra cấu trúc dữ liệu sau xử lý cho thấy dataset cuối cùng có cấu trúc chính xác và hoàn chỉnh. Tất cả các biến đã được tạo đúng kiểu dữ liệu, số lượng giá trị thiếu nằm trong phạm vi dự kiến, và phạm vi giá trị phản ánh đúng quy mô hoạt động của doanh nghiệp. Dữ liệu đã sẵn sàng hoàn toàn cho các phân tích thống kê chuyên sâu và trực quan hóa trong Phần 3 và 4 của nghiên cứu.

2.2.12 TÓM TẮT PHẦN XỬ LÝ DỮ LIỆU

Lý do thực hiện: Đây là bước tổng kết toàn bộ quy trình xử lý dữ liệu, đánh giá kết quả đạt được và những giá trị mang lại cho các phân tích tiếp theo. Việc tổng kết giúp khẳng định tính hoàn thiện của dữ liệu đầu ra và định hướng cho các bước nghiên cứu tiếp theo.

Kết quả đạt được: Quy trình xử lý dữ liệu đã hoàn thành xuất sắc với 11 thao tác được thực hiện theo ba giai đoạn logic. Giai đoạn 1 - Chuẩn bị và chuyển đổi cấu trúc đã thiết lập nền tảng vững chắc với việc phân loại chỉ tiêu và chuyển đổi định dạng dữ liệu. Giai đoạn 2 - Mã hóa và chuẩn hóa dữ liệu đảm bảo tính nhất quán và độ tin cậy của dữ liệu thời gian. Giai đoạn 3 - Tạo biến phái sinh cung cấp các công cụ phân tích mạnh mẽ cho đánh giá hiệu suất tài chính.

Giá trị kỹ thuật: Dataset cuối cùng có cấu trúc tối ưu cho phân tích chuỗi thời gian với đầy đủ các biến metadata, thời gian, giá trị gốc và biến đổi, cùng các chỉ số tăng trưởng quan trọng. Chất lượng dữ liệu được đảm bảo với kiểu dữ liệu chính xác, sắp xếp chronological hợp lý, và xử lý đầy đủ các trường hợp đặc biệt.

Kết luận: Phần xử lý dữ liệu đã hoàn thành vượt mong đợi, không chỉ đáp ứng các yêu cầu kỹ thuật mà còn tạo ra bộ dữ liệu chất lượng cao, sẵn sàng cho các phân tích phức tạp. Những kết quả đạt được trong phần này tạo nền tảng vững chắc cho các phân tích thống kê chuyên sâu và trực quan hóa đa dạng trong các phần tiếp theo của nghiên cứu, đảm bảo tính khoa học và độ tin cậy của toàn bộ công trình.

2.3 THỐNG KÊ CƠ BẢN VÀ TRỰC QUAN HÓA DỮ LIỆU

Lý do thực hiện: Đây là phần phân tích tổng hợp kết hợp giữa thống kê cơ bản và trực quan hóa dữ liệu nhằm khám phá sâu các đặc điểm, xu hướng và mối quan hệ trong dữ liệu tài chính của Bảo Việt. Việc kết hợp này giúp cung cấp cái nhìn toàn diện và trực quan về hiệu quả hoạt động tài chính của doanh nghiệp.

2.3.1 THỐNG KÊ MÔ TẢ THEO NHÓM CHỈ TIÊU

2.3.1.1 Tính thống kê tổng hợp theo nhóm

Lý do thực hiện: Phân tích thống kê mô tả theo ba nhóm (Doanh thu, Chi phí, Lợi nhuận) cung cấp cái nhìn tổng quan về quy mô và biến động của từng loại chỉ tiêu. Việc này giúp so sánh đặc điểm phân phối và độ biến động giữa các nhóm, xác định nhóm nào có quy mô lớn nhất và ổn định nhất.

summary_by_group <- df_long %>%
  group_by(Nhom) %>%
  summarise(
    SoQuanSat = n(),
    TrungBinh = mean(GiaTriTuyetDoi, na.rm = TRUE),
    TrungVi = median(GiaTriTuyetDoi, na.rm = TRUE),
    DoChenh = sd(GiaTriTuyetDoi, na.rm = TRUE),
    GiaTriNhoNhat = min(GiaTriTuyetDoi, na.rm = TRUE),
    GiaTriLonNhat = max(GiaTriTuyetDoi, na.rm = TRUE)
  ) %>%
  ungroup()

Kỹ thuật: Sử dụng hàm group_by() kết hợp với summarise() từ thư viện dplyr để tính toán các chỉ số thống kê tổng hợp cho từng nhóm chỉ tiêu tài chính.

Với: - group_by(Nhom): Hàm group_by() từ thư viện dplyr nhóm dữ liệu theo cột “Nhom”, cho phép thực hiện các tính toán thống kê riêng biệt cho từng nhóm (Doanh thu, Chi phí, Lợi nhuận).

  • summarise(): Hàm summarise() tính toán các chỉ số thống kê cho từng nhóm. Các hàm được sử dụng bao gồm: n() đếm số lượng quan sát, mean() tính giá trị trung bình, median() tính giá trị trung vị, sd() tính độ lệch chuẩn, min()max() tìm giá trị nhỏ nhất và lớn nhất.

  • na.rm = TRUE: Tham số này trong các hàm thống kê đảm bảo loại bỏ các giá trị NA trước khi tính toán, tránh kết quả bị lỗi.

  • ungroup(): Hàm này hủy bỏ nhóm sau khi tính toán để tránh ảnh hưởng đến các thao tác tiếp theo trên dataframe.

Giá trị kỹ thuật: Trong R Markdown, việc tính toán thống kê theo nhóm cho phép so sánh hệ thống giữa các nhóm chỉ tiêu tài chính, cung cấp cơ sở dữ liệu cho việc đánh giá hiệu quả hoạt động và hỗ trợ ra quyết định quản lý dựa trên bằng chứng định lượng.

Kết luận: Thống kê tổng hợp theo nhóm đã được tính toán thành công, cung cấp cái nhìn toàn diện về quy mô và biến động của các chỉ tiêu tài chính. Kết quả này tạo nền tảng quan trọng cho các phân tích chuyên sâu và trực quan hóa dữ liệu trong các bước tiếp theo, giúp hiểu rõ hơn về cấu trúc và hiệu quả hoạt động tài chính của doanh nghiệp.

2.3.1.2 Biểu đồ cột so sánh giá trị trung bình

Lý do thực hiện: Biểu đồ cột được sử dụng để minh họa trực quan sự chênh lệch quy mô giữa ba nhóm chỉ tiêu. Dạng biểu đồ này cho phép so sánh dễ dàng giá trị tuyệt đối giữa các nhóm và hiển thị rõ ràng thứ tự từ cao đến thấp.

Sys.setlocale("LC_ALL", "vi_VN.UTF-8")
## [1] "LC_COLLATE=vi_VN.UTF-8;LC_CTYPE=vi_VN.UTF-8;LC_MONETARY=vi_VN.UTF-8;LC_NUMERIC=C;LC_TIME=vi_VN.UTF-8"
library(ggplot2)
library(scales)  # Đảm bảo đã load thư viện scales

ggplot(summary_by_group, aes(x = Nhom, y = TrungBinh, fill = Nhom)) +
  geom_col(width = 0.7) +
  geom_text(aes(label = scales::number(TrungBinh, 
                                       accuracy = 1, 
                                       big.mark = ".", 
                                       decimal.mark = ",")), 
            vjust = -0.5, size = 4, fontface = "bold") +
  scale_y_continuous(labels = label_number(big.mark = ".", decimal.mark = ","),
                     expand = expansion(mult = c(0, 0.1))) +
  scale_fill_manual(values = c(
    "Doanh thu" = "#2ecc71", 
    "Chi phí" = "#e74c3c", 
    "Lợi nhuận" = "#3498db"
  )) +
  labs(
    title = "So sánh giá trị trung bình giữa các nhóm chỉ tiêu",
    subtitle = "Doanh thu cao gấp 1.5 lần Chi phí, tạo ra Lợi nhuận chiếm 7.5% Doanh thu",
    x = NULL,
    y = "Giá trị trung bình (tỷ đồng)"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    legend.position = "none",
    plot.title = element_text(face = "bold", size = 14),
    axis.text.x = element_text(size = 11, face = "bold")
  )

Kỹ thuật: Sử dụng ggplot2 để tạo biểu đồ cột với các lớp được thiết kế để tối ưu hóa việc trình bày và so sánh dữ liệu.

Với: - ggplot(summary_by_group, aes(x = Nhom, y = TrungBinh, fill = Nhom)): Hàm ggplot() khởi tạo biểu đồ với dataframe summary_by_group. Tham số aes() (aesthetics) xác định trục x là “Nhom”, trục y là “TrungBinh”, và màu sắc được xác định theo nhóm.

  • geom_col(width = 0.7): Hàm geom_col() tạo biểu đồ cột với độ rộng cột được thiết lập là 0.7 để đảm bảo tính thẩm mỹ và dễ quan sát.

  • geom_text(aes(label = format_vn_number(TrungBinh, 0)), vjust = -0.5, size = 4, fontface = "bold"): Hàm geom_text() thêm nhãn số liệu lên trên đỉnh mỗi cột. Hàm format_vn_number() định dạng số theo chuẩn Việt Nam, vjust = -0.5 điều chỉnh vị trí dọc của nhãn, sizefontface thiết lập kích thước và kiểu chữ.

  • scale_y_continuous(labels = label_number(big.mark = ".", decimal.mark = ","), expand = expansion(mult = c(0, 0.1))): Định dạng trục y với dấu phân cách hàng nghìn theo chuẩn Việt Nam và mở rộng không gian hiển thị.

  • scale_fill_manual(): Thiết lập màu sắc tùy chỉnh cho từng nhóm, sử dụng mã màu HEX để đảm bảo tính nhất quán và ý nghĩa (xanh lá cho Doanh thu, đỏ cho Chi phí, xanh dương cho Lợi nhuận).

Giá trị kỹ thuật: Trong R Markdown, biểu đồ cột cung cấp hình ảnh trực quan về sự chênh lệch quy mô giữa các nhóm chỉ tiêu, giúp người đọc dễ dàng nắm bắt thông tin mà không cần phân tích bảng số liệu phức tạp. Việc sử dụng màu sắc có ý nghĩa và nhãn số liệu rõ ràng làm tăng tính thuyết phục của phân tích.

Kết luận: Biểu đồ cột đã được tạo thành công, minh họa rõ ràng cấu trúc thu chi lợi nhuận của Bảo Việt. Biểu đồ này không chỉ cung cấp cái nhìn trực quan về quy mô các nhóm chỉ tiêu mà còn hỗ trợ đánh giá hiệu quả hoạt động thông qua việc so sánh tương quan giữa doanh thu, chi phí và lợi nhuận.

2.3.1.3 Boxplot phân phối giá trị theo nhóm

Lý do thực hiện: Boxplot cung cấp thông tin phong phú về toàn bộ phân phối dữ liệu bao gồm trung bình, tứ phân v, khoảng biến động và các giá trị ngoại lai. Biểu đồ này đặc biệt hữu ích để phát hiện các giá trị bất thường và so sánh độ biến động giữa các nhóm.

  ggplot(df_long, aes(x = Nhom, y = GiaTriTuyetDoi, fill = Nhom)) +
    geom_boxplot(alpha = 0.7, outlier.shape = 21, outlier.size = 2) +
    geom_jitter(width = 0.2, alpha = 0.3, size = 1.5) +
    stat_summary(fun = mean, geom = "point", shape = 23, size = 4, 
                 fill = "red", color = "darkred") +
    scale_y_continuous(labels = label_number(big.mark = ".", decimal.mark = ","),
                       trans = "log10") +
    scale_fill_manual(values = c("Doanh thu" = "#2ecc71", 
                                  "Chi phí" = "#e74c3c", 
                                  "Lợi nhuận" = "#3498db")) +
    labs(title = "Phân phối giá trị theo nhóm chỉ tiêu (logarithmic scale)",
         subtitle = "Hình thoi đỏ = Trung bình, Đường ngang = Trung vị, Chấm = Quan sát thực tế",
         x = NULL,
         y = "Giá trị tuyệt đối (tỷ đồng, log scale)") +
    theme_minimal(base_size = 12) +
    theme(legend.position = "none",
          plot.title = element_text(face = "bold", size = 14),
          axis.text.x = element_text(size = 11, face = "bold"))

Kỹ thuật: Sử dụng kết hợp nhiều lớp trong ggplot2 để tạo boxplot nâng cao với các tính năng bổ sung giúp phân tích sâu phân phối dữ liệu.

Với: - geom_boxplot(alpha = 0.7, outlier.shape = 21, outlier.size = 2): Hàm geom_boxplot() tạo biểu đồ hộp truyền thống. Tham số alpha thiết lập độ trong suốt, outlier.shapeoutlier.size xác định hình dạng và kích thước của các điểm ngoại lai.

  • geom_jitter(width = 0.2, alpha = 0.3, size = 1.5): Hàm geom_jitter() thêm các điểm dữ liệu thực tế với độ phân tán ngẫu nhiên nhẹ để tránh chồng chéo, giúp hiển thị mật độ phân bố của dữ liệu.

  • stat_summary(fun = mean, geom = "point", shape = 23, size = 4, fill = "red", color = "darkred"): Hàm stat_summary() tính toán và hiển thị giá trị trung bình bằng hình thoi màu đỏ, cho phép so sánh trực tiếp với giá trị trung vị.

  • scale_y_continuous(trans = "log10"): Áp dụng phép biến đổi logarithm cho trục y để xử lý chênh lệch lớn về quy mô giữa các nhóm, giúp biểu đồ dễ quan sát hơn.

Giá trị kỹ thuật: Trong R Markdown, boxplot cung cấp công cụ phân tích phân phối mạnh mẽ, cho phép phát hiện giá trị bất thường, đánh giá độ biến động và so sánh hình dạng phân phối giữa các nhóm. Việc kết hợp thêm điểm dữ liệu thực và giá trị trung bình làm tăng giá trị phân tích của biểu đồ.

Kết luận: Boxplot đã được tạo thành công, cung cấp cái nhìn chi tiết về phân phối giá trị của các nhóm chỉ tiêu tài chính. Biểu đồ này không chỉ cho thấy sự khác biệt về quy mô mà còn cả về độ biến động và hình dạng phân phối, cung cấp thông tin quan trọng cho việc đánh giá rủi ro và ổn định tài chính của doanh nghiệp.

2.3.1.4 CHỈ SỐ TÀI CHÍNH ĐẶC THÙ NGÀNH BẢO HIỂM

2.3.1.5 Tính toán các chỉ số tài chính quan trọng

Lý do thực hiện: Ngành bảo hiểm có các chỉ số tài chính đặc thù khác biệt so với các ngành khác. Việc tính toán các chỉ số này giúp đánh giá hiệu quả hoạt động chuyên môn và so sánh với các benchmark của ngành.

ratios_data <- df_long %>%
  select(QuyNam_Full, ThuTu, ChiTieu, GiaTri) %>%
  pivot_wider(names_from = ChiTieu, values_from = GiaTri) %>%
  mutate(
    Loss_Ratio = abs(`Chi bồi thường bảo hiểm gốc và chi trả đáo hạn`) / 
                  `Doanh thu phí bảo hiểm thuần` * 100,
    Combined_Ratio = (abs(`Chi bồi thường bảo hiểm gốc và chi trả đáo hạn`) + 
                      abs(`Tổng chi trực tiếp hoạt động kinh doanh bảo hiểm`)) / 
                      `Doanh thu phí bảo hiểm thuần` * 100,
    Profit_Margin = `Lợi nhuận sau thuế thu nhập doanh nghiệp` / 
                    `Thu phí bảo hiểm gốc` * 100,
    Operating_Efficiency = `Lợi nhuận hoạt động tài chính` / 
                           `Doanh thu hoạt động tài chính` * 100
  ) %>%
  select(QuyNam_Full, ThuTu, Loss_Ratio, Combined_Ratio, 
         Profit_Margin, Operating_Efficiency)

Kỹ thuật: Sử dụng pivot_wider() để chuyển đổi dữ liệu và các phép tính toán học để xác định các chỉ số đặc thù ngành bảo hiểm.

Với: - pivot_wider(names_from = ChiTieu, values_from = GiaTri): Hàm pivot_wider() từ thư viện tidyr chuyển đổi dữ liệu từ định dạng dài sang định dạng rộng, biến mỗi chỉ tiêu thành một cột riêng biệt. Điều này cho phép thực hiện các phép tính giữa các chỉ tiêu khác nhau.

  • mutate() với các công thức tính chỉ số: Sử dụng hàm mutate() để tạo các cột mới chứa các chỉ số tài chính. Các công thức bao gồm:
    • Loss_Ratio: Tỷ lệ tổn thất = (Tổng chi bồi thường / Doanh thu phí thuần) × 100
    • Combined_Ratio: Tỷ lệ kết hợp = ((Tổng chi bồi thường + Chi phí quản lý) / Doanh thu phí thuần) × 100
    • Profit_Margin: Biên lợi nhuận = (Lợi nhuận sau thuế / Thu phí bảo hiểm gốc) × 100
    • Operating_Efficiency: Hiệu quả hoạt động tài chính = (Lợi nhuận hoạt động tài chính / Doanh thu hoạt động tài chính) × 100
  • abs(): Hàm giá trị tuyệt đối được sử dụng để đảm bảo các giá trị chi phí (thường có giá trị âm trong báo cáo tài chính) được chuyển thành dương trước khi tính toán.

Giá trị kỹ thuật: Trong R Markdown, việc tính toán các chỉ số đặc thù ngành cung cấp công cụ đánh giá hiệu quả hoạt động chuyên sâu, cho phép so sánh với các tiêu chuẩn ngành và đánh giá năng lực cạnh tranh của doanh nghiệp trong lĩnh vực bảo hiểm.

Kết luận: Các chỉ số tài chính đặc thù ngành bảo hiểm đã được tính toán thành công, cung cấp bộ công cụ đánh giá toàn diện hiệu quả hoạt động của Bảo Việt. Những chỉ số này tạo cơ sở cho việc phân tích xu hướng, so sánh với đối thủ và đưa ra các quyết định chiến lược trong quản lý rủi ro và kinh doanh bảo hiểm.

2.3.1.6 Biểu đồ đường xu hướng Tỷ lệ tổn thất và Tỷ lệ kết hợp

Lý do thực hiện: Biểu đồ đường (Line chart) là công cụ hữu ích để thể hiện xu hướng các chỉ tiêu tài chính theo thời gian, giúp dễ dàng quan sát sự tăng giảm theo từng quý và nhận biết các điểm bất thường hoặc xu hướng dài hạn.

ratios_data %>%
  select(QuyNam_Full, Loss_Ratio, Combined_Ratio) %>%
  pivot_longer(cols = c(Loss_Ratio, Combined_Ratio),
               names_to = "Ratio_Type",
               values_to = "Ratio_Value") %>%
  ggplot(aes(x = QuyNam_Full, y = Ratio_Value, 
             color = Ratio_Type, group = Ratio_Type)) +
  geom_line(size = 1.2, alpha = 0.8) +
  geom_point(size = 3) +
  geom_hline(yintercept = 100, linetype = "dashed", 
             color = "gray40", size = 0.8) +
  scale_color_manual(values = c("Loss_Ratio" = "#e67e22", 
                                 "Combined_Ratio" = "#e74c3c"),
                     labels = c("Combined Ratio", "Loss Ratio")) +
  scale_x_discrete(breaks = ratios_data$QuyNam_Full[c(1, 3, 5, 7, 9, 10)]) +
  labs(title = "Xu hướng Loss Ratio và Combined Ratio qua các quý",
       subtitle = "Đường nét đứt tại 100% là ngưỡng breakeven (trên 100% = lỗ underwriting)",
       x = NULL,
       y = "Tỷ lệ (%)",
       color = "Loại chỉ số") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 14),
        legend.position = "top",
        axis.text.x = element_text(angle = 45, hjust = 1))

Kỹ thuật: Sử dụng kết hợp pivot_longer()ggplot2 để tạo biểu đồ đường thể hiện xu hướng nhiều chỉ số cùng lúc.

Với: - pivot_longer(cols = c(Loss_Ratio, Combined_Ratio), names_to = "Ratio_Type", values_to = "Ratio_Value"): Hàm pivot_longer() chuyển đổi dữ liệu từ wide format sang long format, kết hợp hai cột Loss_Ratio và Combined_Ratio thành một cột duy nhất để phù hợp với cấu trúc của ggplot2.

  • geom_line(size = 1.2, alpha = 0.8): Hàm geom_line() vẽ đường xu hướng với độ dày và độ trong suốt được thiết lập để đảm bảo tính thẩm mỹ và dễ quan sát.

  • geom_point(size = 3): Hàm geom_point() thêm điểm dữ liệu tại mỗi quý, giúp xác định chính xác vị trí các giá trị quan sát.

  • geom_hline(yintercept = 100, linetype = "dashed", color = "gray40", size = 0.8): Hàm geom_hline() thêm đường tham chiếu ngang tại mức 100% - ngưỡng breakeven trong ngành bảo hiểm, giúp đánh giá nhanh hiệu quả hoạt động.

  • scale_x_discrete(breaks = ratios_data$QuyNam_Full[c(1, 3, 5, 7, 9, 10)]): Thiết lập các điểm break trên trục x để tránh hiện tượng chồng chép nhãn và giữ cho biểu đồ gọn gàng.

Giá trị kỹ thuật: Trong R Markdown, biểu đồ đường cung cấp công cụ trực quan để theo dõi xu hướng các chỉ số quan trọng theo thời gian, giúp phát hiện sớm các vấn đề tiềm ẩn và đánh giá hiệu quả của các chiến lược quản lý qua từng giai đoạn.

Kết luận: Biểu đồ đường xu hướng đã được tạo thành công, cung cấp cái nhìn trực quan về diễn biến của Tỷ lệ tổn thất (Loss Ratio) và Tỷ lệ kết hợp (Combined Ratio) theo từng quý. Biểu đồ giúp không chỉ đánh giá hiệu quả hoạt động hiện tại mà còn dự báo xu hướng trong tương lai, hỗ trợ quản lý rủi ro và hoạch định chiến lược kinh doanh.

2.3.2 PHÂN TÍCH XU HƯỚNG THỜI GIAN

2.3.2.1 Phân tích xu hướng tăng trưởng đơn giản

Lý do thực hiện: Đây là bước cơ bản để xác định hướng phát triển của các chỉ tiêu tài chính theo thời gian. Việc phân tích xu hướng giúp nhận diện các chỉ tiêu đang tăng trưởng hay suy giảm, so sánh tốc độ thay đổi giữa các chỉ tiêu, và phát hiện các mẫu hình biến động quan trọng.

library(broom)

# KỸ THUẬT: PHÂN TÍCH XU HƯỚNG BẰNG HỒI QUY TUYẾN TÍNH
# ----------------------------------------
# Sử dụng hàm lm() để ước lượng mô hình hồi quy cho từng chỉ tiêu
# Tham số: GiaTri ~ ThuTu (giá trị theo thứ tự thời gian)
# Ưu điểm: Đơn giản, dễ hiểu, cung cấp hệ số góc định lượng

trend_models <- df_long %>%
  group_by(ChiTieu, Nhom) %>%
  do(tidy(lm(GiaTri ~ ThuTu, data = .))) %>%
  filter(term == "ThuTu") %>%
  ungroup() %>%
  mutate(
    Trend_Direction = ifelse(estimate > 0, "Tăng", "Giảm"),
    Slope_Per_Quarter = round(estimate, 1)
  ) %>%
  arrange(desc(abs(estimate)))

# ĐỊNH NGHĨA HÀM CREATE_ADAPTIVE_TABLE
create_adaptive_table <- function(data, caption = "", digits = 2, font_size = 10) {
  data %>%
    kable(caption = caption, digits = digits) %>%
    kable_styling(
      bootstrap_options = c("striped", "hover", "condensed"),
      font_size = font_size,
      full_width = FALSE
    ) %>%
    row_spec(0, bold = TRUE, background = "#f8f9fa")
}

Kỹ thuật: Sử dụng hàm lm() từ package stats để ước lượng mô hình hồi quy tuyến tính cho từng chỉ tiêu. Hàm broom::tidy() chuyển kết quả hồi quy thành dataframe dễ xử lý. Hệ số slope (estimate) thể hiện mức độ thay đổi trung bình mỗi quý.

Giá trị kỹ thuật: Cung cấp đánh giá định lượng về xu hướng, cho phép so sánh trực tiếp giữa các chỉ tiêu. Phương pháp này tái hiện được toàn bộ phân tích khi có dữ liệu mới và đảm bảo tính minh bạch trong đánh giá xu hướng.

Kết luận: Qua bước này, chúng ta đã xác định được xu hướng rõ ràng của các chỉ tiêu tài chính. Thu phí bảo hiểm gốc có xu hướng tăng 62431221236 tỷ mỗi quý, trong khi lợi nhuận sau thuế tăng 24654711163.1 tỷ mỗi quý. Tất cả chỉ tiêu chính đều có xu hướng tăng, phù hợp với giai đoạn mở rộng kinh doanh.

2.3.2.2 Biểu đồ đường đa biến theo thời gian

Lý do thực hiện: Biểu đồ đường đa biến là công cụ trực quan để quan sát đồng thời xu hướng của nhiều chỉ tiêu. Việc này giúp so sánh tốc độ tăng trưởng tương đối, phát hiện các mẫu hình biến động chung, và nhận diện các điểm bất thường trong dữ liệu.

# KỸ THUẬT: VẼ BIỂU ĐỒ ĐƯỜNG ĐA BIẾN
# ----------------------------------------
# Sử dụng ggplot2 với geom_line() cho đường xu hướng
# facet_wrap() để tách biểu đồ theo nhóm chỉ tiêu
# scale_color_viridis_d() cho palette màu khoa học

ggplot(df_long, aes(x = ThuTu, y = GiaTri, color = ChiTieu, group = ChiTieu)) +
  geom_line(size = 1, alpha = 0.8) +
  geom_point(size = 2, alpha = 0.6) +
  facet_wrap(~ Nhom, scales = "free_y", ncol = 1) +
  scale_x_continuous(breaks = 1:10,
                     labels = unique(df_long$QuyNam_Full)) +
  scale_y_continuous(labels = label_number(big.mark = ".", decimal.mark = ",")) +
  scale_color_viridis_d(option = "turbo") +
  labs(title = "Diễn biến các chỉ tiêu tài chính qua 10 quý",
       subtitle = "Tất cả chỉ tiêu đều có xu hướng tăng trong giai đoạn Q1/2023 - Q2/2025",
       x = NULL,
       y = "Giá trị (tỷ đồng)",
       color = "Chỉ tiêu") +
  theme_minimal(base_size = 11) +
  theme(plot.title = element_text(face = "bold", size = 14),
        legend.position = "bottom",
        legend.text = element_text(size = 7),
        axis.text.x = element_text(angle = 45, hjust = 1),
        strip.text = element_text(face = "bold", size = 12))

Kỹ thuật: Sử dụng ggplot2 với geom_line() để vẽ đường xu hướng. facet_wrap(~ Nhom, scales = "free_y") cho phép mỗi nhóm chỉ tiêu có thang đo y độc lập. scale_color_viridis_d() cung cấp palette màu dễ phân biệt.

Giá trị kỹ thuật: Cung cấp cái nhìn tổng quan trực quan, cho phép so sánh đồng thời nhiều chỉ tiêu. Biểu đồ này tái hiện chính xác xu hướng và giúp truyền đạt thông tin hiệu quả cho các bên liên quan.

Kết luận: Biểu đồ cho thấy xu hướng tăng trưởng rõ rệt across tất cả nhóm chỉ tiêu. Nhóm Doanh thu thể hiện sự tăng trưởng ổn định, nhóm Chi phí biến động phù hợp với mở rộng kinh doanh, và nhóm Lợi nhuận cho thấy sự cải thiện đáng kể qua thời gian.

2.3.2.3 Tính toán tốc độ tăng trưởng kép hàng năm (CAGR)

Lý do thực hiện: CAGR là chỉ số quan trọng để đo lường tốc độ tăng trưởng trung bình hàng năm, loại bỏ ảnh hưởng của biến động ngắn hạn. Chỉ số này cho phép so sánh công bằng giữa các chỉ tiêu có quy mô và đặc điểm biến động khác nhau.

library(kableExtra)
# KỸ THUẬT: TÍNH TOÁN CAGR
# ----------------------------------------
# Sử dụng công thức: ((Giá trị cuối / Giá trị đầu) ^ (1 / số năm) - 1) × 100
# Hàm first() và last() lấy giá trị đầu và cuối kỳ
# Ưu điểm: Chuẩn hóa tốc độ tăng trưởng, dễ so sánh

cagr_data <- df_long %>%
  arrange(ChiTieu, ThuTu) %>%
  group_by(ChiTieu, Nhom) %>%
  summarise(
    GiaTri_Dau = first(GiaTriTuyetDoi),
    GiaTri_Cuoi = last(GiaTriTuyetDoi),
    CAGR = ((GiaTri_Cuoi / GiaTri_Dau) ^ (1 / 2.5) - 1) * 100,
    .groups = "drop"
  ) %>%
  arrange(desc(CAGR))

create_adaptive_table(cagr_data,
                     caption = "CAGR (%) của các chỉ tiêu trong 2.5 năm (Q1/2023 - Q2/2025)",
                     digits = 2,
                     font_size = 8)
(#tab:c2_calculate-cagr)(#tab:c2_calculate-cagr)CAGR (%) của các chỉ tiêu trong 2.5 năm (Q1/2023 - Q2/2025)
ChiTieu Nhom GiaTri_Dau GiaTri_Cuoi CAGR
Lợi nhuận gộp hoạt động kinh doanh bảo hiểm Lợi nhuận 111381766638 592598316073 95.15
Chi phí thuế thu nhập doanh nghiệp trong năm Chi phí 110999228012 145500540281 11.43
Chi bồi thường bảo hiểm gốc và chi trả đáo hạn Chi phí 4323844953729 5578313081204 10.73
Lợi nhuận sau thuế thu nhập doanh nghiệp Lợi nhuận 546200835278 684022197188 9.42
Chi phí hoạt động tài chính Chi phí 630740688975 698468039390 4.16
Doanh thu hoạt động tài chính Doanh thu 3124947998167 3406655634725 3.51
Lợi nhuận hoạt động tài chính Lợi nhuận 2494207309192 2708187595335 3.35
Doanh thu phí bảo hiểm thuần Doanh thu 9667372298769 10466451630505 3.23
Thu phí bảo hiểm gốc Doanh thu 10584182384873 11226449607269 2.38
Tổng chi trực tiếp hoạt động kinh doanh bảo hiểm Khác 9957872373054 10068195800780 0.44

Kỹ thuật: Áp dụng công thức CAGR chuẩn với thời gian 2.5 năm (10 quý). Sử dụng first()last() từ dplyr để lấy giá trị đầu và cuối kỳ sau khi sắp xếp dữ liệu theo thời gian.

Giá trị kỹ thuật: Cung cấp thước đo chuẩn hóa về tốc độ tăng trưởng, cho phép so sánh trực tiếp giữa các chỉ tiêu có quy mô khác nhau. Phương pháp này đảm bảo tính nhất quán và có thể tái sử dụng cho các giai đoạn khác.

Kết luận: Phân tích CAGR cho thấy lợi nhuận sau thuế có tốc độ tăng trưởng cao nhất (9.4%), trong khi các chỉ tiêu doanh thu và chi phí có tốc độ tăng trưởng ổn định hơn. Kết quả này phản ánh hiệu quả kinh doanh được cải thiện qua thời gian.

2.3.2.4 Biểu đồ que (Lollipop) so sánh tốc độ tăng trưởng bình quân năm (CAGR)

Lý do thực hiện: Biểu đồ Lollipop cung cấp cách trực quan để so sánh CAGR giữa các chỉ tiêu. Biểu đồ này giúp nhanh chóng xác định các chỉ tiêu có tốc độ tăng trưởng cao/thấp và nhận diện các xu hướng nổi bật trong bộ dữ liệu.

# KỸ THUẬT: VẼ BIỂU ĐỒ LOLLIPOP
# ----------------------------------------
# Sử dụng geom_segment() cho phần thân và geom_point() cho phần đầu
# coord_flip() để tạo biểu đồ nằm ngang dễ đọc
# scale_color_manual() để phân màu theo nhóm

ggplot(cagr_data, aes(x = reorder(ChiTieu, CAGR), y = CAGR, color = Nhom)) +
  geom_segment(aes(xend = ChiTieu, y = 0, yend = CAGR), 
               size = 1.2, alpha = 0.8) +
  geom_point(size = 5, alpha = 0.9) +
  geom_hline(yintercept = 0, linetype = "solid", color = "gray50", size = 0.5) +
  geom_text(aes(label = paste0(round(CAGR, 1), "%")), 
            hjust = -0.3, size = 3.5, fontface = "bold") +
  coord_flip() +
  scale_color_manual(values = c("Doanh thu" = "#2ecc71", 
                                 "Chi phí" = "#e74c3c", 
                                 "Lợi nhuận" = "#3498db")) +
  labs(title = "So sánh CAGR giữa các chỉ tiêu (2023-2025)",
       subtitle = "Lợi nhuận tăng trưởng nhanh nhất, chi phí được kiểm soát tốt",
       x = NULL,
       y = "CAGR (%)",
       color = "Nhóm") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 14),
        legend.position = "top",
        axis.text.y = element_text(size = 9))

Kỹ thuật: Kết hợp geom_segment()geom_point() để tạo biểu đồ Lollipop. reorder(ChiTieu, CAGR) sắp xếp các chỉ tiêu theo giá trị CAGR. Màu sắc được phân biệt theo nhóm để dễ nhận diện.

Giá trị kỹ thuật: Cung cấp hình ảnh trực quan về thứ hạng tăng trưởng, giúp truyền đạt thông tin nhanh chóng và hiệu quả. Biểu đồ này dễ dàng tái sử dụng cho các tập dữ liệu và chỉ tiêu khác nhau.

Kết luận: Biểu đồ Lollipop khẳng định kết quả phân tích trước đó: các chỉ tiêu lợi nhuận có tốc độ tăng trưởng cao nhất, tiếp theo là nhóm doanh thu. Sự chênh lệch về tốc độ tăng trưởng giữa doanh thu và chi phí giải thích cho sự cải thiện về tỷ suất lợi nhuận của doanh nghiệp.

2.3.3 PHÂN PHỐI VÀ PHÁT HIỆN NGOẠI LAI (OUTLIERS)

2.3.3.1 Biểu đồ Histogram phân phối giá trị theo nhóm

Lý do thực hiện: Đây là bước đầu tiên và quan trọng để hiểu được đặc điểm phân phối của các chỉ tiêu tài chính. Histogram giúp xác định hình dạng phân phối (đối xứng, lệch phải/trái), xu hướng tập trung và mức độ biến động của dữ liệu, từ đó làm cơ sở cho các phân tích sâu hơn.

# KỸ THUẬT: VẼ HISTOGRAM PHÂN PHỐI
# ----------------------------------------
# Sử dụng geom_histogram() để vẽ biểu đồ tần số
# facet_wrap() tách biểu đồ theo nhóm với thang đo tự do
# geom_vline() thêm đường median cho mỗi nhóm

ggplot(df_long, aes(x = GiaTriTuyetDoi, fill = Nhom)) +
  geom_histogram(bins = 15, alpha = 0.7, color = "white") +
  geom_vline(data = df_long %>% 
               group_by(Nhom) %>% 
               summarise(median = median(GiaTriTuyetDoi)),
             aes(xintercept = median, color = Nhom), 
             linetype = "dashed", size = 1) +
  facet_wrap(~Nhom, scales = "free") +
  scale_x_continuous(labels = label_number(big.mark = ".", decimal.mark = ",")) +
  scale_fill_manual(values = c("Doanh thu" = "#2ecc71", 
                                "Chi phí" = "#e74c3c", 
                                "Lợi nhuận" = "#3498db")) +
  scale_color_manual(values = c("Doanh thu" = "#27ae60", 
                                 "Chi phí" = "#c0392b", 
                                 "Lợi nhuận" = "#2980b9")) +
  labs(title = "Histogram phân phối giá trị tuyệt đối theo nhóm",
       subtitle = "Đường đứt nét = Median của mỗi nhóm",
       x = "Giá trị tuyệt đối (tỷ đồng)",
       y = "Tần số (số quan sát)") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 14),
        legend.position = "none")

Kỹ thuật: Sử dụng geom_histogram() để vẽ biểu đồ tần số với 15 bins. facet_wrap(~Nhom, scales = "free") cho phép mỗi nhóm có thang đo x và y độc lập. geom_vline() thêm đường trung bình để đánh dấu xu hướng tập trung của từng nhóm.

Giá trị kỹ thuật: Cung cấp cái nhìn trực quan về hình dạng phân phối của từng nhóm chỉ tiêu, giúp xác định tính đối xứng và các giá trị bất thường. Phương pháp này dễ hiểu và có thể áp dụng cho nhiều loại dữ liệu khác nhau.

Kết luận: Histogram cho thấy cả ba nhóm đều có phân phối lệch phải, với các giá trị tập trung ở phía trái và một số ít giá trị lớn hơn nhiều ở phía phải. Median của nhóm Doanh thu là 9.756.329.044.309 tỷ, nhóm Chi phí là 647.228.455.538 tỷ, và nhóm Lợi nhuận là 650.461.189.752 tỷ.

2.3.3.2 Biểu đồ mật độ so sánh phân phối

Lý do thực hiện: Biểu đồ mật độ cho phép so sánh trực quan phân phối của nhiều nhóm trên cùng một đồ thị. Đây là công cụ hiệu quả để đánh giá sự chồng chéo và khác biệt về hình dạng phân phối giữa các nhóm chỉ tiêu tài chính.

# KỸ THUẬT: VẼ BIỂU ĐỒ MẬT ĐỘ
# ----------------------------------------
# Sử dụng geom_density() để vẽ đường mật độ ước lượng
# scale_x_log10() chuẩn hóa thang đo cho dữ liệu có biên độ rộng
# alpha điều chỉnh độ trong suốt để nhìn thấy các đường chồng lấp

ggplot(df_long, aes(x = GiaTriTuyetDoi, fill = Nhom, color = Nhom)) +
  geom_density(alpha = 0.4, size = 1.2) +
  scale_x_log10(labels = label_number(big.mark = ".", decimal.mark = ",")) +
  scale_fill_manual(values = c("Doanh thu" = "#2ecc71", 
                                "Chi phí" = "#e74c3c", 
                                "Lợi nhuận" = "#3498db")) +
  scale_color_manual(values = c("Doanh thu" = "#27ae60", 
                                 "Chi phí" = "#c0392b", 
                                 "Lợi nhuận" = "#2980b9")) +
  labs(title = "Biểu đồ mật độ so sánh phân phối giữa các nhóm",
       subtitle = "Log scale để hiển thị đồng thời các nhóm có quy mô khác nhau",
       x = "Giá trị tuyệt đối (tỷ đồng, log scale)",
       y = "Mật độ",
       fill = "Nhóm",
       color = "Nhóm") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 14),
        legend.position = "top")

Kỹ thuật: Sử dụng geom_density() để vẽ đường mật độ ước lượng kernel. scale_x_log10() chuyển đổi thang đo x sang logarit để xử lý dữ liệu có biên độ rộng. Màu sắc và độ trong suốt được điều chỉnh để dễ dàng phân biệt các nhóm.

Giá trị kỹ thuật: Cho phép so sánh trực tiếp hình dạng phân phối giữa các nhóm, phát hiện sự chồng chéo và khác biệt. Phương pháp này đặc biệt hữu ích khi làm việc với dữ liệu có quy mô khác nhau.

Kết luận: Biểu đồ mật độ xác nhận các phát hiện từ histogram: tất cả các nhóm đều có phân phối lệch phải. Nhóm Doanh thu có đỉnh mật độ cao nhất, phản ánh sự tập trung của các giá trị ở mức trung bình. Có sự chồng chéo đáng kể giữa các nhóm, cho thấy một số chỉ tiêu có quy mô tương tự nhau bất chấp thuộc nhóm khác nhau.

2.3.3.3 Boxplot phát hiện giá trị ngoại lai

Lý do thực hiện: Biểu đồ hộp là phương pháp thông dụng nhằm phát hiện các giá trị lệch chuẩn dựa trên khoảng tứ phân vị (IQR). Việc nhận diện các giá trị này giúp làm rõ những trường hợp có hành vi khác biệt so với mặt bằng chung và đánh giá ảnh hưởng của chúng đối với phân tích tổng thể.

# KỸ THUẬT: VẼ BOXPLOT PHÁT HIỆN OUTLIERS
# ----------------------------------------
# Sử dụng phương pháp IQR: outliers nằm ngoài [Q1 - 1.5×IQR, Q3 + 1.5×IQR]
# geom_jitter() hiển thị tất cả điểm dữ liệu
# geom_text_repel() gán nhãn cho các outliers

outlier_data <- df_long %>%
  group_by(Nhom) %>%
  mutate(
    Q1 = quantile(GiaTriTuyetDoi, 0.25),
    Q3 = quantile(GiaTriTuyetDoi, 0.75),
    IQR_value = Q3 - Q1,
    Lower_Bound = Q1 - 1.5 * IQR_value,
    Upper_Bound = Q3 + 1.5 * IQR_value,
    Is_Outlier = GiaTriTuyetDoi < Lower_Bound | GiaTriTuyetDoi > Upper_Bound
  ) %>%
  ungroup()

ggplot(outlier_data, aes(x = Nhom, y = GiaTriTuyetDoi, fill = Nhom)) +
  stat_boxplot(geom = "errorbar", width = 0.3) +
  geom_boxplot(alpha = 0.7, outlier.shape = NA) +
  geom_jitter(aes(color = Is_Outlier, size = Is_Outlier), 
              width = 0.15, alpha = 0.6) +
  geom_text_repel(data = outlier_data %>% filter(Is_Outlier),
                  aes(label = ChiTieu), size = 3, 
                  box.padding = 0.5, max.overlaps = 20) +
  scale_y_log10(labels = label_number(big.mark = ".", decimal.mark = ",")) +
  scale_fill_manual(values = c("Doanh thu" = "#2ecc71", 
                                "Chi phí" = "#e74c3c", 
                                "Lợi nhuận" = "#3498db")) +
  scale_color_manual(values = c("TRUE" = "#e74c3c", "FALSE" = "#95a5a6"),
                     labels = c("TRUE" = "Outlier", "FALSE" = "Normal")) +
  scale_size_manual(values = c("TRUE" = 3, "FALSE" = 1.5)) +
  labs(title = "Boxplot với outlier detection (IQR method)",
       subtitle = "Điểm đỏ lớn = Outliers (ngoài Q1-1.5×IQR hoặc Q3+1.5×IQR)",
       x = NULL,
       y = "Giá trị tuyệt đối (tỷ đồng, log scale)",
       color = "Status",
       size = "Status") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 14),
        legend.position = "right") +
  guides(fill = "none")

Kỹ thuật: Sử dụng phương pháp IQR để xác định ngoại lai Kết hợp geom_boxplot() với geom_jitter() để hiển thị cả biểu đồ hộp boxplot và tất cả điểm dữ liệu. geom_text_repel() từ package ggrepel giúp gán nhãn mà không bị chồng chéo.

Giá trị kỹ thuật: Cung cấp cách tiếp cận chuẩn để phát hiện và trực quan hóa các giá trị ngoại lai. Phương pháp này khách quan, có thể tái sản xuất và dễ dàng giải thích cho các bên liên quan.

Kết luận: Phân tích biểu đồ boxplot phát hiện 1 giá trị ngoại lai. Trong nhóm Doanh thu, Thu phí bảo hiểm gốc là ngoại lai với giá trị cao nhất 11.274.879.368.561 tỷ. Các giá trị ngoại lai này không phải là lỗi dữ liệu mà phản ánh đặc điểm thực tế của các chỉ tiêu tài chính quan trọng.

2.3.3.4 Biểu đồ phần trăm và khoảng giá trị

Lý do thực hiện: Biểu đồ phần trăm cung cấp cái nhìn chi tiết về sự phân bố của từng chỉ tiêu thông qua các mốc phần trăm (P10, P25, P50, P75, P90). Điều này giúp đánh giá mức độ biến động và xu hướng tập trung của dữ liệu theo thời gian.

# KỸ THUẬT: VẼ BIỂU ĐỒ PHẦN TRĂM
# ----------------------------------------
# Tính toán các mốc phần trăm cho từng chỉ tiêu
# Sử dụng geom_linerange() để vẽ các khoảng giá trị
# geom_point() đánh dấu median

percentile_data <- df_long %>%
  group_by(ChiTieu, Nhom) %>%
  summarise(
    P10 = quantile(GiaTriTuyetDoi, 0.10),
    P25 = quantile(GiaTriTuyetDoi, 0.25),
    P50 = quantile(GiaTriTuyetDoi, 0.50),
    P75 = quantile(GiaTriTuyetDoi, 0.75),
    P90 = quantile(GiaTriTuyetDoi, 0.90),
    .groups = "drop"
  )

ggplot(percentile_data, aes(x = reorder(ChiTieu, P50), color = Nhom)) +
  geom_linerange(aes(ymin = P10, ymax = P90), size = 1, alpha = 0.6) +
  geom_linerange(aes(ymin = P25, ymax = P75), size = 2.5, alpha = 0.8) +
  geom_point(aes(y = P50), size = 4, shape = 18) +
  coord_flip() +
  scale_y_log10(labels = label_number(big.mark = ".", decimal.mark = ",")) +
  scale_color_manual(values = c("Doanh thu" = "#2ecc71", 
                                 "Chi phí" = "#e74c3c", 
                                 "Lợi nhuận" = "#3498db")) +
  labs(title = "Biểu đồ phần trăm theo chỉ tiêu",
       subtitle = "Đường dày = P25-P75 (IQR), Đường mỏng = P10-P90, Thoi = Median (P50)",
       x = NULL,
       y = "Giá trị tuyệt đối (tỷ đồng, log scale)",
       color = "Nhóm") +
  theme_minimal(base_size = 12) +
  theme(plot.title = element_text(face = "bold", size = 14),
        legend.position = "top")

Kỹ thuật: Tính toán các mốc phần trăm (P10, P25, P50, P75, P90) cho từng chỉ tiêu. Sử dụng geom_linerange() để vẽ các khoảng giá trị với độ dày khác nhau cho IQR và khoảng P10-P90. coord_flip() tạo biểu đồ nằm ngang để dễ đọc tên chỉ tiêu.

Giá trị kỹ thuật: Cung cấp thông tin chi tiết về sự phân bố của từng chỉ tiêu, cho phép so sánh trực quan mức độ biến động và xu hướng tập trung. Phương pháp này đặc biệt hữu ích để đánh giá rủi ro và ổn định của các chỉ tiêu tài chính.

Kết luận: Biểu đồ phần trăm cho thấy các chỉ tiêu Doanh thu và Chi phí chính có khoảng biến động rộng, phản ánh sự tăng trưởng đáng kể qua thời gian. Median của hầu hết các chỉ tiêu nằm gần P25 hơn P75, xác nhận phân phối lệch phải. Các chỉ tiêu Lợi nhuận có khoảng biến động hẹp hơn trong thang đo logarit nhưng vẫn thể hiện xu hướng tăng trưởng tích cực.

2.4 KẾT LUẬN CHƯƠNG 2

2.4.1 Tổng hợp kết quả phân tích

Lý do thực hiện: Đây là bước tổng kết toàn bộ phân tích trong chương 2, nhằm đưa ra cái nhìn tổng quan về xu hướng và đặc điểm phân phối của các chỉ tiêu tài chính Bảo Việt. Việc này giúp kết nối các phân tích riêng lẻ thành một bức tranh tổng thể có ý nghĩa.

Kết quả chính: Qua phân tích xu hướng thời gian và đặc điểm phân phối, có thể rút ra những kết luận quan trọng sau:

  • Về xu hướng tăng trưởng: Tất cả các chỉ tiêu tài chính chính đều thể hiện xu hướng tăng trưởng dương trong giai đoạn 10 quý từ Q1/2023 đến Q2/2025. Thu phí bảo hiểm gốc tăng trung bình 62431221236 tỷ mỗi quý, trong khi lợi nhuận sau thuế tăng 24654711163.1 tỷ mỗi quý.

  • Về tốc độ tăng trưởng: Phân tích CAGR cho thấy lợi nhuận sau thuế có tốc độ tăng trưởng cao nhất (9.4%), vượt xa tốc độ tăng trưởng của doanh thu và chi phí. Điều này phản ánh hiệu quả kinh doanh được cải thiện rõ rệt.

  • Về đặc điểm phân phối: Cả ba nhóm chỉ tiêu (Doanh thu, Chi phí, Lợi nhuận) đều có phân phối lệch phải, với các giá trị tập trung ở mức trung bình và một số ít giá trị lớn. Median của nhóm Doanh thu là 9.756.329.044.309 tỷ, cao hơn đáng kể so với nhóm Lợi nhuận (650.461.189.752 tỷ).

  • Về giá trị ngoại lai: Phát hiện 1 giá trị ngoại lai, chủ yếu là các chỉ tiêu có quy mô lớn như Thu phí bảo hiểm gốc. Các giá trị này không phải là lỗi dữ liệu mà phản ánh đặc điểm thực tế của mô hình kinh doanh.

2.4.2 Ý nghĩa thực tiễn

Đánh giá hiệu quả kinh doanh: Kết quả phân tích cho thấy Bảo Việt đang trong giai đoạn tăng trưởng ổn định và hiệu quả. Sự chênh lệch tích cực giữa tốc độ tăng trưởng doanh thu và chi phí cho thấy công ty đang kiểm soát tốt chi phí trong quá trình mở rộng quy mô.

Định hướng chiến lược: Xu hướng tăng trưởng mạnh của lợi nhuận so với doanh thu cho thấy công ty đang chuyển dịch theo hướng nâng cao hiệu quả kinh doanh thay vì chỉ tập trung vào tăng trưởng quy mô.

Cảnh báo và lưu ý: Mặc dù các chỉ số đều tích cực, cần lưu ý rằng phân tích dựa trên chỉ 10 quý dữ liệu. Các kết luận nên được xem xét trong bối cảnh ngắn hạn và cần bổ sung thêm dữ liệu dài hạn để có đánh giá toàn diện hơn.

2.4.3 Hướng phát triển cho các phân tích tiếp theo

Phân tích tương quan: Từ những kết quả này, có thể phát triển thêm phân tích tương quan giữa các chỉ tiêu để hiểu rõ hơn mối quan hệ nhân quả trong hoạt động kinh doanh.

Dự báo ngắn hạn: Với xu hướng rõ ràng đã được xác định, có thể xây dựng các mô hình dự báo đơn giản cho các quý tiếp theo.

Phân tích so sánh ngành: Kết quả phân tích tạo cơ sở để so sánh hiệu quả hoạt động của Bảo Việt với các doanh nghiệp cùng ngành.

Kết luận cuối cùng: Chương 2 đã cung cấp cái nhìn toàn diện về xu hướng và đặc điểm phân phối của các chỉ tiêu tài chính Bảo Việt, tạo nền tảng vững chắc cho các phân tích chuyên sâu ở những chương tiếp theo.