Giảng viên hướng dẫn: ThS.Trần Mạnh Tường
Nhóm 12: Trần Mỹ Duyên - MSSV: 2321000308
Em xin gửi lời cảm ơn chân thành đến Th.S Trần Mạnh Tường đã tận tình giúp đỡ, chia sẻ những kinh nghiệm của thầy đến với chúng em. Thầy đã tận tậm góp ý, chỉ giạy, đưa ra hướng nghiên cứu, các công cụ phụ trợ và cách tiếp cận đến môn học để em có thể hoàn thiện bài báo cáo này một cách chỉnh chu và tốt đẹp nhất.
Trong quá trình học tập và viết bài tiểu luận, em đã nỗ lực rất nhiều để tìm hiểu về đề tài và mô hình mình sử dụng. Tuy nhiên, kiến thức và kinh nghiệm còn có hạn chế nên việc sai sót là điều khó tránh khỏi. Nên em rất mong nhận được các ý kiến đánh giá của thầy cho bài tiểu luận này để bản thân em có được cơ hội học hỏi và trau dồi nhiều hơn, để có thể hoàn thiện tốt trong tương lai.
Em xin chân thành cảm ơn!
Em xin cam đoan rằng bài báo cáo tiểu luận này là kết quả của quá trình nghiên cứu, tìm hiểu và tổng hợp kiến thức do chính bản thân em thực hiện. Toàn bộ các số liệu, kết quả phân tích và nội dung trình bày trong bài đều trung thực, được trích dẫn rõ ràng từ những nguồn tài liệu đáng tin cậy và tuân thủ đúng các quy định về trích dẫn học thuật.
Em hoàn toàn chịu trách nhiệm về tính chính xác, trung thực và minh bạch của các nội dung được nêu trong bài tiểu luận. Bài làm này không sao chép hay vi phạm bản quyền của bất kỳ cá nhân hay tổ chức nào.
Em cũng xin khẳng định rằng toàn bộ kết quả nghiên cứu trong bài đều được em trình bày một cách công khai, minh bạch và trung thực, nhằm phục vụ cho mục đích học tập và nghiên cứu khoa học.
Trong bối cảnh ngành bảo hiểm nhân thọ ngày càng cạnh tranh gay gắt, việc duy trì khách hàng cũ được xem là một trong những yếu tố then chốt giúp doanh nghiệp tồn tại và phát triển bền vững. Cùng với sự phát triển mạnh mẽ của khoa học dữ liệu và công nghệ phân tích hành vi, các tổ chức bảo hiểm ngày càng chú trọng đến việc phân tích, dự báo khả năng rời bỏ của khách hàng (customer churn) nhằm đưa ra chiến lược giữ chân hiệu quả.
Để phục vụ mục tiêu này, bộ dữ liệu “Customer Churn Dataset for Life Insurance Industry” được công bố trên nền tảng Kaggle đã trở thành một trong những nguồn dữ liệu tiêu biểu được sử dụng rộng rãi trong các nghiên cứu ứng dụng về lĩnh vực tài chính – bảo hiểm. Kaggle, với vai trò là một cộng đồng toàn cầu chuyên về phân tích dữ liệu và học máy, cung cấp các tập dữ liệu mở chất lượng cao, cho phép các nhà nghiên cứu, sinh viên và chuyên gia thực hành các kỹ thuật thống kê, mô hình dự báo và khai phá dữ liệu trong môi trường thực tế.
Bộ dữ liệu này được thiết kế với mục tiêu mô phỏng một hệ thống khách hàng trong lĩnh vực bảo hiểm nhân thọ, nơi các yếu tố như thông tin hợp đồng, hành vi bồi thường, đặc điểm cá nhân và mức độ gắn bó với công ty bảo hiểm được tổng hợp và ghi nhận. Dữ liệu phản ánh thực tiễn kinh doanh của doanh nghiệp bảo hiểm trong việc quản lý danh mục khách hàng và dự đoán xu hướng rời bỏ, từ đó giúp tối ưu hóa chiến lược chăm sóc khách hàng, nâng cao chất lượng dịch vụ, đồng thời tăng hiệu quả hoạt động kinh doanh.
library(readxl)
# Xác định đường dẫn đến tệp dữ liệu
df <- read_excel("D:/thầy Tường/Customer.xlsx")Đây là bước “nạp” dữ liệu thô vào môi trường R để chuẩn bị phân tích
# Định nghĩa các biến
n_rows <- nrow(df)
# Tạo data frame tạm thời
df_rows <- data.frame(Thong_Tin = "Số dòng ",Gia_Tri = scales::comma(n_rows))
# In ra kết quả
kable( df_rows, caption = "Số dòng dữ liệu", col.names = c("Thông tin", "Giá trị"),
align = "lc",row.names = FALSE)| Thông tin | Giá trị |
|---|---|
| Số dòng | 200,000 |
Kết quả: có 200.000 dòng
# Số cột
n_cols <- ncol(df)
# Tạo data frame tạm thời
df_cols <- data.frame( Thong_Tin = "Số cột", Gia_Tri = n_cols)
# In ra kết quả
kable(df_cols, caption = "Số cột dữ liệu", col.names = c("Thông tin", "Giá trị"),
align = "lc", row.names = FALSE)| Thông tin | Giá trị |
|---|---|
| Số cột | 12 |
Kết quả: có 12 cột
# lập bảng giải thích các biến.
variable_meaning <- data.frame(
Ten_Bien = names(df),
Mo_Ta = c(
"Số thứ tự của khách hàng",
"Tên khách hàng",
"Địa chỉ khách hàng",
"Tên công ty bảo hiểm quản lý hợp đồng",
"Lý do khách hàng yêu cầu bồi thường",
"Mức độ bảo mật dữ liệu của khách hàng",
"Số tiền khách hàng yêu cầu bồi thường",
"Mức phí bảo hiểm của khách hàng",
"Tỷ lệ giữa phí bảo hiểm và số tiền yêu cầu bồi thường",
"Kết quả xử lý yêu cầu bồi thường ",
"Chỉ số khối cơ thể",
"Khách hàng có rời công ty bảo hiểm hay không"))
# In bảng giải thích.
kable(variable_meaning, col.names = c("Tên Biến", "Mô Tả"),
caption = "Giải thích các biến trong dữ liệu")| Tên Biến | Mô Tả |
|---|---|
| Index | Số thứ tự của khách hàng |
| Customer Name | Tên khách hàng |
| Customer_Address | Địa chỉ khách hàng |
| Company Name | Tên công ty bảo hiểm quản lý hợp đồng |
| Claim Reason | Lý do khách hàng yêu cầu bồi thường |
| Data confidentiality | Mức độ bảo mật dữ liệu của khách hàng |
| Claim Amount | Số tiền khách hàng yêu cầu bồi thường |
| Category Premium | Mức phí bảo hiểm của khách hàng |
| Premium/Amount Ratio | Tỷ lệ giữa phí bảo hiểm và số tiền yêu cầu bồi thường |
| Claim Request output | Kết quả xử lý yêu cầu bồi thường |
| BMI | Chỉ số khối cơ thể |
| Churn | Khách hàng có rời công ty bảo hiểm hay không |
# Gọi thư viện.
library(knitr)
# Lập bảng kiểu dữ liệu.
Kieu_du_lieu<-data.frame( Ten_Bien = names(df),Kieu_du_lieu = sapply(df, class))
# In bảng giải thích.
kable(Kieu_du_lieu, col.names = c("Tên Biến", "Kiểu Dữ Liệu"),
caption = "Thống kê kiểu dữ liệu các biến",row.names = FALSE)| Tên Biến | Kiểu Dữ Liệu |
|---|---|
| Index | numeric |
| Customer Name | character |
| Customer_Address | character |
| Company Name | character |
| Claim Reason | character |
| Data confidentiality | character |
| Claim Amount | numeric |
| Category Premium | numeric |
| Premium/Amount Ratio | character |
| Claim Request output | character |
| BMI | numeric |
| Churn | character |
Kết quả: Có 5 biến định định lượng (num) và 7 biến định tính (chr).
# Lập bảng dữ liệu bị thiếu
Du_Lieu_Bi_Thieu<-data.frame( Ten_Bien = names(df),N_A = colSums(is.na(df)))
# In bảng giữ liệu.
kable(Du_Lieu_Bi_Thieu, col.names = c("Tên Biến", "Dữ Liệu Bị thiếu"),
caption = "Thống kê dữ liệu bị thiếu",row.names = FALSE)| Tên Biến | Dữ Liệu Bị thiếu |
|---|---|
| Index | 0 |
| Customer Name | 0 |
| Customer_Address | 0 |
| Company Name | 0 |
| Claim Reason | 0 |
| Data confidentiality | 0 |
| Claim Amount | 0 |
| Category Premium | 0 |
| Premium/Amount Ratio | 0 |
| Claim Request output | 0 |
| BMI | 0 |
| Churn | 0 |
Kết quả: Bộ dữ liệu không có giá trị bị thiếu.
Ý nghĩa: Đây là bước đánh giá tính đầy đủ (completeness) của dữ liệu. Dữ liệu khuyết là một vấn đề nghiêm trọng trong phân tích. Hầu hết các mô hình thống kê (như hồi quy) sẽ tự động loại bỏ toàn bộ hàng (listwise deletion) nếu hàng đó chứa dù chỉ một giá trị NA. Nếu dữ liệu khuyết ở mức cao, điều này sẽ làm giảm kích thước mẫu hiệu dụng (effective sample size), từ đó làm giảm sức mạnh thống kê (statistical power) của mô hình.
# Đếm số hàng trùng lặp (Lệnh của bạn)
Kiem_Tra_Trung_lap <- sum(duplicated(df))
# Tắt ký hiệu khoa học mặc định của R (tùy chọn)
options(scipen = 999)
# Tạo data frame tạm thời
df_trung_lap <- data.frame( Thong_Tin = "Số hàng trùng lặp",
# Định dạng số bằng scales::comma để hiển thị rõ ràng
Gia_Tri = scales::comma(Kiem_Tra_Trung_lap) )
# In ra bảng kable
kable( df_trung_lap, caption = "Dữ liệu trùng lặp", col.names = c("Thông tin", "Giá trị"),
align = "lr", booktabs = TRUE,row.names = FALSE)| Thông tin | Giá trị |
|---|---|
| Số hàng trùng lặp | 0 |
Kết quả: Bộ dữ liệu không có hàng nào trùng lặp.
# thống kê mô tả biến claim Amount
knitr::kable(data.frame( Chi_tieu = names(summary(df$`Claim Amount`)),
Gia_tri = as.numeric(summary(df$`Claim Amount`))),
# Đặt Đặt tiêu đề
caption = "Thống kê biến claim amout",
# Đặt tên cột, Làm tròn số, căn chỉnh lề
col.names = c("Chỉ tiêu thống kê", "Giá trị"),digits = 2,align = "lr")| Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 1.00 |
| 1st Qu. | 245.00 |
| Median | 1390.00 |
| Mean | 1120.48 |
| 3rd Qu. | 1844.00 |
| Max. | 2299.00 |
Kết luận: Các yêu cầu bồi thường phần lớn đều có giá trị ở mức cao (gần \(1390\) đến \(2299\)). Giá trị Trung bình bị kéo xuống thấp hơn do sự tồn tại của một lượng nhỏ các yêu cầu có giá trị rất thấp (gần \(1\)). Điều này cho thấy công ty bảo hiểm phải xử lý một lượng lớn các yêu cầu bồi thường có giá trị lớn.
# Thống kê mô tả biến BMI
knitr::kable(data.frame( Chi_tieu = names(summary(df$BMI)),
Gia_tri = as.numeric(summary(df$BMI))),
# Đặt Đặt tiêu đề
caption = "Thống kê biến 'BMI'",
# Đặt tên cột, Làm tròn số, căn chỉnh lề
col.names = c("Chỉ tiêu thống kê", "Giá trị"),digits = 2,align = "lr")| Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 18.00 |
| 1st Qu. | 20.00 |
| Median | 23.00 |
| Mean | 23.01 |
| 3rd Qu. | 26.00 |
| Max. | 28.00 |
Kết luận: Biến BMI có phân bố rất đối xứng, khi Giá trị Trung bình và Trung vị gần như trùng nhau (≈ 23). Phần lớn khách hàng có BMI trong khoảng 20–26, cho thấy sự đồng nhất cao và hầu hết đều thuộc nhóm cân nặng khỏe mạnh đến thừa cân nhẹ, không có giá trị cực đoan đáng kể.
Các biến Customer Name, Customer Address và Company Name không mang ý nghĩa thống kê.
# Tạo bảng tần suất cho biến Claim Reason
claim_table <- table(df$`Claim Reason`)
# In bảng đẹp
kable(claim_table, caption = "Tần suất biến claim reason",
col.names = c("Lý do yêu cầu", "Tần suất"), align = "lc")| Lý do yêu cầu | Tần suất |
|---|---|
| Medical | 109863 |
| Other | 30187 |
| Phone | 30016 |
| Travel | 29934 |
Nhận Xét: Medical chiếm số lượng áp đảo so với các lý do khác. Điều này cho thấy các yêu cầu bồi thường y tế là vấn đề lớn nhất trong dữ liệu này. Ba loại còn lại (Other, Phone, Travel) có số lượng khá tương đương nhau, dao động quanh mức 30000 trường hợp.
# Tạo bảng tần suất cho biến Data confidentiality
conf_table <- table(df$`Data confidentiality`)
# In bảng đẹp
kable(conf_table, caption = "Tần suất biến data confidentiality",
col.names = c("Mức độ bảo mật", "Tần suất"),align = "lc")| Mức độ bảo mật | Tần suất |
|---|---|
| High | 109863 |
| Low | 29934 |
| Medium | 30016 |
| Very low | 30187 |
Kết quả: Dữ liệu cho thấy có một sự phân cực rõ rệt: phần lớn các bản ghi được coi là có mức độ bảo mật Cao, trong khi ba mức độ còn lại (Low, Medium, Very low) có số lượng bản ghi tương đương nhau và thấp hơn đáng kể so với mức High.
# Tạo bảng tần suất cho biến Claim Request output
claim_output_table <- table(df$`Claim Request output`)
# In bảng đẹp
kable(claim_output_table, caption = "Tần suất biến claim request output",
col.names = c("Kết quả yêu cầu", "Tần suất"),align = "lc")| Kết quả yêu cầu | Tần suất |
|---|---|
| No | 192994 |
| Yes | 7006 |
Kết quả: cho thấy một sự mất cân bằng rất lớn trong dữ liệu. Số lượng yêu cầu bị từ chối (No) (199994) lớn hơn rất nhiều so với số lượng yêu cầu được chấp thuận (Yes) (7006).
# Tạo bảng tần suất cho biến Churn
churn_table <- table(df$Churn)
# In bảng đẹp
kable(churn_table,caption = "Tần suất biến churn",
col.names = c("Trạng thái rời bỏ (Churn)", "Tần suất"),align = "lc")| Trạng thái rời bỏ (Churn) | Tần suất |
|---|---|
| No | 72728 |
| Yes | 127272 |
Kết quả: Cho thấy số lượng khách hàng rời bỏ (Yes) (127272) lớn hơn đáng kể so với số lượng khách hàng duy trì (72728).
Nhận xét: Điều này chỉ ra rằng công ty đang đối mặt với một tỷ lệ khách hàng rời bỏ rất cao.
# Chuyển thành chữ thường, xóa ký tự đặc biệt, thay khoảng trắng bằng "_"
df_clean <- clean_names(df_clean)
# Tạo bảng kết quả
kable( data.frame( STT = seq_along(names(df_clean)), Ten_cot = names(df_clean)),
caption = "Kết quả chuẩn hóa",col.names = c("STT", "Tên cột"), align ="l")| STT | Tên cột |
|---|---|
| 1 | index |
| 2 | customer_name |
| 3 | customer_address |
| 4 | company_name |
| 5 | claim_reason |
| 6 | data_confidentiality |
| 7 | claim_amount |
| 8 | category_premium |
| 9 | premium_amount_ratio |
| 10 | claim_request_output |
| 11 | bmi |
| 12 | churn |
Ý nghĩa:Chuẩn hóa tên cột nhằm thay khoảng trắng và ký tự đặc biệt bằng dấu gạch dưới, giúp tên biến đồng nhất, dễ gọi và tránh lỗi khi xử lý dữ liệu trong R.
# Cập nhật Data Frame "df_clean"
df_clean <- df_clean %>%
# Loại bỏ các cột không cần thiết
select(-c(index, customer_name, customer_address, company_name))
# Tạo bảng kết quả
kable(data.frame(STT = seq_along(names(df_clean)),Ten_cot = names(df_clean)),
caption = "Danh sách cột sau loại bỏ",
col.names = c("STT", "Tên cột"),align = "l")| STT | Tên cột |
|---|---|
| 1 | claim_reason |
| 2 | data_confidentiality |
| 3 | claim_amount |
| 4 | category_premium |
| 5 | premium_amount_ratio |
| 6 | claim_request_output |
| 7 | bmi |
| 8 | churn |
Ý nghĩa:Đoạn mã trên loại bỏ các cột không cần thiết như index, customer_name, customer_address và company_name để giữ lại những biến quan trọng, giúp dữ liệu gọn, dễ phân tích và tránh nhiễu thông tin.
# Chuyển đổi 'claim_request_output' (Yes/No) thành biến số (1/0)
df_clean$claim_output_encoded <- ifelse(df_clean$claim_request_output == "Yes", 1, 0)
# xem 10 hàng đầu
kable(head(df_clean[, c("claim_request_output", "claim_output_encoded")],10),
caption = "10 dòng đầu sau loại bỏ")| claim_request_output | claim_output_encoded |
|---|---|
| No | 0 |
| No | 0 |
| No | 0 |
| No | 0 |
| No | 0 |
| No | 0 |
| No | 0 |
| No | 0 |
| No | 0 |
| No | 0 |
Ý nghĩa: Việc chuyển biến “Yes/No” thành dạng nhị phân (1/0) giúp biến định tính trở thành biến định lượng, từ đó có thể tính toán thống kê như tỷ lệ, trung bình hay xác suất. Mã hóa này cho phép phân tích mối quan hệ với các biến khác, sử dụng trong các mô hình hồi quy và dự đoán. Giá trị trung bình của biến nhị phân thể hiện trực tiếp tỷ lệ xảy ra của sự kiện “Yes” trong tập dữ liệu. Mã hóa tương tự cho biến “Churn”.
# chuyển đổi 'churn' (Yes/No) thành biến số (1/0)
df_clean$churn_encoded <- ifelse(df_clean$churn == "Yes", 1, 0)
# xem 10 hàng đầu
kable(head(df_clean[, c("churn", "churn_encoded")], 10),
caption = "10 dòng đầu sau mã hóa")| churn | churn_encoded |
|---|---|
| Yes | 1 |
| Yes | 1 |
| Yes | 1 |
| Yes | 1 |
| Yes | 1 |
| No | 0 |
| Yes | 1 |
| No | 0 |
| No | 0 |
| No | 0 |
# Xác định thứ tự mức độ
levels_order <- c("Very low", "Low", "Medium", "High")
# Tạo biến factor có thứ tự
df_clean$data_confid_ordinal <- factor(df_clean$data_confidentiality,
levels = levels_order,
ordered = TRUE)
# Xem danh sách 10 hàng đầu tiên
kable(head( data.frame( data_confidentiality = df_clean$data_confidentiality,
mã_số = as.integer(df_clean$data_confid_ordinal)), 10),
caption = "10 dòng đầu sau mã hóa")| data_confidentiality | mã_số |
|---|---|
| Low | 2 |
| High | 4 |
| Medium | 3 |
| Medium | 3 |
| Medium | 3 |
| High | 4 |
| High | 4 |
| Very low | 1 |
| Medium | 3 |
| High | 4 |
Ý nghĩa: Việc mã hóa giúp phần mềm hiểu rõ thứ tự các mức độ (“Very low” → “High”), từ đó khi vẽ biểu đồ cột hoặc hộp, các mức sẽ sắp xếp đúng logic thay vì ngẫu nhiên.
# Thao tác này sẽ tự động tạo ra 4 cột nhị phân mới (0/1)
df_clean <- dummy_cols(df_clean, select_columns = "claim_reason",
remove_first_dummy = FALSE) # Giữ tất cả các cột
# Xem 5 dòng đầu để thấy các cột mới
df_clean %>%
# Chọn cột gốc và tất cả các cột nhị phân mới bắt đầu bằng 'claim_reason_'
select(claim_reason, starts_with("claim_reason_")) %>%
# Lấy 10 dòng đầu tiên để kiểm tra
head(n = 10) %>%
# In kable
kable( caption = "4 cột nhị phân vừa tạo", font_size = 9,scale_down = FALSE )| claim_reason | claim_reason_Medical | claim_reason_Other | claim_reason_Phone | claim_reason_Travel |
|---|---|---|---|---|
| Travel | 0 | 0 | 0 | 1 |
| Medical | 1 | 0 | 0 | 0 |
| Phone | 0 | 0 | 1 | 0 |
| Phone | 0 | 0 | 1 | 0 |
| Phone | 0 | 0 | 1 | 0 |
| Medical | 1 | 0 | 0 | 0 |
| Medical | 1 | 0 | 0 | 0 |
| Other | 0 | 1 | 0 | 0 |
| Phone | 0 | 0 | 1 | 0 |
| Medical | 1 | 0 | 0 | 0 |
Kết quả: Dataset sau khi mã hóa có thêm 4 cột mới (vì có 4 loại lý do khiếu nại). Nó sẽ được dùng trong mô hình hồi quy, phân loại… vì mô hình chỉ hiểu được số, không hiểu chuỗi ký tự. Nếu khách hàng có claim_reason = “Travel”, thì claim_reason_Travel = 1, các cột khác bằng 0. Nếu claim_reason = “Phone”, thì claim_reason_Phone = 1, các cột khác bằng 0. Và tương tự cho các nhóm khác.
# Tạo một biến mới thể hiện lợi nhuận (hoặc lỗ) từ mỗi hợp đồng
df_clean <- df_clean %>%
# (Lợi nhuận = Phí thu vào (premium) - Tiền chi ra (claim))
mutate(profitability = category_premium - claim_amount)
# Xem Thống kê mô tả cho biến
data.frame( "Chỉ tiêu" = names(summary(df_clean$profitability)),
"Giá trị" = as.numeric(summary(df_clean$profitability))) %>%
# In bảng thống kê mô tả
knitr::kable( caption = "Thống kê mô tả biến profitability",
col.names = c("Chỉ tiêu", "Giá trị"), digits = 2,align = "lr")| Chỉ tiêu | Giá trị |
|---|---|
| Min. | 300.00 |
| 1st Qu. | 1652.00 |
| Median | 12180.00 |
| Mean | 7843.31 |
| 3rd Qu. | 12637.00 |
| Max. | 13090.00 |
Ý Nghĩa: Biến premium_amount_ratio biểu thị tỷ lệ giữa phí bảo hiểm và số tiền yêu cầu bồi thường — đây là giá trị số học, cần được xử lý như số để có thể tính toán, thống kê, và trực quan hóa (ví dụ: trung bình, phương sai, biểu đồ, mô hình hồi quy…).
# Cập nhật "df_clean"
df_clean <- df_clean %>%
# Tạo cột mới "loss_ratio" (Tỷ lệ Tổn thất)
mutate(loss_ratio = claim_amount / category_premium)
# Xem thống kê mô tả cho biến
data.frame( "Chỉ tiêu" = names(summary(df_clean$loss_ratio)),
"Giá trị" = as.numeric(summary(df_clean$loss_ratio))) %>%
# In bảng thống kê mô tả
knitr::kable( caption = "Thống kê mô tả biến loss ratio",
col.names = c("Chỉ tiêu", "Giá trị"),digits = 4,align = "lr")| Chỉ tiêu | Giá trị |
|---|---|
| Min. | 0.0025 |
| 1st Qu. | 0.1067 |
| Median | 0.1251 |
| Mean | 0.1250 |
| 3rd Qu. | 0.1432 |
| Max. | 0.2481 |
Ý nghĩa: Biến loss_ratio (tỷ lệ tổn thất) được tạo nhằm phản ánh mối quan hệ giữa số tiền bồi thường và phí bảo hiểm, qua đó đánh giá hiệu quả hoạt động và mức độ rủi ro trong kinh doanh bảo hiểm.
# Kiểm tra xem có trường hợp nào 'category_premium' = 0 (gây ra Inf) không
so_luong_inf <- sum(is.infinite(df_clean$loss_ratio))
# Tạo bảng kết luận
kable( data.frame( Noi_dung = "Số dòng vi phạm", So_luong = so_luong_inf),
caption = "Kết luận kiểm tra 'loss_ratio'",
col.names = c("Nội dung", "Số lượng"),align = "l")| Nội dung | Số lượng |
|---|---|
| Số dòng vi phạm | 0 |
# Cập nhật Data Frame "df_clean"
df_clean <- df_clean %>%
# Tạo một cột mới có tên là "bmi_group"
mutate(bmi_group = cut(bmi, breaks = c(17.9, 24.9, 28.1),
labels = c("Normal (<25)", "Overweight (25-28)"),
right = TRUE,include.lowest = TRUE))
# Xem số lượng khách hàng trong mỗi nhóm BMI
data.frame(table(df_clean$bmi_group)) %>%
kable(caption = "Thống kê số lượng khách hàng theo nhóm BMI",
col.names = c("Nhóm BMI", "Số lượng"),align = "lr",booktabs = TRUE )| Nhóm BMI | Số lượng |
|---|---|
| Normal (<25) | 127272 |
| Overweight (25-28) | 72728 |
Kết quả: Dựa trên ‘summary’ (Min=18, Max=28), ta chia thành 2 nhóm: Dưới 25 là Bình thường / Thừa cân nhẹ, trên 25 là Thừa cân/Béo phì.
# Tính toán các điểm Tứ phân vị
quantiles_claim <- quantile(df_clean$claim_amount, probs = c(0, 0.25, 0.5, 0.75, 1))
# Cập nhật Data Frame "df_clean"
df_clean <- df_clean %>%
# Tạo một cột mới có tên là "claim_group"
mutate(claim_group = cut(claim_amount, breaks = quantiles_claim,
labels = c("Low", "Medium", "High", "Very High"), include.lowest = TRUE))
# In bảng thống kê
data.frame(table(df_clean$claim_group)) %>%
kable( caption = "Thống kê số lượng khách hàng theo nhóm claim amount",
col.names = c("Nhóm Claim Amount", "Số lượng"), align = "lr", booktabs = TRUE)| Nhóm Claim Amount | Số lượng |
|---|---|
| Low | 50043 |
| Medium | 50027 |
| High | 49942 |
| Very High | 49988 |
Ý nghĩa: Việc phân tổ biến Claim Amount theo các tứ phân vị giúp chia khách hàng thành 4 nhóm mức độ bồi thường (Low, Medium, High, Very High), qua đó dễ dàng so sánh và phân tích hành vi, rủi ro giữa các nhóm khách hàng khác nhau.
# Khởi tạo biểu đồ và gán trục X, trục Y
ggplot(df_clean, aes(x = factor(churn_encoded, labels = c("Ở lại", "Rời bỏ")))) +
# Thêm Lớp Biểu đồ Cột
geom_bar(aes(fill = factor(churn_encoded, labels = c("Ở lại", "Rời bỏ"))),
show.legend = FALSE) +
# Thêm Nhãn Số lượng
geom_text(stat = 'count', aes(label = ..count..), vjust = -0.5, size = 5 ) +
# Tùy chỉnh Màu sắc
scale_fill_manual(values = c("Ở lại" = "skyblue", "Rời bỏ" = "tomato")) +
# Mở rộng trục y (tăng giới hạn trên 15%) để nhãn số không bị cắt
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
# Thêm Tiêu đề và Nhãn
labs(title = "TỶ LỆ KHÁCH RỜI BỎ (CHURN) TỔNG THỂ", x ="Trạng thái Khách hàng", y = "Số lượng")Kết quả: Biểu đồ cho thấy sự Mất cân bằng Lớp (Class Imbalance) rõ rệt. Lớp đa số (majority class) là “Rời bỏ” và lớp thiểu số (minority class) là “Ở lại”. Nhận xét: Tỷ lệ khách hàng rời bỏ (Churn Rate) là rất cao, chiếm khoảng 63.6% (127,272 / (127,272 + 72,728)). Đây là một vấn đề nghiêm trọng, cho thấy công ty đang mất đi phần lớn khách hàng của mình.
# Khởi tạo biểu đồ và gán trục X, trục Y
ggplot(df_clean,aes(x=factor(claim_output_encoded,labels = c("Bị từ chối","Được chấp thuận")))) +
# Thêm lớp Biểu đồ Cột
geom_bar(aes(fill = factor(claim_output_encoded, labels = c("Bị từ chối", "Được chấp thuận"))),
show.legend = FALSE) +
#Thêm nhãn số lượng trên đỉnh cột
geom_text(stat = 'count', aes(label = ..count..), vjust = -0.5, size = 3.5) +
# Tùy chỉnh màu
scale_fill_manual(values = c("Bị từ chối"="tomato","Được chấp thuận"="skyblue")) +
# Mở rộng trục Y
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
# Thêm tiêu đề và nhãn trục
labs(title = "TỶ LỆ CHẤP THUẬN YÊU CẦU BỒI THƯỜNG", x = "Kết quả Yêu cầu", y = "Số lượng")Kết quả: Dữ liệu bị thiên lệch cực kỳ nghiêm trọng. Lớp đa số (majority class) là “Bị từ chối” (192,994 quan sát) và lớp thiểu số (minority class) là “Được chấp thuận” (chỉ 7,006 quan sát).
# Tạo một data frame mới "df_gop_b3"
df_gop_b3 <- df_clean %>%
# Lọc ra chỉ 4 cột có tên bắt đầu bằng "claim_reason_"
select(starts_with("claim_reason_")) %>%
# Biến 4 cột "rộng" (wide) thành 2 cột "dài" (long)
pivot_longer(cols = everything(),
# Tên cột mới (claim_reason_label)
names_to = "claim_reason_label",
# Tên cột mới (is_reason): Chứa GIÁ TRỊ (0 hoặc 1) của 4 cột cũ
values_to = "is_reason") %>%
# Chỉ giữ lại những hàng có giá trị "is_reason" == 1
filter(is_reason == 1) %>%
# Tạo cột "claim_reason" bằng cách xóa tiền tố "claim_reason_"
mutate(claim_reason = str_remove(claim_reason_label, "claim_reason_"))
# In 10 DÒNG ĐẦU
kable(head(df_gop_b3, 10),
caption = "10 dòng đầu sau khi gộp",booktabs = TRUE)| claim_reason_label | is_reason | claim_reason |
|---|---|---|
| claim_reason_Travel | 1 | Travel |
| claim_reason_Medical | 1 | Medical |
| claim_reason_Phone | 1 | Phone |
| claim_reason_Phone | 1 | Phone |
| claim_reason_Phone | 1 | Phone |
| claim_reason_Medical | 1 | Medical |
| claim_reason_Medical | 1 | Medical |
| claim_reason_Other | 1 | Other |
| claim_reason_Phone | 1 | Phone |
| claim_reason_Medical | 1 | Medical |
TRỰC QUAN HÓA
# Khởi tạo biểu đồ và gán trục X, trục Y
ggplot(df_gop_b3, aes(x = claim_reason, fill = claim_reason)) +
# Thêm Lớp Biểu đồ Cột
geom_bar(show.legend = FALSE) +
# Thêm nhãn số lượng trên đỉnh cột
geom_text(stat = 'count', aes(label = ..count..), vjust = -0.5) +
# Tăng giới hạn trên của trục y thêm 15% để nhãn số không bị cắt
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
# Thêm tiêu đề và nhãn trục
labs(title = " TỶ TRỌNG CÁC LÝ DO YÊU CẦU BỒI THƯỜNG", x = "Lý do Yêu cầu", y = "Số lượng") Kết quả: Lý do “Medical” (Y tế) là yếu tố áp đảo với 109,863 trường hợp. Con số này chiếm 55% (109,863 / 200,000) toàn bộ các lý do được ghi nhận.Ba nhóm “Other”, “Phone”, và “Travel” có tần suất xuất hiện tương đối đồng đều nhau, đều xấp xỉ 30,000. Cho thấy yếu tố bảo hiểm do y tế rất được quan tâm.
# Tạo data.frame "df_premium"
df_premium <- df_clean %>%
# Đếm số lượng khách hàng cho mỗi "premium_group"
count(premium_group) %>%
# Sắp xếp các nhóm
arrange(desc(premium_group)) %>%
# Tính toán % và vị trí để đặt nhãn
mutate(percentage = n / sum(n),y_pos = cumsum(percentage) - 0.5 * percentage)
# In kết quả
kable(df_premium,
# Đặt tên cột
col.names = c("Nhóm Phí", "Số lượng", "Tỷ lệ %", "Vị trí nhãn Y"),digits = c(0, 0, 2, 2),
caption = "Bảng thống kê tỷ lệ các nhóm phí bảo hiểm",booktabs = TRUE)| Nhóm Phí | Số lượng | Tỷ lệ % | Vị trí nhãn Y |
|---|---|---|---|
| High (trên Mean) | 109863 | 0.55 | 0.27 |
| Medium (Q1-Mean) | 29934 | 0.15 | 0.62 |
| Low (dưới Q1) | 60203 | 0.30 | 0.85 |
TRỰC QUAN HÓA
# Khởi tạo ggplot, Đặt trục X là rỗng, Trục Y là cột tỷ lệ %
ggplot(df_premium, aes(x = "", y = percentage, fill = premium_group)) +
# Vẽ biểu đồ cột
geom_bar(stat = "identity", width = 1, color = "white") +
# Biến biểu đồ cột thành biểu đồ tròn
coord_polar("y", start = 0) +
# Thêm nhãn % vào giữa mỗi phần biểu đồ
geom_text(aes(y = y_pos, label = percent(percentage, accuracy = 0.1)),
color = "black", size = 5) +
# Thêm Tiêu đề
labs(title = "TỶ LỆ KHÁCH HÀNG THEO NHÓM PHÍ BẢO HIỂM")+
# Ẩn tất cả các yếu tố không cần thiết
theme(axis.title = element_blank(), axis.text = element_blank(),
axis.ticks = element_blank(), panel.grid = element_blank())Kết quả: Biểu đồ này cung cấp một cái nhìn tổng quan quan trọng về cơ cấu khách hàng của công ty, Kết quả chỉ ra rằng nhóm ‘High (trên Mean)’ là phân khúc khách hàng lớn nhất và quan trọng nhất:
Nhóm “High” (Phí cao) chiếm đa số: Phát hiện quan trọng nhất là nhóm khách hàng trả phí cao (“High (trên Mean)”) là nhóm lớn nhất, chiếm 54.9% (hơn một nửa) tổng số khách hàng.
Nhóm “Medium” (Phí trung bình) là nhỏ nhất: Nhóm “Medium (Q1-Mean)” là nhóm khách hàng ít ỏi nhất, chỉ chiếm 15.0%.
Sự phân cực: Dữ liệu cho thấy sự phân cực rõ rệt, với phần lớn khách hàng tập trung ở hai thái cực “Low” (30.1%) và “High” (54.9%), thay vì phân bổ đều.
# Tạo data.frame "df_summary_b8"
df_summary_b8 <- df_clean %>%
# Đếm số lượng theo cặp
count(claim_output_encoded, churn_encoded) %>%
# Nhóm theo "claim_output_encoded" (Nhóm Bị từ chối, Nhóm Được chấp thuận)
group_by(claim_output_encoded) %>%
# Tính toán % trong nhóm
mutate(percentage = n / sum(n)) %>%
# Sắp xếp
arrange(churn_encoded) %>%
# Tính vị trí đặt nhãn %
mutate(y_position = cumsum(percentage) - 0.5 * percentage)
# In kết quả
kable(df_summary_b8, caption = "Thống kê tỷ lệ churn theo nhóm kết quả claim",
# Đặt tên cột tiếng Việt
col.names = c("Kết quả Claim", "Trạng thái Churn", "Số lượng (n)",
"Tỷ lệ % (trong nhóm)", "Vị trí nhãn Y" ),
digits = c(0, 0, 0, 2, 2), booktabs = TRUE)| Kết quả Claim | Trạng thái Churn | Số lượng (n) | Tỷ lệ % (trong nhóm) | Vị trí nhãn Y |
|---|---|---|---|---|
| 0 | 0 | 70170 | 0.36 | 0.18 |
| 1 | 0 | 2558 | 0.37 | 0.18 |
| 0 | 1 | 122824 | 0.64 | 0.68 |
| 1 | 1 | 4448 | 0.63 | 0.68 |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục x
ggplot(df_clean,
aes( x = factor(claim_output_encoded,labels = c("Bị từ chối", "Được chấp thuận")),
fill = factor(churn_encoded, levels = c(1, 0),labels = c("Rời bỏ", "Ở lại")))) +
# Thêm Lớp Biểu đồ Cột
geom_bar(position = "fill") +
# Thêm nhãn
geom_text(data = df_summary_b8,
aes(y = y_position, label = scales::percent(percentage, accuracy = 0.1)),
color = "black", size = 5) +
# Tùy chỉnh Trục Y
scale_y_continuous(labels = scales::percent) +
# Tùy chỉnh Màu sắc
scale_fill_manual(values = c("Ở lại" = "skyblue", "Rời bỏ" = "tomato")) +
# Thêm Tiêu đề và Nhãn
labs(title = " TỶ LỆ NGỪNG DỊCH VỤ THEO KẾT QUẢ YÊU CẦU BỒI THƯỜNG ",
x = "Kết quả Yêu cầu", y = "Tỷ lệ", fill = "Trạng thái")+
# Điều chỉnh size tiêu đề
theme(plot.title = element_text(size = 12))Kết quả: Biểu đồ cho thấy sự khác biệt về tỷ lệ khách hàng ngừng sử dụng dịch vụ giữa hai nhóm. kết quả yêu cầu bồi thường là “Bị từ chối” và “Được chấp thuận” hầu như không đáng kể.
Ở cả hai trường hợp, tỷ lệ khách hàng rời bỏ đều xấp xỉ 63–64%, trong khi tỷ lệ ở lại chỉ chiếm khoảng 36%. Điều này cho thấy kết quả xử lý yêu cầu bồi thường không phải là yếu tố ảnh hưởng mạnh đến quyết định tiếp tục sử dụng dịch vụ của khách hàng.
# Tạo data.frame
df_gop_b9 <- df_clean %>%
# Chọn cột 'churn_encoded' VÀ 4 cột dummy 'claim_reason'
select(churn_encoded, starts_with("claim_reason_")) %>%
# Gộp tất cả các cột TRỪ 'churn_encoded'
pivot_longer(cols=-churn_encoded,names_to="claim_reason_label",values_to = "is_reason") %>%
# Chỉ giữ lại các hàng có giá trị = 1 (là lý do thực sự)
filter(is_reason == 1) %>%
# Tạo các cột "claim_reason"
mutate(claim_reason = str_remove(claim_reason_label, "claim_reason_"))
# Tính toán % chur trong từng nhóm lý do
df_summary_b9 <- df_gop_b9 %>%
# Đếm số lượng theo cặp
count(claim_reason, churn_encoded) %>%
# Nhóm theo 4 Lý do
group_by(claim_reason) %>%
# Tính % trong nhóm
mutate(percentage = n / sum(n)) %>%
# Sắp xếp (để tính y_position cho đúng)
arrange(churn_encoded) %>%
# Tính vị trí đặt nhãn %
mutate(y_position = cumsum(percentage) - 0.5 * percentage)
# In kết quả
kable( df_summary_b9,caption = "Thống kê tỷ lệ churn theo nhóm lý do",
col.names = c( "Lý do Claim", "Trạng thái Churn","Số lượng (n)",
"Tỷ lệ % (trong nhóm)", "Vị trí nhãn Y"),
digits = c(0, 0, 0, 2, 2), booktabs = TRUE)| Lý do Claim | Trạng thái Churn | Số lượng (n) | Tỷ lệ % (trong nhóm) | Vị trí nhãn Y |
|---|---|---|---|---|
| Medical | 0 | 39962 | 0.36 | 0.18 |
| Other | 0 | 10984 | 0.36 | 0.18 |
| Phone | 0 | 11028 | 0.37 | 0.18 |
| Travel | 0 | 10754 | 0.36 | 0.18 |
| Medical | 1 | 69901 | 0.64 | 0.68 |
| Other | 1 | 19203 | 0.64 | 0.68 |
| Phone | 1 | 18988 | 0.63 | 0.68 |
| Travel | 1 | 19180 | 0.64 | 0.68 |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục
ggplot(df_gop_b9, aes(x = claim_reason,fill = factor(churn_encoded,
levels = c(1, 0), labels = c("Rời bỏ", "Ở lại")))) +
# Thêm Lớp Biểu đồ Cột
geom_bar(position = "fill") +
# Thêm nhãn Tỷ lệ %
geom_text(data = df_summary_b9, aes(y = y_position,
label = scales::percent(percentage, accuracy = 0.1)), color = "black", size = 5) +
# Tùy chỉnh Trục Y
scale_y_continuous(labels = scales::percent) +
# Tùy chỉnh Màu sắc
scale_fill_manual(values = c("Ở lại" = "skyblue", "Rời bỏ" = "tomato")) +
# Thêm Tiêu đề và Nhãn
labs(title = " TỶ LỆ NGỪNG DỊCH VỤ THEO LÝ DO YÊU CẦU",
x = "Lý do Yêu cầu", y = "Tỷ lệ", fill = "Trạng thái") Kết quả: cho thấy không có sự khác biệt về Tỷ lệ Rời bỏ (Churn Rate) giữa 4 nhóm ‘Lý do Yêu cầu’. Tất cả các nhóm, bất kể là ‘Medical’ (chiếm đa số - Biểu đồ hay ‘Travel’ (chiếm thiểu số), đều có tỷ lệ khách hàng rời bỏ xấp xỉ 63.6%.
# Tạo data.frame "df_summary_b8"
df_summary_b8 <- df_clean %>%
# Loại bỏ NA (nếu có)
na.omit(subset = c("claim_group", "claim_output_encoded")) %>%
# Đếm số lượng theo cặp
count(claim_group, claim_output_encoded) %>%
# Nhóm theo 4 Nhóm "Claim Amount" (Low, Medium, High, Very High)
group_by(claim_group) %>%
# Tính % trong nhóm
mutate(percentage = n / sum(n)) %>%
# Sắp xếp (0 = Từ chối, 1 = Chấp thuận)
arrange(claim_output_encoded) %>%
# Tính vị trí đặt nhãn % (cho biểu đồ cột chồng)
mutate(y_position = cumsum(percentage) - 0.5 * percentage)
# In kết quả
kable( df_summary_b8, caption = "Thống kê tỷ lệ kết quả claim theo nhóm claim amount",
col.names = c("Nhóm Claim Amount", "Kết quả Claim","Số lượng (n)",
"Tỷ lệ % (trong nhóm)", "Vị trí nhãn Y"),
digits = c(0, 0, 0, 4, 4), booktabs = TRUE)| Nhóm Claim Amount | Kết quả Claim | Số lượng (n) | Tỷ lệ % (trong nhóm) | Vị trí nhãn Y |
|---|---|---|---|---|
| Low | 0 | 43037 | 0.86 | 0.43 |
| Medium | 0 | 50027 | 1.00 | 0.50 |
| High | 0 | 49942 | 1.00 | 0.50 |
| Very High | 0 | 49988 | 1.00 | 0.50 |
| Low | 1 | 7006 | 0.14 | 0.93 |
TRỰC QUAN HÓA
# Khởi tạo ggplot,thiết lập trục
ggplot(df_clean, aes(x = claim_group,fill = factor(claim_output_encoded,
levels = c(1, 0), labels = c("Được chấp thuận", "Bị từ chối")))) +
# Thêm Lớp Biểu đồ Cột
geom_bar(position = "fill") +
# Thêm nhãn Tỷ lệ %
geom_text(data = df_summary_b8, aes(y = y_position,
label = scales::percent(percentage, accuracy = 0.1)),
color = "black", size = 5, check_overlap = TRUE) +
# Tùy chỉnh Trục Y
scale_y_continuous(labels = scales::percent) +
# Tùy chỉnh Màu sắc
scale_fill_manual(values = c("Được chấp thuận" = "skyblue", "Bị từ chối" = "tomato")) +
# Thêm Tiêu đề và Nhãn
labs(title = " TỶ LỆ CHẤP THUẬN THEO NHÓM YÊU CẦU",
x = "Nhóm Yêu cầu", y = "Tỷ lệ", fill = "Kết quả Yêu cầu")Kết quả: nhóm Low có 14% yêu cầu được chấp thuận, trong khi 86% bị từ chối. Đáng chú ý, ở ba nhóm còn lại là Medium, High và Very High, toàn bộ yêu cầu (100%) đều bị từ chối.
Điều này phản ánh xu hướng rõ rệt rằng càng có giá trị yêu cầu bồi thường cao, khả năng được chấp thuận càng thấp.
Kết quả có thể xuất phát từ việc công ty bảo hiểm áp dụng quy trình xét duyệt nghiêm ngặt hơn đối với các yêu cầu có giá trị lớn,nhằm kiểm soát rủi ro và hạn chế gian lận trong bồi thường.
# TÍNH TOÁN % KẾT QUẢ CLAIM THEO TỪNG LÝ DO CLAIM
# Tạo data.frame "df_gop_b9"
df_gop_b9 <- df_clean %>%
# Chọn cột 'claim_output_encoded' VÀ 4 cột 'claim_reason'
select(claim_output_encoded, starts_with("claim_reason_")) %>%
# Gộp tất cả các cột TRỪ 'claim_output_encoded'
pivot_longer(cols = -claim_output_encoded, names_to = "claim_reason_label",
values_to = "is_reason" ) %>%
# Chỉ giữ lại các hàng có giá trị = 1 (là lý do thực sự)
filter(is_reason == 1) %>%
# Tạo cột "claim_reason"
mutate(claim_reason = str_remove(claim_reason_label, "claim_reason_"))
# Tính toán % Kết quả Claim theo từng nhóm lý do
df_summary_b9 <- df_gop_b9 %>%
# Đếm số lượng theo cặp
count(claim_reason, claim_output_encoded) %>%
# Nhóm theo 4 Lý do
group_by(claim_reason) %>%
# Tính % trong nhóm
mutate(percentage = n / sum(n)) %>%
# Sắp xếp (0=Từ chối, 1=Chấp thuận)
arrange(claim_output_encoded) %>%
# Tính vị trí đặt nhãn %
mutate(y_position = cumsum(percentage) - 0.5 * percentage)
# In kết quả
kable( df_summary_b9, caption = "Thống kê kết quả tỷ lệ claim theo nhóm lý do claim",
col.names = c("Lý do Claim", "Kết quả Claim","Số lượng (n)",
"Tỷ lệ % (trong nhóm)", "Vị trí nhãn Y" ),
digits = c(0, 0, 0, 4, 4), booktabs = TRUE)| Lý do Claim | Kết quả Claim | Số lượng (n) | Tỷ lệ % (trong nhóm) | Vị trí nhãn Y |
|---|---|---|---|---|
| Medical | 0 | 109863 | 1.0000 | 0.500 |
| Other | 0 | 23181 | 0.7679 | 0.384 |
| Phone | 0 | 30016 | 1.0000 | 0.500 |
| Travel | 0 | 29934 | 1.0000 | 0.500 |
| Other | 1 | 7006 | 0.2321 | 0.884 |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục
ggplot(df_gop_b9, aes(x = claim_reason, fill = factor(claim_output_encoded,
levels = c(1, 0), labels = c("Được chấp thuận", "Bị từ chối")))) +
# Thêm Lớp Biểu đồ Cột
geom_bar(position = "fill") +
# Thêm nhãn Tỷ lệ %
geom_text(data = df_summary_b9,aes(y = y_position, label = scales::percent(percentage,
accuracy = 0.1)), color = "black", size = 5, check_overlap = TRUE) +
# Tùy chỉnh Trục Y
scale_y_continuous(labels = scales::percent) +
# Tùy chỉnh Màu sắc
scale_fill_manual(values = c("Được chấp thuận" = "skyblue", "Bị từ chối" = "tomato")) +
# Thêm Tiêu đề và Nhãn
labs(title = " TỶ LỆ CHẤP THUẬN THEO LÝ DO YÊU CẦU",
x = "Lý do Yêu cầu", y = "Tỷ lệ", fill = "Kết quả Yêu cầu")Kết quả: chỉ có nhóm Other có 23,2% yêu cầu được chấp thuận, trong khi 76,8% bị từ chối. Ba nhóm còn lại gồm Medical, Phone và Travel đều có tỷ lệ bị từ chối đạt 100%, tức là không có yêu cầu nào được chấp thuận. Điều này cho thấy chính sách phê duyệt bồi thường của công ty khá nghiêm ngặt, đặc biệt với các yêu cầu thuộc nhóm Medical và Travel.
# Khởi tạo ggplot, sử dụng data "df_clean"
ggplot(df_clean, aes(x = profitability)) +
# Vẽ đường cong mật độ
geom_density(fill = "darkgreen") +
# Thêm đường trung bình (màu đỏ, đứt nét)
geom_vline(aes(xintercept = mean(profitability)),
color = "red", linetype = "dashed",linewidth = 1.2) +
# Đặt tiêu đề và nhãn trục
labs(title = " PHÂN PHỐI LỢI NHUẬN TỪ HỢP ĐỒNG",subtitle = "Đường đỏ là lợi nhuận trung bình",
x = "Lợi nhuận (Premium - Claim)", y = "Mật độ (Density)")Nhận xét: Quan sát cho thấy phân phối lợi nhuận không đồng nhất, có nhiều đỉnh (multi-modal), phản ánh sự chênh lệch lớn giữa các nhóm hợp đồng. Phần lớn các hợp đồng tập trung ở vùng lợi nhuận cao, tức là phí thu được lớn hơn số tiền bồi thường, cho thấy công ty bảo hiểm nhìn chung đang hoạt động có lãi.
Tuy nhiên, cũng có một tỷ lệ hợp đồng nằm ở vùng lợi nhuận thấp hoặc gần bằng 0, cho thấy vẫn tồn tại các trường hợp rủi ro cao hoặc chi phí bồi thường lớn.
Đường trung bình nằm lệch về bên phải, hàm ý rằng đa số hợp đồng mang lại lợi nhuận cao hơn mức trung bình, và chỉ một phần nhỏ hợp đồng làm giảm hiệu quả chung.
# Khởi tạo ggplot, sử dụng data "df_clean"
ggplot(df_clean, aes(x = loss_ratio)) +
# Vẽ đường cong mật độ
geom_density(fill = "lightblue",color = "steelblue",alpha = 0.6, linewidth = 0.7) +
# Thêm đường trung bình (nét đứt)
geom_vline(aes(xintercept = mean(loss_ratio)),color = "red",linetype = "dashed",linewidth = 1) +
# "Phóng to" (Zoom) trục X mà không cắt bỏ dữ liệu
coord_cartesian(xlim = c(0, 0.5)) +
# Định dạng trục X
scale_x_continuous(labels = scales::percent) +
# Đặt tiêu đề
labs(title = " PHÂN PHỐI MẬT ĐỘ TỶ LỆ TỔN THẤT",
subtitle = "Đường xanh đậm (nét đứt) là tỷ lệ trung bình",
x = "Tỷ lệ tổn thất", y = "Mật độ") +
# Dùng 'theme_minimal' (có lưới)
theme(panel.border = element_rect(color = "black", fill = NA,linewidth = 0.5))Nhận xét: Quan sát cho thấy, phân phối có dạng chuông khá cân đối, tập trung chủ yếu quanh vùng 10–15%, và đường đỏ đứt nét biểu diễn tỷ lệ tổn thất trung bình nằm gần 10%.
Điều này cho thấy đa số hợp đồng có tỷ lệ tổn thất thấp, nghĩa là số tiền bồi thường chiếm một phần nhỏ so với phí bảo hiểm thu được, phản ánh hoạt động kinh doanh bảo hiểm đang ở mức sinh lợi ổn định.
Ngoài ra, phần đuôi bên phải mỏng cho thấy ít hợp đồng có tổn thất cao, chứng tỏ rủi ro được kiểm soát tốt và phân bố lợi nhuận tương đối bền vững.
# Tạo data.frame "df_tonghop_phi"
df_tonghop_phi <- df_clean %>%
# Nhóm toàn bộ 200,000 hàng thành 3 nhóm (Low, Medium, High)
group_by(premium_group) %>%
# Tính tổng cột 'category_premium' cho từng nhóm
summarise( Total_Premium = sum(category_premium, na.rm = TRUE))
# In kết quả:
kable(df_tonghop_phi, caption = "Tổng phí bảo hiểm theo từng nhóm phí",
col.names = c("Nhóm phí", "Tổng Phí"), digits = 0, align = "lr", booktabs = TRUE)| Nhóm phí | Tổng Phí |
|---|---|
| Low (dưới Q1) | 68324613 |
| Medium (Q1-Mean) | 143503596 |
| High (trên Mean) | 1580928570 |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục
ggplot(df_tonghop_phi, aes(x = premium_group, y = Total_Premium, fill = premium_group)) +
# Vẽ cột
geom_col() +
# Thêm nhãn số
geom_text(aes(label = comma(Total_Premium, accuracy = 1)), vjust = -0.5, size = 5) +
# Nới rộng trục Y (thêm 15%) để không bị lấp số
scale_y_continuous( labels = comma, expand = expansion(mult = c(0, 0.15)) ) +
# Thêm tiêu đề
labs(title ="TỔNG PHÍ BẢO HIỂM THEO NHÓM KHÁCH HÀNG",x ="Nhóm Phí", y ="Tổng Phí Bảo Hiểm") Kết quả: cho thấy sự chênh lệch rất lớn giữa các nhóm:
Nhóm High đóng góp khoảng 1,58 tỷ, chiếm phần lớn tổng phí toàn bộ. Nhóm Medium chỉ đóng góp khoảng 143 triệu. Nhóm Low thấp nhất, chỉ khoảng 68 triệu.
Điều này chứng tỏ doanh thu phí bảo hiểm tập trung chủ yếu ở nhóm khách hàng có mức phí cao, và một số ít khách hàng lớn đóng góp phần lớn tổng doanh thu.
Qua đó doanh nghiệp cần duy trì, chăm sóc tốt nhóm khách hàng này, đồng thời xây dựng chính sách khuyến khích nhóm trung bình và thấp để tăng giá trị tổng thể.
# Tạo data frame mới "df_gop_b13"
df_gop_b13 <- df_clean %>%
# Chọn cột 'profitability' VÀ 4 cột dummy 'claim_reason'
select(profitability, starts_with("claim_reason_")) %>%
# Gộp tất cả các cột TRỪ 'profitability'
pivot_longer(cols = -profitability, names_to = "claim_reason_label",
values_to = "is_reason") %>%
# Chỉ giữ lại các hàng có giá trị = 1 (là lý do thực sự)
filter(is_reason == 1) %>%
# Tạo cột "claim_reason"
mutate(claim_reason = str_remove(claim_reason_label, "claim_reason_"))
#Tính Lợi nhuận TRUNG BÌNH (mean)
# Lấy dữ liệu từ "df_gop_b13"
df_summary_b13 <- df_gop_b13 %>%
# Nhóm theo 4 Lý do (Medical, Other, Phone, Travel)
group_by(claim_reason) %>%
# Tính Lợi nhuận TRUNG BÌNH (mean) cho mỗi nhóm
summarise(mean_profit = mean(profitability, na.rm = TRUE))
# In kết quả
kable(df_summary_b13, caption = "Lợi nhuận trung bình theo nhóm lý do claim",
col.names = c("Lý do Claim", "Lợi nhuận Trung bình"),
digits = 2, align = "lr", booktabs = TRUE)| Lý do Claim | Lợi nhuận Trung bình |
|---|---|
| Medical | 12591.26 |
| Other | 349.07 |
| Phone | 1640.58 |
| Travel | 4194.79 |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục
ggplot(df_summary_b13, aes(x = claim_reason, y = mean_profit, fill = claim_reason)) +
# Vẽ cột
geom_col(show.legend = FALSE, color = "black") +
# Thêm nhãn
geom_text(aes(label = round(mean_profit, 0)),vjust = -0.5, color = "black",size = 5) +
# Mở rộng trục Y để có chỗ cho nhãn số
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
# Đặt tiêu đề và nhãn
labs(title = "LỢI NHUẬN TRUNG BÌNH THEO LÝ DO YÊU CẦU",
x = "Lý do Yêu cầu", y = "Lợi nhuận Trung bình")Kết quả:
Nhóm Medical mang lại lợi nhuận trung bình cao nhất (12.591), vượt trội so với các nhóm khác. Nhóm Travel đứng thứ hai với 4.195. Nhóm Phone đạt mức 1.641. Nhóm Other có lợi nhuận trung bình thấp nhất (349).
Sự chênh lệch lớn này cho thấy các yêu cầu liên quan đến Medical là nguồn sinh lợi chính của công ty, trong khi các yêu cầu khác (đặc biệt là Other) mang lại lợi nhuận thấp, cần được xem xét chính sách hoặc tối ưu chi phí.
# Tạo data frame mới "df_b14"
df_b14 <- df_clean %>%
# Nhóm theo 2 nhóm "Kết quả Yêu cầu"
group_by(claim_output_encoded) %>%
# Tính Tỷ lệ tổn thất TRUNG BÌNH (mean) cho mỗi nhóm
summarise(mean_loss_ratio = mean(loss_ratio, na.rm = TRUE))
# Tạo cột mớimới
df_b14 %>% mutate(KetQua = if_else(claim_output_encoded == 1, "Được chấp thuận", "Bị từ chối"),
TyLe = scales::percent(mean_loss_ratio, accuracy = 0.1)) %>%
# Sắp xếp lại cột
select(KetQua, TyLe)%>%
# 5. In ra kable
kable( caption = "Tỷ lệ tổn thất trung bình)",
col.names = c("Kết quả yêu cầu", "Tỷ lệ Tổn thất trung bình"),
align = "lr", booktabs = TRUE)| Kết quả yêu cầu | Tỷ lệ Tổn thất trung bình |
|---|---|
| Bị từ chối | 12.8% |
| Được chấp thuận | 3.0% |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục
ggplot( df_b14, aes(
x = factor(claim_output_encoded, labels = c("Bị từ chối", "Được chấp thuận")),
y = mean_loss_ratio,fill = factor(claim_output_encoded,
labels = c("Bị từ chối", "Được chấp thuận")) )) +
# Vẽ biểu đồ Cột
geom_col() +
# Thêm nhãn % (hiển thị giá trị trung bình)
geom_text(aes(label = scales::percent(mean_loss_ratio, accuracy = 0.1)),
vjust = -0.5,color = "black",size = 5) +
# Định dạng nhãn trục Y thành %, mở rộng trục Y để nhãn số không bị cắt
scale_y_continuous(labels = scales::percent,expand = expansion(mult = c(0, 0.15))) +
# Tùy chỉnh Màu sắc
scale_fill_manual(values = c("Bị từ chối" = "tomato","Được chấp thuận" = "skyblue")) +
# Đặt tiêu đề và nhãn
labs( title = "SO SÁNH TỶ LỆ TỔN THẤT",
x = "Kết quả Yêu cầu", y = "Tỷ lệ Tổn thất Trung bình (Mean Loss Ratio)") +
# Ẩn chú giải (legend)
theme(legend.position = "none")Nhận xét: Biểu đồ cho thấy sự khác biệt rõ rệt về tỷ lệ tổn thất trung bình giữa hai nhóm yêu cầu bảo hiểm. Với các yêu cầu bị từ chối, tỷ lệ tổn thất trung bình đạt 12.8% — cao gấp hơn 4 lần so với nhóm còn lại. Trong khi đó, các yêu cầu được chấp thuận chỉ có tỷ lệ tổn thất trung bình khoảng 3.0%.
Điều này cho thấy: Các yêu cầu bị từ chối thường đi kèm với rủi ro tổn thất cao hơn, Còn những yêu cầu được chấp thuận có mức tổn thất thấp và ổn định hơn, phản ánh quy trình thẩm định rủi ro hiệu quả của công ty.
# Tạo data frame mới "df_gop_b15"
df_gop_b15 <- df_clean %>%
# Chọn cột 'loss_ratio' VÀ 4 cột 'claim_reason'
select(loss_ratio, starts_with("claim_reason_")) %>%
# Gộp tất cả các cột TRỪ 'loss_ratio'
pivot_longer( cols = -loss_ratio, names_to = "claim_reason_label",
values_to = "is_reason" ) %>%
# Chỉ giữ lại các hàng có giá trị = 1 (là lý do thực sự)
filter(is_reason == 1) %>%
# Tạo cột "claim_reason"
mutate(claim_reason = str_remove(claim_reason_label, "claim_reason_"))
# In kết quả
kable( head(df_gop_b15, 10),
caption = "10 dòng đầu sau khi gộp 4 cột dummy (Giữ lại Loss Ratio)", booktabs = TRUE)| loss_ratio | claim_reason_label | is_reason | claim_reason |
|---|---|---|---|
| 0.0786400 | claim_reason_Travel | 1 | Travel |
| 0.1000695 | claim_reason_Medical | 1 | Medical |
| 0.1365333 | claim_reason_Phone | 1 | Phone |
| 0.1242667 | claim_reason_Phone | 1 | Phone |
| 0.1274667 | claim_reason_Phone | 1 | Phone |
| 0.1134121 | claim_reason_Medical | 1 | Medical |
| 0.1564976 | claim_reason_Medical | 1 | Medical |
| 0.0927318 | claim_reason_Other | 1 | Other |
| 0.1194667 | claim_reason_Phone | 1 | Phone |
| 0.1377345 | claim_reason_Medical | 1 | Medical |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục
ggplot(df_gop_b15, aes(x = loss_ratio)) +
# Vẽ đường cong mật độ
geom_density(aes(fill = claim_reason), alpha = 0.7,color = "black", show.legend = FALSE) +
# Tách thành 4 biểu đồ con (2 cột)
facet_wrap(~ claim_reason, ncol = 2) +
# "Phóng to" (Zoom) vào khu vực 0-50%
coord_cartesian(xlim = c(0, 0.5)) +
# Định dạng trục X là %
scale_x_continuous(labels = scales::percent) +
# Đặt tiêu đề và nhãn
labs(title = "PHÂN PHỐI TỶ LỆ TỔN THẤT THEO LÝ DO YÊU CẦU",
subtitle = "Đã phóng to, chỉ hiển thị 0-50%",
x = "Tỷ lệ Tổn thất (Loss Ratio)", y = "Mật độ") Nhận xét:
Nhóm Medical: Có mật độ tập trung cao quanh mức 10–15%, cho thấy các hợp đồng loại này có tỷ lệ tổn thất khá ổn định. Nhóm Other: Tỷ lệ tổn thất trải đều hơn, mật độ thấp → mức độ biến động cao, khó dự đoán hơn. Nhóm Phone: Phân phối tập trung nhất, chủ yếu quanh 10–15%, chứng tỏ loại yêu cầu này có rủi ro thấp và đồng đều. Nhóm Travel: Có phạm vi dao động rộng hơn (từ 10–25%), phản ánh mức độ rủi ro cao hơn, dễ phát sinh biến động tổn thất.
# Tạo data frame tóm tắt "top_6_companies"
top_6_companies <- df %>%
# Nhóm theo Tên Công ty
group_by(`Company Name`) %>%
# Tính TỔNG số tiền bồi thường
summarise(Total_Claim_Amount = sum(`Claim Amount`, na.rm = TRUE) ) %>%
# Sắp xếp giảm dần
arrange(desc(Total_Claim_Amount)) %>%
# Lấy 6 hàng đầu tiên
head(6)
# In kết quả ra
kable(top_6_companies,caption = "Top 6 Công ty có Tổng Tiền Bồi thường Cao nhất",
col.names = c("Tên Công ty", "Tổng Tiền Bồi thường"), booktabs = TRUE)| Tên Công ty | Tổng Tiền Bồi thường |
|---|---|
| Smith LLC | 307837 |
| Smith Group | 298943 |
| Smith and Sons | 287755 |
| Smith Ltd | 277418 |
| Smith Inc | 257402 |
| Smith PLC | 250624 |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục
ggplot(top_6_companies,aes(x = reorder(`Company Name`, Total_Claim_Amount),
y = Total_Claim_Amount)) +
# Vẽ đường (segment)
geom_segment(aes(x = reorder(`Company Name`, Total_Claim_Amount),
xend = reorder(`Company Name`, Total_Claim_Amount),
y = 0, yend = Total_Claim_Amount), color = "grey",linewidth = 1) +
# Vẽ điểm (point)
geom_point(aes(color = `Company Name`), size = 5, show.legend = FALSE) +
# Thêm nhãn số (dùng scales::comma cho số lớn)
geom_text(aes(label = scales::comma(Total_Claim_Amount)),color = "black",size = 5, hjust = -0.3) +
# Biến biểu đồ cột dọc thành biểu đồ ngang (dễ đọc tên công ty hơn)
coord_flip() +
# Mở rộng trục Y (bây giờ là trục X)
scale_y_continuous(
labels = scales::comma,expand = expansion(mult = c(0, 0.15))) +
# Đặt tiêu đề
labs(title = "Top 6 Công ty có Tổng Tiền Bồi thường Cao nhất",
x = "Tên Công ty",y = "Tổng Tiền Bồi thường") +
# Xóa nền xám, giữ lưới ngang
theme(panel.grid.major.y = element_blank(), panel.grid.minor.x = element_blank())# Đếm số lần xuất hiện của mỗi cặp (Công ty, Lý do)
company_reason_counts <- df %>%
count(`Company Name`, `Claim Reason`, name = "So_Luong")
# Với MỖI 'Claim Reason', tìm 'Company Name' có 'So_Luong' cao nhất
top_company_per_reason <- company_reason_counts %>%
# Nhóm dữ liệu theo 4 Lý do (Medical, Other, Phone, Travel)
group_by(`Claim Reason`) %>%
# Sắp xếp và lấy hàng cao nhất (n=1)
slice_max(order_by = So_Luong, n = 1, with_ties = FALSE) %>%
ungroup() %>%
# Sắp xếp kết quả cuối cùng theo thứ tự A-Z của "Claim Reason"
arrange(`Claim Reason`)
# In kết quả ra
kable(top_company_per_reason,
caption = "Công ty có số lượng yêu cầu cao nhất (Theo từng Nguyên nhân)",
col.names = c("Tên Công ty", "Nguyên nhân", "Số lượng Yêu cầu"),booktabs = TRUE)| Tên Công ty | Nguyên nhân | Số lượng Yêu cầu |
|---|---|---|
| Smith LLC | Medical | 153 |
| Smith Group | Other | 55 |
| Smith and Sons | Phone | 44 |
| Smith PLC | Travel | 39 |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục
ggplot(top_company_per_reason, aes(x = `Claim Reason`, y = factor(1), fill = So_Luong)) +
# Vẽ ô vuông
geom_tile(color = "white", linewidth = 2) +
# Thêm nhãn
geom_text( aes(label = paste(`Company Name`, scales::comma(So_Luong), sep = "\n")),
color = "black",size = 5) +
# Đổi thang màu
scale_fill_gradient(low = "moccasin", high = "darkorange", name = "Số lượng") +
# Đặt tiêu đề
labs(title = "Công ty có nhiều Yêu cầu nhất (Theo từng Nguyên nhân)",
x = "Nguyên nhân Yêu cầu", y = NULL) +
# Tùy chỉnh giao diện
theme(legend.position = "bottom", plot.title = element_text(hjust = 0.5, face = "bold"),
# Ẩn các yếu tố của trục Y
axis.text.y = element_blank(), axis.ticks.y = element_blank(),panel.grid = element_blank() )# Tạo data frame tóm tắt "top_5_churn_companies"
top_5_churn_companies <- df %>%
# Lọc ra những khách hàng "Rời bỏ"
filter(Churn == "Yes") %>%
# Nhóm theo Tên Công ty
group_by(`Company Name`) %>%
# Đếm số lượng khách hàng rời bỏ trong mỗi công ty
summarise(Total_Churned = n()) %>%
# Sắp xếp giảm dần
arrange(desc(Total_Churned)) %>%
# Lấy 5 hàng đầu tiên
head(5)
# In kết quả
kable(top_5_churn_companies,caption = "Top 5 Công ty có Số lượng Khách hàng Rời bỏ Cao nhất",
col.names = c("Tên Công ty", "Số lượng Rời bỏ"), booktabs = TRUE)| Tên Công ty | Số lượng Rời bỏ |
|---|---|
| Smith Group | 179 |
| Smith LLC | 169 |
| Smith and Sons | 160 |
| Smith Ltd | 156 |
| Smith Inc | 150 |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục
ggplot(top_5_churn_companies,
aes(x = reorder(`Company Name`, Total_Churned), y = Total_Churned)) +
# Vẽ đường (segment)
geom_segment(aes(x = reorder(`Company Name`, Total_Churned),
xend = reorder(`Company Name`, Total_Churned),
y = 0, yend = Total_Churned), color = "grey",linewidth = 1) +
# Vẽ điểm (point)
geom_point(aes(color = `Company Name`), size = 5, show.legend = FALSE) +
# Thêm nhãn số (số lượng rời bỏ)
geom_text(aes(label = Total_Churned), color = "black", size = 5, hjust = -1) +
# Lật trục (Lollipop nằm ngang dễ đọc hơn)
coord_flip() +
# Mở rộng trục Y (bây giờ là trục X)
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
# Đặt tiêu đề
labs(title = "Top 5 Công ty có Số lượng Khách hàng Rời bỏ Cao nhất",
x = "Tên Công ty", y = "Số lượng Khách hàng Rời bỏ") +
# Xóa lưới dọc (major.y) và lưới ngang phụ (minor.x)
theme( panel.grid.major.y = element_blank(),panel.grid.minor.x = element_blank())# Dùng 'df' (dữ liệu gốc)
top_6_rejected <- df %>%
filter(`Claim Request output` == "No") %>%
count(`Company Name`, name = "So_Luong_Tu_Choi") %>%
arrange(desc(So_Luong_Tu_Choi)) %>%
head(6)
# Tính thêm cột % cho biểu đồ tròn
df_pie_rejected_6 <- top_6_rejected %>% ungroup() %>%
# Tính %: Lấy số lượng của 1 công ty / TỔNG số lượng của 6 công ty
mutate(percentage = So_Luong_Tu_Choi / sum(So_Luong_Tu_Choi),
# Nhãn cho biểu đồ: chỉ %
label_pct = scales::percent(percentage, accuracy = 0.1))
# In kết quả tính toán
kable(df_pie_rejected_6,
caption = "Top 6 Công ty Từ chối Yêu cầu nhiều nhất)",
col.names = c("Tên Công ty", "Số lượng Từ chối", "Tỷ lệ % (trong Top 6)", "Nhãn %"),
digits = c(0, 0, 2, 0),align = "lrrr", booktabs = TRUE)| Tên Công ty | Số lượng Từ chối | Tỷ lệ % (trong Top 6) | Nhãn % |
|---|---|---|---|
| Smith Group | 264 | 0.18 | 18.4% |
| Smith LLC | 247 | 0.17 | 17.2% |
| Smith and Sons | 247 | 0.17 | 17.2% |
| Smith Ltd | 235 | 0.16 | 16.4% |
| Smith Inc | 226 | 0.16 | 15.8% |
| Smith PLC | 215 | 0.15 | 15.0% |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục
ggplot(df_pie_rejected_6, aes(x = "", y = percentage, fill = `Company Name`)) +
# Vẽ cột
geom_col(width = 1, color = "white") +
# Biến thành biểu đồ tròn
coord_polar(theta = "y", start = 0) +
# Thêm nhãn %
geom_text( aes(label = label_pct), position = position_stack (vjust = 0.5),
color = "black", size = 5) +
# Đặt tiêu đề
labs(title = "Tỷ trọng Top 6 Công ty Từ chối Yêu cầu (Pie Chart)", fill = "Tên Công ty")+
# Xóa nền và lưới
theme(axis.title = element_blank(), axis.text = element_blank(),
axis.ticks = element_blank(), panel.grid = element_blank())#
df_gop_bmi <- df_clean %>%
# Chọn cột 'bmi_group' VÀ 4 cột dummy 'claim_reason'
select(bmi_group, starts_with("claim_reason_")) %>%
# Gộp tất cả các cột TRỪ 'bmi_group'
pivot_longer(cols = -bmi_group, names_to = "claim_reason_label",
values_to = "is_reason") %>%
# Chỉ giữ lại các hàng có giá trị = 1 (là lý do thực sự)
filter(is_reason == 1) %>%
# Tạo cột "claim_reason"
mutate(claim_reason = str_remove(claim_reason_label, "claim_reason_"))
# Lọc NHÓM BMI CAO và phân loại Nguyên nhân
df_bmi_high_summary <- df_gop_bmi %>%
# Chỉ giữ lại nhóm BMI cao
filter(bmi_group == "Overweight (25-28)") %>%
# Phân loại: "Medical" vs "Các nguyên nhân khác"
mutate(Reason_Type = if_else(claim_reason == "Medical", "Medical","Các nguyên nhân khác")) %>%
# Đếm số lượng
count(Reason_Type) %>%
# Tính % cho biểu đồ tròn, lấy số lượng (n) chia cho tổng số (sum(n))
mutate(percentage = n / sum(n),label_text = scales::percent(percentage, accuracy = 0.1))
# In kết quả
kable(df_bmi_high_summary, caption = "Tỷ lệ Medical (Chỉ trong Nhóm BMI cao)",
col.names = c("Loại Nguyên nhân", "Số lượng", "Tỷ lệ %", "Nhãn %"),
digits = c(0, 0, 2, 0), align = "lrrr", booktabs = TRUE)| Loại Nguyên nhân | Số lượng | Tỷ lệ % | Nhãn % |
|---|---|---|---|
| Các nguyên nhân khác | 32766 | 0.45 | 45.1% |
| Medical | 39962 | 0.55 | 54.9% |
TRỰC QUAN HÓA
# Khởi tạo ggplot, thiết lập trục
ggplot(df_bmi_high_summary, aes(x = "", y = percentage, fill = Reason_Type)) +
# Vẽ cột
geom_col(width = 1, color = "white") +
# Biến thành biểu đồ tròn
coord_polar(theta = "y", start = 0) +
# Thêm nhãn %
geom_text( aes(label = label_text), position = position_stack(vjust = 0.5),
color = "black", size = 5 ) +
# Tinh chỉnh màu
scale_fill_manual(values = c("Medical" = "pink", "Các nguyên nhân khác" = "khaki1")) +
# Đặt tiêu đề
labs(title = "Tỷ lệ Yêu cầu 'Medical' (Trong nhóm BMI cao)",
fill = "Loại Nguyên nhân") +
# Xóa nền và lưới
theme(axis.title = element_blank(), axis.text = element_blank(),
axis.ticks = element_blank(), panel.grid = element_blank())Nguồn dữ liệu sơ cấp được sử dụng cho nghiên cứu này là bộ dữ liệu bctcabs.xlsx, được thu thập và tổng hợp từ các báo cáo tài chính công bố công khai của Tổng Công ty Cổ phần Bia - Rượu - Nước giải khát Sài Gòn (SABECO). Dữ liệu bao quát giai đoạn hoạt động 10 năm, từ 2015 đến 2024, cho phép thực hiện phân tích xu hướng (trend analysis) và đánh giá hiệu quả hoạt động một cách xuyên suốt.
Bộ dữ liệu bao gồm các chỉ tiêu tài chính then chốt, phản ánh tình hình tài sản và nguồn vốn (như tổng tài sản, nợ phải trả, vốn chủ sở hữu) cùng các chỉ số kết quả kinh doanh cốt lõi (như doanh thu, lợi nhuận sau thuế). Ngoài ra, dữ liệu thô cũng được sử dụng để tính toán các tỷ suất tài chính quan trọng nhằm đánh giá hiệu quả hoạt động và khả năng sinh lời của doanh nghiệp.
Mục tiêu của việc phân tích bộ dữ liệu này là thực hiện một cuộc đánh giá tài chính và hiệu suất kinh doanh của SABECO qua từng thời kỳ. Nghiên cứu tập trung vào việc nhận diện các xu hướng biến động, đánh giá năng lực quản lý tài chính, và hiệu quả sử dụng vốn. Hơn nữa, phân tích này còn nhằm xác định các yếu tố nội tại ảnh hưởng đến khả năng sinh lời, đặt trong bối cảnh cạnh tranh gay gắt của ngành đồ uống tại Việt Nam. Về mặt thực tiễn, kết quả nghiên cứu cung cấp luận cứ khoa học cho việc đề xuất các giải pháp chiến lược nhằm nâng cao hiệu quả hoạt động và năng lực cạnh tranh của SABECO trong tương lai.
library(readxl)
# Xác định đường dẫn đến tệp dữ liệu
bc_raw<- read_excel("D:/thầy Tường/bctcabs.xlsx")Đây là bước “nạp” dữ liệu thô vào môi trường R để chuẩn bị phân tích.
# Tính số hàng của dữ liệu
n_rows_bc <- nrow(bc_raw)
# In kết quả
knitr::kable(data.frame("Chỉ tiêu" = "Số hàng của dữ liệu", "Giá trị" = n_rows_bc),
caption = "Thông tin kích thước dữ liệu",align = "lr", booktabs = TRUE)| Chỉ.tiêu | Giá.trị |
|---|---|
| Số hàng của dữ liệu | 10 |
Số hàng là:10
# Số cột
n_cols_bc <- ncol(bc_raw)
# In kết quả
knitr::kable( data.frame("Chỉ tiêu" = "Số hàng của dữ liệu","Giá trị" = n_cols_bc),
caption = "Thông tin kích thước dữ liệu",align = "lr", booktabs = TRUE)| Chỉ.tiêu | Giá.trị |
|---|---|
| Số hàng của dữ liệu | 11 |
Số cột là: 11
# gọi thư viện
library(knitr)
# lập bảng giải thích các biến
variable_description <- data.frame(
Ten_Bien = names(bc_raw),
Ten_TiengAnh = c(
"Year","Current Assets","Cash and Cash Equivalents","Short-term Financial Investments",
"Non-current Assets","Total Assets","Total Liabilities","Owner’s Equity",
"Net Revenue from Sales and Services","Gross Profit from Sales and Services",
"Financial Income"),
Mo_Ta = c(
"Biến chỉ năm tài chính (2015–2020).",
"Tổng giá trị tài sản ngắn hạn có thể chuyển đổi thành tiền trong vòng một năm.",
"Tiền mặt và các khoản tương đương tiền của doanh nghiệp.",
"Các khoản đầu tư tài chính ngắn hạn như cổ phiếu, trái phiếu ngắn hạn.",
"Tổng tài sản dài hạn (nhà xưởng, thiết bị, bất động sản…).",
"Tổng giá trị tài sản mà doanh nghiệp sở hữu.",
"Tổng nghĩa vụ tài chính mà doanh nghiệp phải thanh toán.",
"Nguồn vốn thuộc cổ đông – phần chênh giữa tài sản và nợ phải trả.",
"Doanh thu thuần từ hoạt động bán hàng và cung cấp dịch vụ.",
"Khoản lợi nhuận sau khi trừ giá vốn hàng bán.",
"Doanh thu từ các hoạt động tài chính như lãi tiền gửi, cổ tức, đầu tư."))
# in bảng giải thích
kable(variable_description, col.names = c("Tên biến", "Tên tiếng anh","Mô tả"),
caption = "Giải thích các biến trong dữ liệu")| Tên biến | Tên tiếng anh | Mô tả |
|---|---|---|
| Năm/Biến | Year | Biến chỉ năm tài chính (2015–2020). |
| Tài sản ngắn hạn | Current Assets | Tổng giá trị tài sản ngắn hạn có thể chuyển đổi thành tiền trong vòng một năm. |
| Tiền và các khoản tương đương tiền | Cash and Cash Equivalents | Tiền mặt và các khoản tương đương tiền của doanh nghiệp. |
| Các khoản đầu tư tài chính ngắn hạn | Short-term Financial Investments | Các khoản đầu tư tài chính ngắn hạn như cổ phiếu, trái phiếu ngắn hạn. |
| Tài sản dài hạn | Non-current Assets | Tổng tài sản dài hạn (nhà xưởng, thiết bị, bất động sản…). |
| Tổng tài sản | Total Assets | Tổng giá trị tài sản mà doanh nghiệp sở hữu. |
| Tổng nợ phải trả | Total Liabilities | Tổng nghĩa vụ tài chính mà doanh nghiệp phải thanh toán. |
| Vốn chủ sở hữu | Owner’s Equity | Nguồn vốn thuộc cổ đông – phần chênh giữa tài sản và nợ phải trả. |
| Doanh thu thuần về bán hàng | ||
| và cung cấp dịch vụ | Net Revenue from Sales and Services | Doanh thu thuần từ hoạt động bán hàng và cung cấp dịch vụ. |
| Lợi nhuận gộp về bán hàng | ||
| và cung cấp dịch vụ | Gross Profit from Sales and Services | Khoản lợi nhuận sau khi trừ giá vốn hàng bán. |
| Doanh thu hoạt động tài chính | Financial Income | Doanh thu từ các hoạt động tài chính như lãi tiền gửi, cổ tức, đầu tư. |
#
library(knitr)
Kieu_du_lieu_bctc <-data.frame( Ten_Bien = names(bc_raw), Kieu_du_lieu = sapply(bc_raw, class))
#
kable(Kieu_du_lieu_bctc, col.names = c("Tên biến", "Kiểu dữ liệu"),
caption = "Thống kê kiểu dữ liệu các biến",row.names = FALSE)| Tên biến | Kiểu dữ liệu |
|---|---|
| Năm/Biến | numeric |
| Tài sản ngắn hạn | numeric |
| Tiền và các khoản tương đương tiền | numeric |
| Các khoản đầu tư tài chính ngắn hạn | numeric |
| Tài sản dài hạn | numeric |
| Tổng tài sản | numeric |
| Tổng nợ phải trả | numeric |
| Vốn chủ sở hữu | numeric |
| Doanh thu thuần về bán hàng | |
| và cung cấp dịch vụ | numeric |
| Lợi nhuận gộp về bán hàng | |
| và cung cấp dịch vụ | numeric |
| Doanh thu hoạt động tài chính | numeric |
Kết luận: Tất cả đều thuộc kiểu dữ liệu numeric. Đây là điều kiện tiên quyết cho mọi phân tích định lượng. Các mô hình thống kê và các phép toán (tính trung bình, phương sai) chỉ hoạt động trên các biến số (numeric). Nếu một cột chỉ tiêu bị R đọc nhầm là character, nó sẽ bị loại bỏ khỏi mọi phân tích toán học.
# Lập bảng dữ liệu bị thiếu
Du_Lieu_Bi_Thieu_bc<-data.frame(Ten_Bien = names(bc_raw), N_A=colSums(is.na(bc_raw)))
# In bảng giữ liệu.
kable(Du_Lieu_Bi_Thieu_bc, col.names = c("Tên biến", "Dữ liệu bị thiếu"),
caption = "Thống kê dữ liệu bị thiếu",row.names = FALSE)| Tên biến | Dữ liệu bị thiếu |
|---|---|
| Năm/Biến | 0 |
| Tài sản ngắn hạn | 0 |
| Tiền và các khoản tương đương tiền | 0 |
| Các khoản đầu tư tài chính ngắn hạn | 0 |
| Tài sản dài hạn | 0 |
| Tổng tài sản | 0 |
| Tổng nợ phải trả | 0 |
| Vốn chủ sở hữu | 0 |
| Doanh thu thuần về bán hàng | |
| và cung cấp dịch vụ | 0 |
| Lợi nhuận gộp về bán hàng | |
| và cung cấp dịch vụ | 0 |
| Doanh thu hoạt động tài chính | 0 |
Kết quả: Không có biến nào vi phạm.
# Đếm số hàng trùng lặp
dup_rows_bc <- sum(duplicated(bc_raw))
# Tắt ký hiệu khoa học mặc định của R (để đảm bảo số lớn hiển thị rõ ràng)
options(scipen = 999)
# Tạo data frame tạm thời để in ra bảng kable
df_trung_lap <- data.frame( Thong_Tin = "Số hàng trùng lặp",
# Định dạng số bằng scales::comma để hiển thị rõ ràng (ví dụ: 1,500)
Gia_Tri = scales::comma(dup_rows_bc))
# In ra bảng kable
kable(df_trung_lap,caption = "Kiểm tra dữ liệu trùng lặp",col.names = c("Thông tin", "Giá trị"),
align = "lr", booktabs = TRUE,row.names = FALSE)| Thông tin | Giá trị |
|---|---|
| Số hàng trùng lặp | 0 |
kết quả: Không có giá trị nào trùng lặp
Tính các giá trị Min và Max, đánh giá Độ lệch (Skewness) bằng cách so sánh Mean (Trung bình) và Median (Trung vị), ta có thể đánh giá sơ bộ độ lệch của phân phối. Nếu Mean chênh lệch đáng kể so với Median, dữ liệu có khả năng bị lệch (skewed), vi phạm giả định về phân phối chuẩn của nhiều mô hình, và có thể đòi hỏi các phép biến đổi (víT dụ: lấy logarit) trước khi phân tích.
Không mô tả biến năm vì nó không có ý nghĩa thống kê.
# Tính toán summary
sum_data <- summary(bc_raw$`Tài sản ngắn hạn`)
# Chuyển sang data.frame
data.frame( "Chỉ tiêu" = names(sum_data),
"Giá trị" = format(as.vector(sum_data), big.mark = ".", trim = TRUE)) %>%
# In kết quả
kable( caption = "Thống kê mô tả tài sản ngắn hạn",
col.names = c("Chỉ tiêu thống kê", "Giá trị"),
align = "lr",booktabs = TRUE, row.names = FALSE) | Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 10.714.345.997.642 |
| 1st Qu. | 13.937.287.658.793 |
| Median | 19.338.991.982.037 |
| Mean | 19.132.051.618.009 |
| 3rd Qu. | 24.519.307.933.646 |
| Max. | 26.860.224.573.663 |
Nhận xét: Với giai đoạn 2015–2024, bảng thống kê cho thấy tài sản ngắn hạn của doanh nghiệp tăng mạnh và ổn định dần qua các năm. Giá trị trung bình (~19.132 nghìn tỷ) và trung vị (~19.339 nghìn tỷ) gần tương đương, cho thấy phân bố khá cân đối, không bị lệch nhiều. So với mức tối thiểu năm đầu (10.714 nghìn tỷ) và tối đa năm gần nhất (26.860 nghìn tỷ).
Có thể thấy doanh nghiệp đã mở rộng quy mô hoạt động, cải thiện khả năng thanh khoản và quản lý vốn lưu động hiệu quả hơn trong 10 năm qua.
# Tính toán summary
sum_data <- summary(bc_raw$`Tiền và các khoản tương đương tiền`)
#Chuyển sang data.frame
data.frame( "Chỉ tiêu" = names(sum_data),
"Giá trị" = format(as.vector(sum_data), big.mark = ".", trim = TRUE)) %>%
# In kết quả
kable( caption = "Thống kê mô tả tiền và các khoản tương đương tiền",
col.names = c("Chỉ tiêu thống kê", "Giá trị"),
align = "lr", booktabs = TRUE, row.names = FALSE, digits = 2)| Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 2.636.774.241.245 |
| 1st Qu. | 3.485.232.684.180 |
| Median | 4.092.674.403.640 |
| Mean | 4.252.031.557.076 |
| 3rd Qu. | 4.474.974.146.779 |
| Max. | 7.935.974.303.078 |
Nhận xét: Tiền và các khoản tương đương tiền của doanh nghiệp có xu hướng tăng ổn định, thể hiện qua giá trị trung bình hơn 4,25 nghìn tỷ đồng và mức tối đa đạt gần 7,94 nghìn tỷ đồng.
Điều này cho thấy doanh nghiệp duy trì khả năng thanh khoản tốt, đồng thời phản ánh hiệu quả trong việc quản lý dòng tiền và dự trữ tài chính, giúp đảm bảo hoạt động sản xuất kinh doanh được duy trì liên tục và an toàn trước biến động thị trường.
# Tính toán summary
sum_data <- summary(bc_raw$`Các khoản đầu tư tài chính ngắn hạn`)
# Chuyển sang data.frame và in kable
data.frame( "Chỉ tiêu" = names(sum_data),
"Giá trị" = format(as.vector(sum_data), big.mark = ".", trim = TRUE)) %>%
# In kết quả
kable( caption = "Thống kê mô tả các khoản đầu tư tài chính ngắn hạn",
col.names = c("Chỉ tiêu thống kê", "Giá trị"),
align = "lr", booktabs = TRUE, row.names = FALSE,digits = 2) | Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 942.766.940.162 |
| 1st Qu. | 6.805.148.028.643 |
| Median | 13.470.323.091.575 |
| Mean | 11.587.072.404.433 |
| 3rd Qu. | 16.884.989.044.275 |
| Max. | 19.411.469.500.000 |
Nhận xét: Các khoản đầu tư tài chính ngắn hạn tăng mạnh, với giá trị trung bình hơn 11,5 nghìn tỷ đồng và mức cao nhất gần 19,4 nghìn tỷ đồng.
Sự gia tăng này cho thấy doanh nghiệp có chiến lược tối ưu hóa nguồn vốn nhàn rỗi, tập trung vào đầu tư ngắn hạn sinh lời, đồng thời phản ánh năng lực tài chính vững vàng và khả năng quản trị vốn linh hoạt trước biến động của thị trường.
# Tính toán summary
sum_data <- summary(bc_raw$`Tài sản dài hạn`)
# Chuyển sang data.frame
data.frame( "Chỉ tiêu" = names(sum_data),
"Giá trị" = format(as.vector(sum_data), big.mark = ".", trim = TRUE)) %>%
# In kết quả
kable( caption = "Thống kê mô tả tài sản dài hạn",
col.names = c("Chỉ tiêu thống kê", "Giá trị"),
align = "lr",booktabs = TRUE,row.names = FALSE, digits = 2)| Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 7.503.219.247.991 |
| 1st Qu. | 7.626.636.934.369 |
| Median | 7.829.732.452.665 |
| Mean | 8.061.028.665.165 |
| 3rd Qu. | 8.361.345.578.724 |
| Max. | 9.377.631.443.590 |
Nhận xét: Trong giai đoạn 2015–2024, giá trị tài sản dài hạn của doanh nghiệp tăng nhẹ nhưng ổn định, dao động từ 7,5 đến 9,4 nghìn tỷ đồng. Sự chênh lệch không quá lớn giữa các mốc thống kê cho thấy doanh nghiệp duy trì đầu tư dài hạn ở mức hợp lý, đảm bảo năng lực sản xuất và cơ sở vật chất ổn định trong dài hạn.
# Tính toán summary
sum_data <- summary(bc_raw$`Tổng tài sản`)
# Chuyển sang data.frame
data.frame( "Chỉ tiêu" = names(sum_data),
"Giá trị" = format(as.vector(sum_data), big.mark = ".", trim = TRUE)) %>%
# In kết quả
kable( caption = "Thống kê mô tả tổng tài sản",
col.names = c("Chỉ tiêu thống kê", "Giá trị"),
align = "lr", booktabs = TRUE,row.names = FALSE, digits = 2) | Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 19.192.865.179.330 |
| 1st Qu. | 22.101.952.530.486 |
| Median | 27.168.724.434.702 |
| Mean | 27.193.080.283.174 |
| 3rd Qu. | 32.701.310.866.595 |
| Max. | 34.465.075.615.756 |
Kết quả: Giai đoạn 2015–2024 cho thấy tổng tài sản của doanh nghiệp duy trì xu hướng tăng ổn định, dao động từ 19,2 nghìn tỷ đến 34,5 nghìn tỷ đồng. Việc giá trị trung bình và trung vị xấp xỉ nhau cho thấy sự phát triển đồng đều, không chịu tác động lớn từ các biến động bất thường, phản ánh nền tảng tài chính vững và khả năng mở rộng hoạt động hiệu quả.
# Tính toán summary
sum_data <- summary(bc_raw$`Tổng nợ phải trả`)
# Chuyển sang data.frame
data.frame("Chỉ tiêu" = names(sum_data),
"Giá trị" = format(as.vector(sum_data), big.mark = ".", trim = TRUE)) %>%
# In kết quả
kable( caption = "Thống kê mô tả tổng nợ phải trả",
col.names = c("Chỉ tiêu thống kê", "Giá trị"),
align = "lr", booktabs = TRUE, row.names = FALSE,digits = 2)| Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 6.159.696.384.430 |
| 1st Qu. | 6.791.321.090.971 |
| Median | 7.550.192.321.990 |
| Mean | 7.650.108.089.131 |
| 3rd Qu. | 8.401.659.875.945 |
| Max. | 9.874.229.696.363 |
Nhận xét: Tổng nợ phải trả của doanh nghiệp tăng dần qua các năm, dao động từ 6,16 nghìn tỷ đến gần 9,87 nghìn tỷ đồng. Giá trị trung bình cao hơn trung vị cho thấy nợ có xu hướng tăng mạnh ở những năm gần đây, phản ánh sự mở rộng quy mô hoạt động đi kèm với nhu cầu vốn lớn hơn, nhưng vẫn trong ngưỡng kiểm soát hợp lý.
# Tính toán summary
sum_data <- summary(bc_raw$`Vốn chủ sở hữu`)
# Chuyển sang data.frame
data.frame("Chỉ tiêu" = names(sum_data),
"Giá trị" = format(as.vector(sum_data), big.mark = ".", trim = TRUE)) %>%
# In kết quả
kable( caption = "Thống kê mô tả vốn chủ sở hữu",
col.names = c("Chỉ tiêu thống kê", "Giá trị"),
align = "lr", booktabs = TRUE, row.names = FALSE,digits = 2 ) | Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 12.433.180.070.596 |
| 1st Qu. | 14.843.343.168.253 |
| Median | 20.645.761.723.646 |
| Mean | 19.542.964.714.043 |
| 3rd Qu. | 23.976.516.312.794 |
| Max. | 25.485.157.894.867 |
Nhận xét: vốn chủ sở hữu của doanh nghiệp tăng trưởng ổn định, dao động từ 12,43 nghìn tỷ đến 25,49 nghìn tỷ đồng. Mức trung vị cao hơn nhiều so với ngưỡng thấp nhất, cho thấy doanh nghiệp liên tục tích lũy lợi nhuận và mở rộng quy mô vốn. Điều này phản ánh năng lực tài chính vững mạnh và khả năng tự chủ cao trong dài hạn.
# Tính toán summary
sum_data <- summary(bc_raw$`Doanh thu thuần về bán hàng\r\nvà cung cấp dịch vụ`)
# Chuyển sang data.frame
data.frame("Chỉ tiêu" = names(sum_data),
"Giá trị" = format(as.vector(sum_data), big.mark = ".", trim = TRUE)) %>%
# In kết quả
kable( caption = "Thống kê mô tả 'doanh thu thuần'",
col.names = c("Chỉ tiêu thống kê", "Giá trị"),
align = "lr", booktabs = TRUE, row.names = FALSE,digits = 2)| Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 26.373.746.293.858 |
| 1st Qu. | 28.586.334.698.312 |
| Median | 31.220.547.627.216 |
| Mean | 31.764.670.136.053 |
| 3rd Qu. | 34.843.855.757.524 |
| Max. | 37.899.059.501.295 |
Nhận xét: doanh thu thuần duy trì xu hướng tăng ổn định, dao động từ 26,37 nghìn tỷ đến 37,89 nghìn tỷ đồng. Giá trị trung bình cao hơn trung vị cho thấy doanh nghiệp có những năm tăng trưởng vượt trội, phản ánh hiệu quả hoạt động kinh doanh và khả năng mở rộng thị trường tích cực.
# Tính toán summary
sum_data <- summary(bc_raw$`Lợi nhuận gộp về bán hàng\r\nvà cung cấp dịch vụ`)
# Chuyển sang data.frame
data.frame( "Chỉ tiêu" = names(sum_data),
"Giá trị" = format(as.vector(sum_data), big.mark = ".", trim = TRUE)) %>%
# In kết quả
kable(caption = "Thống kê mô tả 'lợi nhuận gộp'",
col.names = c("Chỉ tiêu thống kê", "Giá trị"),
align = "lr", booktabs = TRUE, row.names = FALSE,digits = 2)| Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 7.557.743.622.179 |
| 1st Qu. | 8.129.988.160.736 |
| Median | 8.683.306.424.513 |
| Mean | 8.761.549.027.245 |
| 3rd Qu. | 9.261.488.052.258 |
| Max. | 10.770.706.927.084 |
Nhận xét: Trong giai đoạn 2015–2024, lợi nhuận gộp tăng trưởng đều qua các năm, dao động từ 7,56 nghìn tỷ đến 10,77 nghìn tỷ đồng. Giá trị trung bình và trung vị khá gần nhau, cho thấy doanh nghiệp duy trì biên lợi nhuận ổn định, phản ánh khả năng kiểm soát chi phí và hiệu quả sản xuất – kinh doanh bền vững.
# Tính toán summary
sum_data <- summary(bc_raw$`Doanh thu hoạt động tài chính`)
# Chuyển sang data.frame
data.frame( "Chỉ tiêu" = names(sum_data),
"Giá trị" = format(as.vector(sum_data),big.mark = ".", trim = TRUE)) %>%
# In kết quả
kable(caption = "Thống kê mô tả 'doanh thu hoạt động tài chính'",
col.names = c("Chỉ tiêu thống kê", "Giá trị"),
align = "lr",booktabs = TRUE, row.names = FALSE,digits = 2) | Chỉ tiêu thống kê | Giá trị |
|---|---|
| Min. | 418.646.983.429 |
| 1st Qu. | 660.523.055.065 |
| Median | 932.127.070.083 |
| Mean | 888.020.478.391 |
| 3rd Qu. | 1.084.690.114.858 |
| Max. | 1.432.568.520.354 |
Nhận xét: Trong giai đoạn 2015–2024, doanh thu hoạt động tài chính có xu hướng tăng, dao động từ 418,6 tỷ đến hơn 1.432 tỷ đồng. Mức trung bình gần 888 tỷ đồng cho thấy doanh nghiệp duy trì hiệu quả đầu tư tài chính ổn định, góp phần tích cực vào tổng lợi nhuận và khả năng sinh lời ngoài hoạt động kinh doanh chính.
# đọc lại và xem dữ liệu gốc
bc <- read_excel("D:/thầy Tường/bctcabs.xlsx", sheet = 1)
# Lấy tên cột từ dataframe 'bc'
column_names <- names(bc)
# Tạo dataframe tạm thời cho Kable
data.frame( STT = 1:length(column_names), Ten_Bien = column_names) %>%
# Định dạng và in ra bảng Kable
kable( caption = "Phân loại và danh sách các biến Số trong dữ liệu",
col.names = c("STT", "Tên Biến (Column Name)"),
align = "ll", booktabs = TRUE, row.names = FALSE )%>%
# Căn giữa, giữ đúng vị trí và tự động co lại
kable_styling( position = "center",latex_options = c("hold_position", "scale_down"))| STT | Tên Biến (Column Name) |
|---|---|
| 1 | Năm/Biến |
| 2 | Tài sản ngắn hạn |
| 3 | Tiền và các khoản tương đương tiền |
| 4 | Các khoản đầu tư tài chính ngắn hạn |
| 5 | Tài sản dài hạn |
| 6 | Tổng tài sản |
| 7 | Tổng nợ phải trả |
| 8 | Vốn chủ sở hữu |
| 9 | Doanh thu thuần về bán hàng và cung cấp dịch v |
| 10 | Lợi nhuận gộp về bán hàng và cung cấp dịch vụ |
| 11 | Doanh thu hoạt động tài chính |
# Gọi thư viện
library(janitor)
# Xóa ký tự đặc biệt, thay khoảng trắng bằng "_
bc <- clean_names(bc_raw)
# Lấy tên cột từ dataframe 'bc'
column_names <- names(bc)
# Tạo dataframe tạm thời cho Kable
data.frame( STT = 1:length(column_names),Ten_Bien_Sau_Clean = column_names) %>%
# Định dạng và in ra bảng
kable(caption = "Danh sách tên cột đã được chuẩn hóa",
col.names = c("STT", "Tên Biến (Đã Làm Sạch)"),
align = "ll", booktabs = TRUE,row.names = FALSE )| STT | Tên Biến (Đã Làm Sạch) |
|---|---|
| 1 | nam_bien |
| 2 | tai_san_ngan_han |
| 3 | tien_va_cac_khoan_tuong_duong_tien |
| 4 | cac_khoan_dau_tu_tai_chinh_ngan_han |
| 5 | tai_san_dai_han |
| 6 | tong_tai_san |
| 7 | tong_no_phai_tra |
| 8 | von_chu_so_huu |
| 9 | doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu |
| 10 | loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu |
| 11 | doanh_thu_hoat_dong_tai_chinh |
Ý nghĩa: Việc chuẩn hóa tên cột giúp đảm bảo tính nhất quán và tránh lỗi cú pháp khi xử lý dữ liệu trong R. Các tên biến được chuyển về dạng không dấu, viết thường và có gạch dưới, giúp dễ truy cập và thao tác. Quá trình này được thực hiện bằng hàm clean_names() thuộc gói janitor, nhằm tăng tính chính xác và tự động hóa trong phân tích.
Ý nghĩa: Giúp dễ dàng hơn trong việc viết và phân tích dữ liệu.
Đây là bước đảm bảo kiểu dữ liệu (data type integrity). Biến “Năm” về bản chất là một biến thứ tự. Việc chuyển về kiểu integer đảm bảo R hiểu đúng bản chất của nó, giúp biến này hoạt động chính xác trong các mô hình chuỗi thời gian, các phép lọc (ví dụ: filter(Nam > 2018)), hoặc khi dùng làm trục (axis) trong biểu đồ và tối ưu hóa bộ nhớ so với kiểu numeric.
# Tạo cột mới quy mô.
bc <- bc %>%
mutate(quy_mo = case_when( tong_tai_san < 1e9 ~ "Nhỏ", tong_tai_san < 5e9 ~ "Vừa",
TRUE ~ "Lớn" ))
bc %>%
# Đếm tần suất và tỷ lệ phần trăm của từng nhóm Quy mô
count(quy_mo) %>%
mutate(Ti_Le = n / sum(n),
Ti_Le_Phan_Tram = scales::percent(Ti_Le, decimal.mark = ",",accuracy = 0.1)) %>%
# Sắp xếp lại cột
select(quy_mo, n, Ti_Le_Phan_Tram) %>%
# Im kable
kable( caption = "Tần suất phân loại quy mô công ty",
col.names = c("Quy mô", "Tần suất (Số lượng)", "Tỷ lệ (%)"),
align = "lcr", booktabs = TRUE, row.names = FALSE)| Quy mô | Tần suất (Số lượng) | Tỷ lệ (%) |
|---|---|---|
| Lớn | 10 | 100,0% |
Dùng hàm case_when để gán nhãn “Nhỏ”, “Vừa”, “Lớn” dựa trên các ngưỡng giá trị của cột tổng tài sản Kết quả: Bảng số liệu cho thấy quy mô của của các biến đều thuộc loại lớn
# Định nghĩa vector chứa tên các cột cần chuyển đổi
cols_to_num <- c("tai_san_ngan_han", "tong_tai_san", "von_chu_so_huu",
"doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu",
"loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu","quy_mo")
# Áp dụng hàm as.numeric cho tất cả các cột đã chọn
bc[cols_to_num] <- lapply(bc[cols_to_num], as.numeric)
# Tạo dataframe chứa Tên cột và Kiểu dữ liệu
df_structure <- data.frame( Ten_Bien = names(bc), Kieu_Du_Lieu = sapply(bc, class))
# In ra bảng
kable(df_structure, caption = "Tóm tắt cấu trúc dữ liệu)",
col.names = c("Tên Biến", "Kiểu Dữ Liệu"),
align = "lr", booktabs = TRUE, row.names = FALSE)| Tên Biến | Kiểu Dữ Liệu |
|---|---|
| nam | integer |
| tai_san_ngan_han | numeric |
| tien_va_cac_khoan_tuong_duong_tien | numeric |
| cac_khoan_dau_tu_tai_chinh_ngan_han | numeric |
| tai_san_dai_han | numeric |
| tong_tai_san | numeric |
| tong_no_phai_tra | numeric |
| von_chu_so_huu | numeric |
| doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu | numeric |
| loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu | numeric |
| doanh_thu_hoat_dong_tai_chinh | numeric |
| quy_mo | numeric |
Các biến định lượng trong bộ dữ liệu được chuyển đổi sang kiểu số (numeric) nhằm đảm bảo tính chính xác cho các phép tính và mô hình phân tích. Cụ thể, hàm as.numeric() được áp dụng đồng loạt cho các cột liên quan, giúp chuẩn hóa định dạng dữ liệu. Sau đó, cấu trúc dữ liệu được tổng hợp bằng bảng kable() để kiểm tra kiểu biến và xác nhận tính đồng nhất của tập dữ liệu.
# Gán biến
sd_tts <- sd(bc$tong_tai_san, na.rm = TRUE)
mean_tts <- mean(bc$tong_tai_san, na.rm = TRUE)
# Tính hệ số biến thiên
cv_tts <- sd_tts / mean_tts
# TẠO VÀ IN BẢNG KABLE
data.frame(Chỉ_số = "Hệ số Biến thiên (CV)",
# Định dạng CV dưới dạng phần trăm (accuracy = 0.1%):
Giá_trị = scales::percent(cv_tts,decimal.mark = ",", accuracy = 0.01)) %>%
# In kết quả
kable(caption = "Hệ số biến thiên của tổng tài sản",col.names = c("Chỉ số", "Giá trị"),
align = "lr",booktabs = TRUE, row.names = FALSE)| Chỉ số | Giá trị |
|---|---|
| Hệ số Biến thiên (CV) | 21,08% |
Nhận Xét: Biến hệ số biến thiên (CV) được tạo ra để đo mức độ biến động tương đối của Tổng tài sản qua các năm.
CV = 21.1% cho thấy Tổng tài sản biến động ở mức trung bình, tức là giá trị tài sản có thay đổi theo thời gian nhưng vẫn ổn định tương đối, phản ánh quy mô doanh nghiệp phát triển đều đặn, không có biến động quá lớn giữa các năm.
# khởi tạo biểu đồ và gán trục X, trục Y
ggplot(bc, aes(x = nam, y = tong_tai_san/1e9)) +
# Vẽ đường nối các năm, thể hiện xu hướng thay đổi tổng tài sản
geom_line(linewidth = 1.2, color = "pink2") +
# Vẽ đường nối các năm, thể hiện xu hướng thay đổi tổng tài sản
geom_point(size = 2, color = "darkorchid2" ) +
# Ghi giá trị cụ thể của từng điểm lên biểu đồ
geom_text(aes(label = number(tong_tai_san / 1e9, big.mark = ".")),
vjust = -0.5, size = 3.1, color = "black") +
# Định dạng trục Y để CÓ DẤU CHẤM
scale_y_continuous(labels = number_format(big.mark = ".")) +
#Đặt tiêu đề và tên trục X, Y
labs(title = "XU HƯỚNG TỔNG TÀI SẢN (2015–2024)", x = "Năm",
y = "Tổng tài sản (nghìn tỷ đồng)") +
# Chỉnh hiển thị năm và định dạng số có dấu phẩy.
scale_x_continuous(breaks = 2015:2024) +
#Dùng giao diện tối giản, dễ nhìn
theme_minimal(base_family = "Times",base_size = 13)Nhận xét: Biểu đồ thể hiện xu hướng Tổng tài sản giai đoạn 2015–2024 cho thấy:
Giai đoạn 2015–2018: Tổng tài sản tăng chậm, chỉ dao động quanh mức 21–22 nghìn tỷ đồng.
Từ 2019 đến 2022: Tài sản tăng mạnh và liên tục, đặc biệt năm 2019 tăng vọt từ khoảng 22 nghìn tỷ lên gần 27 nghìn tỷ, sau đó tiếp tục đạt 34,465 tỷ đồng vào năm 2022 — mức cao nhất toàn kỳ.
Hai năm cuối (2023–2024): Có dấu hiệu giảm nhẹ, từ 34,056 tỷ xuống 33,439 tỷ đồng, cho thấy tốc độ mở rộng tài sản chững lại.
Kết luận: Giai đoạn 2015–2022 là thời kỳ tăng trưởng mạnh về quy mô tài sản, thể hiện khả năng mở rộng nguồn lực và hoạt động đầu tư. Tuy nhiên, sau 2022, xu hướng giảm nhẹ cho thấy doanh nghiệp cần chú trọng hiệu quả sử dụng tài sản và duy trì ổn định quy mô tài chính.
# Tạo một dataframe mới có tên df_loi_nhuan_tb
df_loi_nhuan_tb <- bc %>%
# Nhóm dữ liệu theo cột 'Nam'
group_by(nam) %>%
# Tính Lợi nhuận gộp trung bình (mean) cho mỗi năm
summarise(loi_nhuan_tb = mean(
loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu, na.rm = TRUE)) %>%
# Sắp xếp lại theo năm
arrange(nam)
df_loi_nhuan_tb_formatted <- df_loi_nhuan_tb %>%
mutate( loi_nhuan_tb = scales::number(loi_nhuan_tb,big.mark = ".", accuracy = 1) )
# In kết quả
kable( df_loi_nhuan_tb_formatted, caption = "Lợi nhuận gộp trung bình qua các năm",
col.names = c("Năm", "Lợi nhuận gộp trung bình"),align = "lr", booktabs = TRUE,
row.names = FALSE)| Năm | Lợi nhuận gộp trung bình |
|---|---|
| 2015 | 7.557.743.622.179 |
| 2016 | 8.267.535.125.754 |
| 2017 | 8.865.518.064.577 |
| 2018 | 8.084.139.172.396 |
| 2019 | 9.550.628.692.014 |
| 2020 | 8.501.094.784.449 |
| 2021 | 7.608.564.811.493 |
| 2022 | 10.770.706.927.084 |
| 2023 | 9.091.362.504.235 |
| 2024 | 9.318.196.568.266 |
# 1. Vẽ biểu đồ đường cho Lợi nhuận gộp Trung bình
ggplot(df_loi_nhuan_tb, aes(x = nam, y = loi_nhuan_tb/1000000)) +
# Vẽ đường và điểm
geom_line(linewidth = 1.2, color = "lightpink") +
geom_point(size = 3, color = "thistle") +
# Thêm nhãn giá trị (đã định dạng)
geom_text( aes(label = scales::number(loi_nhuan_tb/1000000, big.mark = ".", accuracy = 1)),
vjust = -0.7,size = 3.2) +
# Đảm bảo tất cả các năm đều hiển thị
scale_x_continuous(breaks = min(df_loi_nhuan_tb$nam):max(df_loi_nhuan_tb$nam)) +
# Định dạng trục Y (thêm dấu chấm)
scale_y_continuous(labels = number_format(big.mark = ".")) +
# Thêm Tiêu đề
labs( title = "Xu hướng Lợi nhuận gộp Trung bình qua các Năm",
x = "Năm", y = "Lợi nhuận gộp Trung bình (triệu đồng)") +
theme_minimal(base_family = "Times")# Tính giá trị trung bình (loại bỏ NA)
mean_loinhuan <- mean(bc$loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu, na.rm = TRUE)
# Tạo cột mới
data.frame(Chỉ_số = "Trung bình lợi nhuận gộp",
# Định dạng số có dấu phẩy, làm tròn đến số nguyên
Giá_trị = scales::number(mean_loinhuan,big.mark = ".", accuracy = 1)) %>%
# In kết quả
kable( caption = "Trung bình lợi nhuận gộp", col.names = c("Chỉ số", "Giá trị"),
align = "lr", booktabs = TRUE,row.names = FALSE)| Chỉ số | Giá trị |
|---|---|
| Trung bình lợi nhuận gộp | 8.761.549.027.245 |
# Tính tương quan giữa Tổng tài sản và Tổng nợ
tuong_quan_tts_tn <- cor(bc$tong_tai_san, bc$tong_no_phai_tra, use = "complete.obs")
# Tạo cột mới
data.frame(Chỉ_số = "Tương quan (Tổng Tài Sản & Tổng Nợ)",
# Định dạng số, làm tròn đến 3 chữ số thập phân
Giá_trị = scales::number(tuong_quan_tts_tn,decimal.mark = ",", accuracy = 0.001)) %>%
# In kết quả
kable(caption = "Hệ số tương quan giữa tổng tài sản và tổng nợ",
col.names = c("Chỉ số", "Giá trị"), align = "lr", booktabs = TRUE, row.names = FALSE)| Chỉ số | Giá trị |
|---|---|
| Tương quan (Tổng Tài Sản & Tổng Nợ) | 0,745 |
# 1. Vẽ biểu đồ phân tán
# CHIA CHO 1.000.000.000 (Tỷ đồng)
ggplot(bc, aes(x = tong_tai_san / 1000000000, y = tong_no_phai_tra / 1000000000)) +
# Vẽ các điểm dữ liệu
geom_point(color = "skyblue", alpha = 0.8, size = 4) +
# Thêm đường xu hướng
geom_smooth(method = "lm", se = FALSE, color = "red", linetype = "dashed") +
# Dùng geom_text_repel để tự động đẩy nhãn
geom_text_repel(aes(label = nam), size = 3.5,color = "black",box.padding = 0.5,
point.padding = 0.5,segment.color = 'grey50',segment.size = 0.2,max.overlaps = Inf) +
# Cập nhật nhãn trục (scales)
scale_x_continuous(name = "Tổng tài sản (Tỷ đồng)",labels = number_format(big.mark = "."))+
scale_y_continuous(name = "Tổng nợ phải trả (Tỷ đồng)",labels = number_format(big.mark = "."))+
# Thêm Tiêu đề và Phụ đề
labs(title = "MỐI QUAN HỆ GIỮA TỔNG TÀI SẢN VÀ TỔNG NỢ",subtitle = paste("Hệ số tương quan:", scales::number(tuong_quan_tts_tn, accuracy = 0.001, decimal.mark = ",")))+
#
theme_minimal(base_family = "Times")# Tạo cột mới tỷ lệ lợi nhuận gộp
bc <- bc %>%
mutate(ty_le_loi_nhuan_gop = loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu /
doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu)
# Tạo một dataframe có hai cột: STT và Tên Biến Mới
data.frame(STT = 1:length(names(bc)), Ten_Bien_Moi = names(bc)) %>%
# In kết quả
kable(caption = "Danh sách tên cột đã chuẩn hóa",col.names = c("STT", "Tên Biến (Đã Làm Sạch)"),
align = "ll", booktabs = TRUE, row.names = FALSE)| STT | Tên Biến (Đã Làm Sạch) |
|---|---|
| 1 | nam |
| 2 | tai_san_ngan_han |
| 3 | tien_va_cac_khoan_tuong_duong_tien |
| 4 | cac_khoan_dau_tu_tai_chinh_ngan_han |
| 5 | tai_san_dai_han |
| 6 | tong_tai_san |
| 7 | tong_no_phai_tra |
| 8 | von_chu_so_huu |
| 9 | doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu |
| 10 | loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu |
| 11 | doanh_thu_hoat_dong_tai_chinh |
| 12 | quy_mo |
| 13 | ty_le_loi_nhuan_gop |
Nhận xét: Trong phân tích tài chính, các giá trị tuyệt đối (như “Lợi nhuận gộp”) thường khó so sánh giữa các công ty có quy mô khác nhau (vấn đề về tính không đồng nhất). Bằng cách tạo ra một biến tỷ lệ, Biến tỷ lệ này có ý nghĩa kinh tế sâu sắc hơn, phản ánh hiệu quả hoạt động và cho phép so sánh công bằng giữa các doanh nghiệp.
# khởi tạo biểu đồ và gán trục X, trục Y
ggplot(bc, aes(x = nam, y = ty_le_loi_nhuan_gop)) +
# Vẽ đường nối các điểm dữ liệu, biểu thị xu hướng của tỷ lệ lợi nhuận gộp qua các năm
geom_line(color = "cyan3", linewidth = 1.2) +
# Thêm các điểm dữ liệu trên từng năm để dễ quan sát vị trí thực tế của từng giá trị
geom_point(color = "brown1", size = 2.3) +
# Thêm nhãn hiển thị giá trị phần trăm ngay trên các điểm dữ liệu.
geom_text(aes(label = paste0(sub("\\.", ",", round(ty_le_loi_nhuan_gop, 1)), "%")),
vjust = -0.6, size = 3) +
# Đặt tiêu đề và nhãn trục rõ ràng.
labs(title = "TỶ LỆ LỢI NHUẬN GỘP (%)", x = "Năm", y = "%") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024 trên trục hoành.
scale_x_continuous(breaks = 2015:2024) +
# Áp dụng giao diện cổ điển (classic) với nền trắng và trục rõ ràng.
theme_minimal(base_family = "Times")Nhận xét: Giai đoạn 2015–2018: Tỷ lệ lợi nhuận gộp giảm nhẹ từ khoảng 0,28% xuống 0,23%, phản ánh chi phí sản xuất hoặc giá vốn tăng nhanh hơn doanh thu.
Từ 2019–2022: Biên lợi nhuận phục hồi và đạt đỉnh khoảng 0,31% năm 2022, cho thấy doanh nghiệp đã cải thiện hiệu quả hoạt động hoặc cơ cấu sản phẩm.
Năm 2023–2024: Tỷ lệ duy trì ổn định quanh mức 0,3%, thể hiện khả năng sinh lời ổn định dù thị trường có biến động.
Tổng thể: Tỷ suất lợi nhuận gộp có xu hướng biến động nhẹ nhưng vẫn duy trì ổn định, phản ánh doanh nghiệp giữ vững khả năng kiểm soát chi phí và duy trì biên lợi nhuận trong dài hạn.
# TyLeNoTaiSan = Tổng Nợ Phải Trả / Tổng Tài Sản
bc <- bc %>% mutate(ty_le_no_tai_san = tong_no_phai_tra / tong_tai_san)
# Tạo một dataframe mới có tên df_kiem_tra_ty_le_no
df_kiem_tra_ty_le_no <- bc %>%
# Chọn 4 cột cần thiết để kiểm tra
select(nam, tong_tai_san, tong_no_phai_tra, ty_le_no_tai_san )
# Lấy data frame
df_kiem_tra_ty_le_no %>%
# Định dạng các cột số
mutate(tong_no_phai_tra = scales::number(tong_no_phai_tra,big.mark = ".", accuracy = 1),
tong_tai_san = scales::number(tong_tai_san,big.mark = ".", accuracy = 1),
# Định dạng Tỷ lệ nợ thành %
ty_le_no_tai_san= scales::percent(ty_le_no_tai_san, decimal.mark = ",", accuracy = 0.1)) %>%
# In kết quả
kable( caption = "Tỷ lệ nợ trên tổng tài sản",
col.names = c("Năm", "Tổng tài sản", "Tổng nợ", "Tỷ lệ nợ"),
align = "lrrr", booktabs = TRUE, row.names = FALSE)| Năm | Tổng tài sản | Tổng nợ | Tỷ lệ nợ |
|---|---|---|---|
| 2015 | 21.571.925.688.349 | 7.507.221.969.018 | 34,8% |
| 2016 | 19.192.865.179.330 | 6.759.685.108.734 | 35,2% |
| 2017 | 22.013.689.109.910 | 7.593.162.674.962 | 34,5% |
| 2018 | 22.366.742.792.213 | 6.254.837.224.044 | 28,0% |
| 2019 | 26.962.476.094.045 | 6.886.229.037.681 | 25,5% |
| 2020 | 27.374.972.775.358 | 6.159.696.384.430 | 22,5% |
| 2021 | 30.487.024.372.425 | 7.892.238.669.264 | 25,9% |
| 2022 | 34.465.075.615.756 | 9.874.229.696.363 | 28,6% |
| 2023 | 34.056.624.839.705 | 8.571.466.944.838 | 25,2% |
| 2024 | 33.439.406.364.651 | 9.002.313.181.979 | 26,9% |
library(scales)
# khởi tạo biểu đồ và gán trục X, trục Y.
ggplot(bc, aes(x = nam, y = ty_le_no_tai_san )) +
# Tạo lớp vùng tô màu hồng nhạt, biểu diễn diện tích dưới đường xu hướng.
geom_area(fill = "pink", alpha = 0.5) +
# Vẽ đường xu hướng màu đỏ tím để thể hiện sự thay đổi của tỷ lệ qua thời gian.
geom_line(color = "maroon3", linewidth = 1.2) +
# Thêm các điểm dữ liệu trên đường biểu diễn.
geom_point(color = "lightsalmon4", size = 2.5) +
# Hiển thị giá trị cụ thể của từng điểm ngay trên biểu đồ.
geom_text(aes(label = paste0(sub("\\.", ",",round(ty_le_no_tai_san ,2)))),vjust = 2) +
# Đặt tiêu đề và tên trục.
labs(title = "TỶ LỆ NỢ TRÊN TÀI SẢN (%))", x = "Năm", y = "Tỷ lệ (%)") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024 trên trục hoành.
scale_x_continuous(breaks = 2015:2024) +
# Chuyển các giá trị trục tung sang định dạng phần trăm (%).
scale_y_continuous(labels = percent_format(scale = 1)) +
# Áp dụng giao diện tối giản, loại bỏ khung và đường nền thừa.
theme_minimal(base_family = "Times")Nhận xét: Giai đoạn 2015–2017: Tỷ lệ nợ duy trì ổn định ở mức cao (khoảng 34–35%), cho thấy doanh nghiệp phụ thuộc tương đối nhiều vào nguồn vốn vay.
Từ 2018–2020: Tỷ lệ nợ giảm mạnh xuống mức thấp nhất 0.23 năm 2020, phản ánh chính sách giảm đòn bẩy tài chính, tăng vốn chủ sở hữu hoặc trả bớt nợ.
Giai đoạn 2021–2024: Tỷ lệ nợ dao động nhẹ quanh mức 25–29%, thể hiện mức nợ ổn định, doanh nghiệp kiểm soát tốt rủi ro tài chính.
Nhận xét tổng quát: Cơ cấu tài chính ngày càng an toàn và bền vững hơn, với xu hướng giảm phụ thuộc vào nợ vay trong giai đoạn gần đây.
# Thêm biến ROE
bc <- bc %>%
mutate(ROE = loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu / von_chu_so_huu)
# Tạo bảng hiển thị
df_roe <- bc %>%
mutate(ROE_hien_thi = scales::percent(ROE, decimal.mark = ",", accuracy = 0.01)) %>%
select(Năm = nam, `ROE` = ROE_hien_thi)
# In kết quả
kable( df_roe, caption = "Bảng ROE", align = "lr",booktabs = TRUE, row.names = FALSE)| Năm | ROE |
|---|---|
| 2015 | 53,74% |
| 2016 | 66,50% |
| 2017 | 61,48% |
| 2018 | 50,17% |
| 2019 | 47,57% |
| 2020 | 40,07% |
| 2021 | 33,67% |
| 2022 | 43,80% |
| 2023 | 35,67% |
| 2024 | 38,13% |
# Tính giá trị trung bình (loại bỏ NA)
mean_roe <- mean(bc$ROE, na.rm = TRUE)
# Tạo biến
data.frame( Chỉ_số = c( "Trung bình ROE"),
# Định dạng cả hai giá trị thành %
Giá_trị = scales::percent(c(mean_roe),decimal.mark = ",", accuracy = 0.1)) %>%
# In kết quả
kable(caption = "Trung bình chỉ số sinh lời ROE",col.names = c("Chỉ số", "Giá trị Trung bình"),
align = "lr", booktabs = TRUE, row.names = FALSE)| Chỉ số | Giá trị Trung bình |
|---|---|
| Trung bình ROE | 47,1% |
# khởi tạo biểu đồ và gán trục X, trục Y
ggplot(bc, aes(x = nam, y = ROE)) +
geom_line(color = "darkcyan", linewidth = 1.2) +
geom_point(color = "orange", size = 3) +
geom_text(aes(label = paste0(sub("\\.", ",",round(ROE, 2)))),
vjust = -0.6,hjust = -0.22, size = 3) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "TỶ SUẤT SINH LỜI TRÊN VỐN CHỦ SỞ HỮU (%)", x = "Năm", y = "%") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024 trên trục hoành
scale_x_continuous(breaks = 2015:2024) +
# Áp dụng giao diện nền sáng (theme_light)
theme_light(base_family = "Times")Nhận xét: Giai đoạn 2015–2017: ROE tăng mạnh, đạt đỉnh 66,5% năm 2016, phản ánh khả năng tạo lợi nhuận trên vốn chủ sở hữu rất cao.
Giai đoạn 2018–2021: ROE giảm liên tục xuống mức thấp nhất 33,67% năm 2021, cho thấy hiệu quả sử dụng vốn suy giảm, có thể do chi phí hoặc áp lực nợ tăng.
Giai đoạn 2022–2024: ROE phục hồi nhẹ, đạt khoảng 38% năm 2024, thể hiện doanh nghiệp đang dần cải thiện hiệu quả sinh lời.
Tổng quan: ROE biến động mạnh, song vẫn duy trì mức khá cao so với trung bình ngành, phản ánh khả năng sinh lời tốt nhưng chưa ổn định.
# khởi tạo biểu đồ và gán trục X.
ggplot(bc, aes(x = nam)) +
# Vẽ biểu đồ cột (bar) biểu thị Tỷ lệ nợ trên tổng tài sản của SABECO
# Nhân với 100 vì có thể dữ liệu ban đầu ở dạng tỷ lệ thập phân.
geom_col(aes(y = ty_le_no_tai_san * 100), fill = "lightblue", alpha = 0.6) +
# Vẽ đường nối thể hiện ROE (%) qua các năm.
geom_line(aes(y = ROE, color = "ROE"), linewidth = 1.2) +
# Đánh dấu các điểm dữ liệu cụ thể giúp biểu đồ trực quan hơn.
geom_point(aes(y = ROE, color = "ROE"), size = 3) +
# Dùng để thêm trục tung phụ bên phải
# Hiển thị Tỷ lệ nợ (%) với cùng thang giá trị như trục ROE ở bên trái.
scale_y_continuous(sec.axis = sec_axis(~ ., name = "Tỷ lệ nợ (%)")) +
# Đặt tiêu đề và nhãn trục rõ ràng.
labs(title = "ẢNH HƯỞNG CỦA TỶ LỆ NỢ ĐẾN ROE (2015–2024)",
subtitle = "Tỷ lệ nợ tăng cao thường kéo ROE biến động mạnh",
x = "Năm", y = "ROE (%)", color = "") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024 trên trục hoành.
scale_x_continuous(breaks = 2015:2024) +
# Áp dụng giao diện nền sáng (theme_light).
theme_light(base_family = "Times")Nhận xét: Tỷ lệ nợ và ROE biến động cùng chiều trong hầu hết các năm, cho thấy đòn bẩy tài chính có tác động đáng kể đến khả năng sinh lời trên vốn chủ sở hữu. Giai đoạn 2015–2017, khi tỷ lệ nợ cao, ROE đạt mức đỉnh (trên 60%), phản ánh hiệu quả khuếch đại lợi nhuận nhờ vay nợ. Tuy nhiên, từ 2018 trở đi, ROE giảm dần khi doanh nghiệp giảm đòn bẩy tài chính, cho thấy việc sử dụng nợ hợp lý giúp kiểm soát rủi ro nhưng đồng thời làm giảm lợi nhuận kỳ vọng. Từ 2021–2024, ROE có dấu hiệu phục hồi nhẹ cùng mức nợ ổn định, phản ánh xu hướng tái cân bằng giữa hiệu quả sinh lời và an toàn tài chính.
# Tính biến ROA
bc <- bc %>%
mutate(ROA = loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu / tong_tai_san)
# Tạo bảng hiển thị
df_roa <- bc %>%
# Định dạng ROA
mutate(ROA_hien_thi = scales::percent(ROA, decimal.mark = ",", accuracy = 0.01)) %>%
select(Năm = nam, `ROA` = ROA_hien_thi)
# In kết quả
kable( df_roa,caption = "Bảng ROA", align = "lr",booktabs = TRUE, row.names = FALSE)| Năm | ROA |
|---|---|
| 2015 | 35,04% |
| 2016 | 43,08% |
| 2017 | 40,27% |
| 2018 | 36,14% |
| 2019 | 35,42% |
| 2020 | 31,05% |
| 2021 | 24,96% |
| 2022 | 31,25% |
| 2023 | 26,69% |
| 2024 | 27,87% |
# Tính giá trị trung bình (loại bỏ NA)
mean_roa <- mean(bc$ROA, na.rm = TRUE)
# Tạo cột mới
data.frame( Chỉ_số = c( "Trung bình ROA"),
# Định dạng cả hai giá trị thành % (ví dụ: 0.052 -> 5.2%)
Giá_trị = scales::percent(c(mean_roa),decimal.mark = ",", accuracy = 0.1)) %>%
# In kết quả
kable(caption = "Trung bình chỉ số sinh lời ROA",col.names = c("Chỉ số", "Giá trị Trung bình"),
align = "lr", booktabs = TRUE, row.names = FALSE)| Chỉ số | Giá trị Trung bình |
|---|---|
| Trung bình ROA | 33,2% |
# khởi tạo biểu đồ và gán trục X, trục Y
ggplot(bc, aes(x = nam, y = ROA)) +
# Vẽ đường biểu diễn xu hướng ROA qua các năm
geom_line(color = "pink", linewidth = 1.2) +
# Thêm các điểm dữ liệu màu xanh lá tại từng năm
geom_point(color = "green", size = 3) +
# Hiển thị nhãn giá trị ROA ngay gần mỗi điểm, làm tròn đến 2 chữ số thập phân
geom_text(aes(label = paste0(sub("\\.", ",",round(ROA, 2)))), vjust = 1.5, size = 3) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "TỶ SUẤT SINH LỜI TRÊN TÀI SẢN(%)", x = "Năm", y = "%") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024 trên trục hoành
scale_x_continuous(breaks = 2015:2024) +
# Dùng giao diện nền trắng – khung đen (Black & White theme)
theme_bw(base_family = "Times")Nhận xét:
Giai đoạn 2015–2017: ROA tăng mạnh, đạt đỉnh 43,08% năm 2016, cho thấy hiệu quả sử dụng tài sản cao.
Giai đoạn 2018–2021: ROA giảm dần, đặc biệt thấp nhất 24,96% năm 2021, phản ánh hiệu quả sinh lời suy giảm, có thể do chi phí tăng hoặc lợi nhuận giảm.
Giai đoạn 2022–2024: ROA phục hồi nhẹ, dao động quanh mức 27–31%, cho thấy doanh nghiệp dần ổn định trở lại.
Nhìn chung: ROA có xu hướng biến động giảm nhẹ qua thời gian, nhưng vẫn duy trì ở mức khá, thể hiện hiệu quả khai thác tài sản tương đối tốt.
# khởi tạo biểu đồ và gán trục X
ggplot(bc, aes(x = nam)) +
# Vẽ cột biểu diễn tỷ lệ nợ trên tổng tài sản (đổi sang %), màu xanh nhạt trong suốt
geom_col(aes(y = ty_le_no_tai_san * 100), fill = "skyblue", alpha = 0.6) +
# Thêm đường biểu diễn ROA theo năm để so sánh
geom_line(aes(y = ROA, color = "ROA"), linewidth = 1.2) +
# Đánh dấu từng điểm dữ liệu ROA
geom_point(aes(y = ROA, color = "ROA"), size = 3) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "TỶ LỆ NỢ VÀ ROA (2015–2024)",
subtitle = "Phản ánh tác động của đòn bẩy tài chính đến hiệu quả sinh lời",
x = "Năm", y = "Tỷ lệ (%)", color = "") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024 trên trục hoành
scale_x_continuous(breaks = 2015:2024) +
# Áp dụng giao diện tối giản, loại bỏ khung và đường nền thừa
theme_minimal(base_family = "Times")Nhận xét: Trong các năm 2015–2017, tỷ lệ nợ duy trì ở mức cao (trên 30%), song ROA cũng đạt mức khá tốt, cho thấy doanh nghiệp sử dụng đòn bẩy tài chính hiệu quả, tận dụng nguồn vốn vay để mở rộng hoạt động sinh lời.
Từ 2018–2021, tỷ lệ nợ giảm dần nhưng ROA cũng sụt giảm mạnh, đặc biệt năm 2021 ROA chạm mức thấp nhất trong giai đoạn. Điều này phản ánh hiệu quả sử dụng vốn vay suy giảm, có thể do hiệu suất đầu tư kém hoặc tác động tiêu cực từ thị trường (như COVID-19).
Sau năm 2022, mặc dù tỷ lệ nợ tăng trở lại nhẹ, ROA có dấu hiệu hồi phục, cho thấy doanh nghiệp đang dần cải thiện khả năng sinh lời và kiểm soát chi phí vốn tốt hơn.
# # khởi tạo biểu đồ và gán trục X
ggplot(bc, aes(x = nam)) +
# vẽ đường xu hướng liền, thể hiện hiệu quả sinh lời trên tài sản
geom_line(aes(y = ROA, color = "ROA"), linewidth = 1.2) +
# vẽ đường xu hướng gạch đứt, thể hiện hiệu quả sinh lời trên vốn chủ sở hữu
geom_line(aes(y = ROE, color = "ROE"), linewidth = 1.2, linetype = "dashed") +
# đánh dấu mỗi điểm để dễ nhìn hơn
geom_point(aes(y = ROA, color = "ROA"), size = 3) +
geom_point(aes(y = ROE, color = "ROE"), size = 3) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "SO SÁNH ROA VÀ ROE (2015–2024)",x = "Năm", y = "Tỷ lệ (%)",
subtitle = "Hai chỉ tiêu phản ánh hiệu quả sinh lời khác nhau",color = "Chỉ tiêu") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024 trên trục hoành
scale_x_continuous(breaks = 2015:2024) +
# Áp dụng giao diện tối giản, loại bỏ khung và đường nền thừa
theme_minimal(base_family = "Times")Nhận xét:
ROA (tỷ suất sinh lời trên tài sản) duy trì ở mức 30–43%, phản ánh khả năng tạo lợi nhuận từ tổng tài sản tương đối ổn định, dù có giảm nhẹ giai đoạn 2019–2021 do hiệu suất sử dụng tài sản kém hơn.
ROE (tỷ suất sinh lời trên vốn chủ sở hữu) cao hơn đáng kể so với ROA, dao động từ 55–70% đầu kỳ giảm dần còn khoảng 35–40% về cuối kỳ. Điều này cho thấy doanh nghiệp sử dụng đòn bẩy tài chính mạnh nhưng hiệu quả vốn chủ giảm dần theo thời gian.
Giai đoạn 2021–2024, cả hai chỉ tiêu đều có xu hướng ổn định và có dấu hiệu phục hồi nhẹ, cho thấy hiệu quả sử dụng tài sản và vốn chủ đang được cải thiện trở lại.
# Tính toán và lưu lại kết quả vào bc
bc <- bc %>%
# Sắp xếp theo Năm
arrange(nam) %>%
# Công thức Tăng trưởng (%)
mutate(tang_truong_tai_san = (tong_tai_san - lag(tong_tai_san)) / lag(tong_tai_san) * 100)
# Lọc cột
bc %>% transmute(Năm = nam,
`Tổng tài sản (VND)`=format(tong_tai_san, big.mark =".",scientific = FALSE),
`Tăng trưởng tài sản (%)`=round(tang_truong_tai_san, 2)) %>%
# In kết quả
kable( caption = "Tốc độ tăng trưởng(10 hàng đầu)",
col.names = c("Năm", "Tổng tài sản (VND)", "Tăng trưởng tài sản (%)"),
digits = c(0, 0, 4), align = "lrr", booktabs = TRUE,row.names = FALSE)| Năm | Tổng tài sản (VND) | Tăng trưởng tài sản (%) |
|---|---|---|
| 2015 | 21.571.925.688.349 | |
| 2016 | 19.192.865.179.330 | -11.03 |
| 2017 | 22.013.689.109.910 | 14.70 |
| 2018 | 22.366.742.792.213 | 1.60 |
| 2019 | 26.962.476.094.045 | 20.55 |
| 2020 | 27.374.972.775.358 | 1.53 |
| 2021 | 30.487.024.372.425 | 11.37 |
| 2022 | 34.465.075.615.756 | 13.05 |
| 2023 | 34.056.624.839.705 | -1.19 |
| 2024 | 33.439.406.364.651 | -1.81 |
# Tính giá trị trung bình (loại bỏ NA)
mean_tang_truong_tai_san <- mean(bc$tang_truong_tai_san, na.rm = TRUE)
# Tạo cột mới
data.frame(Chỉ_số = "Trung bình tăng trưởng tổng tài sản",
Giá_trị = scales::number(mean_tang_truong_tai_san,decimal.mark = ",", accuracy = 0.01)) %>%
# In kết quả
kable( caption = "Trung bình tăng trưởng tài sản", col.names = c("Chỉ số", "Giá trị"),
align = "lr", booktabs = TRUE,row.names = FALSE)| Chỉ số | Giá trị |
|---|---|
| Trung bình tăng trưởng tổng tài sản | 5,42 |
# khởi tạo biểu đồ và gán trục X, trục Y
ggplot(bc, aes(x = nam, y = tang_truong_tai_san)) +
geom_col(fill = "darkseagreen") +
geom_text(aes(label = paste0(round(tang_truong_tai_san), "%")), vjust = -0.6, size = 3.2) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "TĂNG TRƯỞNG TÀI SẢN (%)", x = "Năm", y = "%") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024 trên trục hoành
scale_x_continuous(breaks = 2015:2024) +
# Áp dụng giao diện tối giản, loại bỏ khung và đường nền thừa
theme_minimal(base_family = "Times")Nhận xét: Giai đoạn 2016–2019: Tăng trưởng biến động mạnh — năm 2016 giảm 11%, sau đó phục hồi mạnh, đạt đỉnh 20,5% năm 2019, phản ánh giai đoạn mở rộng quy mô tích cực.
Giai đoạn 2020–2022: Tài sản tiếp tục tăng ổn định, lần lượt 1,5%, 11,4% và 13%, cho thấy doanh nghiệp vẫn duy trì được xu hướng phát triển. Giai đoạn 2023–2024: Ghi nhận suy giảm nhẹ (-1,2% và -1,8%), có thể do ảnh hưởng từ thị trường chung hoặc chính sách thận trọng trong đầu tư.
Tổng thể: Doanh nghiệp có tăng trưởng tài sản mạnh nhưng thiếu ổn định, chu kỳ tăng – giảm thể hiện sự nhạy cảm với biến động kinh tế vĩ mô.
# khởi tạo biểu đồ và gán trục X
ggplot(bc, aes(x = nam)) +
# Vẽ cột thể hiện tốc độ tăng trưởng tài sản (%), màu xanh nhạt trong suốt
geom_col(aes(y = tang_truong_tai_san), fill = "lightgreen", alpha = 0.6) +
# Thêm đường thể hiện tỷ suất sinh lời vốn chủ sở hữu (ROE)
geom_line(aes(y = ROE, color = "ROE"), linewidth = 1.2) +
# Đánh dấu các điểm dữ liệu của ROE
geom_point(aes(y = ROE, color = "ROE"), size = 3) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "ẢNH HƯỞNG CỦA TĂNG TRƯỞNG TÀI SẢN ĐẾN ROE (2015–2024)",
subtitle = "Mức tăng tài sản thường ảnh hưởng đến hiệu suất sinh lời vốn chủ",
x = "Năm", y = "Tỷ lệ (%)", color = "") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024 trên trục hoành
scale_x_continuous(breaks = 2015:2024) +
# Áp dụng giao diện nền sáng (theme_light)
theme_light(base_family = "Times")Nhận xét: Từ 2015–2018, ROE duy trì ở mức cao trên 50%, cho thấy doanh nghiệp sử dụng vốn chủ sở hữu hiệu quả trong việc tạo ra lợi nhuận. Giai đoạn này, mức tăng trưởng tài sản dương, thể hiện chiến lược mở rộng đầu tư, giúp gia tăng quy mô và hiệu quả kinh doanh.
Tuy nhiên, từ 2019–2021, ROE giảm mạnh, dù tài sản vẫn tăng nhẹ. Điều này có thể xuất phát từ việc doanh nghiệp đầu tư mở rộng nhưng hiệu suất sử dụng tài sản chưa tương xứng, dẫn đến tỷ suất sinh lời trên vốn chủ bị suy giảm.
Sau năm 2022, ROE có dấu hiệu hồi phục nhẹ, song vẫn ở mức thấp hơn giai đoạn đầu, phản ánh rằng doanh nghiệp đang trong quá trình tái cơ cấu nguồn vốn hoặc chuyển hướng đầu tư để tìm lại hiệu quả sinh lời ổn định hơn.
Nhìn chung, biểu đồ cho thấy mối quan hệ thuận chiều nhưng không hoàn toàn tuyến tính giữa tăng trưởng tài sản và ROE – khi tốc độ tăng tài sản cao đi kèm khả năng sinh lời tốt, nhưng nếu tăng trưởng không đi đôi với quản trị vốn hiệu quả, ROE sẽ suy giảm.
# Tính toán biến mới
df_ty_le_tien_mat <- bc %>%
mutate(ty_le_tien = (tien_va_cac_khoan_tuong_duong_tien / tong_tai_san) * 100)%>%
select(nam, ty_le_tien) %>%
# Định dạng %
mutate(Gia_tri_hien_thi = scales::percent(ty_le_tien / 100,accuracy = 0.01, decimal.mark = ","))
# In bảng
kable(df_ty_le_tien_mat %>% select(nam, Gia_tri_hien_thi),
caption = "Tỷ lệ tiền mặt trên tổng tài sản",
col.names = c("Năm", "Tỷ lệ Tiền mặt (%)"),
align = "lr", booktabs = TRUE, row.names = FALSE) %>%
kable_styling(position = "center", latex_options = "hold_position")| Năm | Tỷ lệ Tiền mặt (%) |
|---|---|
| 2015 | 36,79% |
| 2016 | 17,95% |
| 2017 | 11,98% |
| 2018 | 19,97% |
| 2019 | 15,27% |
| 2020 | 9,96% |
| 2021 | 11,83% |
| 2022 | 11,81% |
| 2023 | 14,80% |
| 2024 | 13,39% |
# khởi tạo biểu đồ và gán trục X, trục Y
ggplot(df_ty_le_tien_mat, aes(x = nam, y = ty_le_tien)) +
# các lớp vẽ vùng, đường, điểm
geom_area(fill = "paleturquoise", alpha = 0.5) +
geom_line(color = "dodgerblue", linewidth = 1) +
geom_point(color = "blue2", size = 3) +
# Dùng trực tiếp cột 'Gia_tri_hien_thi' bạn đã tạo
geom_text(aes(label = Gia_tri_hien_thi),vjust = -0.8,hjust= 0.3,size = 3.4) +
# Tùy chỉnh trục X
scale_x_continuous(breaks =min(df_ty_le_tien_mat$nam):max(df_ty_le_tien_mat$nam)) +
# Tùy chỉnh trục Y
scale_y_continuous(labels = function(x) paste0(x, "%")) +
# Thêm tiêu đề, phụ đề, nhãn trục và chú thích
labs(title = "TỶ LỆ TIỀN MẶT TRÊN TỔNG TÀI SẢN",
x = "Năm", y = "Tỷ lệ (%)") +
# Áp dụng giao diện tối giản
theme_minimal(base_family = "Times")Nhận xét: Tỷ lệ tiền mặt trên tổng tài sản có xu hướng giảm mạnh từ năm 2015 đến 2020, sau đó dao động nhẹ và phục hồi nhẹ ở giai đoạn 2021–2024. Điều này cho thấy doanh nghiệp giảm dần mức nắm giữ tiền mặt, có thể nhằm tăng hiệu quả sử dụng tài sản hoặc chuyển hướng đầu tư vào các tài sản sinh lời khác.
Giai đoạn đầu (2015–2018): Biến động mạnh, có thể do điều chỉnh chiến lược tài chính. Giai đoạn giữa và cuối (2019–2024): Ổn định và duy trì ở mức hợp lý, phản ánh sự cân bằng giữa khả năng thanh khoản và hiệu quả sử dụng vốn.
Kết luận:Tỷ lệ tiền mặt trên tổng tài sản giảm và ổn định dần, cho thấy doanh nghiệp đang tối ưu hóa cấu trúc tài sản, giảm tồn quỹ tiền mặt dư thừa để nâng cao hiệu quả đầu tư và lợi nhuận.
# Tính toán biến mới
df_ty_le_dautu <- bc %>%
mutate(ty_le_dautu = (cac_khoan_dau_tu_tai_chinh_ngan_han / tong_tai_san) * 100)%>%
select(nam, ty_le_dautu) %>%
# Định dạng %
mutate(Gia_tri_hien_thi = scales::percent(ty_le_dautu / 100,accuracy = 0.01, decimal.mark = ","))
# In bảng
kable(df_ty_le_dautu %>% select(nam, Gia_tri_hien_thi),
caption = "Tỷ lệ đầu tư tài chính ngắn hạn trên tổng tài sản",
col.names = c("Năm", "Tỷ lệ đầu tư"),
align = "lr", booktabs = TRUE, row.names = FALSE) %>%
kable_styling(position = "center", latex_options = "hold_position")| Năm | Tỷ lệ đầu tư |
|---|---|
| 2015 | 4,37% |
| 2016 | 16,54% |
| 2017 | 29,79% |
| 2018 | 33,73% |
| 2019 | 45,96% |
| 2020 | 53,14% |
| 2021 | 55,73% |
| 2022 | 56,32% |
| 2023 | 52,09% |
| 2024 | 49,54% |
TRỰC QUAN HÓA
# khởi tạo biểu đồ và gán trục X, Y
ggplot(df_ty_le_dautu, aes(x = nam, y = ty_le_dautu)) +
geom_area(fill = "lavender", alpha = 0.5) +
# Vẽ các đường kẻ
geom_line(linewidth = 1.2, color = "plum") +
# Vẽ dấu chấm tại các điểm dữ liệu
geom_point(size = 3, color = "purple") +
# Thêm nhãn văn bản
geom_text(aes( label = Gia_tri_hien_thi), vjust = -1, size = 3) +
# Tùy chỉnh trục X, trục Y
scale_x_continuous(breaks = min(df_ty_le_dautu$nam):max(df_ty_le_dautu$nam)) +
scale_y_continuous(labels = function(x) paste0(x, "%")) +
# Thêm tiêu đề, phụ đề, nhãn trục và chú thích
labs(title = "TỶ LỆ ĐẦU TƯ TÀI CHÍNH NGẮN HẠN TRÊN TỔNG TÀI SẢN",
x = "Năm", y = "Tỷ lệ (%)") +
# Áp dụng giao diện tối giản
theme_minimal(base_family = "Times")
* Nhận xét**:Tỷ lệ đầu tư tài chính ngắn hạn tăng mạnh
từ năm 2015 đến 2021, sau đó giảm nhẹ trong giai đoạn 2022–2024.
Giai đoạn 2015–2021: Tăng trưởng mạnh mẽ, phản ánh chiến lược mở rộng đầu tư tài chính ngắn hạn.
Giai đoạn 2022–2024: Điều chỉnh giảm, thể hiện xu hướng cân đối lại cơ cấu tài sản.
Dù giảm nhẹ, tỷ lệ đầu tư vẫn ở mức cao (gần 50%), chứng tỏ doanh nghiệp vẫn duy trì lượng đầu tư ngắn hạn đáng kể.
# khởi tạo biểu đồ và gán trục X, trục Y.
ggplot(bc, aes(x = nam, y = tai_san_ngan_han)) +
# Tạo vùng tô màu dưới đường biểu diễn, màu xanh nhạt.
geom_area(fill = "lightblue", alpha = 0.4) +
# Vẽ đường xu hướng chính, thể hiện mức biến động tài sản ngắn hạn.
geom_line(color = "darkblue", linewidth = 1.2) +
# Đánh dấu các giá trị cụ thể từng năm bằng các điểm màu đỏ.
geom_point(color = "red", size = 3) +
# Hiển thị nhãn giá trị thực tế phía trên mỗi điểm (làm tròn đến số nguyên).
geom_text(aes(label = scales::number(tai_san_ngan_han,big.mark = ".")),
angle = 90,hjust = 1.1, vjust = 1) +
# Định dạng trục Y để CÓ DẤU CHẤM
scale_y_continuous(labels = number_format(big.mark = ".")) +
#Đặt tên biểu đồ, nhãn trục X và Y .
labs(title = "XU HƯỚNG TÀI SẢN NGẮN HẠN (2015–2024)",x = "Năm", y = "Giá trị (tỷ đồng)") +
# Hiển thị từng năm từ 2015 đến 2024 trên trục X.
scale_x_continuous(breaks = 2015:2024) +
# Chọn giao diện sáng nhẹ, giúp biểu đồ rõ ràng và dễ đọc.
theme_light(base_family = "Times")
* Nhận xét**:Tài sản ngắn hạn có xu hướng tăng mạnh qua
các năm, cho thấy khả năng thanh khoản và quy mô tài sản lưu động của
doanh nghiệp được mở rộng đáng kể.
Tuy nhiên, đến năm 2024, giá trị có dấu hiệu giảm nhẹ, thể hiện sự điều chỉnh hoặc thu hẹp quy mô đầu tư ngắn hạn.
# khởi tạo biểu đồ và gán trục X, trục Y.
ggplot(bc, aes(x = nam, y = tai_san_dai_han)) +
# Vẽ biểu đồ cột để thể hiện giá trị tài sản dài hạn theo từng năm,
geom_col(fill = "steelblue3") +
# Hiển thị nhãn giá trị cụ thể trên đầu mỗi cột.
geom_text(aes(label = scales::number(tai_san_ngan_han, big.mark = ".")),
angle = 90, vjust = 1,hjust = 1.1, color = "azure") +
# Định dạng trục Y để CÓ DẤU CHẤM
scale_y_continuous(labels = number_format(big.mark = ".")) +
# Đặt tiêu đề và tên trục rõ ràng.
labs(title = "XU HƯỚNG TÀI SẢN DÀI HẠN (2015–2024)", x = "Năm", y = "Tỷ đồng") +
# Hiển thị các mốc năm từ 2015 đến 2024 trên trục hoành.
scale_x_continuous(breaks = 2015:2024) +
# Dùng giao diện nền trắng – khung đen (Black & White theme).
theme_bw(base_family = "Times")Nhận xét: Trong giai đoạn 2015–2024, tài sản dài hạn có xu hướng tăng nhẹ, nhưng mức độ biến động thấp hơn đáng kể so với tài sản ngắn hạn. Điều này phản ánh rằng doanh nghiệp duy trì chính sách đầu tư dài hạn ổn định, không có biến động mạnh về cơ cấu tài sản cố định hoặc đầu tư dài hạn.
Mặc dù có sự dao động nhẹ, nhưng nhìn chung, tài sản dài hạn duy trì ở mức ổn định và chiếm tỷ trọng đáng kể trong tổng tài sản.
Sự ổn định này thể hiện chiến lược đầu tư dài hạn bền vững, giúp doanh nghiệp đảm bảo năng lực sản xuất, cơ sở vật chất và lợi thế cạnh tranh lâu dài.
Tuy nhiên, việc giảm nhẹ vào năm 2024 cần được theo dõi để đảm bảo rằng đây chỉ là điều chỉnh tạm thời, không ảnh hưởng đến hiệu quả sử dụng vốn dài hạn.
# khởi tạo biểu đồ và gán trục X
ggplot(bc, aes(x = nam)) +
# Vẽ vùng diện tích (area chart) thể hiện "Tài sản ngắn hạn"
geom_area(aes(y = tai_san_ngan_han/1000, fill = "Ngắn hạn"), alpha = 0.4) +
# Vẽ vùng diện tích (area chart) thể hiện "Tài sản dài hạn"
geom_area(aes(y = tai_san_dai_han/1000, fill = "Dài hạn"), alpha = 0.4) +
# Thêm đường viền làm nổi bật rõ xu hướng của "Tài sản ngắn hạn"
geom_line(aes(y = tai_san_ngan_han/1000, color = "Ngắn hạn"), linewidth = 1.2) +
# Thêm đường viền làm nổi bật rõ xu hướng của "Tài sản dài hạn"
geom_line(aes(y = tai_san_dai_han/1000, color = "Dài hạn"), linewidth = 1.2) +
# Định dạng trục Y để CÓ DẤU CHẤM
scale_y_continuous(labels = number_format(big.mark = ".")) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "TÀI SẢN NGẮN HẠN VÀ DÀI HẠN (2015–2024)",
x = "Năm", y = "Giá trị (nghìn tỷ đồng)", color = "Loại tài sản") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024 trên trục hoành
scale_x_continuous(breaks = 2015:2024) +
# Áp dụng giao diện tối giản, loại bỏ khung và đường nền thừa
theme_minimal(base_family = "Times")Nhận xét: Trong giai đoạn 2015–2024, tài sản ngắn hạn chiếm tỷ trọng lớn và tăng mạnh qua các năm, đặc biệt từ 2018 đến 2022. Ngược lại, tài sản dài hạn duy trì ổn định với mức tăng nhẹ về cuối kỳ. Điều này cho thấy doanh nghiệp tập trung mở rộng quy mô hoạt động ngắn hạn và tăng khả năng thanh khoản, trong khi vẫn giữ cơ cấu tài sản dài hạn ổn định.
# Khởi tạo biểu đồ với dữ liệu bc
ggplot(bc) +
# Vẽ đường xu hướng thể hiện "Tổng tài sản"," doanh thu thuần"và lợi nhuận gộp
# Các giá trị được chia cho 1000 để đổi sang đơn vị nghìn tỷ đồng
geom_line(aes(x = nam, y = tong_tai_san/1000, color = "Tổng tài sản"), linewidth = 1.2) +
geom_line(aes(x = nam, y = doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu/1000,
color = "Doanh thu"), linewidth = 1.2) +
geom_line(aes(x = nam, y = loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu/1000,
color = "Lợi nhuận gộp"), linewidth = 1.2) +
# Thêm tiêu đề, phụ đề, nhãn trục và chú thích màu để biểu đồ rõ ràng
labs(title = "TỔNG HỢP: TÀI SẢN, DOANH THU, LỢI NHUẬN (2015–2024)",
subtitle = "Đơn vị: nghìn tỷ đồng", x = "Năm", y = "Giá trị (nghìn tỷ đồng)",
color = "Chỉ tiêu") +
# Hiển thị đầy năm
scale_x_continuous(breaks = 2015:2024) +
# Áp dụng giao diện tối giản, loại bỏ khung và đường nền thừa
theme_minimal(base_family = "Times")Nhận xét: Giai đoạn 2015–2019, doanh thu và lợi nhuận gộp tăng ổn định, song đến 2020–2021 có dấu hiệu suy giảm rõ rệt. Ngược lại, tổng tài sản tăng đều qua các năm, cho thấy doanh nghiệp mở rộng quy mô đầu tư dù hiệu quả sinh lời có biến động. Từ 2022–2024, cả doanh thu và lợi nhuận phục hồi, phản ánh sự ổn định trở lại trong hoạt động kinh doanh.
# Đặt ngưỡng
nguong_dt_tc <- 1000000000000 # 1 nghìn tỷ
# Tính toán
df_dt_tc_vuot_nguong <- bc %>%
# Lọc: theo Doanh thu Hoạt động Tài chính
filter(doanh_thu_hoat_dong_tai_chinh > nguong_dt_tc) %>%
# Tạo biến mới (chia Tỷ đồng)
mutate( Doanh_thu_TC_Ty_dong = doanh_thu_hoat_dong_tai_chinh / 1000000000,
Doanh_thu_Hien_thi = scales::number(Doanh_thu_TC_Ty_dong,
big.mark = ".", accuracy = 1)) %>%
arrange(nam) # Sắp xếp
# In kết quả
kable(df_dt_tc_vuot_nguong %>% select(nam, Doanh_thu_Hien_thi),
caption = "Năm có doanh thu hoạt động tài chính vượt 1.000 tỷ đồng",
col.names = c("Năm", "Doanh thu TC (Tỷ đồng)"),
align = "lr", booktabs = TRUE, row.names = FALSE) %>%
kable_styling(position = "center", latex_options = "hold_position")| Năm | Doanh thu TC (Tỷ đồng) |
|---|---|
| 2021 | 1.120 |
| 2022 | 1.091 |
| 2023 | 1.433 |
| 2024 | 1.067 |
# Khởi tạo (DỌC): X = Năm (Tên), Y = Doanh thu (Số)
ggplot(df_dt_tc_vuot_nguong, aes(x = reorder(factor(nam), Doanh_thu_TC_Ty_dong),
y = Doanh_thu_TC_Ty_dong)) +
# Vẽ đường: y = 0, yend = Doanh thu
geom_segment(aes(x = reorder(factor(nam), Doanh_thu_TC_Ty_dong),
xend = reorder(factor(nam), Doanh_thu_TC_Ty_dong),
y = 0, yend = Doanh_thu_TC_Ty_dong),color = "gray", linewidth = 1)+
# Vẽ điểm
geom_point(aes(color = factor(nam)), size = 5,show.legend = FALSE) +
# Thêm nhãn giá trị
geom_text(aes(label = Doanh_thu_Hien_thi), size = 4, hjust= -0.7) +
# Lật trục
coord_flip() +
# Tùy chỉnh trục Y
scale_y_continuous(labels = number_format(big.mark = "."),
expand = expansion(mult = c(0, 0.15))) +
# Thêm bảng màu
scale_color_brewer(palette = "Set2") +
# Tiêu đề
labs(title = "CÁC NĂM CÓ DOANH THU HOẠT ĐỘNG VƯỢT 1.000 TỶ ĐỒNG",
subtitle = "Biểu đồ Lollipop", x ="Năm", y ="Doanh thu hoạt động (tỷ đồng)") +
# Giao diện
theme_minimal(base_family = "Times") +
theme(panel.grid.major.y = element_blank(),panel.grid.minor.x = element_blank())