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!
CHƯƠNG 1: BỘ DỮ LIỆU CUSTOMER CHURN DATASET FOR LIFE INSURANCE INDUSTRY
Bộ dữ liệu Customer Churn Dataset for Life Insurance Industry được thu thập và công bố trên nền tảng Kaggle – một trong những kho dữ liệu mở lớn nhất thế giới dành cho học máy, thống kê và khoa học dữ liệu. Dữ liệu này mô phỏng hồ sơ của khách hàng trong lĩnh vực bảo hiểm nhân thọ, được sử dụng phổ biến để nghiên cứu hành vi rời bỏ (churn) của khách hàng và phân tích các yếu tố ảnh hưởng đến quyết định tiếp tục hay chấm dứt hợp đồng bảo hiểm. Bộ dữ liệu phản ánh thông tin của khách hàng trong lĩnh vực bảo hiểm nhân thọ, bao gồm nhiều đặc điểm nhân khẩu học, hành vi tiêu dùng và tình trạng rời bỏ dịch vụ (churn).
Tổng thể bộ dữ liệu chứa hàng nghìn quan sát (mỗi quan sát là một khách hàng), giúp phản ánh tương đối toàn diện về hành vi duy trì hợp đồng của người mua bảo hiểm. Dữ liệu được xử lý dưới dạng bảng, không chứa giá trị định danh cá nhân, đảm bảo tính ẩn danh và phù hợp cho mục đích học tập và nghiên cứu học thuật.
Mục tiêu của việc phân tích bộ dữ liệu này là nhằm tìm hiểu các yếu tố ảnh hưởng đến khả năng rời bỏ của khách hàng, qua đó giúp các công ty bảo hiểm: Xác định nhóm khách hàng có nguy cơ rời bỏ cao. Xây dựng chính sách chăm sóc khách hàng phù hợp. Cải thiện hiệu quả hoạt động kinh doanh và quản lý rủi ro.
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
library(skimr)
library(knitr)
# Xem cấu trúc của data frame:tổng số quan sát (dòng), tổng số biến (cột), tên của từng cột và quan trọng nhất là kiểu dữ liệu (data type) của cột đó (ví dụ: numeric, character, dttm).
thong_ke_skim_df <- skim(df) # Lưu kết quả
# In kết quả
kable( thong_ke_skim_df,
caption = "Bảng Thống kê Mô tả Chi tiết",
digits = 2)| skim_type | skim_variable | n_missing | complete_rate | character.min | character.max | character.empty | character.n_unique | character.whitespace | numeric.mean | numeric.sd | numeric.p0 | numeric.p25 | numeric.p50 | numeric.p75 | numeric.p100 | numeric.hist |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| character | Customer Name | 0 | 1 | 6 | 29 | 0 | 120428 | 0 | ||||||||
| character | Customer_Address | 0 | 1 | 19 | 68 | 0 | 200000 | 0 | ||||||||
| character | Company Name | 0 | 1 | 6 | 36 | 0 | 127489 | 0 | ||||||||
| character | Claim Reason | 0 | 1 | 5 | 7 | 0 | 4 | 0 | ||||||||
| character | Data confidentiality | 0 | 1 | 3 | 8 | 0 | 4 | 0 | ||||||||
| character | Premium/Amount Ratio | 0 | 1 | 3 | 20 | 0 | 1769 | 0 | ||||||||
| character | Claim Request output | 0 | 1 | 2 | 3 | 0 | 2 | 0 | ||||||||
| character | Churn | 0 | 1 | 2 | 3 | 0 | 2 | 0 | ||||||||
| numeric | Index | 0 | 1 | 99999.50 | 57735.17 | 0 | 49999.75 | 99999.5 | 149999.2 | 199999 | ▇▇▇▇▇ | |||||
| numeric | Claim Amount | 0 | 1 | 1120.48 | 796.66 | 1 | 245.00 | 1390.0 | 1844.0 | 2299 | ▇▂▁▆▆ | |||||
| numeric | Category Premium | 0 | 1 | 8963.78 | 6114.74 | 399 | 1875.00 | 14390.0 | 14390.0 | 14390 | ▅▂▁▁▇ | |||||
| numeric | BMI | 0 | 1 | 23.01 | 3.16 | 18 | 20.00 | 23.0 | 26.0 | 28 | ▇▅▆▅▆ |
Nhận xét Đâylà bước kiểm tra chất lượng dữ liệu quan trọng nhất. Nó cho biết:
Loại biến (Variable Type): Biến nào là số (num), số nguyên (int), chuỗi ký tự (chr), hay biến phân loại (factor). Điều này quyết định phép thống kê nào có thể áp dụng. Kích thước mẫu (N): Tổng số quan sát (hàng). Tên và Cấu trúc cột: Giúp xác nhận việc làm sạch tên cột có cần thiết không. Đối với một số biến không có ý nghĩa thống kê, dữ liệu sẽ cho ra ô trống.
# Đị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 của dữ liệu",
Gia_Tri = scales::comma(n_rows))
# In ra kết quả
kable(
df_rows,
caption = "Thông tin về Kích thước Dữ liệu (Số Dòng)",
col.names = c("Thông tin", "Giá trị"),
align = "lc",
row.names = FALSE)| Thông tin | Giá trị |
|---|---|
| Số dòng của dữ liệu | 200,000 |
# Số cột
n_cols <- ncol(df)
# Tạo data frame tạm thời
df_cols <- data.frame(
Thong_Tin = "Số cột của dữ liệu",
Gia_Tri = n_cols)
# In ra kết quả
kable(
df_cols,
caption = "Thông tin về Kích thước Dữ liệu",
col.names = c("Thông tin", "Giá trị"),
align = "lc", # Căn lề trái cho tên thông tin, căn lề giữa cho giá trị
row.names = FALSE)| Thông tin | Giá trị |
|---|---|
| Số cột của dữ liệu | 12 |
# Gọi thư viện.
library(knitr)
# 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 trong bộ dữ liệu",
"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 = "BẢNG GIẢI THÍCH CÁC BIẾN TRONG GIỮ LIỆU")| Tên Biến | Mô Tả |
|---|---|
| Index | Số thứ tự của khách hàng trong bộ dữ liệu |
| 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 = "BẢNG 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).
# Gọi thư viện.
library(knitr)
# 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 = "BẢNG THỐNG KÊ DỮ LIỆU CÓ BỊ THIẾU KHÔNG",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.
# Đế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 = "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ả: 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 = "Bảng Thống kê Mô tả Biến 'Claim Amount'",
# Đặ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: Phần lớn các yêu cầu bồi thường đề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 Category Premium
# Thống kê mô tả biến Category Premium
knitr::kable(data.frame( Chi_tieu = names(summary(df$`Category Premium`)),
Gia_tri = as.numeric(summary(df$`Category Premium`))),
# Đặt Đặt tiêu đề
caption = "Bảng Thống kê Mô tả Biến 'Category Premium'",
# Đặ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. | 399.00 |
| 1st Qu. | 1875.00 |
| Median | 14390.00 |
| Mean | 8963.78 |
| 3rd Qu. | 14390.00 |
| Max. | 14390.00 |
Kết luận: Phần lớn khách hàng đều đóng mức phí bảo hiểm cao nhất (khoảng 14.390$). Giá trị trung bình thấp hơn trung vị do ảnh hưởng của một nhóm nhỏ khách hàng có mức phí thấp, cho thấy sự tập trung mạnh vào nhóm khách hàng cao cấp.
# 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 = "Bảng Thống kê Mô tả 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ê.
# Đếm tần suất của biến Claim Reason
claim_table <- table(df$`Claim Reason`)
# In bảng đẹp
kable(claim_table, caption = "Bảng tần suất của biến Claim Reason",
col.names = c("Lý do yêu cầu bồi thường", "Tần suất"),
align = "lc")| Lý do yêu cầu bồi thường | Tần suất |
|---|---|
| Medical | 109863 |
| Other | 30187 |
| Phone | 30016 |
| Travel | 29934 |
Medical (109863): Có 109863 trường hợp yêu cầu bồi thường liên quan đến lý do Y tế/Sức khỏe.
Other (30187): Có 30187 trường hợp yêu cầu bồi thường thuộc các lý do Khác (không được phân loại cụ thể).
Phone (30016): Có 30016 trường hợp yêu cầu bồi thường liên quan đến Điện thoại (có thể là hư hỏng, mất mát thiết bị, hoặc các vấn đề liên quan đến dịch vụ).
Travel (29934): Có 29934 trường hợp yêu cầu bồi thường liên quan đến Du lịch (có thể là hủy chuyến, mất hành lý, trễ giờ, v.v.).
Lý do phổ biến nhất là 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.
# Số lần xuất hiện của các giá trị trong biến Data confidentiality
conf_table <- table(df$`Data confidentiality`)
# In bảng đẹp
kable(conf_table,
caption = "Bảng tần suất của biến Data confidentiality",
col.names = c("Mức độ bảo mật dữ liệu", "Tần suất"),
align = "lc")| Mức độ bảo mật dữ liệu | 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.
# Số lần xuất hiện của các giá trị trong biến Claim Request output
claim_output_table <- table(df$`Claim Request output`)
# In bảng đẹp
kable(claim_output_table,
caption = "Bảng tần suất của biến Claim Request output",
col.names = c("Kết quả yêu cầu bồi thường", "Tần suất"),
align = "lc")| Kết quả yêu cầu bồi thường | 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).
# Số lần xuất hiện của các giá trị trong biến Churn
# 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 = "Bảng tần suất của 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).
Đ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.
options(repos = c(CRAN = "https://cloud.r-project.org"))
install.packages("fastDummies")
install.packages("tidyr")
install.packages("janitor")## package 'janitor' successfully unpacked and MD5 sums checked
##
## The downloaded binary packages are in
## C:\Users\DELL\AppData\Local\Temp\RtmpcZo00j\downloaded_packages
# 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)
# In kết quả
kable(data.frame("Tên sau chuẩn hóa" = names(df_clean)),
caption = "Kết quả chuẩn hóa")| Tên.sau.chuẩn.hóa |
|---|
| index |
| customer_name |
| customer_address |
| company_name |
| claim_reason |
| data_confidentiality |
| claim_amount |
| category_premium |
| premium_amount_ratio |
| claim_request_output |
| bmi |
| churn |
# 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))
# In 5 dòng đầu tiên của dữ liệu đã làm sạch
kable(head(df_clean, 5),caption = "5 dòng đầu sau khi loại bỏ")| claim_reason | data_confidentiality | claim_amount | category_premium | premium_amount_ratio | claim_request_output | bmi | churn |
|---|---|---|---|---|---|---|---|
| Travel | Low | 377 | 4794 | 0.0786400 | No | 21 | Yes |
| Medical | High | 1440 | 14390 | 0.1000695 | No | 24 | Yes |
| Phone | Medium | 256 | 1875 | 0.1365333 | No | 18 | Yes |
| Phone | Medium | 233 | 1875 | 0.1242667 | No | 24 | Yes |
| Phone | Medium | 239 | 1875 | 0.1274667 | No | 21 | Yes |
# 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 khi mã hóa")| 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.
# 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 khi 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)
# Thống kê số lượng theo từng mức độ
kable(
data.frame("Mức độ" = names(summary(df_clean$data_confid_ordinal)),
"Số lượng" = as.numeric(summary(df_clean$data_confid_ordinal))),
caption = "Thống kê số lượng theo từng mức độ")| Mức.độ | Số.lượng |
|---|---|
| Very low | 30187 |
| Low | 29934 |
| Medium | 30016 |
| High | 109863 |
# 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 khi 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 |
# 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) %>%
# Sử dụng hàm in kable đẹp
kable( caption = "Kiểm tra 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 kết quả đã có trong bộ dữ liệu chưa
knitr::kable( data.frame("Tên Biến" = names(df_clean)),
caption = "Danh sách các biến trong df_clean",
booktabs = TRUE)| Tên.Biến |
|---|
| claim_reason |
| data_confidentiality |
| claim_amount |
| category_premium |
| premium_amount_ratio |
| claim_request_output |
| bmi |
| churn |
| claim_output_encoded |
| churn_encoded |
| data_confid_ordinal |
| claim_reason_Medical |
| claim_reason_Other |
| claim_reason_Phone |
| claim_reason_Travel |
| profitability |
# 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 = "Bảng Thống kê Mô tả Biến 'Profitability'",
col.names = c("Chỉ tiêu Thống kê", "Giá trị"),
digits = 2,
align = "lr")| Chỉ tiêu Thống kê | 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 kết quả đã có trong bộ dữ liệu chưa
knitr::kable( data.frame("Tên Biến" = names(df_clean)),
caption = "Danh sách các biến trong df_clean ",
booktabs = TRUE)| Tên.Biến |
|---|
| claim_reason |
| data_confidentiality |
| claim_amount |
| category_premium |
| premium_amount_ratio |
| claim_request_output |
| bmi |
| churn |
| claim_output_encoded |
| churn_encoded |
| data_confid_ordinal |
| claim_reason_Medical |
| claim_reason_Other |
| claim_reason_Phone |
| claim_reason_Travel |
| profitability |
| loss_ratio |
# 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 = "Bảng Thống kê Mô tả Biến 'Loss Ratio'",
col.names = c("Chỉ tiêu Thống kê", "Giá trị"),
digits = 4,
align = "lr")| Chỉ tiêu Thống kê | 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))
# In kết luận
cat("Kết luận: Tìm thấy tổng cộng", so_luong_inf, "dòng có 'loss_ratio'.")## Kết luận: Tìm thấy tổng cộng 0 dòng có 'loss_ratio'.
# 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), # +0.1 để bao gồm cả giá trị Max
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 = 8 ) +
# 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ả: Dữ liệu cho thấy có 127,272 khách hàng đã “Rời bỏ” và 72,728 khách hàng “Ở lại”. 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 = 7) +
# 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 4 cột dummy (Pivot Longer)",
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"),
# Làm tròn số % cho đẹp
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 = 10) +
# 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 = "Bảng 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" ),
# Làm tròn số %
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 = 10) +
# 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")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 = "Bảng 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), # Làm tròn %
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 = 10) +
# 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 = "Bảng 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 = 9, 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", # Cột mới chứa TÊN
values_to = "is_reason" ) %>% # Cột mới chứa GIÁ TRỊ (0/1)
# 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 = "Bảng Thống kê Tỷ lệ Kết quả 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 = 9, 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 (Doanh thu) theo từng Nhóm phí",
col.names = c("Nhóm Phí", "Tổng Phí (Doanh thu)"),
digits = 0, # Không cần số thập phân
align = "lr", booktabs = TRUE)| Nhóm Phí | Tổng Phí (Doanh thu) |
|---|---|
| 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 = 7) +
# 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 = 7) +
# 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 (Theo Kết quả Yêu cầu)",
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 = 8) +
# Đị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 TRUNG BÌNH ('Được chấp thuận' vs 'Bị từ chối')",
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 = 8, 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 = 8, 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 = 8) +
# Đổ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 = 7, show.legend = FALSE) +
# Thêm nhãn số (số lượng rời bỏ)
geom_text(aes(label = Total_Churned), color = "black", size = 7, 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 = 8 ) +
# Đặ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 = 8 ) +
# 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())CHƯƠNG 2: PHÂN TÍCH BÁO CÁO TÀI CHÍNH ABS
Bộ dữ liệu bctcabs.xlsx được sử dụng trong tiểu luận này được thu thập từ các báo cáo tài chính công bố công khai của công ty bia SABECO trong giai đoạn 2015–2024. Dữ liệu phản ánh tình hình hoạt động kinh doanh của doanh nghiệp qua nhiều chỉ tiêu tài chính quan trọng như tổng tài sản, nợ phải trả, vốn chủ sở hữu, doanh thu, lợi nhuận sau thuế và các tỷ suất phản ánh hiệu quả hoạt động. Việc sử dụng bộ dữ liệu này trong nghiên cứu nhằm phân tích xu hướng biến động tài chính và hiệu quả kinh doanh của SABECO qua từng năm, đồng thời xác định các yếu tố ảnh hưởng đến khả năng sinh lời của doanh nghiệp. Thông qua các chỉ tiêu tài chính, nghiên cứu giúp đánh giá sức khỏe tài chính, năng lực quản lý và hiệu quả sử dụng vốn của công ty trong bối cảnh cạnh tranh gay gắt của ngành đồ uống Việt Nam. Ngoài ra, việc phân tích bộ dữ liệu này còn mang ý nghĩa thực tiễn khi minh họa ứng dụng của phân tích dữ liệu tài chính trong nghiên cứu doanh nghiệp, đồng thời hỗ trợ đề xuất các giải pháp nâng cao hiệu quả hoạt động và khả năng sinh lợi của SABECO trong những năm tới.
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")Ý nghĩa thống kê: Đây là bước “nạp” dữ liệu thô vào môi trường R để chuẩn bị phân tích.
library(skimr)
library(knitr)
# Xem cấu trúc của data frame:tổng số quan sát (dòng), tổng số biến (cột), tên của từng cột và quan trọng nhất là kiểu dữ liệu (data type) của cột đó (ví dụ: numeric, character, dttm).
thong_ke_skim <- skim(bc_raw) # Lưu kết quả
# In kết quả
kable( thong_ke_skim,
caption = "Bảng Thống kê Mô tả Chi tiết",
digits = 2)| skim_type | skim_variable | n_missing | complete_rate | numeric.mean | numeric.sd | numeric.p0 | numeric.p25 | numeric.p50 | numeric.p75 | numeric.p100 | numeric.hist |
|---|---|---|---|---|---|---|---|---|---|---|---|
| numeric | Năm/Biến | 0 | 1 | 2019.5 | 3.03 | 2015 | 2017.25 | 2019.5 | 2021.75 | 2024 | ▇▇▇▇▇ |
| numeric | Tài sản ngắn hạn | 0 | 1 | 19132051618009.1 | 6078828813938.14 | 10714345997642 | 13937287658793.00 | 19338991982036.5 | 24519307933645.50 | 26860224573663 | ▇▂▅▂▇ |
| numeric | Tiền và các khoản tương đương tiền | 0 | 1 | 4252031557076.4 | 1503589362411.39 | 2636774241245 | 3485232684179.50 | 4092674403639.5 | 4474974146778.75 | 7935974303078 | ▇▇▂▁▂ |
| numeric | Các khoản đầu tư tài chính ngắn hạn | 0 | 1 | 11587072404432.7 | 6567659498445.56 | 942766940162 | 6805148028642.75 | 13470323091575.0 | 16884989044275.25 | 19411469500000 | ▃▃▁▃▇ |
| numeric | Tài sản dài hạn | 0 | 1 | 8061028665165.1 | 582648368073.17 | 7503219247991 | 7626636934369.25 | 7829732452665.0 | 8361345578723.50 | 9377631443590 | ▇▁▃▁▁ |
| numeric | Tổng tài sản | 0 | 1 | 27193080283174.2 | 5731623073747.43 | 19192865179330 | 22101952530485.75 | 27168724434701.5 | 32701310866594.50 | 34465075615756 | ▇▂▅▂▇ |
| numeric | Tổng nợ phải trả | 0 | 1 | 7650108089131.3 | 1213389936635.51 | 6159696384430 | 6791321090970.75 | 7550192321990.0 | 8401659875944.50 | 9874229696363 | ▇▃▂▃▂ |
| numeric | Vốn chủ sở hữu | 0 | 1 | 19542964714042.9 | 4895696529753.96 | 12433180070596 | 14843343168253.25 | 20645761723646.0 | 23976516312794.25 | 25485157894867 | ▇▂▂▅▇ |
| numeric | Doanh thu thuần về bán hàng | ||||||||||
| và cung cấp dịch vụ | 0 | 1 | 31764670136052.8 | 3952939590434.11 | 26373746293858 | 28586334698312.00 | 31220547627215.5 | 34843855757524.25 | 37899059501295 | ▇▅▂▅▅ | |
| numeric | Lợi nhuận gộp về bán hàng | ||||||||||
| và cung cấp dịch vụ | 0 | 1 | 8761549027244.7 | 979687902289.57 | 7557743622179 | 8129988160735.50 | 8683306424513.0 | 9261488052258.25 | 10770706927084 | ▇▅▇▂▂ | |
| numeric | Doanh thu hoạt động tài chính | 0 | 1 | 888020478391.0 | 313055858311.62 | 418646983429 | 660523055065.25 | 932127070082.5 | 1084690114858.00 | 1432568520354 | ▅▅▅▇▂ |
Đây là bước kiểm tra dữ liệu (data sanity check) then chốt. Nó giúp xác nhận các cột chứa chỉ tiêu tài chính (ví dụ: “Tài sản”, “Nợ”) đã được R nhận diện đúng là kiểu numeric. Nếu R đọc nhầm một cột số thành character, điều đó cho thấy sự tồn tại của các ký tự phi số (ví dụ: dấu phẩy, “N/A”) cần phải được làm sạch trước khi tính toán.
Table: 10 dòng đầu tiên của bộ dữ liệu thô (bc_raw)
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ụ| Doanh thu hoạt động tài chính| |——–:|—————-:|———————————-:|———————————–:|—————:|————–:|—————-:|————–:|———————————————-:|——————————————–:|—————————–:| | 2015| 12194294244759| 7935974303078| 942766940162| 9377631443590| 21571925688349| 7507221969018| 14064666319331| 27144301587344| 7557743622179| 418646983429| | 2016| 10714345997642| 3444825444503| 3174321174216| 8478519181688| 19192865179330| 6759685108734| 12433180070596| 30568677767775| 8267535125754| 751041069989| | 2017| 13686327476651| 2636774241245| 6558801231269| 8327361633259| 22013689109910| 7593162674962| 14420489034948| 34438171048592| 8865518064577| 506107630554| | 2018| 14690168205219| 4467391585137| 7544188420764| 7676574586994| 22366742792213| 6254837224044| 16111905568169| 35948552561947| 8084139172396| 630350383424| | 2019| 19164602511633| 4115884646637| 12393226750273| 7797873582412| 26962476094045| 6886229037681| 20076247056364| 37899059501295| 9550628692014| 889852505295| | 2020| 19513381452440| 2726137088387| 14547419432877| 7861591322918| 27374972775358| 6159696384430| 21215276390928| 27961323837011| 8501094784449| 974401634870| | 2021| 22877033322264| 3606454403209| 16991239000000| 7609991050161| 30487024372425| 7892238669264| 22594785703161| 26373746293858| 7608564811493| 1119597121857| | 2022| 26860224573663| 4069464160642| 19411469500000| 7604851042093| 34465075615756| 9874229696363| 24590845919393| 34979083993835| 10770706927084| 1090560762647| | 2023| 26553405591714| 5039908030600| 17741052417665| 7503219247991| 34056624839705| 8571466944838| 25485157894867| 30461367282215| 9091362504235| 1432568520354| | 2024| 25066732804106| 4477501667326| 16566239177101| 8372673560545| 33439406364651| 9002313181979| 24437093182672| 31872417486656| 9318196568266| 1067078171491|
Trực quan số liệu 10 năm của Báo Cáo Tài Chính ABS.
# 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ố 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 |
# 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 = "Bảng 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 = "BẢNG 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.
# Đế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
Ý nghĩa thống kê: Cung cấp cái nhìn tổng quan đầu tiên về phân phối (distribution) của dữ liệu:
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.
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2015 2017 2020 2020 2022 2024
Đây là biến năm 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ị" = as.vector(sum_data)) %>%
# In kết quả
kable( caption = "Bảng 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. | 10714345997642 |
| 1st Qu. | 13937287658793 |
| Median | 19338991982037 |
| Mean | 19132051618009 |
| 3rd Qu. | 24519307933646 |
| Max. | 26860224573663 |
Nhận xét: Biến Tài sản ngắn hạn có phân bố tương đối đối xứng, được xác định bởi sự tương đồng chặt chẽ giữa Giá trị Trung bình (\(Mean = 1.913 \times 10^{13}\)) và Giá trị Trung vị (\(Median = 1.934 \times 10^{13}\)).
Giá trị tài sản ngắn hạn của các quan sát dao động trong khoảng từ \(1.071 \times 10^{13}\) (thấp nhất) đến \(2.686 \times 10^{13}\) (cao nhất). Phần lớn dữ liệu (50% quan sát ở giữa) tập trung trong khoảng tứ phân vị, từ \(1.394 \times 10^{13}\) (Phân vị 25%) đến \(2.452 \times 10^{13}\) (Phân vị 75%).
Kết luận: Kết quả này cho thấy, về tổng thể, dữ liệu “Tài sản ngắn hạn” được phân bổ khá đồng đều, tập trung quanh giá trị trung tâm (khoảng \(1.9 \times 10^{13}\)). Việc Trung bình và Trung vị gần nhau cho thấy không có các giá trị ngoại lai (outlier) quá cực đoan (quá cao hoặc quá thấp) làm ảnh hưởng và bóp méo (skew) phân phối chung của bộ dữ liệu.
# 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ị" = as.vector(sum_data)) %>%
# In kết quả
kable( caption = "Bảng 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. | 2636774241245 |
| 1st Qu. | 3485232684180 |
| Median | 4092674403640 |
| Mean | 4252031557076 |
| 3rd Qu. | 4474974146779 |
| Max. | 7935974303078 |
Nhận xét:Biến Tiền và các khoản tương đương tiền có phân bố gần như đối xứng, được thể hiện qua sự tương đồng chặt chẽ giữa Giá trị Trung bình (\(Mean = 4.252 \times 10^{12}\)) và Giá trị Trung vị (\(Median = 4.093 \times 10^{12}\)).
Giá trị của biến này dao động trong khoảng từ \(2.637 \times 10^{12}\) (thấp nhất) đến \(7.936 \times 10^{12}\) (cao nhất). 50% dữ liệu trung tâm tập trung rất chặt chẽ trong khoảng tứ phân vị, từ \(3.485 \times 10^{12}\) (Phân vị 25%) đến \(4.475 \times 10^{12}\) (Phân vị 75%).
Kết luận: Kết quả này cho thấy dữ liệu phân bổ rất tập trung quanh giá trị trung tâm (khoảng \(4.1 \times 10^{12}\) đến \(4.2 \times 10^{12}\)). Việc Giá trị Trung bình (\(Mean\)) chỉ cao hơn một chút so với Trung vị (\(Median\)) cho thấy dữ liệu có độ lệch phải không đáng kể, chứng tỏ không có các giá trị ngoại lai cực đoan làm ảnh hưởng và bóp méo phân phối chung.
# 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ị" = as.vector(sum_data)) %>%
# In kết quả
kable( caption = "Bảng 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. | 942766940162 |
| 1st Qu. | 6805148028643 |
| Median | 13470323091575 |
| Mean | 11587072404433 |
| 3rd Qu. | 16884989044275 |
| Max. | 19411469500000 |
Nhận xét:Biến Các khoản đầu tư tài chính ngắn hạn có phân bố lệch trái (left-skewed), được thể hiện rõ qua việc Giá trị Trung bình (\(Mean = 1.159 \times 10^{13}\)) thấp hơn đáng kể so với Giá trị Trung vị (\(Median = 1.347 \times 10^{13}\)).
Giá trị của biến này dao động trong khoảng từ \(9.428 \times 10^{11}\) (thấp nhất) đến \(1.941 \times 10^{13}\) (cao nhất). 50% dữ liệu trung tâm (khoảng tứ phân vị) nằm trong khoảng từ \(6.805 \times 10^{12}\) (Phân vị 25%) đến \(1.688 \times 10^{13}\) (Phân vị 75%).
Kết luận: Kết quả này cho thấy, về tổng thể, phần lớn dữ liệu tập trung ở mức giá trị cao, nhưng bị kéo về bên trái (giá trị thấp) bởi một số quan sát. Việc Trung bình bị kéo xuống thấp hơn Trung vị cho thấy sự ảnh hưởng của các giá trị nhỏ (đặc biệt là giá trị Min), làm bóp méo (skew) phân phối chung.
# 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ị" = as.vector(sum_data)) %>%
# In kết quả
kable( caption = "Bảng 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. | 7503219247991 |
| 1st Qu. | 7626636934369 |
| Median | 7829732452665 |
| Mean | 8061028665165 |
| 3rd Qu. | 8361345578724 |
| Max. | 9377631443590 |
Nhận xét:Biến Tài sản dài hạn có phân bố tương đối đối xứng, với Giá trị Trung bình (\(Mean = 8.061 \times 10^{12}\)) và Giá trị Trung vị (\(Median = 7.830 \times 10^{12}\)) khá gần nhau.
Giá trị của biến này dao động trong khoảng từ \(7.503 \times 10^{12}\) (thấp nhất) đến \(9.378 \times 10^{12}\) (cao nhất). Điều đáng chú ý là 50% dữ liệu trung tâm tập trung rất chặt chẽ trong khoảng tứ phân vị, từ \(7.627 \times 10^{12}\) (Phân vị 25%) đến \(8.361 \times 10^{12}\) (Phân vị 75%).
Kết luận: Kết quả này cho thấy, về tổng thể, dữ liệu “Tài sản dài hạn” rất đồng đều, có độ phân tán thấp. Việc Trung bình chỉ cao hơn Trung vị một chút cho thấy có độ lệch phải không đáng kể, nhưng nhìn chung phân phối rất tập trung và không có dấu hiệu bị bóp méo (skew) bởi các giá trị ngoại lai.
# 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ị" = as.vector(sum_data)) %>%
# In kết quả
kable( caption = "Bảng 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. | 19192865179330 |
| 1st Qu. | 22101952530486 |
| Median | 27168724434702 |
| Mean | 27193080283174 |
| 3rd Qu. | 32701310866595 |
| Max. | 34465075615756 |
# 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ị" = as.vector(sum_data)) %>%
# In kết quả
kable( caption = "Bảng 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. | 6159696384430 |
| 1st Qu. | 6791321090971 |
| Median | 7550192321990 |
| Mean | 7650108089131 |
| 3rd Qu. | 8401659875945 |
| Max. | 9874229696363 |
Nhận xét: Biến Tổng nợ phải trả có phân bố tương đối đối xứng, được thể hiện qua sự tương đồng rất chặt chẽ giữa Giá trị Trung bình (\(Mean = 7.650 \times 10^{12}\)) và Giá trị Trung vị (\(Median = 7.550 \times 10^{12}\)).
Giá trị tổng nợ phải trả của các quan sát dao động trong khoảng từ \(6.160 \times 10^{12}\) (thấp nhất) đến \(9.874 \times 10^{12}\) (cao nhất). Phần lớn dữ liệu (50% quan sát ở giữa) tập trung trong khoảng tứ phân vị, từ \(6.791 \times 10^{12}\) (Phân vị 25%) đến \(8.402 \times 10^{12}\) (Phân vị 75%).
Kết luận: Kết quả này cho thấy, về tổng thể, dữ liệu “Tổng nợ phải trả” được phân bổ khá đồng đều. Việc Trung bình chỉ cao hơn Trung vị một chút cho thấy độ lệch phải là không đáng kể, chứng tỏ bộ dữ liệu không có các giá trị ngoại lai (outlier) cực đoan làm bóp méo (skew) phân phối chung.
# 1. Tính toán summary
sum_data <- summary(bc_raw$`Vốn chủ sở hữu`)
# 2. Chuyển sang data.frame và in kable
data.frame(
"Chỉ tiêu" = names(sum_data),
"Giá trị" = as.vector(sum_data)
) %>%
kable(
caption = "Bảng 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. | 12433180070596 |
| 1st Qu. | 14843343168253 |
| Median | 20645761723646 |
| Mean | 19542964714043 |
| 3rd Qu. | 23976516312794 |
| Max. | 25485157894867 |
Nhận xét: Biến Vốn chủ sở hữu có phân bố lệch trái, được xác định rõ khi Giá trị Trung bình (\(Mean = 1.954 \times 10^{13}\)) thấp hơn đáng kể so với Giá trị Trung vị (\(Median = 2.065 \times 10^{13}\)).
Giá trị vốn chủ sở hữu dao động trong khoảng từ \(1.243 \times 10^{13}\) (thấp nhất) đến \(2.549 \times 10^{13}\) (cao nhất). 50% dữ liệu trung tâm (khoảng tứ phân vị) nằm trong khoảng từ \(1.484 \times 10^{13}\) (Phân vị 25%) đến \(2.398 \times 10^{13}\) (Phân vị 75%).
Kết luận: Kết quả này cho thấy, về tổng thể, phần lớn dữ liệu “Vốn chủ sở hữu” tập trung ở mức giá trị cao (quanh Trung vị \(2.065 \times 10^{13}\)). Tuy nhiên, sự xuất hiện của các giá trị thấp hơn (đặc biệt là giá trị Min) đã “kéo” Giá trị Trung bình (\(Mean\)) xuống thấp hơn. Điều này cho thấy sự bóp méo (skew) về phía bên trái của phân phối.
# 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ị" = as.vector(sum_data)) %>%
# In kết quả
kable( caption = "Bảng 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. | 26373746293858 |
| 1st Qu. | 28586334698312 |
| Median | 31220547627216 |
| Mean | 31764670136053 |
| 3rd Qu. | 34843855757524 |
| Max. | 37899059501295 |
Nhận xétBiến Doanh thu thuần về bán hàng và cung cấp dịch vụ có phân bố tương đối đối xứng, được thể hiện qua sự tương đồng chặt chẽ giữa Giá trị Trung bình (\(Mean = 3.176 \times 10^{13}\)) và Giá trị Trung vị (\(Median = 3.122 \times 10^{13}\)).
Giá trị doanh thu thuần của các quan sát dao động trong khoảng từ \(2.637 \times 10^{13}\) (thấp nhất) đến \(3.790 \times 10^{13}\) (cao nhất). Phần lớn dữ liệu (50% quan sát ở giữa) tập trung trong khoảng tứ phân vị, từ \(2.859 \times 10^{13}\) (Phân vị 25%) đến \(3.484 \times 10^{13}\) (Phân vị 75%).
Kết luận: Kết quả này cho thấy, về tổng thể, dữ liệu “Doanh thu thuần” được phân bổ khá đồng đều và tập trung quanh giá trị trung tâm (khoảng \(3.1 \times 10^{13}\)). Việc Trung bình chỉ cao hơn Trung vị một chút cho thấy có độ lệch phải không đáng kể, chứng tỏ bộ dữ liệu không có các giá trị ngoại lai (outlier) cực đoan làm bóp méo (skew) phân phối chung.
# 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ị" = as.vector(sum_data)) %>%
# In kết quả
kable(caption = "Bảng 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. | 7557743622179 |
| 1st Qu. | 8129988160736 |
| Median | 8683306424513 |
| Mean | 8761549027245 |
| 3rd Qu. | 9261488052258 |
| Max. | 10770706927084 |
Nhận xét: Biến Lợi nhuận gộp về bán hàng và cung cấp dịch vụ có phân bố tương đối đối xứng, được thể hiện qua sự tương đồng rất chặt chẽ giữa Giá trị Trung bình (\(Mean = 8.762 \times 10^{12}\)) và Giá trị Trung vị (\(Median = 8.683 \times 10^{12}\)).
Giá trị lợi nhuận gộp của các quan sát dao động trong khoảng từ \(7.558 \times 10^{12}\) (thấp nhất) đến \(1.077 \times 10^{13}\) (cao nhất). Phần lớn dữ liệu (50% quan sát ở giữa) tập trung trong khoảng tứ phân vị, từ \(8.130 \times 10^{12}\) (Phân vị 25%) đến \(9.261 \times 10^{12}\) (Phân vị 75%).
Kết luận: Kết quả này cho thấy, về tổng thể, dữ liệu “Lợi nhuận gộp” được phân bổ khá đồng đều, tập trung quanh giá trị trung tâm (khoảng \(8.7 \times 10^{12}\)). Việc Trung bình chỉ cao hơn Trung vị một chút cho thấy có độ lệch phải không đáng kể, chứng tỏ bộ dữ liệu không có các giá trị ngoại lai (outlier) cực đoan làm bóp méo (skew) phân phối chung.
# 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ị" = as.vector(sum_data)) %>%
# In kết quả
kable(caption = "Bảng 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. | 418646983429 |
| 1st Qu. | 660523055065 |
| Median | 932127070083 |
| Mean | 888020478391 |
| 3rd Qu. | 1084690114858 |
| Max. | 1432568520354 |
Nhận xét: Biến Doanh thu hoạt động tài chính có phân bố lệch trái (left-skewed), được xác định khi Giá trị Trung bình (\(Mean = 8.880 \times 10^{11}\)) thấp hơn so với Giá trị Trung vị (\(Median = 9.321 \times 10^{11}\)).
Giá trị doanh thu tài chính dao động trong khoảng từ \(4.186 \times 10^{11}\) (thấp nhất) đến \(1.433 \times 10^{12}\) (cao nhất). 50% dữ liệu trung tâm (khoảng tứ phân vị) nằm trong khoảng từ \(6.605 \times 10^{11}\) (Phân vị 25%) đến \(1.085 \times 10^{12}\) (Phân vị 75%).
Kết luận: Kết quả này cho thấy, về tổng thể, phần lớn dữ liệu “Doanh thu hoạt động tài chính” tập trung ở mức giá trị cao (quanh Trung vị \(9.321 \times 10^{11}\)). Tuy nhiên, sự xuất hiện của các giá trị thấp hơn (đặc biệt là giá trị Min) đã “kéo” Giá trị Trung bình (\(Mean\)) xuống thấp hơn. Điều này cho thấy sự bóp méo (skew) về phía bên trái của phân phối.
# gọi thư viện
library(readxl)
# đọ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 = "Bảng 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 = "lr", booktabs = TRUE, row.names = FALSE )| 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 = "Bảng Danh Sách Tên Cột Đã Được Chuẩn Hóa ('bc')",
col.names = c("STT", "Tên Biến (Đã Làm Sạch)"),
align = "lr", 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 thống kê: Giúp dễ dàng hơn trong việc viết và phân tích dữ liệu.
Ý nghĩa: Đâ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.
Kết quả: Không có biến nào vi phạm.
Ý 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.
Ý nghãi: Đây là bước làm sạch dữ liệu (data cleaning) an toàn. Các hàng trống không chứa bất kỳ thông tin thống kê nào . Chúng là “nhiễu” (noise) và có thể gây lỗi trong một số thuật toán. Việc loại bỏ chúng giúp dọn dẹp bộ dữ liệu mà không làm mất thông tin vì chúng không đại diện cho một quan sát hợp lệ nào.
# Sử dụng hàm mutate (từ gói dplyr) để tạo một cột mới tên là TyLeLoiNhuanGop, với giá trị được tính bằng cách lấy cột "lợi nhuận gộp về bán hàng và cung cấp dịch vụ" chia cho cột "doanh thu thuần về bán hàng và cung cấp dịch vụ"
bc <- bc %>%
mutate(TyLeLoiNhuanGop = 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 = "Bảng Danh Sách Tên Cột Đã Được Chuẩn Hóa (Bao gồm biến mới)",
col.names = c("STT", "Tên Biến (Đã Làm Sạch)"),
align = "lr", 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 | TyLeLoiNhuanGop |
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.
# Tạo cột mới quy mô. 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
bc <- bc %>%
mutate(QuyMo = 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(QuyMo) %>%
mutate(Ti_Le = n / sum(n),
Ti_Le_Phan_Tram = scales::percent(Ti_Le, accuracy = 0.1)) %>%
# Sắp xếp lại cột
select(QuyMo, n, Ti_Le_Phan_Tram) %>%
# Im kable
kable( caption = "Bảng Thống kê 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% |
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")
# Á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 = "BẢNG TÓM TẮT CẤU TRÚC DỮ LIỆU (Sau khi chuyển đổi kiể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 |
| TyLeLoiNhuanGop | numeric |
| QuyMo | character |
# Bỏ 2 biến: quy_mo và nam
bc_selected <- bc %>%
select(-QuyMo, -Nam)
# Tóm tắt dữ liệu với skimr
skim_data <- skim(bc_selected)
# In ra bảng thống kê
kable(skim_data,
caption = "Bảng Thống kê Mô tả Chi tiết (Đơn vị: Tỷ đồng)",
digits = 2)| skim_type | skim_variable | n_missing | complete_rate | numeric.mean | numeric.sd | numeric.p0 | numeric.p25 | numeric.p50 | numeric.p75 | numeric.p100 | numeric.hist |
|---|---|---|---|---|---|---|---|---|---|---|---|
| numeric | tai_san_ngan_han | 0 | 1 | 19132051618009.10 | 6078828813938.14 | 10714345997642.00 | 13937287658793.00 | 19338991982036.50 | 24519307933645.5 | 26860224573663.00 | ▇▂▅▂▇ |
| numeric | tien_va_cac_khoan_tuong_duong_tien | 0 | 1 | 4252031557076.40 | 1503589362411.39 | 2636774241245.00 | 3485232684179.50 | 4092674403639.50 | 4474974146778.8 | 7935974303078.00 | ▇▇▂▁▂ |
| numeric | cac_khoan_dau_tu_tai_chinh_ngan_han | 0 | 1 | 11587072404432.70 | 6567659498445.56 | 942766940162.00 | 6805148028642.75 | 13470323091575.00 | 16884989044275.2 | 19411469500000.00 | ▃▃▁▃▇ |
| numeric | tai_san_dai_han | 0 | 1 | 8061028665165.10 | 582648368073.17 | 7503219247991.00 | 7626636934369.25 | 7829732452665.00 | 8361345578723.5 | 9377631443590.00 | ▇▁▃▁▁ |
| numeric | tong_tai_san | 0 | 1 | 27193080283174.20 | 5731623073747.43 | 19192865179330.00 | 22101952530485.75 | 27168724434701.50 | 32701310866594.5 | 34465075615756.00 | ▇▂▅▂▇ |
| numeric | tong_no_phai_tra | 0 | 1 | 7650108089131.30 | 1213389936635.51 | 6159696384430.00 | 6791321090970.75 | 7550192321990.00 | 8401659875944.5 | 9874229696363.00 | ▇▃▂▃▂ |
| numeric | von_chu_so_huu | 0 | 1 | 19542964714042.90 | 4895696529753.96 | 12433180070596.00 | 14843343168253.25 | 20645761723646.00 | 23976516312794.2 | 25485157894867.00 | ▇▂▂▅▇ |
| numeric | doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu | 0 | 1 | 31764670136052.80 | 3952939590434.11 | 26373746293858.00 | 28586334698312.00 | 31220547627215.50 | 34843855757524.2 | 37899059501295.00 | ▇▅▂▅▅ |
| numeric | loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu | 0 | 1 | 8761549027244.70 | 979687902289.57 | 7557743622179.00 | 8129988160735.50 | 8683306424513.00 | 9261488052258.2 | 10770706927084.00 | ▇▅▇▂▂ |
| numeric | doanh_thu_hoat_dong_tai_chinh | 0 | 1 | 888020478391.00 | 313055858311.62 | 418646983429.00 | 660523055065.25 | 932127070082.50 | 1084690114858.0 | 1432568520354.00 | ▅▅▅▇▂ |
| numeric | TyLeLoiNhuanGop | 0 | 1 | 0.28 | 0.03 | 0.22 | 0.26 | 0.28 | 0.3 | 0.31 | ▂▃▂▃▇ |
Kết quả: ở đây ta bỏ hai biến “quy mô” và “năm” ra vì hai biến này không có ý nghĩa thống kê. Từ đó nhìn được thống kê cơ bản 1 cách khách quan của các biến còn lại, bao gồm các biến vừa tạo mới.
# Tắt ký hiệu khoa học mặc định của R (tùy chọn)
options(scipen = 999)
# Tính toán và tạo bảng kable trong một chuỗi lệnh
data.frame( Chỉ_số = "Trung bình Tổng tài sản",
# Tính mean và định dạng số ngay lập tức
Giá_trị = scales::comma(mean(bc$tong_tai_san, na.rm = TRUE), accuracy = 1))%>%
# In kết quả
kable( caption = "Thống kê Mô tả: Tổ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 tài sản | 27,193,080,283,174 |
# Tắt ký hiệu khoa học mặc định của R (tùy chọn)
options(scipen = 999)
# Tính toán và tạo bảng kable trong một chuỗi lệnh
data.frame( Chỉ_số = "Trung vị Tổng tài sản",
# Tính median và định dạng số ngay lập tức
Giá_trị = scales::comma(median(bc$tong_tai_san, na.rm = TRUE),accuracy = 1)) %>%
# In kết quả
kable( caption = "Thống kê Mô tả: Tổng Tài Sản",
col.names = c("Chỉ số", "Giá trị"),
align = "lr",booktabs = TRUE,row.names = FALSE)| Chỉ số | Giá trị |
|---|---|
| Trung vị Tổng tài sản | 27,168,724,434,702 |
# Tắt ký hiệu khoa học mặc định của R (tùy chọn)
options(scipen = 999)
# Tính toán và tạo bảng kable trong một chuỗi lệnh
data.frame(Chỉ_số = "Độ lệch chuẩn Tổng tài sản",
# Tính sd và định dạng số (làm tròn đến số nguyên gần nhất)
Giá_trị = scales::comma(sd(bc$tong_tai_san, na.rm = TRUE), accuracy = 1)) %>%
# In kết quả
kable( caption = "Thống kê Mô tả: Tổng Tài Sản",
col.names = c("Chỉ số", "Giá trị"),
align = "lr",booktabs = TRUE, row.names = FALSE)| Chỉ số | Giá trị |
|---|---|
| Độ lệch chuẩn Tổng tài sản | 5,731,623,073,747 |
# Tính toán và tạo bảng kable trong một chuỗi lệnh
data.frame(Chỉ_số = "Phương sai Tổng tài sản",
# Tính var và định dạng số (giữ 2 chữ số thập phân: accuracy=0.01)
Giá_trị = scales::comma(var(bc$tong_tai_san, na.rm = TRUE), accuracy = 0.01))%>%
# In kết quả
kable(caption = "Thống kê Mô tả: Tổng Tài Sản",
col.names = c("Chỉ số", "Giá trị"),
align = "lr",booktabs = TRUE,row.names = FALSE)| Chỉ số | Giá trị |
|---|---|
| Phương sai Tổng tài sản | 32,851,503,059,513,944,156,860,484.00 |
# 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, accuracy = 0.1)) %>%
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.1% |
# Tính giá trị Min và Max
min_ts <- min(bc$tong_tai_san, na.rm = TRUE)
max_ts <- max(bc$tong_tai_san, na.rm = TRUE)
# Tắt ký hiệu khoa học
options(scipen = 999)
# Tạo và in bảng kable
data.frame( Chỉ_số = c("Giá trị Tối thiểu (Min)", "Giá trị Tối đa (Max)"),
# Định dạng số có dấu phân cách, làm tròn đến số nguyên
Giá_trị = scales::comma(c(min_ts, max_ts), accuracy = 1)) %>%
kable(
caption = "Phạm vi Phân phối 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ị |
|---|---|
| Giá trị Tối thiểu (Min) | 19,192,865,179,330 |
| Giá trị Tối đa (Max) | 34,465,075,615,756 |
# Tính thống kê mô tả
summary_data <-summary(select(bc, tong_tai_san, tong_no_phai_tra,
von_chu_so_huu))
# In kết quả
kable(summary_data,
caption = "Tóm tắt Thống kê cho 3 biến chính)",
booktabs = TRUE,
# Định dạng số: 2 chữ số thập phân, dùng dấu phẩy hàng nghìn
format.args = list(decimal.mark = ".", big.mark = ",", digits = 2)
)| tong_tai_san | tong_no_phai_tra | von_chu_so_huu | |
|---|---|---|---|
| Min. :19192865179300 | Min. :6159696384430 | Min. :12433180070600 | |
| 1st Qu.:22101952530500 | 1st Qu.:6791321090970 | 1st Qu.:14843343168300 | |
| Median :27168724434700 | Median :7550192321990 | Median :20645761723600 | |
| Mean :27193080283200 | Mean :7650108089130 | Mean :19542964714000 | |
| 3rd Qu.:32701310866600 | 3rd Qu.:8401659875940 | 3rd Qu.:23976516312800 | |
| Max. :34465075615800 | Max. :9874229696360 | Max. :25485157894900 |
# Tạo một dataframe mới có tên df_doanh_thu_theo_nam
df_doanh_thu_theo_nam <- bc %>%
# Nhóm dữ liệu theo cột 'Nam'
group_by(Nam) %>%
# Tính tổng doanh thu thuần cho mỗi năm
summarise(Tong_DT = sum(
doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu, na.rm = TRUE)) %>%
# Sắp xếp lại theo năm
arrange(Nam)
# Chuyển cột số thành văn bản đã định dạng
df_doanh_thu_theo_nam_formatted <- df_doanh_thu_theo_nam %>%
mutate(
# Định dạng số có dấu phẩy, làm tròn đến số nguyên
Tong_DT = scales::comma(Tong_DT, accuracy = 1) )
# In kết quảquả
kable( df_doanh_thu_theo_nam_formatted,
caption = "Tổng Doanh thu thuần qua các Năm",
col.names = c("Năm", "Tổng Doanh thu thuần"),
align = "lr", booktabs = TRUE, row.names = FALSE)| Năm | Tổng Doanh thu thuần |
|---|---|
| 2015 | 27,144,301,587,344 |
| 2016 | 30,568,677,767,775 |
| 2017 | 34,438,171,048,592 |
| 2018 | 35,948,552,561,947 |
| 2019 | 37,899,059,501,295 |
| 2020 | 27,961,323,837,011 |
| 2021 | 26,373,746,293,858 |
| 2022 | 34,979,083,993,835 |
| 2023 | 30,461,367,282,215 |
| 2024 | 31,872,417,486,656 |
# 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(LoiNhuanTB = 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(
# Định dạng số có dấu phẩy, làm tròn đến số nguyên
LoiNhuanTB = scales::comma(LoiNhuanTB, 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 |
ket_qua_max <- bc %>%
filter(tong_tai_san == max(tong_tai_san, na.rm = TRUE)) %>%
select(Nam, tong_tai_san) %>%
distinct()
# Chuyển cột số thành văn bản đã định dạng
ket_qua_max_formatted <- ket_qua_max %>%
mutate(
# Định dạng số có dấu phẩy, làm tròn đến số nguyên
tong_tai_san = scales::comma(tong_tai_san, accuracy = 1))
# In kết quả
kable(
ket_qua_max_formatted, # Dùng đối tượng đã định dạng
caption = "Năm có Tổng Tài Sản Lớn Nhất (Max)",
col.names = c("Năm", "Tổng Tài Sản (Max)"),
align = "lr",
booktabs = TRUE,
row.names = FALSE
)| Năm | Tổng Tài Sản (Max) |
|---|---|
| 2022 | 34,465,075,615,756 |
# Tìm năm và giá trị Tổng Tài Sản nhỏ nhất
ket_qua_min <- bc %>%
filter(tong_tai_san == min(tong_tai_san, na.rm = TRUE)) %>%
select(Nam, tong_tai_san) %>%
distinct()
# Chuyển cột số thành văn bản đã định dạng
ket_qua_min_formatted <- ket_qua_min %>%
mutate(
# Định dạng số có dấu phẩy, làm tròn đến số nguyên
tong_tai_san = scales::comma(tong_tai_san, accuracy = 1) )
# In kết quả
kable(
ket_qua_min_formatted, # Dùng đối tượng đã định dạng
caption = "Năm có Tổng Tài Sản Tối Thiểu (Min)",
col.names = c("Năm", "Tổng Tài Sản (Min)"),
align = "lr",
booktabs = TRUE,
row.names = FALSE
)| Năm | Tổng Tài Sản (Min) |
|---|---|
| 2016 | 19,192,865,179,330 |
# TyLeNoTaiSan = Tổng Nợ Phải Trả / Tổng Tài Sản
bc <- bc %>% mutate(TyLeNoTaiSan = 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, TyLeNoTaiSan)
# Lấy data frame
df_kiem_tra_ty_le_no %>%
# Định dạng các cột số
mutate(
# Định dạng 2 cột tài sản có dấu phẩy
tong_no_phai_tra = scales::comma(tong_no_phai_tra, accuracy = 1),
tong_tai_san = scales::comma(tong_tai_san, accuracy = 1),
# Định dạng Tỷ lệ nợ thành %
TyLeNoTaiSan = scales::percent(TyLeNoTaiSan, accuracy = 0.1)) %>%
# In kết quảquả
kable( caption = "Kiểm tra Tỷ lệ Nợ trên Tổng Tài Sản (Toàn bộ)",
col.names = c("Năm", "Tổng Nợ", "Tổng Tài sản", "Tỷ Lệ Nợ"),
align = "lrrr", booktabs = TRUE, row.names = FALSE)| Năm | Tổng Nợ | Tổng Tài sả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% |
# Tính giá trị trung bình (loại bỏ NA)
mean_tylenotaisan <- mean(bc$TyLeNoTaiSan, na.rm = TRUE)
# tạo cột mới
data.frame(
Chỉ_số = "Trung bình Tỷ Lệ Nợ trên Tổng Tài sản",
# Định dạng kết quả thành % (ví dụ: 0.852 -> 85.2%)
Giá_trị = scales::percent(mean_tylenotaisan, accuracy = 0.1)) %>%
# In kết quả
kable(
caption = "Trung bình Tỷ Lệ Nợ (Toàn bộ Dữ liệu)",
col.names = c("Chỉ số", "Giá trị"),
align = "lr",
booktabs = TRUE,
row.names = FALSE)| Chỉ số | Giá trị |
|---|---|
| Trung bình Tỷ Lệ Nợ trên Tổng Tài sản | 28.7% |
# ROA = (Lợi nhuận gộp / Tổng Tài sản) * 100
bc <- bc %>%
mutate(ROA = loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu / tong_tai_san * 100)
# Tạo một dataframe mới có tên df_kiem_tra_roa
df_kiem_tra_roa <- bc %>%
# Chọn 2 cột cần thiết
select(Nam, ROA)
# In kết quả
kable(df_kiem_tra_roa,caption = "BẢNG ROA ",col.names = c("Năm", "ROA (%)"),
digits = 4, align = "lr",booktabs = TRUE, row.names = FALSE) | Năm | ROA (%) |
|---|---|
| 2015 | 35.0351 |
| 2016 | 43.0761 |
| 2017 | 40.2728 |
| 2018 | 36.1436 |
| 2019 | 35.4219 |
| 2020 | 31.0543 |
| 2021 | 24.9567 |
| 2022 | 31.2511 |
| 2023 | 26.6948 |
| 2024 | 27.8659 |
# ROE = (Lợi nhuận gộp / Vốn Chủ Sở hữu) * 100
bc <- bc %>%
mutate(ROE = loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu / von_chu_so_huu * 100)
# Tạo một dataframe mới có tên df_kiem_tra_roe
df_kiem_tra_roe <- bc %>%
# Chọn 2 cột cần thiết
select(Nam, ROE)
# In kết quả
kable(df_kiem_tra_roe, caption = "BẢNG ROE", col.names = c("Năm", "ROE (%)"),
digits = 4, align = "lr", booktabs = TRUE,row.names = FALSE)| Năm | ROE (%) |
|---|---|
| 2015 | 53.7357 |
| 2016 | 66.4957 |
| 2017 | 61.4786 |
| 2018 | 50.1749 |
| 2019 | 47.5718 |
| 2020 | 40.0706 |
| 2021 | 33.6740 |
| 2022 | 43.7997 |
| 2023 | 35.6732 |
| 2024 | 38.1314 |
# Tính giá trị trung bình (loại bỏ NA)
mean_roa <- mean(bc$ROA, na.rm = TRUE)
mean_roe <- mean(bc$ROE, na.rm = TRUE)
# Tạo cột mới
data.frame(
Chỉ_số = c("Trung bình ROA (Sinh lời trên Tài sản)",
"Trung bình ROE (Sinh lời trên Vốn CSH)"),
# Định dạng cả hai giá trị thành % (ví dụ: 0.052 -> 5.2%)
Giá_trị = scales::percent(c(mean_roa/100, mean_roe/100), accuracy = 0.1)) %>%
# In kết quả
kable(
caption = "Trung bình các Chỉ số Sinh lời (ROA & 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 ROA (Sinh lời trên Tài sản) | 33.2% |
| Trung bình ROE (Sinh lời trên Vốn CSH) | 47.1% |
# 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 (ví dụ: 0.875)
Giá_trị = scales::number(tuong_quan_tts_tn, accuracy = 0.001)
) %>%
# In kết quả
kable(caption = "Hệ số Tương quan Pearson (r)",
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 |
# 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::comma(mean_loinhuan, 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 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(TangTruong_TS = (tong_tai_san - lag(tong_tai_san)) / lag(tong_tai_san) * 100)
# Lọc cột
bc %>% select(Nam, tong_tai_san, TangTruong_TS) %>%
# In kết quả
kable( caption = "BẢNG KIỂM TRA TỐC ĐỘ TĂNG TRƯỞNG TỔNG TÀI SẢN (10 HÀNG ĐẦU)",
col.names = c("Năm", "Tổng Tài Sản (VND)", "Tăng trưởng TS (%)"),
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 TS (%) |
|---|---|---|
| 2015 | 21571925688349 | |
| 2016 | 19192865179330 | -11.0285 |
| 2017 | 22013689109910 | 14.6973 |
| 2018 | 22366742792213 | 1.6038 |
| 2019 | 26962476094045 | 20.5472 |
| 2020 | 27374972775358 | 1.5299 |
| 2021 | 30487024372425 | 11.3682 |
| 2022 | 34465075615756 | 13.0483 |
| 2023 | 34056624839705 | -1.1851 |
| 2024 | 33439406364651 | -1.8123 |
# Tính giá trị trung bình (loại bỏ NA)
mean_tangtruong_ts <- mean(bc$TangTruong_TS, 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_tangtruong_ts, accuracy = 0.00001)
) %>%
# In kết quả
kable(
caption = "Trung bình Tăng trưởng Tổ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.41875 |
# tải thư viện.
install.packages("ggplot2")
library(ggplot2)
library(scales)
# khởi tạo biểu đồ và gán trục X, trục Y.
ggplot(bc, aes(x = Nam, y = tong_tai_san)) +
# 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 = "coral3") +
# 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 = 3, color = "green4") +
# Ghi giá trị cụ thể của từng điểm lên biểu đồ.
geom_text(aes(label = round(tong_tai_san,0)),
angle = 90, vjust = -0.6, size = 8) +
#Đặ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 (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) +
scale_y_continuous(labels = comma) +
#Dùng giao diện tối giản, dễ nhìn.
theme_minimal(base_size = 19)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.
library(ggplot2)
# 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 = round(tai_san_ngan_han,0)),
angle = 90,hjust = 1.1, vjust = 1) +
#Đặt tên biểu đồ, nhãn trục X và Y .
labs(title = "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_size = 19)Nhận xét: Giai đoạn 2020–2022 trùng với thời kỳ hậu Covid-19, khi các doanh nghiệp có xu hướng tăng dự trữ tiền mặt, hàng tồn kho và đầu tư ngắn hạn để đảm bảo thanh khoản. Sau đó, bước sang 2023–2024, xu hướng ổn định và thu hẹp tài sản ngắn hạn phản ánh sự chuyển hướng sang quản trị hiệu quả và cân đối tài chính dài 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 = round(tai_san_dai_han,0)),
angle = 90, vjust = 1,hjust = 1.1, color = "azure") +
# Đặt tiêu đề và tên trục rõ ràng.
labs(title = "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_size = 19)Nhận xét: Giai đoạn 2015–2018: Tài sản dài hạn giảm liên tục từ khoảng 9.378 nghìn tỷ xuống 7.676 nghìn tỷ đồng, phản ánh việc doanh nghiệp thu hẹp đầu tư dài hạn hoặc khấu hao tài sản cố định.
Giai đoạn 2019–2023: Duy trì ổn định quanh mức 7.6–7.8 nghìn tỷ đồng, cho thấy quy mô đầu tư dài hạn được giữ vững, không mở rộng thêm đáng kể.
Năm 2024: Có dấu hiệu phục hồi nhẹ, tăng trở lại 8.372 nghìn tỷ đồng, cho thấy doanh nghiệp bắt đầu tái đầu tư vào tài sản cố định hoặc dự án dài hạn.
Liên hệ thực tế: Xu hướng này phù hợp với tình hình chung của doanh nghiệp Việt Nam giai đoạn hậu Covid-19 — giai đoạn đầu thắt chặt đầu tư dài hạn để duy trì thanh khoản, sau đó phục hồi và tái cơ cấu đầu tư khi kinh tế ổn định trở lại.
library(scales)
# khởi tạo biểu đồ và gán trục X, trục Y.
ggplot(bc, aes(x = Nam, y = TyLeNoTaiSan)) +
# 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 = round(TyLeNoTaiSan,2)), vjust = 2) +
# Đặt tiêu đề và tên trục.
labs(title = "Tỷ lệ Nợ/Tổng tài sản (2015–2024)",
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_size = 19)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.
# khởi tạo biểu đồ và gán trục X, trục Y.
ggplot(bc, aes(x = Nam, y = doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu)) +
# Vẽ đường xu hướng màu xanh, thể hiện sự thay đổi của doanh thu thuần qua các năm.
geom_line(color = "darkgreen", linewidth = 1.2) +
# Thêm các điểm dữ liệu màu cam tại từng năm.
geom_point(color = "orange", size = 3) +
# Hiển thị giá trị doanh thu cụ thể ngay trên từng điểm.
geom_text(
aes(label = round(doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu,0)),
vjust = -0.6, size = 7) +
# Đặt tiêu đề và nhãn trục.
labs(title = "Doanh thu thuần (2015–2024)", x = "Năm", y = "Tỷ đồng") +
# 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_classic(base_size = 19)Nhận xét: Biểu đồ thể hiện doanh thu thuần giai đoạn 2015–2024, có thể chú thích như sau:
🔹 2015–2019: Doanh thu tăng liên tục, đạt đỉnh năm 2019, cho thấy hoạt động kinh doanh mở rộng và tăng trưởng mạnh.
🔹 2020–2021: Doanh thu giảm sâu, đặc biệt năm 2021 xuống mức thấp nhất, có thể do tác động của dịch COVID-19 và suy giảm thị trường.
🔹 2022–2024: Doanh thu phục hồi trở lại, nhưng chưa đạt mức cao như giai đoạn trước đại dịch, thể hiện quá trình phục hồi dần của doanh nghiệp.
📊 Nhận xét tổng quát: Doanh thu có xu hướng biến động mạnh, chịu ảnh hưởng bởi yếu tố kinh tế vĩ mô, song xu hướng hồi phục sau khủng hoảng cho thấy khả năng thích ứng của doanh nghiệp.
# khởi tạo biểu đồ và gán trục X, trục Y.
ggplot(bc, aes(x = Nam, y = loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu)) +
# Vẽ biểu đồ cột (column chart) để thể hiện giá trị lợi nhuận gộp theo từng năm.
geom_col(fill = "lightsteelblue1") +
# Hiển thị nhãn giá trị trên mỗi cột.
geom_text(
aes(label = round(loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu, 0)),
angle = 90, vjust = 0.2, hjust = 1.1 ) +
# Đặt tiêu đề và tên trục.
labs(title = "Lợi nhuận gộp qua các năm", x = "Năm", y = "Tỷ đồng") +
# 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_size = 19)Nhận xét:
Giai đoạn năm 22015-2019: Lợi nhuận gộp tăng đều qua các năm, đạt đỉnh năm 2019, phản ánh hiệu quả hoạt động kinh doanh được cải thiện.
Giai đoạn năm 2020–2021: Lợi nhuận giảm mạnh, khả năng do tác động của đại dịch COVID-19 khiến chi phí tăng và doanh thu giảm.
Giai đoạn năm 2022–2024: Lợi nhuận phục hồi rõ rệt, đặc biệt năm 2022 đạt mức cao nhất toàn giai đoạn, cho thấy doanh nghiệp đã thích ứng và cải thiện biên lợi nhuận.
Tổng kết: Giai đoạn 10 năm cho thấy xu hướng lợi nhuận tăng trưởng nhưng có biến động, phản ánh sức bật mạnh mẽ sau khủng hoảng và tiềm năng tăng trưởng dài hạn.
# 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 = round(ROA, 2)), vjust = 1.5, size = 7) +
# Đặ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 (ROA)", 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_size = 19)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, 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 = round(ROE, 2)), vjust = -0.6,hjust = -0.22, size = 7) +
# Đặ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 (ROE)",
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_size = 19)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ới dữ liệu bc_clean (đã loại bỏ giá trị NA)
bc_clean <- na.omit(bc)
# khởi tạo biểu đồ và gán trục X, trục Y
ggplot(bc_clean, aes(x = Nam, y = TangTruong_TS)) +
geom_col(fill = "darkseagreen") +
geom_text(aes(label = paste0(round(TangTruong_TS,1), "%")),
vjust = -0.6, size = 6) +
# Đặ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_size = 19)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, trục Y
ggplot(bc, aes(x = Nam, y = TyLeLoiNhuanGop)) +
# 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(round(TyLeLoiNhuanGop,1), "%")),
vjust = -0.6, size = 8) +
# Đặ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_classic(base_size = 19)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.
# # 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_size = 19)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.
# 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 = TyLeNoTaiSan * 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_size = 19)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.
# khởi tạo biểu đồ và gán trục X
ggplot(bc, aes(x = Nam)) +
# Vẽ đường biểu diễn "Doanh thu thuần"
# Chia cho 1000 để quy đổi đơn vị sang nghìn tỷ đồng
geom_line(aes(y = doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu/1000,
color = "Doanh thu"), linewidth = 1.2) +
# Vẽ đường nét đứt thể hiện "Lợi nhuận gộp"
# Chia cho 1000 để quy đổi đơn vị sang nghìn tỷ đồng.
geom_line(aes(y = loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu/1000,
color = "Lợi nhuận gộp"), linewidth = 1.2, linetype = "dashed") +
# Thêm điểm biểu diễn "Doanh thu thuần" cho từng năm
geom_point(aes(y = doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu/1000,
color = "Doanh thu"), size = 3) +
# Thêm điểm biểu diễn "Lợi nhuận gộp" cho từng năm
geom_point(aes(y = loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu/1000,
color = "Lợi nhuận gộp"), size = 3) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "Doanh thu và Lợi nhuận gộp (2015–2024)",
subtitle = "Quan hệ giữa doanh thu thuần và lợi nhuận gộp",
x = "Năm", y = "Giá trị (nghìn tỷ đồng)", 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_size = 19)Nhận xét: Giai đoạn 2015–2019, doanh thu tăng trưởng mạnh và ổn định, kéo theo lợi nhuận gộp duy trì xu hướng tăng tương ứng, cho thấy hoạt động kinh doanh hiệu quả. Từ 2020–2021, doanh thu sụt giảm đáng kể, phản ánh giai đoạn khó khăn, tuy nhiên biên lợi nhuận gộp vẫn được duy trì ở mức ổn định, cho thấy doanh nghiệp kiểm soát tốt chi phí sản xuất. Giai đoạn 2022–2024, doanh thu hồi phục, song tốc độ tăng lợi nhuận gộp chậm hơn, hàm ý rằng chi phí đầu vào hoặc áp lực cạnh tranh có thể ảnh hưởng đến khả năng sinh lời.
# khởi tạo biểu đồ và gán trục X
ggplot(bc, aes(x = Nam)) +
# Vẽ đường thể hiện “Tổng tài sản” theo từng năm
# Chia cho 1000 để quy đổi đơn vị sang nghìn tỷ đồng
geom_line(aes(y = tong_tai_san/1000, color = "Tổng tài sản"),
linewidth = 1.2) +
# vẽ đường nét đứt thể hiện "Vốn chủ sở hữu"
# Chia cho 1000 để quy đổi đơn vị sang nghìn tỷ đồng.
geom_line(aes(y = von_chu_so_huu/1000, color = "Vốn chủ sở hữu"),
linewidth = 1.2, linetype = "dashed") +
# Thêm điểm thể hiện “Tổng tài sản” cho từng năm
# Chia cho 1000 để quy đổi đơn vị sang nghìn tỷ đồng
geom_point(aes(y = tong_tai_san/1000, color = "Tổng tài sản"), size = 3) +
# Thêm điểm thể hiện "Vốn chủ sở hữu"
# Cho từng năm,chia cho 1000 để quy đổi đơn vị sang nghìn tỷ đồng
geom_point(aes(y = von_chu_so_huu/1000, color = "Vốn chủ sở hữu"), size = 3) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "Tổng tài sản và Vốn chủ sở hữu (2015–2024)",
x = "Năm", y = "Giá trị (nghìn tỷ đồng)", 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) +
# Dùng giao diện nền trắng – khung đen (Black & White theme).
theme_bw(base_size = 19)Nhận xét: Giai đoạn 2015–2024, tổng tài sản và vốn chủ sở hữu đều có xu hướng tăng ổn định, phản ánh quy mô hoạt động của doanh nghiệp mở rộng qua thời gian. Từ năm 2020 trở đi, tốc độ tăng tài sản nhanh hơn vốn chủ sở hữu, cho thấy doanh nghiệp có thể đã gia tăng sử dụng nợ vay để tài trợ cho tài sản. Giai đoạn 2023–2024, cả hai chỉ tiêu có dấu hiệu chững lại, hàm ý doanh nghiệp đang bước vào giai đoạn ổn định hoặc điều chỉnh cơ cấu tài chính.
# 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) +
# Đặt tiêu đề và nhãn trục rõ ràng.
labs(title = "Tài sản ngắn hạn vs 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_size = 19)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à gán trục X, trục Y
ggplot(bc, aes(x = Nam, y = tong_tai_san/1000, color = QuyMo)) +
# Vẽ các đường xu hướng theo từng nhóm quy mô
geom_line(linewidth = 1.2) +
# Thêm các điểm dữ liệu tại từng năm
geom_point(size = 3) +
# đặt tiêu đề, phụ đề và nhãn trục, đồng thời chú thích màu là “Quy mô”
labs(title = "Ảnh hưởng của Quy mô doanh nghiệp đến Tổng tài sản",
subtitle = "Nhóm quy mô Lớn - Vừa - Nhỏ",
x = "Năm", y = "Tổng tài sản (nghìn tỷ đồng)", color = "Quy mô") +
# 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 sáng
theme_light(base_size = 19)Nhận xét: Tổng tài sản của nhóm doanh nghiệp quy mô lớn tăng mạnh và ổn định trong dài hạn, đặc biệt từ năm 2018 trở đi. Điều này phản ánh khả năng mở rộng hoạt động và tích lũy nguồn lực tài chính vững chắc của các doanh nghiệp lớn, giúp duy trì vị thế dẫn đầu trên thị trường.
# khởi tạo biểu đồ và gán trục X, trục Y
ggplot(bc, aes(x = Nam, y = doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu/1000,
color = QuyMo)) +
# Vẽ đường biểu diễn màu hồng cam thể hiện xu hướng doanh thu qua các năm
geom_line(color = "salmon",linewidth = 1.2) +
# Đánh dấu từng điểm dữ liệu trên đường
geom_point(color = "salmon", size = 3) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "Ảnh hưởng của Quy mô đến Doanh thu thuần (2015–2024)",
x = "Năm", y = "Doanh thu (nghìn tỷ đồng)", color = "Quy mô") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024
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_size = 19)Nhận xét: Từ năm 2015 đến 2019, doanh thu thuần của nhóm doanh nghiệp quy mô lớn tăng trưởng mạnh mẽ, đạt đỉnh vào năm 2019.Tuy nhiên, từ 2020 đến 2021, doanh thu giảm sâu – có thể do tác động của đại dịch COVID-19 và sự gián đoạn chuỗi cung ứng. Sau giai đoạn sụt giảm, doanh thu phục hồi đáng kể trong năm 2022, dù chưa trở lại mức đỉnh cũ, cho thấy sức bật và khả năng thích ứng cao của nhóm doanh nghiệp lớn.
# khởi tạo biểu đồ và gán trục X, trục Y
ggplot(bc, aes(x = Nam, y = ROA, color = QuyMo)) +
# Vẽ đường xu hướng ROA màu vàng nhạt cho các năm
geom_line(color = "lightgoldenrod2",linewidth = 1.2) +
# Thêm các điểm đánh dấu giá trị ROA từng năm
geom_point(color = "lightgoldenrod2",size = 3) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "Ảnh hưởng của Quy mô doanh nghiệp đến ROA",
x = "Năm", y = "ROA (%)", color = "Quy mô") +
# Hiển thị đầy đủ các mốc năm từ 2015 đến 2024
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_classic(base_size = 19)Nhận xét: Tỷ suất ROA của nhóm doanh nghiệp quy mô lớn đạt mức cao nhất vào năm 2016, phản ánh hiệu quả sử dụng tài sản tối ưu trong giai đoạn này.
Từ 2017 đến 2021, ROA liên tục giảm, cho thấy hiệu quả sinh lời trên tài sản suy yếu — có thể do chi phí đầu tư mở rộng hoặc biến động thị trường, đặc biệt giai đoạn chịu ảnh hưởng của COVID-19.
Sau năm 2021, ROA có dấu hiệu phục hồi nhẹ nhưng chưa quay lại mức đỉnh ban đầu, cho thấy các doanh nghiệp đang trong quá trình tái cơ cấu và tối ưu nguồn lực để cải thiện khả năng sinh lời.
# 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 = TyLeNoTaiSan * 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_size = 19)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.
# loại bỏ các giá trị bị thiếu để tránh lỗi khi vẽ
bc_clean <- na.omit(bc)
# khởi tạo biểu đồ và gán trục X
ggplot(bc_clean, 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 = TangTruong_TS), 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 = "Tăng trưởng tài sản và 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_size = 19)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.
# khởi tạo biểu đồ và gán trục X
ggplot(bc, aes(x = ROA)) +
# Vẽ biểu đồ tần suất (histogram) để thể hiện phân bố của ROA
geom_histogram(fill = "palegreen", color = "black", bins = 8) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "Phân phối ROA", x = "ROA (%)", y = "Tần suất") +
# Áp dụng giao diện nền sáng (theme_light)
theme_light(base_size = 19)Nhận xét: Quan sát cho thấy phần lớn các giá trị ROA tập trung trong khoảng 28%–36%, thể hiện mức sinh lời trung bình – khá ổn định của doanh nghiệp. Số năm có ROA vượt trên 40% chiếm tỷ lệ thấp, cho thấy hiệu suất sinh lời cao chỉ đạt được trong một vài giai đoạn đặc biệt thuận lợi (ví dụ: tăng trưởng doanh thu hoặc giảm chi phí vốn).
Ngược lại, chỉ có một vài năm ROA giảm dưới 25%, phản ánh những giai đoạn doanh nghiệp gặp khó khăn trong sử dụng tài sản để tạo ra lợi nhuận, có thể do hiệu quả đầu tư giảm hoặc chi phí vận hành tăng.
Nhìn chung, phân phối ROA khá lệch phải nhẹ, cho thấy đa phần doanh nghiệp đạt mức sinh lời khá, và chỉ có một số năm đạt mức sinh lời nổi bật vượt trội. Điều này chứng tỏ khả năng sinh lợi của doanh nghiệp tương đối ổn định theo thời gian, ít biến động cực đoan.
# khởi tạo biểu đồ và gán trục X
ggplot(bc, aes(x = ROE)) +
# Vẽ biểu đồ mật độ (density plot) để thể hiện phân phối xác suất của ROE
geom_density(fill = "pink", alpha = 0.5) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "Phân phối ROE", x = "ROE (%)", y = "Mật độ") +
# Áp dụng giao diện tối giản, loại bỏ khung và đường nền thừa
theme_minimal(base_size = 19)Nhận xét: Biểu đồ mật độ trên cho thấy phân phối của ROE (%) có dạng lệch phải nhẹ, tập trung chủ yếu trong khoảng 35% – 50%. Đây là vùng có mật độ cao nhất, phản ánh rằng đa số giai đoạn nghiên cứu doanh nghiệp đạt mức sinh lời trên vốn chủ ở mức trung bình – khá ổn định.
Sau mức 50%, đường mật độ giảm dần, cho thấy ít năm đạt ROE vượt trội trên 55% – 60%, thường rơi vào các giai đoạn doanh nghiệp có hiệu suất sử dụng vốn chủ sở hữu cao hoặc tỷ lệ đòn bẩy thấp.
Phân phối này không đối xứng hoàn toàn, điều đó hàm ý rằng hiệu quả sinh lời từ vốn chủ có xu hướng dao động nhẹ quanh mức trung bình, chứ không quá biến động cực đoan. Nói cách khác, doanh nghiệp duy trì khả năng tạo lợi nhuận ổn định trên mỗi đồng vốn chủ sở hữu, thể hiện sự bền vững trong chính sách tài chính và chiến lược đầu tư.
# khởi tạo biểu đồ và gán trục X, trục Y
ggplot(bc, aes(x = factor(Nam), y = ROA)) +
# Vẽ biểu đồ hộp (boxplot) thể hiện phân bố giá trị ROA theo từng năm
geom_boxplot(fill = "brown", color = "skyblue", width = 0.6) +
# Đặt tiêu đề và nhãn trục rõ ràng
labs(title = "Phân bố ROA theo năm", x = "Năm", y = "ROA (%)") +
# Thêm đường viền đen bao quanh biểu đồ, giúp khung hiển thị rõ ràng
theme( panel.border = element_rect(color = "black", fill = NA, linewidth = 0.8))+
# Áp dụng giao diện tối giản (minimal)
theme_minimal(base_size = 19) Nhận xét: ROA của doanh nghiệp biến động rõ rệt theo thời gian. Giai đoạn 2016–2017 ghi nhận mức ROA cao nhất (trên 40%), cho thấy khả năng sinh lời trên tài sản rất tốt. Từ 2018 đến 2021, ROA giảm dần mạnh, đặc biệt năm 2021 đạt mức thấp nhất khoảng 25%, phản ánh giai đoạn hiệu quả sử dụng tài sản suy giảm. Sau đó, ROA phục hồi nhẹ từ 2022–2024, nhưng vẫn chưa quay lại mức đỉnh trước đó. Điều này cho thấy doanh nghiệp đang trong quá trình cải thiện hiệu quả hoạt động, song chưa đạt mức ổn định cao như giai đoạn đầu.
# Khởi tạo biểu đồ với dữ liệu bc
ggplot(bc) +
# Vẽ đường xu hướng đại diện cho doanh thu thuần
geom_line(aes(x = Nam, y = doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu,
color = "Doanh thu"),linewidth = 1.2 ) +
# Vẽ đường xu hướng thể hiện lợi nhuận gộp
geom_line(aes(x = Nam, y = loi_nhuan_gop_ve_ban_hang_va_cung_cap_dich_vu,
color = "Lợi nhuận"), linewidth = 1.2) +
# Đặt tiêu đề, tên trục và chú thích màu.
labs(title = "Doanh thu và Lợi nhuận gộp (2015–2024)",
x = "Năm", y = "Tỷ đồng", 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_size = 19)Nhận xét: Giai đoạn 2015–2019, doanh thu tăng liên tục, đạt đỉnh vào năm 2019, cho thấy sự mở rộng quy mô kinh doanh mạnh mẽ. Tuy nhiên, năm 2020–2021 ghi nhận sự sụt giảm rõ rệt ở cả doanh thu và lợi nhuận, phản ánh tác động tiêu cực từ biến động kinh tế hoặc chi phí tăng cao.
Sau đó, từ 2022–2024, doanh nghiệp phục hồi nhẹ, doanh thu và lợi nhuận gộp dần ổn định nhưng chưa đạt mức đỉnh cũ. Nhìn chung, xu hướng cho thấy doanh nghiệp có khả năng phục hồi tốt sau giai đoạn suy giảm, nhưng cần cải thiện hiệu quả sinh lời để duy trì tăng trưởng bền vững.
# 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" qua các năm
# 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) +
# Vẽ đường xu hướng thể hiện "Doanh thu thuần" qua các năm
# Các giá trị được chia cho 1000 để đổi sang đơn vị nghìn tỷ đồng
geom_line(aes(x = Nam, y = doanh_thu_thuan_ve_ban_hang_va_cung_cap_dich_vu/1000, color = "Doanh thu"), linewidth = 1.2) +
# Vẽ đường xu hướng thể hiện "Lợi nhuận gộp" qua các năm
# Các giá trị chia cho 1000 để đổi sang đơn vị nghìn tỷ đồng
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 đủ 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_size = 19)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.