Trong bối cảnh ngành ngân hàng ngày càng cạnh tranh khốc liệt, việc duy trì và mở rộng nguồn vốn huy động, đặc biệt từ kênh tiền gửi tiết kiệm cá nhân, trở thành một trong những ưu tiên chiến lược của các tổ chức tài chính. Gửi tiết kiệm vẫn luôn được xem là lựa chọn an toàn trong danh mục đầu tư cá nhân, đặc biệt trong điều kiện thị trường tài chính đầy biến động và rủi ro như hiện nay . Chính vì thế, để có thể thu hút hiệu quả dòng vốn này, các tổ chức ngân hàng cần thấu hiểu sâu sắc về hành vi và động lực ra quyết định của khách hàng. Song song đó cần phải điều chỉnh những chiến lược hợp lý để đạt được hiệu quả tốt nhất cho danh mục này.
Sự khác biệt về đặc điểm, cũng như điều kiện tài chính của mỗi khách hàng khiến cho hành vi lựa chọn gửi tiết kiệm trở nên đa dạng và khó dự đoán. Chính vì vậy, việc nghiên cứu một cách có hệ thống các yếu tố có thể ảnh hưởng đến quyết định gửi tiết kiệm là cần thiết, nhằm giúp hiểu rõ hơn về xu hướng, động lực và đặc điểm hành vi tài chính của khách hàng. Những câu hỏi đặt ra là: Đặc điểm cá nhân như tuổi tác, tình trạng hôn nhân có ảnh hưởng như thế nào đến khả năng tham gia gửi tiết kiệm? Những yếu tố tài chính như tình trạng vay vốn, có sở hữu nhà ở, hoặc từng tiếp cận các chiến dịch tiếp thị của ngân hàng liệu có đóng vai trò quyết định?
Việc lựa chọn đề tài “Phân tích các yếu tố ảnh hưởng đến quyết định tham gia gửi tiết kiệm của khách hàng” không chỉ xuất phát từ tính thực tiễn rõ rệt trong hoạt động ngân hàng, mà còn là một bài toán nghiên cứu kinh tế lượng điển hình trong phân tích hành vi lựa chọn nhị phân. Kết quả của nghiên cứu kỳ vọng sẽ mang lại những hiểu biết sâu sắc, từ đó hỗ trợ các ngân hàng thiết kế chính sách chăm sóc khách hàng phù hợp và đưa ra quyết định chiến lược hiệu quả hơn trong huy động vốn.
Đề tài tập trung vào hành vi đăng ký gửi tiền tiết kiệm kỳ hạn của khách hàng cá nhân tại ngân hàng, thể hiện dưới dạng một biến định tính nhị phân (có hoặc không tham gia).
Các yếu tố được giả định là có ảnh hưởng đến quyết định này bao gồm:
Đặc trưng cá nhân như độ tuổi (phân theo nhóm tuổi), tình trạng hôn nhân (đã lập gia đình hay chưa).
Yếu tố tài chính như sở hữu khoản vay, có nhà ở, kết quả tương tác tiếp thị trước đó với ngân hàng.
Thông tin hành vi quá khứ từ các chiến dịch marketing.
Về không gian: Nghiên cứu khai thác bộ dữ liệu thực tế có tên “bank.csv” từ một chiến dịch tiếp thị ngân hàng tại khu vực châu Âu. Mặc dù dữ liệu không đại diện cho thị trường Việt Nam, nó phản ánh chân thực các tình huống tiếp cận khách hàng trong ngành tài chính – ngân hàng, do đó vẫn có thể cung cấp những quan sát có giá trị và khái quát hóa trong bối cảnh quốc tế.
Về thời gian: Dữ liệu được thu thập tại một thời điểm cố định, không có yếu tố thời gian lặp lại theo chuỗi, nên được xem là dữ liệu dạng cắt ngang (cross-sectional data).
Nghiên cứu sử dụng phương pháp định lượng với các bước chính như sau:
Tiền xử lý dữ liệu: Làm sạch, phân loại và biến đổi biến phù hợp với mô hình hồi quy nhị phân (như phân nhóm tuổi, nhị phân hóa các biến phân loại).
Thống kê mô tả: Tổng hợp đặc điểm mẫu nghiên cứu, biểu đồ phân phối, tỉ lệ phân bố giữa các nhóm.
Phân tích đơn biến: Đánh giá mối liên hệ giữa từng biến độc lập với biến phụ thuộc qua kiểm định chi-squared, Odds Ratio (OR) và Risk Ratio (RR).
Ước lượng mô hình hồi quy: Áp dụng ba mô hình nhị phân: logit, probit và cloglog để đánh giá ảnh hưởng của các yếu tố.
Đánh giá mô hình: So sánh AIC và Brier Score để lựa chọn mô hình phù hợp nhất.
Phân tích kết quả: Diễn giải hệ số hồi quy, xác định các yếu tố có ý nghĩa thống kê và ảnh hưởng thực tế đến xác suất gửi tiết kiệm.
Ngoài danh mục bảng biểu; danh mục hình ảnh; danh mục kí hiệu, viết tắt; tài liệu tham khảo và phụ lục, bài nghiên cứu bao gồm những chương sau:
Bộ dữ liệu được sử dụng trong nghiên cứu này được thu thập từ một chiến dịch tiếp thị qua điện thoại do một ngân hàng tại châu Âu thực hiện. Đây là bộ dữ liệu được công bố bởi UCI Machine Learning Repository – một kho dữ liệu uy tín dành cho học thuật và nghiên cứu. Với 4.521 quan sát, bộ dữ liệu phản ánh hành vi phản hồi của khách hàng khi được mời tham gia gửi tiết kiệm có kỳ hạn, kèm theo các thông tin nhân khẩu học, tình trạng tài chính và lịch sử tương tác của họ.
# Gọi thư viện
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.5.1
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.5.1
# Đọc dữ liệu
data <- read.csv("C:/Users/Admin/Downloads/bank.csv",
sep = ",", header = TRUE, fileEncoding = "UTF-8")
head(data) # xem 2 dòng đầu
## age job marital education default balance housing loan contact day
## 1 30 unemployed married primary no 1787 no no cellular 19
## 2 33 services married secondary no 4789 yes yes cellular 11
## 3 35 management single tertiary no 1350 yes no cellular 16
## 4 30 management married tertiary no 1476 yes yes unknown 3
## 5 59 blue-collar married secondary no 0 yes no unknown 5
## 6 35 management single tertiary no 747 no no cellular 23
## month duration campaign pdays previous poutcome y
## 1 oct 79 1 -1 0 unknown no
## 2 may 220 1 339 4 failure no
## 3 apr 185 1 330 1 failure no
## 4 jun 199 4 -1 0 unknown no
## 5 may 226 1 -1 0 unknown no
## 6 feb 141 2 176 3 failure no
colSums(is.na(data))
## age job marital education default balance housing loan
## 0 0 0 0 0 0 0 0
## contact day month duration campaign pdays previous poutcome
## 0 0 0 0 0 0 0 0
## y
## 0
# 3. Chuyển các biến định tính sang factor
data$y <- as.factor(data$y)
data$loan <- as.factor(data$loan)
data$housing <- as.factor(data$housing)
data$marital <- as.factor(data$marital)
data$poutcome <- as.factor(data$poutcome)
Các biến định tính trong bộ dữ liệu phản ánh đặc điểm phi số lượng của khách hàng và lịch sử tương tác, bao gồm:
job: Nghề nghiệp (student, blue-collar, retired, etc.)
marital: Tình trạng hôn nhân (single, married, divorced)
education: Trình độ học vấn
default, housing, loan: Có khoản vay mặc định, khoản vay mua nhà, hoặc vay cá nhân (yes/no)
contact: Phương thức liên lạc
month, day_of_week: Thời điểm liên lạc
poutcome: Kết quả chiến dịch tiếp thị trước đó
y: khách hàng có đồng ý gửi tiết kiệm kỳ hạn hay không (yes/no)
Các biến định lượng thể hiện đặc điểm có thể đo lường và tính toán, bao gồm:
age: Tuổi khách hàng
duration: Thời lượng cuộc gọi (tính bằng giây)
campaign: Số lần tiếp xúc trong chiến dịch hiện tại
pdays: Số ngày kể từ lần liên hệ gần nhất trong chiến dịch trước
previous: Số lần liên hệ trước đó
emp.var.rate, cons.price.idx, cons.conf.idx, euribor3m, nr.employed: Các chỉ tiêu kinh tế vĩ mô
balance: Số dư tài khoản (có thể đã được làm sạch trước khi đưa vào mô hình)
Biến phụ thuộc trong nghiên cứu, được xây dựng từ biến gốc y (giá trị ban đầu gồm “yes” hoặc “no”), sau đó được mã hóa lại dưới dạng nhị phân: bằng 1 nếu khách hàng đồng ý gửi tiết kiệm, và bằng 0 nếu từ chối. Đây là biến định danh phản ánh quyết định tham gia gửi tiền tiết kiệm của khách hàng.
Để phục vụ phân tích hồi quy, một số biến độc lập đã được lựa chọn và xử lý sơ bộ nhằm đảm bảo tính thống nhất, ý nghĩa thống kê và khả năng giải thích trong mô hình. Cụ thể:
Biến age: Tuổi của khách hàng, là biến định lượng,đã được phân nhóm thành ba nhóm tuổi: young, middle và old. Tuổi là chỉ số cơ bản trong phân tích hành vi tài chính vì nó liên quan đến mức thu nhập, nhu cầu chi tiêu và khả năng tích lũy.
Biến marital: Tình trạng hôn nhân của khách hàng, ban đầu có nhiều nhóm như “single”, “married”, “divorced” đã được rút gọn thành biến nhị phân với hai giá trị: “married” và “not_married”. Biến này cho thấy cho thấy sự ổn định trong đời sống cá nhân – một yếu tố có thể ảnh hưởng đến xu hướng tiết kiệm.
Biến housing: Khách hàng có đang vay mua nhà
không (yes / no). Việc có khoản vay nhà ở có
thể ảnh hưởng đến quyết định phân bổ tài chính, từ đó tác động đến hành
vi gửi tiết kiệm.
Biến loan: Cho biết khách hàng hiện có khoản vay
cá nhân tiêu dùng không (yes / no). Biến này
phản ánh khả năng tài chính và nhu cầu tiết kiệm, cho thấy được khả năng
tài chính cũng như áp lực chi tiêu của khách hàng.
Biến poutcome: Kết quả của chiến dịch tiếp thị
trước đó, gồm các giá trị như success,
failure, unknown, v.v. Biến này phản ánh mức
độ hiệu quả của các chiến dịch marketing trong việc ảnh hưởng đến hành
vi khách hàng.Biến này được chọn nhằm đánh giá mức độ tác động của các
nỗ lực tiếp cận khách hàng đến hành vi gửi tiết kiệm hiện tại.
Những biến này được lựa chọn dựa trên cả lý luận hành vi tài chính lẫn kinh nghiệm thực tiễn trong lĩnh vực ngân hàng.
str(data)
## 'data.frame': 4521 obs. of 17 variables:
## $ age : int 30 33 35 30 59 35 36 39 41 43 ...
## $ job : chr "unemployed" "services" "management" "management" ...
## $ marital : Factor w/ 3 levels "divorced","married",..: 2 2 3 2 2 3 2 2 2 2 ...
## $ education: chr "primary" "secondary" "tertiary" "tertiary" ...
## $ default : chr "no" "no" "no" "no" ...
## $ balance : int 1787 4789 1350 1476 0 747 307 147 221 -88 ...
## $ housing : Factor w/ 2 levels "no","yes": 1 2 2 2 2 1 2 2 2 2 ...
## $ loan : Factor w/ 2 levels "no","yes": 1 2 1 2 1 1 1 1 1 2 ...
## $ contact : chr "cellular" "cellular" "cellular" "unknown" ...
## $ day : int 19 11 16 3 5 23 14 6 14 17 ...
## $ month : chr "oct" "may" "apr" "jun" ...
## $ duration : int 79 220 185 199 226 141 341 151 57 313 ...
## $ campaign : int 1 1 1 4 1 2 1 2 2 1 ...
## $ pdays : int -1 339 330 -1 -1 176 330 -1 -1 147 ...
## $ previous : int 0 4 1 0 0 3 2 0 0 2 ...
## $ poutcome : Factor w/ 4 levels "failure","other",..: 4 1 1 4 4 1 2 4 4 1 ...
## $ y : Factor w/ 2 levels "no","yes": 1 1 1 1 1 1 1 1 1 1 ...
summary(data)
## age job marital education
## Min. :19.00 Length:4521 divorced: 528 Length:4521
## 1st Qu.:33.00 Class :character married :2797 Class :character
## Median :39.00 Mode :character single :1196 Mode :character
## Mean :41.17
## 3rd Qu.:49.00
## Max. :87.00
## default balance housing loan contact
## Length:4521 Min. :-3313 no :1962 no :3830 Length:4521
## Class :character 1st Qu.: 69 yes:2559 yes: 691 Class :character
## Mode :character Median : 444 Mode :character
## Mean : 1423
## 3rd Qu.: 1480
## Max. :71188
## day month duration campaign
## Min. : 1.00 Length:4521 Min. : 4 Min. : 1.000
## 1st Qu.: 9.00 Class :character 1st Qu.: 104 1st Qu.: 1.000
## Median :16.00 Mode :character Median : 185 Median : 2.000
## Mean :15.92 Mean : 264 Mean : 2.794
## 3rd Qu.:21.00 3rd Qu.: 329 3rd Qu.: 3.000
## Max. :31.00 Max. :3025 Max. :50.000
## pdays previous poutcome y
## Min. : -1.00 Min. : 0.0000 failure: 490 no :4000
## 1st Qu.: -1.00 1st Qu.: 0.0000 other : 197 yes: 521
## Median : -1.00 Median : 0.0000 success: 129
## Mean : 39.77 Mean : 0.5426 unknown:3705
## 3rd Qu.: -1.00 3rd Qu.: 0.0000
## Max. :871.00 Max. :25.0000
Bộ dữ liệu gồm 4521 quan sát và 17 cột giá trị thể hiện đặc điểm cho từng khách hàng khác.
Để phục vụ nghiên cứu, tác giả đã xử lý biến đổi các nhóm biến như sau:
# 1) Biến phụ thuộc: yes = 1, no = 0 (giữ độc lập dạng factor)
data$y_bin <- ifelse(data$y == "yes", 1, 0)
# 2) Giữ loan/housing là factor yes/no (đúng thứ tự mức)
data$loan_bin <- factor(data$loan, levels = c("no","yes"))
data$housing_bin <- factor(data$housing, levels = c("no","yes"))
# 3) Đặt mức tham chiếu cho biến phân loại (để R tự tạo dummy khi hồi quy)
data$marital <- factor(data$marital, levels = c("divorced","married","single"))
data$poutcome <- factor(data$poutcome, levels = c("unknown","failure","other","success"))
# 4) age giữ liên tục
stopifnot(is.numeric(data$age))
# 5) Tạo data_transformed (TRÁNH dùng cbind vì dễ bị ép kiểu ma trận)
data_transformed <- data.frame(
y = data$y_bin, # phụ thuộc 0/1
loan = data$loan_bin, # độc lập giữ factor yes/no
housing = data$housing_bin, # độc lập giữ factor yes/no
age = data$age, # liên tục
marital = data$marital, # factor 3 mức
poutcome= data$poutcome # factor 4 mức (unknown là tham chiếu)
)
# Kiểm tra nhanh
str(data_transformed)
## 'data.frame': 4521 obs. of 6 variables:
## $ y : num 0 0 0 0 0 0 0 0 0 0 ...
## $ loan : Factor w/ 2 levels "no","yes": 1 2 1 2 1 1 1 1 1 2 ...
## $ housing : Factor w/ 2 levels "no","yes": 1 2 2 2 2 1 2 2 2 2 ...
## $ age : int 30 33 35 30 59 35 36 39 41 43 ...
## $ marital : Factor w/ 3 levels "divorced","married",..: 2 2 3 2 2 3 2 2 2 2 ...
## $ poutcome: Factor w/ 4 levels "unknown","failure",..: 1 2 2 1 1 2 3 1 1 2 ...
Kiểm tra các biến
## =========================
## 0) Kiểm tra nhanh dữ liệu
## =========================
cat("Cấu trúc data_transformed:\n")
## Cấu trúc data_transformed:
str(data_transformed)
## 'data.frame': 4521 obs. of 6 variables:
## $ y : num 0 0 0 0 0 0 0 0 0 0 ...
## $ loan : Factor w/ 2 levels "no","yes": 1 2 1 2 1 1 1 1 1 2 ...
## $ housing : Factor w/ 2 levels "no","yes": 1 2 2 2 2 1 2 2 2 2 ...
## $ age : int 30 33 35 30 59 35 36 39 41 43 ...
## $ marital : Factor w/ 3 levels "divorced","married",..: 2 2 3 2 2 3 2 2 2 2 ...
## $ poutcome: Factor w/ 4 levels "unknown","failure",..: 1 2 2 1 1 2 3 1 1 2 ...
cat("\nSố NA theo cột:\n")
##
## Số NA theo cột:
print(sapply(data_transformed, function(x) sum(is.na(x))))
## y loan housing age marital poutcome
## 0 0 0 0 0 0
## ===============================
## 1) Hàm mô tả cho từng loại biến
## ===============================
describe_numeric <- function(x, name){
x_no_na <- x[!is.na(x)]
out <- c(
Variable = name,
N = length(x),
NA_count = sum(is.na(x)),
Mean = if (length(x_no_na)) round(mean(x_no_na), 3) else NA,
SD = if (length(x_no_na)) round(sd(x_no_na), 3) else NA,
Min = if (length(x_no_na)) round(min(x_no_na), 3) else NA,
Q1 = if (length(x_no_na)) round(quantile(x_no_na, 0.25, names = FALSE), 3) else NA,
Median = if (length(x_no_na)) round(median(x_no_na), 3) else NA,
Q3 = if (length(x_no_na)) round(quantile(x_no_na, 0.75, names = FALSE), 3) else NA,
Max = if (length(x_no_na)) round(max(x_no_na), 3) else NA
)
return(out)
}
describe_factor <- function(x, name){
tab <- table(x, useNA = "ifany")
prop <- prop.table(tab)
cat("\n=====================================\n")
cat("Biến phân loại:", name, "\n")
cat("Tần suất (count):\n"); print(tab)
cat("Tỉ lệ (%) :\n"); print(round(prop*100, 2))
invisible(NULL)
}
Kết quả thống kê mô tả của biến phụ thuộc
cat("\n========== 2.1. Biến phụ thuộc: y ==========\n")
##
## ========== 2.1. Biến phụ thuộc: y ==========
if(is.numeric(data_transformed$y)){
tab_y <- table(factor(data_transformed$y, levels = c(0,1)), useNA = "ifany")
prop_y <- prop.table(tab_y)
cat("Phân phối y (0/1):\n"); print(tab_y)
cat("Tỉ lệ y (0/1) % :\n"); print(round(prop_y*100, 2))
} else {
describe_factor(data_transformed$y, "y")
}
## Phân phối y (0/1):
##
## 0 1
## 4000 521
## Tỉ lệ y (0/1) % :
##
## 0 1
## 88.48 11.52
Biểu đồ biến y
library(ggplot2)
ggplot(data_transformed, aes(x = factor(y))) +
geom_bar(fill = "steelblue") +
labs(title = "Biểu đồ thống kê mô tả biến y", x = "y (0 = không, 1 = có)", y = "Số lượng")
Sau khi được biến đổi về dạng nhị phân, trong đó giá trị 1 đại diện cho
khách hàng đồng ý gửi tiết kiệm và giá trị 0 đại diện cho khách hàng từ
chối, kết quả thống kê cho thấy có 4.000 khách hàng (chiếm 88,476%)
không tham gia gửi tiết kiệm và chỉ có 521 khách hàng (chiếm 11,524%)
đồng ý gửi tiết kiệm.
Phân phối này cho thấy dữ liệu bị mất cân bằng khá nghiêm trọng, với phần lớn khách hàng không tham gia gửi tiết kiệm. Đây là một đặc điểm quan trọng cần lưu ý trong quá trình xây dựng và đánh giá mô hình hồi quy nhị phân, vì sự mất cân đối giữa hai nhóm có thể ảnh hưởng đến độ chính xác và khả năng dự đoán của mô hình. Tuy nhiên, nó cũng phản ánh phần nào thực tế thị trường, khi phần lớn khách hàng vẫn còn e ngại hoặc chưa có động lực rõ ràng để tham gia các sản phẩm tiết kiệm.
Biểu đồ cột minh họa tỷ lệ phân phối của biến y cho thấy sự chênh lệch rõ rệt giữa hai nhóm, làm nổi bật tính chất bất cân xứng của hành vi tài chính này trong tập dữ liệu.
Kết quả thống kê mô tả
cat("\n========== Biến độc lập: age ==========\n")
##
## ========== Biến độc lập: age ==========
print(describe_numeric(data_transformed$age, "age"))
## Variable N NA_count Mean SD Min Q1 Median
## "age" "4521" "0" "41.17" "10.576" "19" "33" "39"
## Q3 Max
## "49" "87"
op <- par(no.readonly = TRUE)
par(mfrow = c(1,2))
hist(data_transformed$age, main = "Histogram tuổi (age)",
xlab = "age", col = "gray", border = "white")
boxplot(data_transformed$age, horizontal = TRUE, main = "Boxplot tuổi (age)")
par(op)
Đối với biến age, độ tuổi của khách hàng trong tập dữ liệu dao động từ 19 đến 87 tuổi. Giá trị trung vị (median) là 39 tuổi, trong khi tuổi trung bình (mean) là khoảng 41,17 tuổi. Điều này cho thấy phần lớn khách hàng thuộc nhóm trung niên, là nhóm tuổi có xu hướng ổn định về thu nhập và có khả năng tham gia gửi tiết kiệm cao hơn.
cat("\n========== Biến độc lập: loan ==========\n")
##
## ========== Biến độc lập: loan ==========
describe_factor(data_transformed$loan, "loan")
##
## =====================================
## Biến phân loại: loan
## Tần suất (count):
## x
## no yes
## 3830 691
## Tỉ lệ (%) :
## x
## no yes
## 84.72 15.28
barplot(table(data_transformed$loan),
main = "Phân phối loan (yes/no)", ylab = "Số lượng")
Với biến loan, thống kê cho thấy có 691 khách hàng có khoản vay tiêu
dùng, chiếm 15,28% toàn bộ mẫu. Ngược lại, có đến 3.830 khách hàng
(chiếm 84,72%) không có khoản vay. Điều này cho thấy phần lớn khách hàng
trong mẫu dữ liệu không bị ràng buộc bởi khoản vay tiêu dùng, từ đó có
thể có tiềm năng tích lũy hoặc gửi tiết kiệm cao hơn.
# Thống kê biến housing (0/1)
cat("\n========== 2.3. Biến độc lập: housing ==========\n")
##
## ========== 2.3. Biến độc lập: housing ==========
describe_factor(data_transformed$housing, "housing")
##
## =====================================
## Biến phân loại: housing
## Tần suất (count):
## x
## no yes
## 1962 2559
## Tỉ lệ (%) :
## x
## no yes
## 43.4 56.6
ggplot(data_transformed, aes(x = factor(housing))) +
geom_bar(fill = "lightgreen") +
labs(title = "Tình trạng vay mua nhà (housing)", x = "housing", y = "Số lượng")
Biến housing phản ánh tình trạng vay mua nhà của khách hàng. Kết quả cho
thấy có 2.559 người đang vay mua nhà (chiếm 56,60%) và 1.962 người không
vay (chiếm 43,40%). Tỷ lệ khách hàng có khoản vay mua nhà tương đối cao,
điều này có thể ảnh hưởng đến quyết định tài chính cá nhân như việc phân
bổ thu nhập giữa trả nợ và gửi tiết kiệm.
cat("\n========== 2.4. Biến độc lập: marital ==========\n")
##
## ========== 2.4. Biến độc lập: marital ==========
describe_factor(data_transformed$marital, "marital")
##
## =====================================
## Biến phân loại: marital
## Tần suất (count):
## x
## divorced married single
## 528 2797 1196
## Tỉ lệ (%) :
## x
## divorced married single
## 11.68 61.87 26.45
barplot(table(data_transformed$marital),
main = "Phân phối marital", ylab = "Số lượng", las = 2)
Biến marital đại diện cho tình trạng hôn nhân. Trong đó, tỷ lệ khách
hàng đã kết hôn chiếm trung bình 61,87% và nhóm độc thân chiếm 26,45%.
Phần còn lại thuộc nhóm ly hôn. Đây là một biến xã hội quan trọng có thể
ảnh hưởng đến hành vi tài chính, khi người có gia đình thường ưu tiên
tiết kiệm để phục vụ các kế hoạch lâu dài hoặc đảm bảo cho gia đình.
cat("\n========== 2.5. Biến độc lập: poutcome ==========\n")
##
## ========== 2.5. Biến độc lập: poutcome ==========
describe_factor(data_transformed$poutcome, "poutcome")
##
## =====================================
## Biến phân loại: poutcome
## Tần suất (count):
## x
## unknown failure other success
## 3705 490 197 129
## Tỉ lệ (%) :
## x
## unknown failure other success
## 81.95 10.84 4.36 2.85
barplot(table(data_transformed$poutcome),
main = "Phân phối poutcome", ylab = "Số lượng", las = 2)
Cuối cùng, biến poutcome – kết quả của chiến dịch tiếp thị trước đó. Trong đó, nhóm unknown chiếm tỷ lệ cao nhất, tới 81,95%, cho thấy phần lớn khách hàng không có thông tin rõ ràng về kết quả chiến dịch marketing trước đó. Các nhóm còn lại có tỷ lệ khá nhỏ: other chiếm 4,36% và success chỉ chiếm 2,85%. Việc có quá nhiều quan sát thuộc nhóm “không rõ” có thể làm suy giảm mức độ giải thích của biến này trong mô hình, nhưng mặt khác cũng cho thấy tiềm năng cải thiện hoạt động marketing trong thực tế.
Bảng kết quả thống kê:
## Helper nhỏ gọn
## ================
pct_row <- function(tab) round(prop.table(tab, 1) * 100, 2)
## =========================================================
## 1) y (0/1) ~ age (numeric, giữ liên tục, KHÔNG gộp nhóm)
## =========================================================
cat("\n===== 1) y ~ age (liên tục) =====\n")
##
## ===== 1) y ~ age (liên tục) =====
# Thống kê mean/SD theo y
cat("\nThống kê age theo y:\n")
##
## Thống kê age theo y:
by_stats <- by(data_transformed$age, data_transformed$y, function(x) {
c(N = length(x),
Mean = mean(x, na.rm = TRUE),
SD = sd(x, na.rm = TRUE),
Min = min(x, na.rm = TRUE),
Q1 = as.numeric(quantile(x, 0.25, na.rm = TRUE)),
Median = median(x, na.rm = TRUE),
Q3 = as.numeric(quantile(x, 0.75, na.rm = TRUE)),
Max = max(x, na.rm = TRUE))
})
print(by_stats)
## data_transformed$y: 0
## N Mean SD Min Q1 Median Q3 Max
## 4000.0000 40.9980 10.1884 19.0000 33.0000 39.0000 48.0000 86.0000
## ------------------------------------------------------------
## data_transformed$y: 1
## N Mean SD Min Q1 Median Q3 Max
## 521.00000 42.49136 13.11577 19.00000 32.00000 40.00000 50.00000 87.00000
# Kiểm định khác biệt phân phối age giữa y=0 và y=1
age_y0 <- data_transformed$age[data_transformed$y == 0]
age_y1 <- data_transformed$age[data_transformed$y == 1]
cat("\nWelch t-test (age ~ y):\n"); print(t.test(age_y0, age_y1))
##
## Welch t-test (age ~ y):
##
## Welch Two Sample t-test
##
## data: age_y0 and age_y1
## t = -2.5024, df = 604.47, p-value = 0.0126
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## -2.6653503 -0.3213752
## sample estimates:
## mean of x mean of y
## 40.99800 42.49136
cat("\nWilcoxon rank-sum test (age ~ y):\n"); print(wilcox.test(age_y0, age_y1))
##
## Wilcoxon rank-sum test (age ~ y):
##
## Wilcoxon rank sum test with continuity correction
##
## data: age_y0 and age_y1
## W = 1011360, p-value = 0.274
## alternative hypothesis: true location shift is not equal to 0
# Biểu đồ
op <- par(no.readonly = TRUE); par(mfrow = c(1,2))
boxplot(age ~ y, data = data_transformed,
names = c("y=0","y=1"),
main = "Boxplot tuổi theo y", ylab = "age")
hist(age_y0, main = "Histogram age (y=0)", xlab = "age", col = "gray", border = "white")
par(op)
Kết quả thống kê mô tả cho thấy nhóm khách hàng đăng ký gửi tiết kiệm (y=1) có tuổi trung bình khoảng 42,49 tuổi, còn nhóm không đăng ký (y=0) thì có số tuổi trung bình khoảng 40,99 tuổi. Khoảng chênh lệch trung bình là gần 1,5 năm, tuy nhiên độ lệch chuẩn của nhóm y=1 lớn hơn, phản ánh sự phân tán tuổi cao hơn. Quan sát boxplot cho thấy cả hai nhóm đều tập trung chủ yếu ở độ tuổi trung niên, nhưng nhóm y=1 có một số khách hàng ở độ tuổi rất cao (70–80+) đóng vai trò là giá trị ngoại lệ.
Giả thiết kiểm định
H₀: Không có sự khác biệt về phân phối tuổi giữa nhóm có và không đăng ký gửi tiết kiệm.
H₁: Có sự khác biệt về phân phối tuổi giữa nhóm có và không đăng ký gửi tiết kiệm.
Kết quả kiểm định và diễn giải
Kiểm định t-test cho thấy sự khác biệt về trung bình tuổi là có ý nghĩa thống kê (p = 0,0126), với khoảng tin cậy 95% cho chênh lệch trung bình từ 0,32 đến 2,67 năm.
Ngược lại, kiểm định phi tham số Wilcoxon (p = 0,274) không bác bỏ giả thuyết H₀, cho thấy phân phối thứ hạng (median) của hai nhóm không khác biệt rõ rệt.
Điều này hàm ý rằng sự khác biệt tuổi chỉ xuất hiện ở giá trị trung bình và chủ yếu do một số cá nhân lớn tuổi hơn kéo trung bình của nhóm đăng ký lên cao, trong khi phần lớn khách hàng ở hai nhóm vẫn có độ tuổi tương đồng.
cat("\n===== 4) y ~ marital =====\n")
##
## ===== 4) y ~ marital =====
tab_marital <- table(data_transformed$marital, data_transformed$y)
cat("\nBảng đếm (marital x y):\n"); print(addmargins(tab_marital))
##
## Bảng đếm (marital x y):
##
## 0 1 Sum
## divorced 451 77 528
## married 2520 277 2797
## single 1029 167 1196
## Sum 4000 521 4521
cat("\nTỷ lệ theo hàng (%):\n"); print(pct_row(tab_marital))
##
## Tỷ lệ theo hàng (%):
##
## 0 1
## divorced 85.42 14.58
## married 90.10 9.90
## single 86.04 13.96
barplot(tab_marital, beside = TRUE, legend = TRUE,
main = "Phân phối y theo marital", ylab = "Số lượng", las = 2)
## Cơ cấu marital trong nhóm đã đăng ký (y = 1)
# Xác định chỉ số y==1 (tương thích cả numeric 0/1 và factor "0"/"1" hoặc "no"/"yes")
is_y1 <- if (is.factor(data_transformed$y)) {
levels_y <- levels(data_transformed$y)
if (all(c("0","1") %in% levels_y)) data_transformed$y == "1" else data_transformed$y == "yes"
} else {
data_transformed$y == 1
}
# Lọc marital của nhóm y=1
marital_y1 <- droplevels(data_transformed$marital[is_y1])
# Bảng đếm & tỷ lệ %
tab_y1 <- table(marital_y1, useNA = "no")
prop_y1 <- prop.table(tab_y1) * 100
N_y1 <- sum(tab_y1)
# In tổng
cat(sprintf("Cơ cấu trong nhóm đã đăng ký (y = 1, N = %d)\n\n", N_y1))
## Cơ cấu trong nhóm đã đăng ký (y = 1, N = 521)
# Sắp xếp thứ tự in như yêu cầu: Married, Single, Divorced
print_order <- c("married", "single", "divorced")
print_order <- print_order[print_order %in% names(tab_y1)] # phòng trường hợp thiếu mức
for (lvl in print_order) {
cnt <- as.integer(tab_y1[lvl])
pct <- as.numeric(prop_y1[lvl])
cat(sprintf("%s: %d người → %.2f%% tổng số đã đăng ký\n",
tools::toTitleCase(lvl), cnt, pct))
}
## Married: 277 người → 53.17% tổng số đã đăng ký
## Single: 167 người → 32.05% tổng số đã đăng ký
## Divorced: 77 người → 14.78% tổng số đã đăng ký
# (Tuỳ chọn) Tạo data.frame kết quả nếu cần chèn bảng
result_marital_y1 <- data.frame(
Marital = tools::toTitleCase(names(tab_y1)),
Count = as.integer(tab_y1),
Percent = round(as.numeric(prop_y1), 2),
check.names = FALSE
)
# View(result_marital_y1) # mở xem nếu chạy trong RStudio
Thống kê chéo giữa các biến này và quyết định gửi tiết kiệm cho thấy tình trạng hôn nhân có liên quan nhất định đến hành vi tài chính của khách hàng.
Đối với khách hàng đã kết hôn có tỷ lệ gửi tiết kiệm đạt 53,17%. Điều này cho thấy rằng những người đã kết hôn – thường có trách nhiệm tài chính ổn định hơn, nhu cầu tiết kiệm phục vụ cho gia đình – có xu hướng gửi tiết kiệm cao hơn.
Tuy nhiên, điều thú vị được quan sát ở tỷ lệ gửi tiết kiệm trong nhóm độc thân tương đối cao, đạt 32,05%. Mặc dù tổng số khách hàng độc thân thấp hơn nhiều so với nhóm đã kết hôn, nhưng tỷ lệ gửi tiết kiệm cho thấy đây là một phân khúc khách hàng tiềm năng, có thể chịu ảnh hưởng bởi các yếu tố cá nhân như mục tiêu tích lũy, đầu tư, hoặc độc lập tài chính.
cat("\n===== 2) y ~ loan =====\n")
##
## ===== 2) y ~ loan =====
tab_loan <- table(data_transformed$loan, data_transformed$y)
cat("\nBảng đếm (loan x y):\n"); print(addmargins(tab_loan))
##
## Bảng đếm (loan x y):
##
## 0 1 Sum
## no 3352 478 3830
## yes 648 43 691
## Sum 4000 521 4521
cat("\nTỷ lệ theo hàng (%):\n"); print(pct_row(tab_loan))
##
## Tỷ lệ theo hàng (%):
##
## 0 1
## no 87.52 12.48
## yes 93.78 6.22
# Biểu đồ
barplot(tab_loan, beside = TRUE, legend = TRUE,
main = "Phân phối y theo loan", ylab = "Số lượng")
# Xác định chỉ số y == 1 (hoạt động với y là numeric 0/1, factor "0"/"1" hoặc "no"/"yes")
is_y1 <- if (is.factor(data_transformed$y)) {
lev <- levels(data_transformed$y)
if (all(c("0","1") %in% lev)) {
data_transformed$y == "1"
} else if (all(c("no","yes") %in% lev)) {
data_transformed$y == "yes"
} else {
stop("Levels của y không rõ (kỳ vọng '0/1' hoặc 'no/yes').")
}
} else {
data_transformed$y == 1
}
# Hàm in cơ cấu cho một biến factor trong nhóm y=1
print_composition_y1 <- function(var, var_name, print_order = NULL) {
x <- droplevels(var[is_y1])
tab <- table(x, useNA = "no")
prop <- prop.table(tab) * 100
N <- sum(tab)
cat(sprintf("\nCơ cấu trong nhóm đã đăng ký (y = 1, N = %d) — %s\n\n", N, var_name))
# Nếu có yêu cầu thứ tự in cụ thể
if (!is.null(print_order)) {
print_order <- print_order[print_order %in% names(tab)]
} else {
print_order <- names(tab)
}
for (lvl in print_order) {
cnt <- as.integer(tab[lvl])
pct <- as.numeric(prop[lvl])
cat(sprintf("%s: %d người → %.2f%% tổng số đã đăng ký\n",
tools::toTitleCase(lvl), cnt, pct))
}
# (Tuỳ chọn) trả về data.frame để chèn bảng vào báo cáo
invisible(data.frame(
Level = names(tab),
Count = as.integer(tab),
Percent = round(as.numeric(prop), 2),
check.names = FALSE
))
}
## 1) loan (yes/no) — in Yes trước cho dễ đọc
res_loan <- print_composition_y1(
var = data_transformed$loan,
var_name = "loan",
print_order = c("yes","no")
)
##
## Cơ cấu trong nhóm đã đăng ký (y = 1, N = 521) — loan
##
## Yes: 43 người → 8.25% tổng số đã đăng ký
## No: 478 người → 91.75% tổng số đã đăng ký
Biến loan thể hiện tình trạng vay tiêu dùng cá nhân của khách hàng trong đó “Yes” là khách hàng có vay tiêu dùng và “No” là không vay. Kết quả phân tích thống kê chéo giữa biến này và quyết định gửi tiết kiệm (y) cho thấy sự khác biệt rõ rệt giữa hai nhóm.
Trong tổng số khách hàng không có khoản vay tiêu dùng, 91.75% lựa chọn gửi tiết kiệm, trong khi đó tỷ lệ này ở nhóm khách hàng có vay chỉ là 8,25%. Đây là một chênh lệch đáng kể, phản ánh ảnh hưởng tiêu cực của việc đang vay tiêu dùng đến khả năng và xu hướng gửi tiết kiệm của khách hàng.
Mặt khác, nhóm không vay tiêu dùng chiếm đa số trong dữ liệu (tổng cộng 4.000 người), và cũng đóng góp gần như toàn bộ vào số lượng khách hàng có hành vi gửi tiết kiệm. Điều này hoàn toàn hợp lý, bởi những người có nghĩa vụ trả nợ thường ưu tiên dòng tiền cho chi tiêu bắt buộc trước khi nghĩ đến tiết kiệm.
cat("\n===== 3) y ~ housing =====\n")
##
## ===== 3) y ~ housing =====
tab_housing <- table(data_transformed$housing, data_transformed$y)
cat("\nBảng đếm (housing x y):\n"); print(addmargins(tab_housing))
##
## Bảng đếm (housing x y):
##
## 0 1 Sum
## no 1661 301 1962
## yes 2339 220 2559
## Sum 4000 521 4521
cat("\nTỷ lệ theo hàng (%):\n"); print(pct_row(tab_housing))
##
## Tỷ lệ theo hàng (%):
##
## 0 1
## no 84.66 15.34
## yes 91.40 8.60
barplot(tab_housing, beside = TRUE, legend = TRUE,
main = "Phân phối y theo housing", ylab = "Số lượng")
res_housing <- print_composition_y1(
var = data_transformed$housing,
var_name = "housing",
print_order = c("yes","no")
)
##
## Cơ cấu trong nhóm đã đăng ký (y = 1, N = 521) — housing
##
## Yes: 220 người → 42.23% tổng số đã đăng ký
## No: 301 người → 57.77% tổng số đã đăng ký
Biến housing thể hiện tình trạng vay mua nhà của khách hàng, trong đó “Yes” là khách hàng có khoản vay mua nhà, còn “No” là không vay. Khi phân tích mối liên hệ giữa biến này và quyết định gửi tiết kiệm (y), kết quả cho thấy có sự phân hóa đáng kể giữa hai nhóm.
Trong nhóm khách hàng không có khoản vay mua nhà thì 57,77% lựa chọn gửi tiết kiệm, trong khi tỷ lệ này giảm còn 42,23% đối với nhóm có vay mua nhà.
Sự khác biệt này phản ánh logic tài chính phổ biến: khách hàng đang có nghĩa vụ trả nợ vay mua nhà thường có áp lực tài chính cao hơn, dẫn đến xu hướng tiết chế chi tiêu và không ưu tiên các khoản tiết kiệm dài hạn. Trong khi đó, những người không có gánh nặng trả nợ nhà ở có điều kiện tài chính linh hoạt hơn để tham gia các sản phẩm tiết kiệm.
cat("\n===== 5) y ~ poutcome =====\n")
##
## ===== 5) y ~ poutcome =====
tab_pout <- table(data_transformed$poutcome, data_transformed$y)
cat("\nBảng đếm (poutcome x y):\n"); print(addmargins(tab_pout))
##
## Bảng đếm (poutcome x y):
##
## 0 1 Sum
## unknown 3368 337 3705
## failure 427 63 490
## other 159 38 197
## success 46 83 129
## Sum 4000 521 4521
cat("\nTỷ lệ theo hàng (%):\n"); print(pct_row(tab_pout))
##
## Tỷ lệ theo hàng (%):
##
## 0 1
## unknown 90.90 9.10
## failure 87.14 12.86
## other 80.71 19.29
## success 35.66 64.34
barplot(tab_pout, beside = TRUE, legend = TRUE,
main = "Phân phối y theo poutcome", ylab = "Số lượng", las = 2)
res_poutcome <- print_composition_y1(
var = data_transformed$poutcome,
var_name = "poutcome",
print_order = c("success","other","failure","unknown")
)
##
## Cơ cấu trong nhóm đã đăng ký (y = 1, N = 521) — poutcome
##
## Success: 83 người → 15.93% tổng số đã đăng ký
## Other: 38 người → 7.29% tổng số đã đăng ký
## Failure: 63 người → 12.09% tổng số đã đăng ký
## Unknown: 337 người → 64.68% tổng số đã đăng ký
Kết quả phân tích cho thấy, tình trạng kết quả chiến dịch trước đó có mối liên hệ mạnh với khả năng khách hàng gửi tiết kiệm trong hiện tại.
Với nhóm khách hàng có kết quả chiến dịch thành công trong quá khứ đạt tỷ lệ gửi tiết kiệm rất cao – 64,34%. Ngược lại, những khách hàng không thuộc nhóm success như unknow và failure chỉ có tỷ lệ gửi tiết kiệm là 9,1% và 12.29%. Chênh lệch này cực kỳ rõ rệt, cho thấy rằng chiến dịch tiếp thị hiệu quả trong quá khứ là một chỉ báo cực kỳ mạnh mẽ cho hành vi tài chính hiện tại.
Với nhóm khách hàng thuộc loại “other” (tức đã có tiếp xúc nhưng không rõ ràng thành công/thất bại) có tỷ lệ gửi tiết kiệm là 19,29%. Dù sự chênh lệch không mạnh như nhóm success, nhưng điều này vẫn cho thấy rằng bất kỳ sự tiếp cận hay liên hệ nào trong quá khứ đều có khả năng gia tăng xác suất khách hàng gửi tiết kiệm.
library(epitools)
Kiểm định chi bình phương
## Chuẩn hoá biến đầu vào
## ===========================
# Y: chấp nhận 0/1 numeric hoặc factor "0/1" / "no/yes"
y_vec <- data_transformed$y
if (is.factor(y_vec)) {
lev <- levels(y_vec)
if (all(c("0","1") %in% lev)) {
y_num <- as.numeric(y_vec) - 1L # "0","1" -> 0,1
} else if (all(c("no","yes") %in% lev)) {
y_num <- as.integer(y_vec == "yes")
} else {
stop("Levels của y chưa rõ (kỳ vọng '0/1' hoặc 'no/yes').")
}
} else {
y_num <- as.integer(y_vec)
}
stopifnot(all(y_num %in% c(0,1)))
age <- data_transformed$age
stopifnot(is.numeric(age))
## =======================================
## 1) CHI-SQUARE trên age_group × y
## =======================================
# Nếu đã có sẵn age_group thì dùng, nếu chưa thì tạo theo khoảng quen thuộc
if (!("age_group" %in% names(data_transformed))) {
age_group <- cut(
age,
breaks = c(18, 30, 40, 50, 60, 100),
right = FALSE,
labels = c("18–29","30–39","40–49","50–59","60+")
)
} else {
age_group <- data_transformed$age_group
}
tab_age <- table(age_group, y_num, useNA = "no")
colnames(tab_age) <- c("y=0","y=1")
cat("\n[Chi-square] Bảng age_group × y:\n"); print(addmargins(tab_age))
##
## [Chi-square] Bảng age_group × y:
## y_num
## age_group y=0 y=1 Sum
## 18–29 408 74 482
## 30–39 1623 185 1808
## 40–49 1080 123 1203
## 50–59 770 84 854
## 60+ 119 55 174
## Sum 4000 521 4521
chisq_res <- chisq.test(tab_age, correct = FALSE)
cat("\nKết quả Pearson Chi-square (age_group ~ y):\n")
##
## Kết quả Pearson Chi-square (age_group ~ y):
print(chisq_res)
##
## Pearson's Chi-squared test
##
## data: tab_age
## X-squared = 83.113, df = 4, p-value < 2.2e-16
Giả thuyết kiểm định:
H0: Không có xu hướng tỷ lệ đăng ký gửi tiết kiệm tăng hoặc giảm theo thứ bậc nhóm tuổi.
H1: Có xu hướng tỷ lệ đăng ký gửi tiết kiệm tăng hoặc giảm theo thứ bậc nhóm tuổi.
Kết quả thống kê cho thấy giá trị Chi-squared đạt 83.113 với 4 bậc tự do, và p-value < 2.2e-16.
Với mức ý nghĩa 5%, ta bác bỏ giả thuyết H₀ rằng hai biến độc lập. Điều này cho thấy có mối quan hệ có ý nghĩa thống kê giữa độ tuổi và hành vi gửi tiết kiệm của khách hàng. Quan sát bảng số liệu, nhóm 60+ chiếm khoảng 10,55% tổng số người đăng ký (55/521) dù quy mô nhóm nhỏ, nhưng tỷ lệ đăng ký trong nhóm này cao hơn hẳn (31,61%) so với các nhóm tuổi trẻ hơn, cho thấy khách hàng lớn tuổi có xu hướng gửi tiết kiệm nhiều hơn. Như vậy, kết quả kiểm định đã khẳng định lại rằng độ tuổi là một yếu tố có ảnh hưởng rõ rệt đến hành vi tài chính của khách hàng.
library(DescTools)
## Warning: package 'DescTools' was built under R version 4.5.1
## 2) Cochran–Armitage trend test
# Base R: prop.trend.test(x = successes, n = totals)
success <- as.numeric(tab_age[, "y=1"]) # số y=1 theo từng nhóm tuổi (theo thứ tự levels(age_group))
total <- rowSums(tab_age)
cat("\nCochran–Armitage trend test (base R):\n")
##
## Cochran–Armitage trend test (base R):
print(prop.trend.test(x = success, n = total))
##
## Chi-squared Test for Trend in Proportions
##
## data: success out of total ,
## using scores: 1 2 3 4 5
## X-squared = 3.6367, df = 1, p-value = 0.05652
if (requireNamespace("DescTools", quietly = TRUE)) {
cat("\nCochran–Armitage trend test (DescTools):\n")
print(DescTools::CochranArmitageTest(tab_age))
}
##
## Cochran–Armitage trend test (DescTools):
##
## Cochran-Armitage test for trend
##
## data: tab_age
## Z = -1.907, dim = 5, p-value = 0.05652
## alternative hypothesis: two.sided
Giả thiết kiểm định:
H0: Không tồn tại xu hướng tuyến tính giữa tỷ lệ khách hàng đăng ký gửi tiết kiệm và nhóm tuổi.
H1: Có tồn tại xu hướng tuyến tính giữa tỷ lệ khách hàng đăng ký gửi tiết kiệm và nhóm tuổi.
Kết quả & kết luận:
Kiểm định Cochran–Armitage cho thấy giá trị p=0.05652 (> 0.05), do đó chưa đủ bằng chứng thống kê để bác bỏ giả thuyết H0 ở mức ý nghĩa 5%. Tuy nhiên, nếu xét ở mức ý nghĩa 10% thì xu hướng tăng tỷ lệ đăng ký ở nhóm tuổi cao hơn có thể tồn tại và có ý nghĩa. Điều này phù hợp với quan sát từ bảng tần suất, nơi nhóm tuổi 60+ và 18–29 có sự chênh lệch rõ rệt về tỷ lệ gửi tiết kiệm.
Kết quả tỷ lệ OR và RR
## 3) 2×2: age60plus × y và RR/OR
age60plus <- as.integer(age >= 60)
tab_2x2 <- table(age60plus, y_num)
dimnames(tab_2x2) <- list(age60plus = c("0(<60)","1(>=60)"), y = c("0","1"))
cat("\nBảng 2×2 (age60plus × y):\n"); print(addmargins(tab_2x2))
##
## Bảng 2×2 (age60plus × y):
## y
## age60plus 0 1 Sum
## 0(<60) 3881 466 4347
## 1(>=60) 119 55 174
## Sum 4000 521 4521
if (requireNamespace("epitools", quietly = TRUE)) {
cat("\nRR (epitools::riskratio):\n"); print(epitools::riskratio(tab_2x2))
cat("\nOR (epitools::oddsratio):\n"); print(epitools::oddsratio(tab_2x2))
} else {
cat('\n(Gợi ý) Cài epitools để RR/OR kèm CI chính xác: install.packages("epitools")\n')
a <- tab_2x2["1(>=60)","1"]; b <- tab_2x2["1(>=60)","0"]
c <- tab_2x2["0(<60)","1"]; d <- tab_2x2["0(<60)","0"]
risk1 <- a/(a+b); risk0 <- c/(c+d); RR <- risk1/risk0
se_logRR <- sqrt((1/a)-(1/(a+b))+(1/c)-(1/(c+d)))
CI_RR <- exp(log(RR) + c(-1,1)*1.96*se_logRR)
OR <- (a*d)/(b*c)
se_logOR <- sqrt(1/a + 1/b + 1/c + 1/d)
CI_OR <- exp(log(OR) + c(-1,1)*1.96*se_logOR)
cat(sprintf("RR (tự tính): %.3f (95%% CI: %.3f–%.3f)\n", RR, CI_RR[1], CI_RR[2]))
cat(sprintf("OR (tự tính): %.3f (95%% CI: %.3f–%.3f)\n", OR, CI_OR[1], CI_OR[2]))
}
##
## RR (epitools::riskratio):
## $data
## y
## age60plus 0 1 Total
## 0(<60) 3881 466 4347
## 1(>=60) 119 55 174
## Total 4000 521 4521
##
## $measure
## risk ratio with 95% C.I.
## age60plus estimate lower upper
## 0(<60) 1.000000 NA NA
## 1(>=60) 2.948609 2.33157 3.728944
##
## $p.value
## two-sided
## age60plus midp.exact fisher.exact chi.square
## 0(<60) NA NA NA
## 1(>=60) 4.509726e-13 3.599488e-13 2.634564e-17
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
##
## OR (epitools::oddsratio):
## $data
## y
## age60plus 0 1 Total
## 0(<60) 3881 466 4347
## 1(>=60) 119 55 174
## Total 4000 521 4521
##
## $measure
## odds ratio with 95% C.I.
## age60plus estimate lower upper
## 0(<60) 1.000000 NA NA
## 1(>=60) 3.853072 2.740905 5.355213
##
## $p.value
## two-sided
## age60plus midp.exact fisher.exact chi.square
## 0(<60) NA NA NA
## 1(>=60) 4.509726e-13 3.599488e-13 2.634564e-17
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
Giả thiết kiểm định:
H0: Có sự khác biệt về khả năng đăng ký gửi tiết kiệm giữa hai nhóm tuổi này.
H1: Không có sự khác biệt về khả năng đăng ký gửi tiết kiệm giữa nhóm khách hàng ≥ 60 tuổi và nhóm < 60 tuổi.
Kết luận:
Bảng 2×2 cho thấy, trong tổng số 174 khách hàng từ 60 tuổi trở lên, có 55 người đăng ký gửi tiết kiệm (31,61%), trong khi ở nhóm < 60 tuổi, tỷ lệ này chỉ là 10,73% (466/4347).
Kết quả tính Risk Ratio (RR) cho thấy RR = 2,95 (95% CI: 2,33 – 3,73, p < 0,001), nghĩa là khách hàng từ 60 tuổi trở lên có xác suất đăng ký gửi tiết kiệm cao gấp gần 3 lần so với nhóm trẻ hơn.
Tương tự, Odds Ratio (OR) = 3,85 (95% CI: 2,74 – 5,36, p < 0,001), cho thấy tỷ lệ odds gửi tiết kiệm ở nhóm ≥ 60 tuổi cao hơn khoảng 3,85 lần so với nhóm < 60 tuổi.
Điều này phản ánh rằng khách hàng cao tuổi thường có xu hướng ưu tiên các kênh tài chính an toàn như gửi tiết kiệm, do nhu cầu bảo toàn vốn, ít chịu rủi ro và có khả năng tài chính ổn định hơn sau nhiều năm tích lũy. Đây là một phân khúc khách hàng tiềm năng quan trọng đối với ngân hàng.
library(epitools)
tbl_loan <- table(data_transformed$loan, data_transformed$y)
print(tbl_loan)
##
## 0 1
## no 3352 478
## yes 648 43
cat("\n▶ Chi-square test:\n")
##
## ▶ Chi-square test:
print(chisq.test(tbl_loan))
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tbl_loan
## X-squared = 21.872, df = 1, p-value = 2.915e-06
cat("\n▶ Risk Ratio (RR):\n")
##
## ▶ Risk Ratio (RR):
print(riskratio(tbl_loan))
## $data
##
## 0 1 Total
## no 3352 478 3830
## yes 648 43 691
## Total 4000 521 4521
##
## $measure
## risk ratio with 95% C.I.
## estimate lower upper
## no 1.0000000 NA NA
## yes 0.4986103 0.3688821 0.6739613
##
## $p.value
## two-sided
## midp.exact fisher.exact chi.square
## no NA NA NA
## yes 4.424553e-07 5.385544e-07 2.121926e-06
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
cat("\n▶ Odds Ratio (OR):\n")
##
## ▶ Odds Ratio (OR):
print(oddsratio(tbl_loan))
## $data
##
## 0 1 Total
## no 3352 478 3830
## yes 648 43 691
## Total 4000 521 4521
##
## $measure
## odds ratio with 95% C.I.
## estimate lower upper
## no 1.0000000 NA NA
## yes 0.4669204 0.3333488 0.637634
##
## $p.value
## two-sided
## midp.exact fisher.exact chi.square
## no NA NA NA
## yes 4.424553e-07 5.385544e-07 2.121926e-06
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
Kiểm định Chi bình phương
Giả thuyết kiểm định:
H0: Tình trạng vay cá nhân (loan) độc lập với quyết định gửi tiết kiệm.
H1: Tình trạng vay cá nhân (loan) có mối liên hệ với quyết định gửi tiết kiệm.
Kết quả kiểm định Chi bình phương cho thấy:
X² = 21.872, bậc tự do = 1
p-value = 2.915×10⁻⁶
Vì p-value nhỏ hơn 0.05, ta bác bỏ giả thuyết H₀, khẳng định rằng biến loan và y có mối liên hệ có ý nghĩa thống kê. Nói cách khác, việc khách hàng có đang vay tiêu dùng hay không ảnh hưởng đáng kể đến quyết định gửi tiết kiệm.
**Risk Ratio (RR) và Odds Ratio (OR)**
Dựa trên kết quả tính toán:
Risk Ratio (RR) = 0.499 (KTC 95%: 0.369 – 0.674) nghĩa là khách hàng có vay cá nhân có xác suất gửi tiết kiệm chỉ bằng khoảng 49.9% so với khách hàng không vay cá nhân.
Odds Ratio (OR) = 0.467 (KTC 95%: 0.333 – 0.638) cho thấy khả năng gửi tiết kiệm ở nhóm có vay cá nhân chỉ bằng khoảng 46.7% so với nhóm không vay cá nhân khi so xét theo tỷ lệ chênh lệch odds.
-> Điều này hàm ý rằng khách hàng đang có khoản vay cá nhân thường ít đăng ký gửi tiết kiệm hơn, có thể do hạn chế về nguồn vốn khả dụng hoặc ưu tiên trả nợ trước khi thực hiện các khoản tiết kiệm mới.
cat("\n===== 3.2.3. Biến housing và y =====\n")
##
## ===== 3.2.3. Biến housing và y =====
tbl_housing <- table(data_transformed$housing, data_transformed$y)
print(tbl_housing)
##
## 0 1
## no 1661 301
## yes 2339 220
cat("\n▶ Chi-square test:\n")
##
## ▶ Chi-square test:
print(chisq.test(tbl_housing))
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tbl_housing
## X-squared = 48.885, df = 1, p-value = 2.715e-12
cat("\n▶ Risk Ratio (RR):\n")
##
## ▶ Risk Ratio (RR):
print(riskratio(tbl_housing))
## $data
##
## 0 1 Total
## no 1661 301 1962
## yes 2339 220 2559
## Total 4000 521 4521
##
## $measure
## risk ratio with 95% C.I.
## estimate lower upper
## no 1.0000000 NA NA
## yes 0.5603829 0.4758116 0.659986
##
## $p.value
## two-sided
## midp.exact fisher.exact chi.square
## no NA NA NA
## yes 2.610356e-12 2.690195e-12 1.939825e-12
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
cat("\n▶ Odds Ratio (OR):\n")
##
## ▶ Odds Ratio (OR):
print(oddsratio(tbl_housing))
## $data
##
## 0 1 Total
## no 1661 301 1962
## yes 2339 220 2559
## Total 4000 521 4521
##
## $measure
## odds ratio with 95% C.I.
## estimate lower upper
## no 1.0000000 NA NA
## yes 0.5191987 0.4311656 0.6243184
##
## $p.value
## two-sided
## midp.exact fisher.exact chi.square
## no NA NA NA
## yes 2.610356e-12 2.690195e-12 1.939825e-12
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
Kiểm định Chi bình phương
Giả thuyết kiểm định:
H0: Tình trạng vay mua nhà độc lập với quyết định gửi tiết kiệm.
H1: Tình trạng vay mua nhà có liên hệ với quyết định gửi tiết kiệm.
Kết quả kiểm định Chi bình phương cho thấy:
Giá trị thống kê X² = 48.885
Bậc tự do = 1
p-value = 2.715×10⁻¹²
Vì p-value nhỏ hơn 0.05, ta bác bỏ giả thuyết H₀, kết luận rằng tình trạng vay mua nhà có liên quan đến quyết định gửi tiết kiệm của khách hàng.
RR và OR
Risk Ratio (RR) = 0.560 (KTC 95%: 0.476–0.660): Nhóm có vay nhà có xác suất đăng ký gửi tiết kiệm chỉ bằng ~56% so với nhóm không vay nhà. Nói cách khác, xác suất đăng ký ở nhóm vay nhà thấp hơn khoảng 44%.
Odds Ratio (OR) = 0.519 (KTC 95%: 0.431–0.624): Odds đăng ký gửi tiết kiệm ở nhóm có vay nhà chỉ bằng ~52% so với nhóm không vay nhà.
cat("\n===== 3.2.4. Biến maritalmarried và y =====\n")
##
## ===== 3.2.4. Biến maritalmarried và y =====
data_transformed$married_bin <- ifelse(data_transformed$marital == "married", 1, 0)
tbl_married <- table(data_transformed$married_bin, data_transformed$y)
print(tbl_married)
##
## 0 1
## 0 1480 244
## 1 2520 277
cat("\n▶ Chi-square test:\n")
##
## ▶ Chi-square test:
print(chisq.test(tbl_married))
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tbl_married
## X-squared = 18.477, df = 1, p-value = 1.719e-05
cat("\n▶ Risk Ratio (RR):\n")
##
## ▶ Risk Ratio (RR):
print(riskratio(tbl_married))
## $data
##
## 0 1 Total
## 0 1480 244 1724
## 1 2520 277 2797
## Total 4000 521 4521
##
## $measure
## risk ratio with 95% C.I.
## estimate lower upper
## 0 1.0000000 NA NA
## 1 0.6997368 0.5955157 0.8221977
##
## $p.value
## two-sided
## midp.exact fisher.exact chi.square
## 0 NA NA NA
## 1 1.704266e-05 1.894662e-05 1.383384e-05
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
cat("\n▶ Odds Ratio (OR):\n")
##
## ▶ Odds Ratio (OR):
print(oddsratio(tbl_married))
## $data
##
## 0 1 Total
## 0 1480 244 1724
## 1 2520 277 2797
## Total 4000 521 4521
##
## $measure
## odds ratio with 95% C.I.
## estimate lower upper
## 0 1.00000 NA NA
## 1 0.66675 0.5549223 0.8015052
##
## $p.value
## two-sided
## midp.exact fisher.exact chi.square
## 0 NA NA NA
## 1 1.704266e-05 1.894662e-05 1.383384e-05
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
Kiểm định Chi bình phương
Để đánh giá mối liên hệ giữa tình trạng hôn nhân (đã kết hôn) và quyết định gửi tiết kiệm, ta sử dụng kiểm định Chi bình phương với giả thuyết:
H₀: Tình trạng đã kết hôn (maritalmarried) độc lập với quyết định gửi tiết kiệm (y).
H₁: Tình trạng đã kết hôn có liên hệ với quyết định gửi tiết kiệm.
Kết quả kiểm định cho thấy giá trị Chi-squared = 18.477 với 1 bậc tự do và p-value = 1.719e-05. Với p-value nhỏ hơn 0.05, ta bác bỏ giả thuyết H₀ có ý nghĩa thống kê và kết luận rằng tình trạng hôn nhân có liên hệ với quyết định gửi tiết kiệm.
Phân tích Risk Ratio và Odds Ratio:
Giá trị Risk Ratio (RR) được tính là 0.700 (KTC 95%: 0.596–0.822) và OR = 0.667 (KTC 95%: 0.555–0.802) < 1 ⇒ khách hàng đã kết hôn có xác suất và tỷ lệ odds đăng ký thấp hơn so với nhóm độc thân và ly hôn . Cụ thể trong dữ liệu: nhóm đã kết hôn có 277/2797 = 9.90% quyết định đăng ký, trong khi nhóm độc thân và ly hôn thì chỉ có 244/1724 = 14.15% quyết định đăng ký mở tài khoản tiết kiêm
-> Người đã kết hôn có thể ưu tiên dòng tiền cho chi tiêu/gánh nặng gia đình hoặc các mục tiêu tài chính khác, nên ít đăng ký gửi tiết kiệm hơn so với nhóm không phải đã kết hôn. Kết quả ổn định (KTC RR/OR không chứa 1) và phù hợp với trực giác tài chính.
cat("\n===== 3.2.5. Biến poutcomesuccess và y =====\n")
##
## ===== 3.2.5. Biến poutcomesuccess và y =====
data_transformed$success_bin <- ifelse(data_transformed$poutcome == "success", 1, 0)
tbl_success <- table(data_transformed$success_bin, data_transformed$y)
print(tbl_success)
##
## 0 1
## 0 3954 438
## 1 46 83
cat("\n▶ Chi-square test:\n")
##
## ▶ Chi-square test:
print(chisq.test(tbl_success))
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tbl_success
## X-squared = 358, df = 1, p-value < 2.2e-16
cat("\n▶ Risk Ratio (RR):\n")
##
## ▶ Risk Ratio (RR):
print(riskratio(tbl_success))
## $data
##
## 0 1 Total
## 0 3954 438 4392
## 1 46 83 129
## Total 4000 521 4521
##
## $measure
## risk ratio with 95% C.I.
## estimate lower upper
## 0 1.000000 NA NA
## 1 6.451736 5.518716 7.542497
##
## $p.value
## two-sided
## midp.exact fisher.exact chi.square
## 0 NA NA NA
## 1 0 5.528602e-48 5.345547e-81
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
cat("\n▶ Odds Ratio (OR):\n")
##
## ▶ Odds Ratio (OR):
print(oddsratio(tbl_success))
## $data
##
## 0 1 Total
## 0 3954 438 4392
## 1 46 83 129
## Total 4000 521 4521
##
## $measure
## odds ratio with 95% C.I.
## estimate lower upper
## 0 1.00000 NA NA
## 1 16.24307 11.22788 23.77592
##
## $p.value
## two-sided
## midp.exact fisher.exact chi.square
## 0 NA NA NA
## 1 0 5.528602e-48 5.345547e-81
##
## $correction
## [1] FALSE
##
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
Kiểm định Chi bình phương:
Kiểm định Chi bình phương được sử dụng để xem xét mối quan hệ giữa biến poutcomesuccess (kết quả thành công của chiến dịch tiếp thị trước đó) và biến phụ thuộc y. Giả thuyết được đặt ra như sau:
H₀: Hai biến độc lập – kết quả tiếp thị trước đó không ảnh hưởng đến quyết định gửi tiết kiệm.
H₁: Hai biến có liên hệ – kết quả tiếp thị trước đó ảnh hưởng đến hành vi gửi tiết kiệm.
Kết quả cho thấy Chi-squared = 358, với p-value < 2.2e-16, thấp hơn rất nhiều so với ngưỡng 0.05. Do đó, ta bác bỏ giả thuyết H₀ và kết luận rằng kết quả tiếp thị thành công trong quá khứ có liên hệ rất mạnh với hành vi gửi tiết kiệm.
Phân tích Risk Ratio và Odds Ratio:
Giá trị Risk Ratio (RR) là 6.45, nghĩa là tỷ lệ khách hàng gửi tiết kiệm trong nhóm từng tham gia thành công chiến dịch trước cao hơn khoảng 6.5 lần so với nhóm chưa từng thành công. Qua đó cho thấy nhóm khách hàng có tương tác hiệu quả trong quá khứ có tiềm năng cao hơn trong hiện tại.
Trong khi đó, Odds Ratio (OR) là 16.24, cho thấy Tỷ lệ odds gửi tiết kiệm ở nhóm từng thành công trong chiến dịch trước cao hơn hơn 16 lần so với nhóm chưa từng tham gia thành công.
Các khoảng tin cậy 95% cho cả RR ([5.52; 7.54]) và OR ([11.23; 23.78]) đều không chứa giá trị 1, xác nhận độ tin cậy cao của các ước lượng này. Kết quả này cho thấy ngân hàng nên đặc biệt chú trọng đến nhóm khách hàng đã từng tham gia thành công các chiến dịch trước, vì họ có xác suất tái tham gia gửi tiết kiệm rất cao so với các nhóm còn lại.
Trong hồi quy logistic, kiểm định đa cộng tuyến nhằm phát hiện sự phụ thuộc tuyến tính cao giữa các biến độc lập. Khi các biến giải thích có tương quan mạnh với nhau, mô hình sẽ trở nên không ổn định: hệ số ước lượng có thể bị méo lệch, sai số lớn, dẫn đến việc diễn giải sai ý nghĩa của biến.
Kiểm định hệ số phồng phương sai (Variance Inflation Factor – VIF) được sử dụng để đánh giá mức độ đa cộng tuyến giữa các biến độc lập.
Kết quả kiểm định
## ===========================
## 3.3. Kiểm định đa cộng tuyến
## ===========================
suppressPackageStartupMessages({
library(car) # vif / GVIF
})
## Warning: package 'car' was built under R version 4.5.1
# (Tuỳ chọn) ggplot2 cho biểu đồ;
has_gg <- requireNamespace("ggplot2", quietly = TRUE)
model_logit <- glm(y ~ age + loan + housing + marital + poutcome,
data = data_transformed,
family = binomial)
# Tính VIF
vif_raw <- vif(model_logit)
# Chuyển kết quả thành data frame
if (is.matrix(vif_raw)) {
vif_df <- data.frame(
Term = rownames(vif_raw),
GVIF = vif_raw[, "GVIF"],
Df = vif_raw[, "Df"],
GVIF_adj = vif_raw[, "GVIF"]^(1 / (2 * vif_raw[, "Df"]))
)
vif_df$Value <- ifelse(vif_df$Df > 1, vif_df$GVIF_adj, vif_df$GVIF)
} else {
vif_df <- data.frame(
Term = names(vif_raw),
GVIF = as.numeric(vif_raw),
Df = 1,
GVIF_adj = as.numeric(vif_raw),
Value = as.numeric(vif_raw)
)
}
# Vẽ biểu đồ VIF
ggplot(vif_df, aes(x = reorder(Term, Value), y = Value)) +
geom_col(fill = "steelblue") +
coord_flip() +
geom_hline(yintercept = 5, linetype = "dashed", color = "red") +
geom_hline(yintercept = 10, linetype = "dashed", color = "darkred") +
labs(title = "Đa cộng tuyến: VIF/GVIF",
x = "Biến giải thích",
y = "VIF / GVIF^(1/(2·Df))") +
theme_minimal()
Kết quả kiểm định hệ số phồng phương sai (VIF) cho các biến độc lập
trong mô hình hồi quy logistic cho thấy tất cả các biến đều có giá trị
VIF nhỏ hơn 2, Biến có giá trị lớn nhất cũng chỉ quanh khoảng từ 1 tới
1.3; đa số gần bằng 1, cho thấy tương quan tuyến tính giữa các biến giải
thích rất thấp., cho thấy không có hiện tượng đa cộng tuyến nghiêm trọng
xảy ra giữa các biến độc lập.
library(margins)
## Warning: package 'margins' was built under R version 4.5.1
library(broom)
## Warning: package 'broom' was built under R version 4.5.1
library(future)
## Warning: package 'future' was built under R version 4.5.1
library(jtools)
## Warning: package 'jtools' was built under R version 4.5.1
##
## Attaching package: 'jtools'
## The following object is masked from 'package:DescTools':
##
## %nin%
library(pROC)
## Warning: package 'pROC' was built under R version 4.5.1
## Type 'citation("pROC")' for a citation.
##
## Attaching package: 'pROC'
## The following objects are masked from 'package:stats':
##
## cov, smooth, var
# Tạo mô hình hồi quy
model_logit <- glm(y ~ age + loan + housing + marital + poutcome,
data = data_transformed, family = binomial(link = "logit"))
model_probit <- glm(y ~ age + loan + housing + marital + poutcome,
data = data_transformed, family = binomial(link = "probit"))
model_cloglog <- glm(y ~ age + loan + housing + marital + poutcome,
data = data_transformed, family = binomial(link = "cloglog"))
# Hiển thị bảng hệ số hồi quy dạng data frame
jtools::export_summs(list("Logistic" = model_logit,
"Probit" = model_probit,
"Cloglog" = model_cloglog ),scale = TRUE)
| Logistic | Probit | Cloglog | |
|---|---|---|---|
| (Intercept) | -1.65 *** | -1.00 *** | -1.74 *** |
| (0.14) | (0.08) | (0.13) | |
| age | 0.12 * | 0.06 * | 0.09 |
| (0.05) | (0.03) | (0.05) | |
| loanyes | -0.61 *** | -0.31 *** | -0.56 *** |
| (0.17) | (0.08) | (0.16) | |
| housingyes | -0.54 *** | -0.27 *** | -0.51 *** |
| (0.10) | (0.05) | (0.09) | |
| maritalmarried | -0.52 *** | -0.27 *** | -0.47 *** |
| (0.15) | (0.08) | (0.13) | |
| maritalsingle | -0.04 | -0.02 | -0.07 |
| (0.17) | (0.09) | (0.15) | |
| poutcomefailure | 0.45 ** | 0.23 ** | 0.43 ** |
| (0.15) | (0.08) | (0.14) | |
| poutcomeother | 0.92 *** | 0.50 *** | 0.85 *** |
| (0.19) | (0.11) | (0.17) | |
| poutcomesuccess | 2.76 *** | 1.63 *** | 2.22 *** |
| (0.20) | (0.12) | (0.13) | |
| N | 4521 | 4521 | 4521 |
| AIC | 2936.71 | 2937.22 | 2939.36 |
| BIC | 2994.46 | 2994.97 | 2997.11 |
| Pseudo R2 | 0.13 | 0.13 | 0.13 |
| All continuous predictors are mean-centered and scaled by 1 standard deviation. The outcome variable is in its original units. *** p < 0.001; ** p < 0.01; * p < 0.05. | |||
## Cài gói (nếu chưa có)
#
#
library(pROC)
library(ggplot2)
## Xác suất dự đoán
p_logit <- predict(model_logit, type = "response")
p_probit <- predict(model_probit, type = "response")
p_cloglog <- predict(model_cloglog, type = "response")
## ROC & AUC
roc_logit <- roc(response = data_transformed$y, predictor = p_logit, quiet = TRUE)
roc_probit <- roc(response = data_transformed$y, predictor = p_probit, quiet = TRUE)
roc_cloglog <- roc(response = data_transformed$y, predictor = p_cloglog, quiet = TRUE)
auc_logit <- auc(roc_logit)
auc_probit <- auc(roc_probit)
auc_cloglog <- auc(roc_cloglog)
cat("AUC - Logit :", as.numeric(auc_logit), "\n")
## AUC - Logit : 0.686322
cat("AUC - Probit :", as.numeric(auc_probit), "\n")
## AUC - Probit : 0.6861809
cat("AUC - Cloglog:", as.numeric(auc_cloglog), "\n")
## AUC - Cloglog: 0.6859247
## Chuẩn bị dữ liệu để vẽ ggplot
df_logit <- data.frame(
FPR = 1 - roc_logit$specificities,
TPR = roc_logit$sensitivities,
Model = sprintf("Logit (AUC=%.4f)", as.numeric(auc_logit))
)
df_probit <- data.frame(
FPR = 1 - roc_probit$specificities,
TPR = roc_probit$sensitivities,
Model = sprintf("Probit (AUC=%.4f)", as.numeric(auc_probit))
)
df_cloglog <- data.frame(
FPR = 1 - roc_cloglog$specificities,
TPR = roc_cloglog$sensitivities,
Model = sprintf("Cloglog (AUC=%.4f)", as.numeric(auc_cloglog))
)
df_roc <- rbind(df_logit, df_probit, df_cloglog)
## Vẽ ROC
ggplot(df_roc, aes(x = FPR, y = TPR, color = Model)) +
geom_line(size = 1) +
geom_abline(slope = 1, intercept = 0, linetype = 2) +
coord_equal() +
labs(title = "Đường cong ROC: Logit vs Probit vs Cloglog",
x = "False Positive Rate (1 - Specificity)",
y = "True Positive Rate (Sensitivity)") +
theme_minimal() +
theme(legend.title = element_blank())
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
poutcomesuccess luôn có hệ số dương rất lớn và có ý nghĩa (Logit ≈ 2.76; Probit ≈ 1.63; Cloglog ≈ 2.22). Nghĩa là khách hàng đã từng “thành công” ở chiến dịch trước có xác suất đăng ký cao hơn rõ rệt ở hiện tại. Đây là biến mạnh nhất và ổn định nhất trong cả ba mô hình.
age có hệ số dương nhỏ (Logit ≈ 0.12; Probit ≈ 0.06; Cloglog ≈ 0.09, đa số có ý nghĩa), gợi ý tuổi cao hơn → xác suất đăng ký tăng nhẹ.
loanyes và housingyes đều có hệ số âm và có ý nghĩa ở cả ba mô hình (ví dụ Logit: loan ≈ −0.61; housing ≈ −0.54): đang có khoản vay (tiêu dùng/nhà ở) làm giảm xác suất đăng ký—hợp lý vì ràng buộc tài chính.
maritalmarried âm và có ý nghĩa (Logit ≈ −0.52…), còn maritalsingle không ý nghĩa: đã kết hôn có xu hướng ít đăng ký hơn nhóm tham chiếu, trong khi độc thân không khác biệt rõ.
Ba mô hình cho cùng chiều tác động và mức ý nghĩa tương tự, khác nhau chủ yếu ở thang đo hệ số do hàm liên kết khác nhau.
AUC gần như tương đương: Logit ≈ 0.6863, Probit ≈ 0.6862, Cloglog ≈ 0.6859. Các đường ROC gần trùng nhau, cho thấy ba mô hình có độ phân biệt ở mức trung bình và gần như không khác biệt thực tiễn.
Điều này nhất quán với bảng hệ số: biến quan trọng giống nhau nên hiệu năng dự báo cũng tương tự.
Bảng so sánh kết quả mô hình
# Giả sử 3 mô hình đã được tạo trước:
# model_logit, model_probit, model_cloglog
# Gói cần thiết
library(pROC)
library(pscl) # Để tính Pseudo R²
## Warning: package 'pscl' was built under R version 4.5.1
## Classes and Methods for R originally developed in the
## Political Science Computational Laboratory
## Department of Political Science
## Stanford University (2002-2015),
## by and under the direction of Simon Jackman.
## hurdle and zeroinfl functions by Achim Zeileis.
# Tính AUC cho từng mô hình
auc_logit <- auc(model_logit$y, fitted(model_logit))
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
auc_probit <- auc(model_probit$y, fitted(model_probit))
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
auc_cloglog <- auc(model_cloglog$y, fitted(model_cloglog))
## Setting levels: control = 0, case = 1
## Setting direction: controls < cases
# Tạo bảng tổng hợp các chỉ số
results <- data.frame(
Model = c("Logit", "Probit", "Cloglog"),
AIC = c(AIC(model_logit), AIC(model_probit), AIC(model_cloglog)),
BIC = c(BIC(model_logit), BIC(model_probit), BIC(model_cloglog)),
Pseudo_R2 = c(pR2(model_logit)["McFadden"],
pR2(model_probit)["McFadden"],
pR2(model_cloglog)["McFadden"]),
AUC = c(auc_logit, auc_probit, auc_cloglog)
)
## fitting null model for pseudo-r2
## fitting null model for pseudo-r2
## fitting null model for pseudo-r2
# In ra bảng so sánh
print(results)
## Model AIC BIC Pseudo_R2 AUC
## 1 Logit 2936.714 2994.463 0.09665308 0.6863220
## 2 Probit 2937.221 2994.969 0.09649619 0.6861809
## 3 Cloglog 2939.360 2997.108 0.09583424 0.6859247
Dựa trên kết quả phân tích từ ba mô hình hồi quy nhị phân gồm Logistic (logit), Probit và Complementary log-log (cloglog), có thể nhận thấy rằng mô hình logistic cho hiệu quả tốt nhất xét trên nhiều phương diện. Cụ thể, mô hình logistic có giá trị AIC thấp nhất (2936.71) và BIC thấp nhất (2994.46), cho thấy mô hình này vừa phù hợp dữ liệu tốt, vừa ít phức tạp hơn so với hai mô hình còn lại. Ngoài ra, logistic cũng có giá trị Pseudo R² cao nhất (0.0967), thể hiện mức độ giải thích phương sai trong dữ liệu nhỉnh hơn một chút. Đặc biệt, khi đánh giá khả năng phân loại thông qua diện tích dưới đường cong ROC (AUC), mô hình logistic tiếp tục vượt trội với AUC đạt 0.6863 – cao hơn nhẹ so với Probit (0.6862) và cloglog (0.6859).
Từ những so sánh trên, có thể kết luận rằng mô hình logistic là lựa chọn phù hợp nhất trong ba mô hình. Dù sự khác biệt về mặt số liệu không lớn, nhưng logistic thể hiện sự ổn định và hiệu quả hơn trên cả bốn tiêu chí đánh giá quan trọng.
Hàm hồi quy
logit(P)=−1.65+0.12⋅age−0.61⋅loanyes−0.54⋅housingyes−0.52⋅maritalmarried−0.04⋅maritalsingle+0.45⋅poutcomefailure+0.92⋅poutcomeother+2.76⋅poutcomesuccess
Mục tiêu của phần này là đánh giá khả năng áp dụng mô hình hồi quy Logistic đã lựa chọn vào việc dự báo xác suất khách hàng đồng ý gửi tiết kiệm. Kết quả dự báo sẽ giúp ngân hàng tập trung nguồn lực tiếp thị vào nhóm khách hàng tiềm năng nhất.
## 0) Chuẩn bị ---------------------------------------------------------------
set.seed(2025)
stopifnot(all(c("y","age","loan","housing","marital","poutcome") %in% names(data_transformed)))
# Đảm bảo kiểu dữ liệu
data_transformed$y <- as.integer(data_transformed$y)
data_transformed$loan <- factor(data_transformed$loan, levels = c("no","yes"))
data_transformed$housing <- factor(data_transformed$housing, levels = c("no","yes"))
data_transformed$marital <- factor(data_transformed$marital, levels = c("divorced","married","single"))
data_transformed$poutcome <- factor(data_transformed$poutcome, levels = c("unknown","failure","other","success"))
## 1) Chia tập train/test ----------------------------------------------------
idx <- sample(seq_len(nrow(data_transformed)), size = 0.7*nrow(data_transformed))
train <- data_transformed[idx, ]
test <- data_transformed[-idx, ]
## 2) Ước lượng mô hình Logit trên train ------------------------------------
mod_logit <- glm(
y ~ age + loan + housing + marital + poutcome,
data = train,
family = binomial(link = "logit")
)
summary(mod_logit)
##
## Call:
## glm(formula = y ~ age + loan + housing + marital + poutcome,
## family = binomial(link = "logit"), data = train)
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.457793 0.332837 -7.384 1.53e-13 ***
## age 0.017611 0.005901 2.984 0.002842 **
## loanyes -0.700464 0.207150 -3.381 0.000721 ***
## housingyes -0.437670 0.121123 -3.613 0.000302 ***
## maritalmarried -0.458639 0.171617 -2.672 0.007530 **
## maritalsingle 0.033983 0.199146 0.171 0.864505
## poutcomefailure 0.408268 0.176841 2.309 0.020962 *
## poutcomeother 0.945942 0.222441 4.253 2.11e-05 ***
## poutcomesuccess 2.606472 0.231767 11.246 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 2266.8 on 3163 degrees of freedom
## Residual deviance: 2062.2 on 3155 degrees of freedom
## AIC: 2080.2
##
## Number of Fisher Scoring iterations: 5
Kết quả hồi quy cho thấy, tuổi có ảnh hưởng tích cực và có ý nghĩa thống kê (p = 0.0028), nghĩa là người lớn tuổi có xu hướng mở tài khoản nhiều hơn. Ngược lại, những khách hàng có khoản vay cá nhân hoặc vay mua nhà có khả năng mở tài khoản thấp hơn, thể hiện qua hệ số âm và p-value < 0.001. Về tình trạng hôn nhân, khách hàng đã kết hôn có xác suất mở tài khoản thấp hơn nhóm tham chiếu, trong khi nhóm độc thân không có sự khác biệt đáng kể. Đặc biệt, kết quả của chiến dịch marketing trước đó là yếu tố dự báo mạnh mẽ nhất: nếu chiến dịch trước thành công, khả năng khách hàng mở tài khoản tăng lên rất đáng kể (hệ số = 2.606, p < 0.001).
Về chất lượng mô hình, Mô hình sau khi thêm các biến giải thích đã giảm đáng kể sai số so với mô hình rỗng (null deviance = 2266.8, residual deviance = 2062.2), chứng tỏ các biến độc lập có khả năng giải thích hành vi của khách hàng.
Ngưỡng phân loại tối ưu (Threshold)
## 3) Dự báo xác suất & chọn ngưỡng tối ưu (Youden J) -----------------------
library(pROC)
# Xác suất dự báo trên test
prob_test <- predict(mod_logit, newdata = test, type = "response")
# ROC & AUC
roc_logit <- roc(response = test$y, predictor = prob_test, quiet = TRUE)
auc(roc_logit)
## Area under the curve: 0.6989
# Ngưỡng tối ưu theo Youden J
opt <- coords(roc_logit, x = "best", best.method = "youden", transpose = TRUE)
thr <- as.numeric(opt["threshold"]); thr
## [1] 0.1080811
Mô hình hồi quy logistic cho thấy hiệu quả phân loại tương đối tốt với diện tích dưới đường cong ROC (AUC) đạt 0.6989, phản ánh khả năng phân biệt giữa hai nhóm (khách hàng đăng ký và không đăng ký) là khá ổn định.
Thông qua việc áp dụng chỉ số Youden J – một thước đo tối ưu hóa sự cân bằng giữa độ nhạy (recall) và độ đặc hiệu (specificity) – ngưỡng phân loại được xác định là 0.108. Điều này có nghĩa là các quan sát có xác suất lớn hơn 10.8% sẽ được phân loại là có khả năng đăng ký tham gia. Việc chọn ngưỡng phù hợp này giúp giảm thiểu sai số phân loại và đảm bảo kết quả dự báo có ý nghĩa thống kê và giá trị thực tiễn.
Ma trận nhầm lẫn (Confusion Matrix)
## 4) Ma trận nhầm lẫn & các chỉ số đánh giá --------------------------------
pred_cls <- ifelse(prob_test >= thr, 1L, 0L)
TP <- sum(pred_cls == 1 & test$y == 1)
TN <- sum(pred_cls == 0 & test$y == 0)
FP <- sum(pred_cls == 1 & test$y == 0)
FN <- sum(pred_cls == 0 & test$y == 1)
acc <- (TP + TN) / length(pred_cls)
prec <- TP / (TP + FP)
rec <- TP / (TP + FN)
f1 <- 2*prec*rec/(prec+rec)
list(
Threshold = thr,
Confusion = matrix(c(TN, FP, FN, TP), nrow = 2,
dimnames = list("Thực tế" = c("0","1"), "Dự báo" = c("0","1"))),
Metrics = c(Accuracy = acc, Precision = prec, Recall = rec, F1 = f1, AUC = as.numeric(auc(roc_logit)))
)
## $Threshold
## [1] 0.1080811
##
## $Confusion
## Dự báo
## Thực tế 0 1
## 0 769 52
## 1 433 103
##
## $Metrics
## Accuracy Precision Recall F1 AUC
## 0.6425940 0.1921642 0.6645161 0.2981187 0.6989185
Sau khi xác định ngưỡng phân loại tối ưu là 0.108, ta áp dụng ngưỡng này để phân loại khách hàng trong tập kiểm tra. Ma trận nhầm lẫn (confusion matrix) cho thấy rằng mô hình dự báo đúng 769 trường hợp âm tính (không đăng ký) và 103 trường hợp dương tính (có đăng ký), trong khi dự báo sai 52 trường hợp không đăng ký (false positives) và 433 trường hợp có đăng ký (false negatives).
Về mặt đánh giá mô hình, độ chính xác tổng thể (accuracy) đạt khoảng 64.26%, cho thấy tỷ lệ phân loại đúng tương đối khá. Tuy nhiên, precision (độ chính xác của nhóm dự báo dương tính) chỉ đạt 19.2%, phản ánh rằng trong số những người được mô hình dự đoán sẽ đăng ký, chỉ có một phần nhỏ thực sự làm điều đó. Dù vậy, recall (độ bao phủ đối với nhóm thực sự đăng ký) khá cao, đạt 66.45%, tức mô hình đã nhận diện được phần lớn những người có khả năng đăng ký. Chỉ số F1-score, thước đo trung hòa giữa precision và recall, ở mức 0.298, cho thấy mô hình vẫn ưu tiên phát hiện đúng nhóm mục tiêu, dù chưa hoàn hảo.
Cuối cùng, AUC = 0.6989, tiếp tục khẳng định khả năng phân biệt hai nhóm khá tốt. Mô hình này phù hợp cho các bài toán cần phát hiện đúng nhiều khách hàng tiềm năng (ưu tiên recall), chấp nhận tỷ lệ dương tính giả cao để không bỏ sót người thực sự quan tâm.
## 5) Bảng decile & Lift (phân nhóm theo xác suất dự báo) -------------------
library(dplyr)
lift_tbl <- test |>
mutate(prob = prob_test) |>
arrange(desc(prob)) |>
mutate(decile = ntile(prob, 10)) |>
group_by(decile) |>
summarise(
n = n(),
actual_1 = sum(y == 1),
rate = actual_1 / n,
avg_prob = mean(prob)
) |>
ungroup() |>
mutate(
cum_actual_1 = cumsum(actual_1),
baseline = mean(test$y == 1),
lift = rate / baseline
)
lift_tbl
## # A tibble: 10 × 8
## decile n actual_1 rate avg_prob cum_actual_1 baseline lift
## <int> <int> <int> <dbl> <dbl> <int> <dbl> <dbl>
## 1 1 136 6 0.0441 0.0428 6 0.114 0.386
## 2 2 136 6 0.0441 0.0601 12 0.114 0.386
## 3 3 136 9 0.0662 0.0686 21 0.114 0.579
## 4 4 136 9 0.0662 0.0812 30 0.114 0.579
## 5 5 136 12 0.0882 0.0907 42 0.114 0.772
## 6 6 136 10 0.0735 0.101 52 0.114 0.644
## 7 7 136 20 0.147 0.115 72 0.114 1.29
## 8 8 135 15 0.111 0.129 87 0.114 0.973
## 9 9 135 23 0.170 0.148 110 0.114 1.49
## 10 10 135 45 0.333 0.326 155 0.114 2.92
Để đánh giá hiệu quả phân loại của mô hình hồi quy logistic, dữ liệu được chia thành 10 nhóm (decile) theo xác suất dự báo tăng dần. Mỗi nhóm chứa xấp xỉ 135–136 quan sát, cho phép so sánh tỷ lệ sự kiện thực tế với xác suất trung bình dự báo trong từng nhóm.
Kết quả cho thấy, các nhóm decile đầu tiên (từ 1 đến 4) có tỷ lệ sự kiện thực tế (actual rate) dao động từ 4,4% đến 6,6%, tương ứng với xác suất dự báo trung bình (average predicted probability) từ 4,3% đến 8,1%. Điều này phản ánh rằng mô hình có khả năng nhận diện chính xác các quan sát thuộc nhóm nguy cơ thấp.
Từ nhóm decile thứ 5 trở đi, tỷ lệ sự kiện thực tế bắt đầu gia tăng đáng kể, đạt 8,8% đến 14,7% ở các nhóm giữa, và đạt cực đại ở decile 10 với 33,3%. Đồng thời, xác suất dự báo trung bình của decile 10 cũng cao nhất, ở mức 32,6%. Mối quan hệ tuyến tính giữa xác suất dự báo và tỷ lệ sự kiện thực tế cho thấy mô hình có tính phân biệt hợp lý.
Về mặt định lượng, chỉ số Lift được sử dụng để đo lường mức độ cải thiện trong việc phát hiện đúng sự kiện so với mô hình ngẫu nhiên. Các kết quả lift cho thấy:
Nhóm decile 10 có Lift = 2,92, nghĩa là mô hình hiệu quả gấp 2,92 lần so với mô hình phân loại ngẫu nhiên trong việc nhận diện đúng các quan sát xảy ra sự kiện.
Nhóm decile 9 cũng đạt Lift = 1,49, tiếp tục khẳng định khả năng nhận diện đúng các đối tượng mục tiêu.
Trong khi đó, các nhóm đầu tiên có chỉ số lift dưới 1 (dao động từ 0,38 đến 0,77), phù hợp với các quan sát nguy cơ thấp.
Kết luận Tổng thể, mô hình hồi quy logistic cho thấy khả năng phân loại tốt, với xác suất dự báo và tỷ lệ sự kiện thực tế có sự tương đồng tăng dần qua các nhóm decile. Đặc biệt, các chỉ số Lift ở các nhóm cuối (decile 9–10) đều lớn hơn 1 và vượt trội so với baseline, cho thấy mô hình có khả năng dự báo có ý nghĩa thống kê và giá trị ứng dụng thực tiễn cao trong việc xác định nhóm đối tượng có xác suất xảy ra sự kiện cao.
Mô hình hồi quy logistic được xây dựng nhằm dự báo xác suất khách hàng đăng ký tham gia chương trình ngân hàng. Sau quá trình xây dựng, đánh giá và hiệu chỉnh, mô hình cuối cùng bao gồm các biến giải thích có ý nghĩa thống kê như: độ tuổi, tình trạng vay cá nhân (loan), sở hữu nhà (housing), tình trạng hôn nhân (marital), và kết quả chiến dịch tiếp thị trước đó (poutcome).
Các hệ số hồi quy cho thấy một số yếu tố có ảnh hưởng rõ rệt đến khả năng đăng ký, như:
Khách hàng từng thành công trong chiến dịch tiếp thị trước có xác suất đăng ký cao hơn rõ rệt (hệ số dương mạnh).
Những người đang vay cá nhân hoặc đang có nhà lại có xu hướng không tham gia (hệ số âm).
Tuổi tác cũng là yếu tố có ảnh hưởng, dù mức độ tác động không quá lớn.
Mức độ phù hợp của mô hình được đánh giá bằng AIC (2080.21) và độ lệch (residual deviance = 2062.2), cho thấy mô hình cải thiện đáng kể so với mô hình rỗng (null deviance = 2266.8). Trên tập kiểm tra, mô hình đạt AUC = 0.6989, phản ánh năng lực phân biệt hai nhóm (đăng ký/không đăng ký) ở mức khá.
Việc xác định ngưỡng tối ưu theo tiêu chí Youden J giúp tăng cường khả năng nhận diện đúng nhóm khách hàng mục tiêu (recall = 66.45%), dù phải đánh đổi độ chính xác trong nhóm dương tính (precision = 19.21%). Đây là đặc điểm phù hợp cho mục tiêu tiếp thị, khi ưu tiên không bỏ sót khách hàng tiềm năng.
Kết quả phân tích hồi quy nhị phân cho thấy một số biến độc lập có ảnh hưởng đáng kể đến quyết định tham gia gửi tiết kiệm của khách hàng. Dựa trên các hệ số hồi quy, odds ratio cũng như độ phù hợp mô hình, các khuyến nghị sau đây được đề xuất nhằm hỗ trợ ngân hàng thiết kế chiến lược tiếp cận và phát triển sản phẩm tiết kiệm một cách hiệu quả hơn.
Tái khai thác hiệu quả nhóm khách hàng từng tham gia thành công chiến dịch trước. Biến poutcomesuccess có hệ số dương lớn nhất và có ý nghĩa thống kê rất cao (p < 0.001), với odds ratio xấp xỉ 13.87 trong mô hình logit, cho thấy khách hàng đã từng tham gia thành công một chiến dịch trước đó có khả năng đăng ký gửi tiết kiệm cao gấp gần 14 lần so với nhóm chưa từng tham gia. Đây là một chỉ báo quan trọng giúp ngân hàng nhận diện và tập trung nguồn lực vào nhóm khách hàng tiềm năng sẵn có.
Từ kết quả này, ngân hàng nên xây dựng các chiến lược tiếp thị lại (re-marketing) đối với tập khách hàng đã từng phản hồi tích cực trong các chiến dịch trước. Các hình thức có thể triển khai bao gồm ưu đãi cá nhân hóa, chương trình tích điểm thưởng cho khách hàng quay lại hoặc áp dụng mức lãi suất cộng thêm dành riêng cho nhóm này. Đồng thời, nên khai thác dữ liệu lịch sử tương tác để phát triển các mô hình dự báo hành vi khách hàng, từ đó tối ưu hóa nguồn lực tiếp thị và nâng cao hiệu quả chuyển đổi.
Phát triển sản phẩm chuyên biệt dành cho khách hàng cao tuổi Biến age60plus có ảnh hưởng tích cực đến xác suất đăng ký gửi tiết kiệm (β = 1.08, OR ≈ 2.94), hàm ý rằng khách hàng từ 60 tuổi trở lên có khả năng đăng ký cao gần gấp ba lần so với nhóm trẻ hơn. Đây là nhóm khách hàng thường có mức độ ổn định tài chính cao hơn, nhu cầu tiết kiệm an toàn lớn hơn và ít ràng buộc về chi tiêu so với nhóm trung niên hoặc trẻ tuổi.
Trên cơ sở đó, ngân hàng nên xây dựng các sản phẩm tiết kiệm chuyên biệt dành cho người cao tuổi, với các đặc điểm như kỳ hạn linh hoạt, quyền lợi rút trước không mất lãi, tích hợp bảo hiểm sức khỏe hoặc hỗ trợ tư vấn tài chính hưu trí. Ngoài ra, việc tổ chức các hội thảo tài chính dành cho người cao tuổi, kết hợp chăm sóc khách hàng qua các kênh truyền thống như chi nhánh, tổng đài hoặc thư tín cũng sẽ giúp tăng cường mức độ tiếp cận và gắn bó với nhóm khách hàng này.
Giảm rào cản tài chính cho khách hàng có nghĩa vụ chi tiêu cao Các biến loan, housing, và maritalmarried đều có hệ số âm và có ý nghĩa thống kê (p < 0.001), phản ánh xu hướng nhóm khách hàng đang có khoản vay, trả góp nhà hoặc đã lập gia đình có xác suất gửi tiết kiệm thấp hơn. Kết quả này cho thấy các rào cản tài chính cá nhân đang ảnh hưởng tiêu cực đến hành vi tích lũy, đặc biệt trong bối cảnh thu nhập có thể đang được ưu tiên cho chi tiêu hoặc nghĩa vụ tài chính khác.
Để khắc phục điều này, ngân hàng cần phát triển các sản phẩm tiết kiệm linh hoạt, cho phép gửi với số tiền nhỏ theo định kỳ (ví dụ: tiết kiệm từng ngày, tiết kiệm tích lũy theo tuần/tháng) nhằm giảm áp lực tài chính ban đầu. Bên cạnh đó, nên tích hợp chức năng tư vấn tài chính cá nhân cho khách hàng có nghĩa vụ tài chính cao, giúp họ thiết lập kế hoạch quản lý thu chi hiệu quả giữa chi tiêu – trả nợ – tiết kiệm. Một số hình thức tích hợp gửi tiết kiệm vào gói vay tiêu dùng cũng có thể xem xét để khuyến khích hành vi tích lũy song song.
Ưu tiên sử dụng mô hình logit trong ứng dụng thực tiễn Mặc dù kết quả đánh giá độ phù hợp mô hình cho thấy probit có AIC và BIC nhỏ hơn đôi chút, mô hình logit vẫn được khuyến nghị sử dụng trong thực tiễn nhờ khả năng diễn giải rõ ràng thông qua odds ratio. Với AUC ~ 0.886 và RMSE ≈ 0.36 ở cả ba mô hình, sự khác biệt về hiệu suất dự báo không đáng kể; do đó, tính dễ hiểu và khả năng áp dụng là yếu tố nên được ưu tiên.
Việc sử dụng mô hình logit giúp các nhà quản trị, đặc biệt là các bộ phận không chuyên về thống kê như marketing hoặc chăm sóc khách hàng, có thể hiểu rõ ràng hơn về mức độ tác động của từng yếu tố đến quyết định gửi tiết kiệm. Đây là cơ sở quan trọng để xây dựng các công cụ hỗ trợ ra quyết định như bảng phân loại khách hàng, hệ thống gợi ý sản phẩm hoặc quy trình chăm sóc khách hàng theo phân khúc hành vi.