Nhóm chúng em xin gửi lời cảm ơn chân thành và sâu sắc đến Thầy Trần Mạnh Tường, giảng viên hướng dẫn học phần “Ngôn ngữ lập trình trong phân tích dữ liệu”, đã tận tình giảng dạy, hướng dẫn và hỗ trợ chúng em trong suốt quá trình học tập cũng như thực hiện bài tiểu luận này.
Nhờ sự hướng dẫn và góp ý quý báu của Thầy, nhóm đã có cơ hội tiếp cận, tìm hiểu và vận dụng ngôn ngữ lập trình R vào phân tích dữ liệu thực tế, từ đó củng cố thêm kiến thức về thống kê, lập trình và tư duy khoa học trong nghiên cứu.
Mặc dù nhóm đã cố gắng hết sức, nhưng do thời gian và kinh nghiệm còn hạn chế, bài làm chắc chắn vẫn còn nhiều thiếu sót. Nhóm rất mong nhận được sự góp ý từ Thầy để bài nghiên cứu được hoàn thiện hơn.
Nhóm chọn đề tài “Phân tích bộ dữ liệu về các yếu tố sinh học và lối sống ảnh hưởng đến nguy cơ mắc bệnh tiểu đường bằng ngôn ngữ lập trình R” nhằm kết hợp giữa kiến thức lập trình và ứng dụng thực tiễn trong y học. Bệnh tiểu đường hiện là vấn đề sức khỏe cộng đồng nghiêm trọng, việc hiểu rõ nguyên nhân và yếu tố nguy cơ là cần thiết để đưa ra biện pháp phòng tránh.
Bên cạnh đó, bộ dữ liệu “Diabetes Health Indicators Dataset” có quy mô lớn, chứa 31 biến và 100.000 quan sát, cung cấp thông tin phong phú về sức khỏe, lối sống và nhân khẩu học. Đây là nguồn dữ liệu lý tưởng để sinh viên rèn luyện kỹ năng phân tích dữ liệu thực tế. Đồng thời, việc sử dụng R giúp nhóm phát triển kỹ năng xử lý dữ liệu, thống kê mô tả và trình bày kết quả bằng công cụ lập trình hiện đại.
Mục tiêu tổng quát của đề tài là ứng dụng ngôn ngữ R trong phân tích dữ liệu y sinh học để nhận diện các yếu tố sinh học và lối sống có ảnh hưởng đến nguy cơ mắc bệnh tiểu đường. Cụ thể, nhóm hướng đến:
Xử lý, làm sạch và mã hóa dữ liệu theo chuẩn y học (WHO, CDC, AHA).
Phân tích thống kê mô tả và kiểm định mối liên hệ giữa các biến sinh học (như huyết áp, cholesterol, insulin, triglycerides…) với giai đoạn bệnh.
Trực quan hóa dữ liệu bằng biểu đồ để mô tả xu hướng và mối tương quan giữa các yếu tố sức khỏe và lối sống.
Đối tượng nghiên cứu:
Dữ liệu của 100.000 cá nhân trong bộ “Diabetes Health Indicators Dataset”, bao gồm các chỉ số sinh học, lối sống, tiền sử bệnh và thông tin nhân khẩu học.
Phạm vi nghiên cứu:
Nghiên cứu tập trung vào 10 biến chính gồm 6 biến định lượng (như huyết áp tâm trương, cholesterol, triglycerides, insulin, tỷ lệ eo/hông) và 4 biến định tính (trình độ học vấn, việc làm, giai đoạn bệnh, tiền sử gia đình). Phân tích được thực hiện bằng R thông qua các bước thống kê, kiểm định và trực quan hóa dữ liệu, không đi sâu vào mô hình dự báo.
Đề tài sử dụng phương pháp định lượng với công cụ chính là ngôn ngữ lập trình R. Các bước nghiên cứu bao gồm:
Tiền xử lý dữ liệu: đọc, làm sạch, mã hóa và loại bỏ giá trị ngoại lai dựa trên chuẩn y học.
Thống kê mô tả: xác định đặc điểm trung bình, phương sai, hệ số biến thiên của các biến định lượng.
Kiểm định thống kê và phân tích tương quan: áp dụng các kiểm định K–S, ANOVA, Kruskal–Wallis, Chi-square, Pearson để xác định mối liên hệ giữa các yếu tố.
Trực quan hóa dữ liệu: sử dụng ggplot2 để xây dựng các biểu đồ Histogram, Boxplot, Scatter, Density, Violin, Bar Chart và Facet nhằm minh họa kết quả.
Đề tài góp phần ứng dụng thực tế ngôn ngữ lập trình R trong phân tích dữ liệu y học, giúp sinh viên hiểu rõ quy trình xử lý và khai thác dữ liệu lớn. Nghiên cứu cũng chỉ ra mối liên hệ giữa các yếu tố sinh học (HDL, LDL, triglycerides, insulin, WHR) với tiến triển bệnh tiểu đường, qua đó làm rõ vai trò của lối sống và yếu tố di truyền trong nguy cơ mắc bệnh.
Kết quả nghiên cứu cung cấp minh chứng khoa học cho việc sử dụng R trong lĩnh vực y sinh học, đồng thời góp phần nâng cao nhận thức cộng đồng về tầm quan trọng của dinh dưỡng, vận động và tầm soát sớm bệnh tiểu đường.
1. # Thiết lập đường dẫn làm việc
2. setwd("C:/Users/maica/Downloads/PHAN1")
3. # Đọc dữ liệu từ file Excel
4. diabetes <- read_excel("Diabetes Health Indicators Dataset.xlsx")
read_excel: Đọc toàn bộ file Excel vào bộ nhớ RAM, mỗi cột trong file được ánh xạ thành một vector trong R giúp R có thể xử lý từng biến một cách riêng biệt.
datatable(d): Tạo bảng dữ liệu tương tác cho phép người dùng quan sát toàn bộ tập dữ liệu lớn (100.000 dòng) một cách trực quan, có thể tìm kiếm, sắp xếp, và lọc nhanh theo biến hoặc từ khóa.
Đây là bước đọc và chuẩn hóa dữ liệu ban đầu, giúp chuyển đổi từ file Excel sang dạng khung dữ liệu (data frame) trong R. Việc hiển thị dữ liệu dưới dạng bảng tương tác giúp nhìn tổng quan về các biến và cấu trúc dữ liệu, từ đó xác định rõ các yếu tố cần phân tích.
Bảng hiển thị danh sách biến
Lệnh names(diabetes) được sử dụng để liệt kê toàn bộ tên các biến (cột) trong bộ dữ liệu Diabetes Health Indicators Dataset. R trả về một vector chứa tên của tất cả 31 biến, giúp người dùng nhận biết cấu trúc dữ liệu và xác định loại thông tin được thu thập trong tập dữ liệu.
Hai vector variable và description được khai báo: variable lưu trữ tên của các biến trong bộ dữ liệu (gồm 31 biến).
description lưu trữ mô tả chi tiết tương ứng với từng biến.
Hàm data.frame() được sử dụng để kết hợp hai vector này lại thành một khung dữ liệu mới có tên là variable_description.
Hàm kable() của gói knitr để hiển thị bảng mô tả
Bảng trên thể hiện mô tả đầy đủ của 31 biến trong bộ dữ liệu Diabetes Health Indicators Dataset, phản ánh nhiều khía cạnh khác nhau về người tham gia khảo sát, bao gồm:
Đặc điểm nhân khẩu học: age, gender, ethnicity, education_level, income_level, employment_status.
Thói quen và lối sống: smoking_status, alcohol_consumption_per_week, physical_activity_minutes_per_week, diet_score, sleep_hours_per_day, screen_time_hours_per_day.
Tiền sử bệnh lý: family_history_diabetes, hypertension_history, cardiovascular_history.
Chỉ số sức khỏe: bmi, waist_to_hip_ratio, systolic_bp, diastolic_bp, heart_rate.
Chỉ số sinh hóa: cholesterol_total, hdl_cholesterol, ldl_cholesterol, triglycerides, glucose_fasting, glucose_postprandial, insulin_level, hba1c.
Chỉ số về bệnh tiểu đường: diabetes_risk_score, diabetes_stage, diagnosed_diabetes.
Các biến này cung cấp cái nhìn toàn diện về nhân khẩu học, thói quen sinh hoạt, sức khỏe và tình trạng bệnh lý của từng cá nhân.
1. dim(diabetes)
## [1] 100000 31
Lệnh dim(diabetes) được sử dụng để kiểm tra kích thước của bộ dữ liệu đang phân tích.
Kết quả đầu tiên (100000) cho biết số lượng quan sát (số hàng) trong tập dữ liệu, tức là 100.000 cá nhân được khảo sát. Kết quả thứ hai (31) cho biết số lượng biến (số cột), tương ứng với 31 đặc trưng được ghi nhận cho mỗi cá nhân.
Bộ dữ liệu Diabetes Health Indicators Dataset có 100.000 quan sát và 31 biến, là một tập dữ liệu lớn và đa dạng, phản ánh nhiều khía cạnh khác nhau của đối tượng nghiên cứu. Với quy mô này, dữ liệu đủ mạnh để thực hiện các phân tích thống kê, hồi quy và mô hình dự báo về nguy cơ mắc bệnh tiểu đường.
1. str(diabetes, strict.width = "cut")
## tibble [100,000 × 31] (S3: tbl_df/tbl/data.frame)
## $ age : num [1:100000] 58 48 60 74 46 46 75 62 ..
## $ gender : chr [1:100000] "Male" "Female" "Male" "..
## $ ethnicity : chr [1:100000] "Asian" "White" "Hispan"..
## $ education_level : chr [1:100000] "Highschool" "Highschoo"..
## $ income_level : chr [1:100000] "Lower-Middle" "Middle""..
## $ employment_status : chr [1:100000] "Employed" "Employed" ""..
## $ smoking_status : chr [1:100000] "Never" "Former" "Never"..
## $ alcohol_consumption_per_week : num [1:100000] 0 1 1 0 1 2 0 1 1 3 ...
## $ physical_activity_minutes_per_week: num [1:100000] 215 143 57 49 109 124 53..
## $ diet_score : num [1:100000] 5.7 6.7 6.4 3.4 7.2 9 9...
## $ sleep_hours_per_day : num [1:100000] 7.9 6.5 10 6.6 7.4 6.2 7..
## $ screen_time_hours_per_day : num [1:100000] 7.9 8.7 8.1 5.2 5 5.4 8 ..
## $ family_history_diabetes : num [1:100000] 0 0 1 0 0 0 0 0 0 0 ...
## $ hypertension_history : num [1:100000] 0 0 0 0 0 0 1 1 0 0 ...
## $ cardiovascular_history : num [1:100000] 0 0 0 0 0 0 0 1 1 0 ...
## $ bmi : num [1:100000] 30.5 23.1 22.2 26.8 21.2..
## $ waist_to_hip_ratio : num [1:100000] 0.89 0.8 0.81 0.88 0.78 ..
## $ systolic_bp : num [1:100000] 134 129 115 120 92 95 12..
## $ diastolic_bp : num [1:100000] 78 76 73 93 67 81 77 83 ..
## $ heart_rate : num [1:100000] 68 67 74 68 67 57 81 76 ..
## $ cholesterol_total : num [1:100000] 239 116 213 171 210 218 ..
## $ hdl_cholesterol : num [1:100000] 41 55 66 50 52 61 46 49 ..
## $ ldl_cholesterol : num [1:100000] 160 50 99 79 125 119 161..
## $ triglycerides : num [1:100000] 145 30 36 140 160 179 15..
## $ glucose_fasting : num [1:100000] 136 93 118 139 137 100 1..
## $ glucose_postprandial : num [1:100000] 236 150 195 253 184 133 ..
## $ insulin_level : num [1:100000] 6.36 2 5.07 5.28 12.74 ...
## $ hba1c : num [1:100000] 8.18 5.63 7.51 9.03 7.2 ..
## $ diabetes_risk_score : num [1:100000] 29.6 23 44.7 38.2 23.5 2..
## $ diabetes_stage : chr [1:100000] "Type 2" "No Diabetes" "..
## $ diagnosed_diabetes : num [1:100000] 1 0 1 1 1 0 0 1 1 0 ...
Lệnh str(diabetes) được sử dụng để kiểm tra cấu trúc tổng quát của bộ dữ liệu. Nhận xét
Dữ liệu mô phỏng tình huống phân tích các yếu tố ảnh hưởng đến nguy cơ mắc bệnh tiểu đường.
1. sum(sapply(diabetes, is.character) | sapply(diabetes, is.factor))
## [1] 7
sapply(diabetes, is.factor) Kiểm tra xem từng biến có thuộc kiểu dữ liệu factor (biến phân loại) hay không. Kết quả cũng là vector TRUE/FALSE.
Dấu “|” (hoặc) được dùng để kết hợp hai điều kiện trên. Một biến sẽ được xem là biến định tính nếu nó là kiểu character hoặc factor.
Bộ dữ liệu có 7 biến định tính, gồm các biến như: gender, ethnicity, education_level, income_level, employment_status, smoking_status, và diabetes_stage.
Các biến này mô tả đặc điểm nhân khẩu học và hành vi lối sống, có vai trò quan trọng trong việc phân loại đối tượng và phân tích sự khác biệt giữa các nhóm trong nghiên cứu bệnh tiểu đường.
1. sum(sapply(diabetes, is.numeric))
## [1] 24
Hàm sapply(diabetes, is.numeric) Duyệt qua toàn bộ các cột trong bộ dữ liệu diabetes và kiểm tra xem biến có kiểu dữ liệu số (numeric) không. Kết quả trả về là vector TRUE/FALSE, với giá trị TRUE cho các biến định lượng.
Bộ dữ liệu Diabetes Health Indicators Dataset có 24 biến định lượng, bao gồm các biến như: “age”, “bmi”, “waist_to_hip_ratio”,” systolic_bp”, “diastolic_bp”, “cholesterol_total”, “hdl_cholesterol”, “ldl_cholesterol”, “glucose_fasting”, “hba1c”, “insulin_level”,…
1. library(kableExtra)
2. library(knitr)
3. if (knitr::is_latex_output()) {
4. df_tmp <- head(diabetes, 6)
5. df_part1 <- df_tmp[, 1:8]
6. df_part2 <- df_tmp[, 9:15]
7. df_part3 <- df_tmp[, 16:24]
8. df_part4 <- df_tmp[, 25:ncol(df_tmp)]
9. print(kbl(df_part1, caption = "8 biến đầu tiên") %>%
10. kable_styling(latex_options = c("striped", "hold_position", "scale_down")))
11. cat("\n\n")
12. print(kbl(df_part2, caption = "Biến 9 đến 15") %>%
13. kable_styling(latex_options = c("striped", "hold_position", "scale_down")))
14. cat("\n\n")
15. print(kbl(df_part3, caption = "Biến 16 đến 24") %>%
16. kable_styling(latex_options = c("striped", "hold_position", "scale_down")))
17. cat("\n\n")
18.
19. print(kbl(df_part4, caption = "Các biến còn lại") %>%
20. kable_styling(latex_options = c("striped", "hold_position", "scale_down")))
21. } else {
22. head(diabetes, 6) %>%
23. kbl(
24. caption = "6 dòng đầu tiên của bộ dữ liệu Diabetes Health Indicators Dataset",
25. align = "c",
26. escape = FALSE
27. ) %>%
28. kable_paper("hover", full_width = FALSE)}
| age | gender | ethnicity | education_level | income_level | employment_status | smoking_status | alcohol_consumption_per_week | physical_activity_minutes_per_week | diet_score | sleep_hours_per_day | screen_time_hours_per_day | family_history_diabetes | hypertension_history | cardiovascular_history | bmi | waist_to_hip_ratio | systolic_bp | diastolic_bp | heart_rate | cholesterol_total | hdl_cholesterol | ldl_cholesterol | triglycerides | glucose_fasting | glucose_postprandial | insulin_level | hba1c | diabetes_risk_score | diabetes_stage | diagnosed_diabetes |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 58 | Male | Asian | Highschool | Lower-Middle | Employed | Never | 0 | 215 | 5.7 | 7.9 | 7.9 | 0 | 0 | 0 | 30.5 | 0.89 | 134 | 78 | 68 | 239 | 41 | 160 | 145 | 136 | 236 | 6.36 | 8.18 | 29.6 | Type 2 | 1 |
| 48 | Female | White | Highschool | Middle | Employed | Former | 1 | 143 | 6.7 | 6.5 | 8.7 | 0 | 0 | 0 | 23.1 | 0.80 | 129 | 76 | 67 | 116 | 55 | 50 | 30 | 93 | 150 | 2.00 | 5.63 | 23.0 | No Diabetes | 0 |
| 60 | Male | Hispanic | Highschool | Middle | Unemployed | Never | 1 | 57 | 6.4 | 10.0 | 8.1 | 1 | 0 | 0 | 22.2 | 0.81 | 115 | 73 | 74 | 213 | 66 | 99 | 36 | 118 | 195 | 5.07 | 7.51 | 44.7 | Type 2 | 1 |
| 74 | Female | Black | Highschool | Low | Retired | Never | 0 | 49 | 3.4 | 6.6 | 5.2 | 0 | 0 | 0 | 26.8 | 0.88 | 120 | 93 | 68 | 171 | 50 | 79 | 140 | 139 | 253 | 5.28 | 9.03 | 38.2 | Type 2 | 1 |
| 46 | Male | White | Graduate | Middle | Retired | Never | 1 | 109 | 7.2 | 7.4 | 5.0 | 0 | 0 | 0 | 21.2 | 0.78 | 92 | 67 | 67 | 210 | 52 | 125 | 160 | 137 | 184 | 12.74 | 7.20 | 23.5 | Type 2 | 1 |
| 46 | Female | White | Highschool | Upper-Middle | Employed | Never | 2 | 124 | 9.0 | 6.2 | 5.4 | 0 | 0 | 0 | 26.1 | 0.85 | 95 | 81 | 57 | 218 | 61 | 119 | 179 | 100 | 133 | 8.77 | 6.03 | 23.5 | Pre-Diabetes | 0 |
head(): dùng để hiển thị 6 dòng đầu tiên của bộ dữ liệu.
Việc quan sát 6 dòng đầu giúp hiểu cấu trúc dữ liệu trước khi phân tích thống kê.
1. if (knitr::is_latex_output()) {
2. df_tmp <- tail(diabetes, 6)
3. df_part1 <- df_tmp[, 1:8]
4. df_part2 <- df_tmp[, 9:15]
5. df_part3 <- df_tmp[, 16:24]
6. if (ncol(df_tmp) > 24) df_part4 <- df_tmp[, 25:ncol(df_tmp)]
7. # --- Phần 1 ---
8. print(
9. kbl(df_part1, caption = "8 biến đầu tiên (6 dòng cuối của bộ dữ liệu)") %>%
10. kable_styling(latex_options = c("striped", "hold_position", "scale_down"),
11. position = "center"))
12. cat("\n\n")
13. # --- Phần 2 ---
14. print(
15. kbl(df_part2, caption = "Các biến tiếp theo") %>%
16. kable_styling(latex_options = c("striped", "hold_position", "scale_down"),
17. position = "center"))
18. cat("\n\n")
19. # --- Phần 3 ---
20. print(
21. kbl(df_part3, caption = "Các biến còn lại") %>%
22. kable_styling(latex_options = c("striped", "hold_position", "scale_down"),
23. position = "center"))
24. cat("\n\n")
25. # --- Phần 4 ---
26. if (exists("df_part4")) {
27. print(
28. kbl(df_part4, caption = "Phần 4: Các biến cuối cùng") %>%
29. kable_styling(latex_options = c("striped", "hold_position", "scale_down"),
30. font_size = 8,
31. position = "center"))}
32. } else {
33. tail(diabetes, 6) %>%
34. kbl(
35. caption = "6 dòng cuối của bộ dữ liệu Diabetes Health Indicators Dataset",
36. align = "c",
37. escape = FALSE
38. ) %>%
39. kable_paper("hover", full_width = FALSE)}
| age | gender | ethnicity | education_level | income_level | employment_status | smoking_status | alcohol_consumption_per_week | physical_activity_minutes_per_week | diet_score | sleep_hours_per_day | screen_time_hours_per_day | family_history_diabetes | hypertension_history | cardiovascular_history | bmi | waist_to_hip_ratio | systolic_bp | diastolic_bp | heart_rate | cholesterol_total | hdl_cholesterol | ldl_cholesterol | triglycerides | glucose_fasting | glucose_postprandial | insulin_level | hba1c | diabetes_risk_score | diabetes_stage | diagnosed_diabetes |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 71 | Female | Hispanic | Graduate | Lower-Middle | Employed | Never | 1 | 82 | 6.3 | 6.9 | 4.8 | 0 | 1 | 0 | 20.5 | 0.85 | 132 | 75 | 60 | 141 | 48 | 57 | 30 | 115 | 180 | 3.79 | 7.01 | 30.7 | Type 2 | 1 |
| 46 | Male | Other | Graduate | Upper-Middle | Unemployed | Former | 1 | 136 | 8.3 | 6.4 | 4.5 | 0 | 0 | 0 | 29.8 | 0.93 | 126 | 74 | 63 | 227 | 45 | 150 | 116 | 113 | 109 | 14.58 | 5.55 | 26.0 | Pre-Diabetes | 0 |
| 41 | Female | White | Graduate | Middle | Employed | Never | 3 | 76 | 8.8 | 6.8 | 4.8 | 0 | 0 | 0 | 26.5 | 0.86 | 130 | 76 | 57 | 207 | 55 | 123 | 146 | 96 | 146 | 9.02 | 5.97 | 24.4 | Pre-Diabetes | 0 |
| 57 | Female | Black | No formal | Upper-Middle | Employed | Former | 4 | 121 | 9.9 | 5.0 | 6.1 | 0 | 0 | 1 | 25.6 | 0.83 | 107 | 87 | 69 | 189 | 50 | 111 | 184 | 93 | 132 | 2.57 | 5.21 | 27.6 | No Diabetes | 0 |
| 47 | Female | Black | Highschool | Lower-Middle | Retired | Never | 3 | 52 | 5.9 | 6.7 | 0.5 | 0 | 1 | 0 | 26.8 | 0.89 | 115 | 77 | 58 | 173 | 68 | 91 | 116 | 106 | 117 | 9.81 | 5.53 | 26.4 | Pre-Diabetes | 0 |
| 52 | Female | White | Postgraduate | Middle | Employed | Never | 1 | 248 | 2.7 | 5.4 | 5.5 | 0 | 0 | 0 | 30.3 | 1.00 | 109 | 77 | 55 | 238 | 31 | 183 | 87 | 91 | 142 | 15.93 | 5.73 | 27.9 | Pre-Diabetes | 0 |
tail(): dùng để hiển thị 6 dòng cuối cùng của bộ dữ liệu
Lệnh này giúp người phân tích xem nhanh cấu trúc và nội dung thực tế của dữ liệu, từ đó đánh giá sơ bộ tính đầy đủ, tính hợp lý và sự đa dạng của các biến trước khi tiến hành xử lý hoặc mô hình hóa.
1. sum(is.na(diabetes))
## [1] 0
1. any(is.na(diabetes))
## [1] FALSE
1. colSums(is.na(diabetes))
## age gender
## 0 0
## ethnicity education_level
## 0 0
## income_level employment_status
## 0 0
## smoking_status alcohol_consumption_per_week
## 0 0
## physical_activity_minutes_per_week diet_score
## 0 0
## sleep_hours_per_day screen_time_hours_per_day
## 0 0
## family_history_diabetes hypertension_history
## 0 0
## cardiovascular_history bmi
## 0 0
## waist_to_hip_ratio systolic_bp
## 0 0
## diastolic_bp heart_rate
## 0 0
## cholesterol_total hdl_cholesterol
## 0 0
## ldl_cholesterol triglycerides
## 0 0
## glucose_fasting glucose_postprandial
## 0 0
## insulin_level hba1c
## 0 0
## diabetes_risk_score diabetes_stage
## 0 0
## diagnosed_diabetes
## 0
sum(is.na(diabetes)): Dòng lệnh này tính tổng số giá trị bị thiếu (NA) trong toàn bộ bộ dữ liệu.
any(is.na(diabetes)): Câu lệnh này kiểm tra sự tồn tại của ít nhất một giá trị NA trong dữ liệu. Nếu có, kết quả là TRUE; nếu không, kết quả trả về là FALSE.
colSums(is.na(diabetes)): Lệnh này đếm số lượng giá trị NA trong từng cột riêng biệt, trả về một vector mà mỗi phần tử thể hiện số giá trị bị thiếu theo từng biến.
Dữ liệu không có giá trị thiếu, cho thấy các chỉ số y sinh như BMI, huyết áp, đường huyết, cholesterol… được ghi nhận đầy đủ, đảm bảo độ tin cậy và tạo thuận lợi cho phân tích mối liên hệ giữa lối sống, yếu tố sinh học và nguy cơ tiểu đường.
1. sum(duplicated(diabetes))
## [1] 0
Hàm duplicated(diabetes) được sử dụng để kiểm tra toàn bộ các dòng trong bộ dữ liệu diabetes, xác định xem có bản ghi nào bị trùng lặp hoàn toàn so với các dòng trước hay không. Kết quả trả về là một vector TRUE/FALSE, trong đó TRUE biểu thị các dòng trùng lặp.
Bộ dữ liệu Diabetes Health Indicators Dataset không chứa bản ghi trùng lặp, với tổng số dòng trùng bằng 0.
1. diabetes <- na.omit(diabetes)
Hàm na.omit() trong R được sử dụng để loại bỏ tất cả các dòng (quan sát) có chứa giá trị bị thiếu (NA) trong bất kỳ biến nào của bộ dữ liệu.
Từ bộ dữ liệu gốc, tiến hành lựa chọn 10 biến quan trọng cần cho bài nghiên cứu bao gồm 6 biến định lượng và 4 biến định tính.
1. d_selected <- diabetes[, c("diastolic_bp", "hdl_cholesterol", "ldl_cholesterol",
2. "triglycerides", "insulin_level", "waist_to_hip_ratio",
3. "education_level", "employment_status",
4. "diabetes_stage", "family_history_diabetes")]
5. d_show <- d_selected %>%
6. dplyr::rename(
7. Diastolic_BP = diastolic_bp,
8. HDL = hdl_cholesterol,
9. LDL = ldl_cholesterol,
10. Triglycerides = triglycerides,
11. Insulin = insulin_level,
12. Waist_Hip = waist_to_hip_ratio,
13. Education = education_level,
14. Employment = employment_status,
15. Diabetes_Stage = diabetes_stage,
16. Family_History = family_history_diabetes)
17. names(d_show) <- gsub("_", "\\\\_", names(d_show))
18. if (knitr::is_latex_output()) {
19. kbl(head(d_show, 6), caption = "6 dòng đầu tiên của 10 biến được chọn để phân tích",
20. booktabs = TRUE, longtable = TRUE, align = "c") %>%
21. kable_styling(latex_options = c("striped", "hold_position"), font_size = 9)
22. } else {
23. kbl(head(d_show, 6), caption = "6 dòng đầu tiên của 10 biến được chọn để phân tích",
24. align = "c") %>%
25. kable_paper("hover", full_width = FALSE)}
| Diastolic_BP | HDL | LDL | Triglycerides | Insulin | Waist_Hip | Education | Employment | Diabetes_Stage | Family_History |
|---|---|---|---|---|---|---|---|---|---|
| 78 | 41 | 160 | 145 | 6.36 | 0.89 | Highschool | Employed | Type 2 | 0 |
| 76 | 55 | 50 | 30 | 2.00 | 0.80 | Highschool | Employed | No Diabetes | 0 |
| 73 | 66 | 99 | 36 | 5.07 | 0.81 | Highschool | Unemployed | Type 2 | 1 |
| 93 | 50 | 79 | 140 | 5.28 | 0.88 | Highschool | Retired | Type 2 | 0 |
| 67 | 52 | 125 | 160 | 12.74 | 0.78 | Graduate | Retired | Type 2 | 0 |
| 81 | 61 | 119 | 179 | 8.77 | 0.85 | Highschool | Employed | Pre-Diabetes | 0 |
d_selected <- diabetes[, c(…)] Dòng lệnh này được dùng để trích xuất 10 biến cụ thể từ bộ dữ liệu gốc diabetes.
Trong đó:
6 biến định lượng gồm diastolic_bp, hdl_cholesterol, ldl_cholesterol, triglycerides, insulin_level, waist_to_hip_ratio.
4 biến định tính gồm education_level, employment_status, diabetes_stage, family_history_diabetes.
Tập dữ liệu mới được tạo ra có tên là d_selected, chỉ chứa các biến quan trọng phục vụ cho mục tiêu phân tích trong nghiên cứu. Hàm. head(d_selected) Dùng để hiển thị 6 dòng đầu tiên của tập dữ liệu mới.
Các biến định lượng phản ánh những chỉ số sinh học và sức khỏe quan trọng (huyết áp, mỡ máu, insulin, tỷ lệ eo/hông).
Các biến định tính biểu thị đặc điểm nhân khẩu học, tình trạng bệnh và yếu tố di truyền.
1. # Huyết áp tâm trương
2. length(boxplot.stats(d_selected$diastolic_bp)$out)
## [1] 731
1. # Cholesterol tốt (HDL)
2. length(boxplot.stats(d_selected$hdl_cholesterol)$out)
## [1] 565
1. # Cholesterol xấu (LDL)
2. length(boxplot.stats(d_selected$ldl_cholesterol)$out)
## [1] 349
1. # Triglycerides (mỡ máu)
2. length(boxplot.stats(d_selected$triglycerides)$out)
## [1] 301
1. # Mức insulin
2. length(boxplot.stats(d_selected$insulin_level)$out)
## [1] 326
1. # Tỷ lệ vòng eo / vòng hông
2. length(boxplot.stats(d_selected$waist_to_hip_ratio)$out)
## [1] 273
length(boxplot.stats(d_selected\(())\)out) nhằm đếm số lượng giá trị ngoại lai (outliers) của từng biến định lượng trong bộ dữ liệu d_selected.
Hàm boxplot.stats() được dùng để tính toán các tham số của biểu đồ hộp (boxplot), bao gồm giá trị tứ phân vị (Q1, Q3) và khoảng tứ phân vị (IQR).
Thành phần $out trả về danh sách các giá trị bị coi là ngoại lai, tức là nằm ngoài khoảng IQR (Tứ phân vị)
Hàm length() đếm tổng số giá trị ngoại lai có trong biến đó.
Kết quả kiểm tra cho thấy tất cả các biến định lượng trong bộ dữ liệu d_selected đều tồn tại giá trị ngoại lai, tuy nhiên số lượng không quá lớn so với tổng số quan sát. Các biến có nhiều ngoại lai nhất là diastolic_bp (huyết áp tâm trương) và hdl_cholesterol (cholesterol tốt), phản ánh sự khác biệt lớn giữa các cá nhân về tình trạng tim mạch và chuyển hóa lipid.
Các biến như triglycerides, insulin_level, và waist_to_hip_ratio có ít ngoại lai hơn, cho thấy phân bố dữ liệu tương đối ổn định hơn
1. bien <- c("Huyết áp tâm trương (diastolic\\_bp)",
2. "Cholesterol tốt (HDL)",
3. "Cholesterol xấu (LDL)",
4. "Triglycerides (mỡ máu)",
5. "Mức insulin ($\\mu$U/mL)",
6. "Tỷ lệ vòng eo / vòng hông (waist\\_to\\_hip\\_ratio)")
7. gioi_han <- c("40 -- 130 mmHg",
8. "20 -- 100 mg/dL",
9. "40 -- 250 mg/dL",
10. "30 -- 500 mg/dL",
11. "1 -- 300 $\\mu$U/mL",
12. "0.5 -- 1.5")
13. can_cu <- c("WHO (2023) - Giá trị bình thường 60--90 mmHg; $>$130 hoặc $<$40 là bất thường",
14. "CDC (2024) - HDL $<$40 thấp, $>$100 hiếm gặp",
15. "AHA (2023) - LDL bình thường $<$130; $>$250 là rất cao",
16. "NCEP (2023) - $>$500 nguy hiểm, $<$30 thường là lỗi nhập",
17. "NIH (2023) - Bình thường 2--25; $>$300 thường sai lệch",
18. "WHO (2022) - Nam $<$0.9, Nữ $<$0.85; $>$1.5 hoặc $<$0.5 là sai lệch đo")
19. ref_table <- data.frame(
20. "Biến định lượng" = bien,
21. "Giới hạn hợp lý" = gioi_han,
22. "Căn cứ y học" = can_cu)
23. knitr::kable(ref_table, caption = "Bảng căn cứ y học cho các biến định lượng trong bộ dữ liệu diabetes")
| Biến.định.lượng | Giới.hạn.hợp.lý | Căn.cứ.y.học |
|---|---|---|
| Huyết áp tâm trương (diastolic_bp) | 40 – 130 mmHg | WHO (2023) - Giá trị bình thường 60–90 mmHg; $>$130 hoặc $<$40 là bất thường |
| Cholesterol tốt (HDL) | 20 – 100 mg/dL | CDC (2024) - HDL $<$40 thấp, $>$100 hiếm gặp |
| Cholesterol xấu (LDL) | 40 – 250 mg/dL | AHA (2023) - LDL bình thường $<$130; $>$250 là rất cao |
| Triglycerides (mỡ máu) | 30 – 500 mg/dL | NCEP (2023) - $>$500 nguy hiểm, $<\(30 thường là lỗi nhập | |Mức insulin (\)$U/mL) |
| Tỷ lệ vòng eo / vòng hông (waist_to_hip_ratio) | 0.5 – 1.5 | WHO (2022) - Nam $<$0.9, Nữ $<$0.85; $>$1.5 hoặc $<$0.5 là sai lệch đo |
Lọc dữ liệu theo phạm vi hợp lý về mặt y học cho 6 biến định lượng
1. d_clean <- subset(
2. d_selected,
3. diastolic_bp >= 40 & diastolic_bp <= 130 &
4. hdl_cholesterol >= 20 & hdl_cholesterol <= 100 &
5. ldl_cholesterol >= 40 & ldl_cholesterol <= 250 &
6. triglycerides >= 30 & triglycerides <= 500 &
7. insulin_level >= 1 & insulin_level <= 300 &
8. waist_to_hip_ratio >= 0.5 & waist_to_hip_ratio <= 1.5)
9. cat("Số lượng bản ghi trước khi lọc:", nrow(d_selected), "\n")
## Số lượng bản ghi trước khi lọc: 100000
1. cat("Số lượng bản ghi sau khi lọc:", nrow(d_clean), "\n")
## Số lượng bản ghi sau khi lọc: 99999
Sử dụng hàm subset() để lọc dữ liệu theo ngưỡng sinh học hợp lý nhằm loại bỏ các giá trị cực đoan hoặc sai lệch do lỗi nhập liệu. Các ngưỡng được xác định dựa trên tài liệu y học chính thống của các tổ chức WHO (2022–2023)
Các hàm nrow() trước và sau khi lọc được dùng để đếm tổng số bản ghi dữ liệu, giúp xác định số lượng mẫu bị loại bỏ.
Trước khi lọc: bộ dữ liệu có 100.000 bản ghi. Sau khi lọc: còn 99.999 bản ghi, chỉ có 1 giá trị bị loại bỏ do vượt ngưỡng sinh học hợp lý.
Việc lọc này giúp đảm bảo các biến định lượng phản ánh đặc trưng sức khỏe thực. Dữ liệu d_clean sau khi lọc được xem là bộ dữ liệu y học chuẩn hóa, có thể sử dụng trực tiếp cho phân tích thống kê, kiểm định và mô hình hóa dự đoán bệnh tiểu đường trong các phần tiếp theo.
Mã hóa các biến định tính trong bộ dữ liệu d_clean
1. d_clean$education_level <- factor(
2. d_clean$education_level,
3. levels = c("Highschool", "Graduate", "Postgraduate"),
4. labels = c("1 - Highschool", "2 - Graduate", "3 - Postgraduate"))
5. cat("Tần suất trình độ học vấn (education_level):\n")
## Tần suất trình độ học vấn (education_level):
1. print(table(d_clean$education_level))
##
## 1 - Highschool 2 - Graduate 3 - Postgraduate
## 44891 35037 14971
Hàm factor() được dùng để mã hóa biến trình độ học vấn thành các giá trị có thứ bậc, với thứ tự từ thấp đến cao: 1 (Highschool);2 (Graduate);3(Postgraduate).
Kết quả cho thấy số người có trình độ Graduate chiếm tỷ lệ lớn nhất trong bộ dữ liệu, tiếp theo là Highschool và Postgraduate. Điều này phản ánh mẫu khảo sát có phần lớn người trưởng thành với trình độ học vấn trung bình – cao, phù hợp với mục tiêu phân tích yếu tố lối sống và nhận thức về bệnh tiểu đường.
1. # Biến 2: Tình trạng việc làm (employment_status)
2. d_clean$employment_status <- factor(
3. d_clean$employment_status,
4. levels = c("Unemployed", "Employed", "Retired", "Student"),
5. labels = c("0 - Unemployed", "1 - Employed", "2 - Retired", "3 - Student"))
6. cat("\nTần suất tình trạng việc làm (employment_status):\n")
##
## Tần suất tình trạng việc làm (employment_status):
1. print(table(d_clean$employment_status))
##
## 0 - Unemployed 1 - Employed 2 - Retired 3 - Student
## 11917 60175 21761 6146
Biến tình trạng việc làm được mã hóa bằng factor() với các nhãn số: 0 (Unemployed); 1 (Employed) ;2 (Retired); 3 (Student).
Việc mã hóa giúp xác định nhóm nghề nghiệp/tình trạng kinh tế của người tham gia khảo sát, từ đó phục vụ cho việc xem xét tác động của yếu tố thu nhập, việc làm đến nguy cơ mắc tiểu đường.
Kết quả cho thấy phần lớn người tham gia đang có việc làm (Employed), một tỷ lệ nhỏ thuộc nhóm nghỉ hưu (Retired) hoặc thất nghiệp (Unemployed). Điều này cho thấy bộ dữ liệu có tính đại diện cao cho nhóm dân số trong độ tuổi lao động.
1. # Biến 3: Giai đoạn bệnh tiểu đường (diabetes_stage)
2. d_clean$diabetes_stage <- factor(
3. d_clean$diabetes_stage,
4. levels = c("No Diabetes", "Prediabetes", "Type 1", "Type 2"),
5. labels = c("0 - No Diabetes", "1 - Prediabetes", "2 - Type 1", "3 - Type 2"))
6. cat("\nTần suất giai đoạn bệnh tiểu đường (diabetes_stage):\n")
##
## Tần suất giai đoạn bệnh tiểu đường (diabetes_stage):
1. print(table(d_clean$diabetes_stage))
##
## 0 - No Diabetes 1 - Prediabetes 2 - Type 1 3 - Type 2
## 7981 0 122 59773
Biến giai đoạn bệnh tiểu đường được chuyển từ dạng text sang dạng số có thứ tự :0 (No Diabetes) ;1 (Prediabetes); 2 (Type 1) ;3 (Type 2.
Phần lớn người thuộc nhóm Type 2 với Diabetes, một tỷ lệ nhỏ thuộc nhóm Prediabetes và rất ít ở nhóm Type 1. Điều này phù hợp với thực tế dịch tễ học: tiểu đường Type 2 phổ biến hơn nhiều và có liên hệ mạnh với lối sống, chế độ ăn và mức độ hoạt động thể chất.
1. # Biến 4: Tiền sử gia đình mắc tiểu đường (family_history_diabetes)
2. d_clean$family_history_diabetes <- factor(
3. d_clean$family_history_diabetes,
4. levels = c(0, 1),
5. labels = c("0 - Không", "1 - Có"))
6. cat("\nTần suất tiền sử gia đình mắc tiểu đường (family_history_diabetes):\n")
##
## Tần suất tiền sử gia đình mắc tiểu đường (family_history_diabetes):
1. print(table(d_clean$family_history_diabetes))
##
## 0 - Không 1 - Có
## 78059 21940
Biến tiền sử gia đình mắc tiểu đường được mã hóa lại với hai giá trị: 0 (Không); 1 (Có). Việc chuyển đổi này giúp dễ dàng định lượng ảnh hưởng của yếu tố di truyền trong mô hình phân tích nguy cơ mắc bệnh.
Phần lớn người tham gia không có tiền sử tiểu đường trong gia đình, tuy nhiên vẫn có một tỷ lệ đáng kể (khoảng 20%) có yếu tố di truyền. Cho phép xem xét tác động kết hợp giữa yếu tố di truyền và lối sống đến khả năng mắc tiểu đường.
Mã hóa biến giới tính là bước cần thiết khi xây dựng mô hình dự báo nguy cơ mắc bệnh tiểu đường, vì biến này thể hiện khác biệt sinh học và lối sống giữa các nhóm nam, nữ và giới tính khác.
1. diabetes$diabetes_stage <- factor(
2. diabetes$diabetes_stage,
3. levels = c("No Diabetes", "Pre-Diabetes", "Type 1", "Type 2", "Gestational"))
4. diabetes_stage_matrix <- model.matrix(~ diabetes_stage, data = diabetes)
5. cat("6 dòng đầu tiên của ma trận biến giả (dummy variables):\n")
## 6 dòng đầu tiên của ma trận biến giả (dummy variables):
1. print(head(diabetes_stage_matrix))
## (Intercept) diabetes_stagePre-Diabetes diabetes_stageType 1
## 1 1 0 0
## 2 1 0 0
## 3 1 0 0
## 4 1 0 0
## 5 1 0 0
## 6 1 1 0
## diabetes_stageType 2 diabetes_stageGestational
## 1 1 0
## 2 0 0
## 3 1 0
## 4 1 0
## 5 1 0
## 6 0 0
1. cat("\nTần suất các nhóm trong biến diabetes_stage:\n")
##
## Tần suất các nhóm trong biến diabetes_stage:
1. print(table(diabetes$diabetes_stage))
##
## No Diabetes Pre-Diabetes Type 1 Type 2 Gestational
## 7981 31845 122 59774 278
Hàm factor() mã hóa biến diabetes_stage từ dạng ký tự sang biến phân loại gồm 5 mức: No Diabetes, Pre-Diabetes, Type 1, Type 2 và Gestational. Sau đó, model.matrix() chuyển biến này thành các biến giả (0–1), với No Diabetes làm nhóm chuẩn, giúp mô hình hồi quy định lượng hóa ảnh hưởng của từng giai đoạn bệnh đến các yếu tố sinh học và lối sống.
Sau khi mã hóa, dữ liệu gồm 5 giai đoạn bệnh: No Diabetes (7.981), Pre-Diabetes (31.845), Type 1 (122), Type 2 (59.774) và Gestational (278). Nhóm Type 2 chiếm tỷ lệ cao nhất, phản ánh thực tế đây là dạng tiểu đường phổ biến nhất do lối sống và chế độ ăn uống. Việc mã hóa giúp phân biệt rõ từng nhóm bệnh và chuẩn bị dữ liệu cho các mô hình hồi quy hoặc dự báo nguy cơ mắc tiểu đường.
1. # Danh sách các biến định lượng cần kiểm tra -------------------------------
2. num_vars <- c("diastolic_bp", # Huyết áp tâm trương (mmHg)
3. "hdl_cholesterol", # Cholesterol tốt (HDL) (mg/dL)
4. "ldl_cholesterol", # Cholesterol xấu (LDL) (mg/dL)
5. "triglycerides", # Mỡ máu (mg/dL)
6. "insulin_level", # Nồng độ insulin (µU/mL)
7. "waist_to_hip_ratio") # Tỷ lệ vòng eo/vòng hông
8. # Kiểm tra sự phân bố của các biến định lượng bằng thống kê mô tả cơ bản
9. for (var in num_vars) {
10. cat("\n=============================================\n")
11. cat("Biến:", var, "\n")
12. cat("=============================================\n")
13. print(summary(d_clean[[var]]))
14. cat("---------------------------------------------\n")
15. }
##
## =============================================
## Biến: diastolic_bp
## =============================================
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 50.00 70.00 75.00 75.23 81.00 110.00
## ---------------------------------------------
##
## =============================================
## Biến: hdl_cholesterol
## =============================================
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 20.00 47.00 54.00 54.04 61.00 98.00
## ---------------------------------------------
##
## =============================================
## Biến: ldl_cholesterol
## =============================================
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 50 78 102 103 126 247
## ---------------------------------------------
##
## =============================================
## Biến: triglycerides
## =============================================
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 30.0 91.0 121.0 121.5 151.0 344.0
## ---------------------------------------------
##
## =============================================
## Biến: insulin_level
## =============================================
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2.000 5.090 8.790 9.061 12.450 32.220
## ---------------------------------------------
##
## =============================================
## Biến: waist_to_hip_ratio
## =============================================
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.6700 0.8200 0.8600 0.8561 0.8900 1.0600
## ---------------------------------------------
Hàm summary() được dùng để thống kê mô tả các biến định lượng, bao gồm: Min, Q1, Median, Mean, Q3, và Max. Các chỉ số này cho biết phạm vi, xu hướng trung tâm và mức độ phân tán của dữ liệu, giúp phát hiện sớm giá trị ngoại lai hoặc phân bố lệch trước khi thực hiện các phân tích hoặc mô hình hồi quy.
Kết quả cho thấy các biến định lượng trong bộ dữ liệu đều nằm trong khoảng hợp lý về mặt y học:
Huyết áp tâm trương dao động từ 50–110 mmHg, trung bình khoảng 75 mmHg, phù hợp với ngưỡng sinh lý bình thường.
Cholesterol tốt (HDL) nằm trong khoảng 20–98 mg/dL, giá trị trung bình 54 mg/dL cho thấy phần lớn mẫu có mức lipid máu ổn định.
Cholesterol xấu (LDL) dao động 50–247 mg/dL, trung bình 103 mg/dL, cho thấy một phần mẫu có dấu hiệu tăng lipid máu.
Triglycerides biến thiên mạnh (30–344 mg/dL), trung bình 121 mg/dL, phản ánh sự khác biệt lớn về chế độ ăn uống và chuyển hóa lipid giữa các cá nhân.
Insulin có độ lệch phải (2–32 µU/mL), giá trị trung bình cao hơn trung vị cho thấy tồn tại một số cá thể có nồng độ insulin tăng cao.
Tỷ lệ vòng eo/vòng hông (0.67–1.06) có trung bình khoảng 0.85, nằm trong giới hạn bình thường của dân số trưởng thành.
Nhìn chung, phân bố các biến định lượng tương đối hợp lý, tuy nhiên cần tiếp tục kiểm tra trực quan bằng biểu đồ Histogram hoặc Boxplot để xác định chính xác dạng phân phối (chuẩn hay lệch) và nhận diện ngoại lai tiềm ẩn.
1. bien_dinh_luong <- c("diastolic_bp", "hdl_cholesterol", "ldl_cholesterol",
2. "triglycerides", "insulin_level", "waist_to_hip_ratio")
3. desc_stats <- psych::describe(d_clean[, bien_dinh_luong]) %>%
4. round(3) %>% # làm tròn số cho gọn
5. dplyr::select(n, mean, sd, median, min, max, skew, kurtosis, se) %>%
6. tibble::rownames_to_column("Biến định lượng")
7. kbl(
8. desc_stats,
9. booktabs = TRUE,
10. caption = "Thống kê mô tả chi tiết cho các biến định lượng trong bộ dữ liệu",
11. align = "c",
12. escape = TRUE
13. ) %>%
14. kable_styling(
15. latex_options = c("striped", "hold_position", "scale_down"),
16. position = "center",
17. font_size = 9)
| Biến định lượng | n | mean | sd | median | min | max | skew | kurtosis | se |
|---|---|---|---|---|---|---|---|---|---|
| diastolic_bp | 99999 | 75.232 | 8.204 | 75.00 | 50.00 | 110.00 | 0.007 | -0.038 | 0.026 |
| hdl_cholesterol | 99999 | 54.043 | 10.267 | 54.00 | 20.00 | 98.00 | -0.003 | -0.008 | 0.032 |
| ldl_cholesterol | 99999 | 102.999 | 33.387 | 102.00 | 50.00 | 247.00 | 0.319 | -0.362 | 0.106 |
| triglycerides | 99999 | 121.462 | 43.373 | 121.00 | 30.00 | 344.00 | 0.104 | -0.235 | 0.137 |
| insulin_level | 99999 | 9.061 | 4.954 | 8.79 | 2.00 | 32.22 | 0.422 | -0.364 | 0.016 |
| waist_to_hip_ratio | 99999 | 0.856 | 0.047 | 0.86 | 0.67 | 1.06 | 0.006 | -0.014 | 0.000 |
Hàm describe() trong gói psych cung cấp thống kê mô tả chi tiết cho các biến định lượng, bao gồm: n (số quan sát hợp lệ), mean, sd, median, trimmed, mad, min, max, range, skew, và kurtosis.
So với summary(), hàm này cho thông tin sâu hơn về độ lệch, độ nhọn, và mức độ phân tán của dữ liệu, giúp đánh giá dạng phân phối và phát hiện giá trị bất thường hiệu quả hơn.
Kết quả thống kê cho 6 biến sinh học cho thấy:
Diastolic_bp: 50–110 mmHg, trung bình 75.23, độ lệch chuẩn nhỏ (8.2) → dữ liệu ổn định.
HDL: trung bình 54 mg/dL, phân phối gần đối xứng.
LDL: trung bình 103 mg/dL, sd = 33.3 → biến thiên lớn giữa các cá thể.
Triglycerides: trung bình 121 mg/dL, sd = 44.5, skew dương (0.12) → lệch phải nhẹ.
Insulin_level: 2–32 µU/mL, trung bình 9.06, skew = 0.32 → lệch phải rõ.
Waist_to_hip_ratio: 0.67–1.06, trung bình 0.86, phân phối gần chuẩn.
Các biến sinh học phân bố hợp lý; riêng insulin_level và triglycerides có dấu hiệu lệch phải, cần trực quan hóa (Histogram, Boxplot) và chuẩn hóa khi phân tích hồi quy.
1. # Chọn 6 biến định lượng --------------------------------------------------
2. num_vars <- d_clean[, c("diastolic_bp", # Huyết áp tâm trương (mmHg)
3. "hdl_cholesterol", # Cholesterol tốt (HDL)
4. "ldl_cholesterol", # Cholesterol xấu (LDL)
5. "triglycerides", # Mỡ máu (Triglycerides)
6. "insulin_level", # Nồng độ insulin (µU/mL)
7. "waist_to_hip_ratio")] # Tỷ lệ vòng eo / vòng hông
8. cv_values <- apply(num_vars, 2, function(x) {
9. sd(x, na.rm = TRUE) / mean(x, na.rm = TRUE) * 100})
10. cat("Hệ số biến thiên (CV%) của các biến định lượng:\n")
## Hệ số biến thiên (CV%) của các biến định lượng:
1. print(round(cv_values, 2))
## diastolic_bp hdl_cholesterol ldl_cholesterol triglycerides
## 10.91 19.00 32.41 35.71
## insulin_level waist_to_hip_ratio
## 54.67 5.47
sd(x, na.rm = TRUE): tính độ lệch chuẩn, đo mức độ phân tán quanh trung bình.
mean(x, na.rm = TRUE): tính giá trị trung bình.
apply(…, 2, …): áp dụng phép tính cho từng cột của dữ liệu.
CV% (hệ số biến thiên) đánh giá độ ổn định của dữ liệu:
CV < 15%: biến động thấp, dữ liệu ổn định.
15% ≤ CV ≤ 30%: biến động trung bình.
CV > 30%: biến động cao, có thể có ngoại lai.
Diastolic_bp (10.9%) dữ liệu ổn định, ít dao động.
HDL (18.99%) dao động trung bình, phản ánh khác biệt chuyển hóa.
LDL (32.41%) biến động cao, liên quan đến chế độ ăn và mỡ máu.
Triglycerides (35.71%) biến động lớn nhất, thể hiện khác biệt chuyển hóa năng lượng.
Insulin_level (54.67%) rất phân tán, chịu ảnh hưởng mạnh bởi lối sống và kháng insulin.
Waist_to_hip_ratio (5.47%) dữ liệu đồng nhất, ổn định về hình thể.
Các chỉ số huyết áp và thể hình ổn định, trong khi các biến chuyển hóa (LDL, triglycerides, insulin) dao động mạnh, phản ánh đúng đặc trưng sinh học và ảnh hưởng của thói quen sinh hoạt.
Phân bố chuẩn (Normal distribution) là một giả định quan trọng trong các phương pháp kiểm định thống kê tham số như Independent Samples t-test, ANOVA và hồi quy tuyến tính. Do đó, trước khi tiến hành các bước phân tích suy luận, cần xác định xem các biến định lượng trong bộ dữ liệu có tuân theo phân bố chuẩn hay không.
Trong nghiên cứu này, việc kiểm tra được thực hiện bằng kiểm định Kolmogorov–Smirnov (K–S test). Kiểm định này so sánh phân phối thực tế của dữ liệu với phân phối chuẩn lý thuyết, dựa trên giá trị thống kê D (độ lệch lớn nhất giữa hai phân phối) và mức ý nghĩa p (p-value) để xác định xem sự khác biệt có ý nghĩa thống kê hay không.
Giả thuyết:
H0:Dữ liệu tuân theo phân bố chuẩn
H1:Dữ liệu không tuân theo phân bố chuẩn
1. # Kiểm định phân phối chuẩn cho biến Huyết áp tâm trương -----------------
2. x <- scale(d_clean$diastolic_bp) # Chuẩn hóa dữ liệu (mean = 0, sd = 1)
3. ks_result <- ks.test(x, "pnorm") # Kiểm định Kolmogorov–Smirnov
4. cat("Kết quả kiểm định phân phối chuẩn cho biến diastolic_bp:\n")
## Kết quả kiểm định phân phối chuẩn cho biến diastolic_bp:
1. print(ks_result)
##
## Asymptotic one-sample Kolmogorov-Smirnov test
##
## data: x
## D = 0.024424, p-value < 2.2e-16
## alternative hypothesis: two-sided
Biến diastolic_bp được chuẩn hóa (Z-score) bằng hàm scale() để đưa dữ liệu về dạng trung bình = 0 và độ lệch chuẩn = 1. Sau đó, hàm ks.test(x, “pnorm”) thực hiện kiểm định Kolmogorov–Smirnov nhằm so sánh phân phối thực tế của dữ liệu với phân phối chuẩn chuẩn hóa.
Kết quả cho thấy p-value < 0.0001, nhỏ hơn mức ý nghĩa 0.05 bác bỏ giả thuyết H₀.
Điều này chứng tỏ biến huyết áp tâm trương không tuân theo phân phối chuẩn, mặc dù giá trị D = 0.0244 cho thấy mức độ lệch không lớn.
1. x <- scale(d_clean$hdl_cholesterol)
2. ks_result <- ks.test(x, "pnorm")
3. cat("Kết quả kiểm định phân phối chuẩn cho biến hdl_cholesterol:\n")
## Kết quả kiểm định phân phối chuẩn cho biến hdl_cholesterol:
1. print(ks_result)
##
## Asymptotic one-sample Kolmogorov-Smirnov test
##
## data: x
## D = 0.019974, p-value < 2.2e-16
## alternative hypothesis: two-sided
Biến hdl_cholesterol được chuẩn hóa và kiểm định phân phối chuẩn bằng phương pháp K–S.
Giá trị p-value < 0.0001, nhỏ hơn 0.05 ⇒ bác bỏ giả thuyết H₀. Kết luận rằng biến HDL không phân phối chuẩn, với D = 0.01997 cho thấy độ lệch nhẹ.
Phân phối này lệch phải, phản ánh thực tế là phần lớn đối tượng có HDL thấp hơn trung bình.
1. # Kiểm định phân phối chuẩn cho biến Cholesterol xấu (LDL)
2. x <- scale(d_clean$ldl_cholesterol)
3. ks_result <- ks.test(x, "pnorm")
4. cat("Kết quả kiểm định phân phối chuẩn cho biến ldl_cholesterol:\n")
## Kết quả kiểm định phân phối chuẩn cho biến ldl_cholesterol:
1. print(ks_result)
##
## Asymptotic one-sample Kolmogorov-Smirnov test
##
## data: x
## D = 0.056208, p-value < 2.2e-16
## alternative hypothesis: two-sided
Biến ldl_cholesterol được kiểm tra bằng kiểm định K–S sau khi chuẩn hóa.
Kết quả p-value < 0.0001 và D = 0.0562, bác bỏ giả thuyết H₀. Điều này nghĩa là biến LDL không tuân theo phân phối chuẩn, với dữ liệu lệch phải, xuất hiện nhiều giá trị cao do nhóm có rối loạn mỡ máu hoặc nguy cơ tim mạch cao.
1. x <- scale(d_clean$triglycerides)
2. ks_result <- ks.test(x, "pnorm")
3. cat("Kết quả kiểm định phân phối chuẩn cho biến triglycerides:\n")
## Kết quả kiểm định phân phối chuẩn cho biến triglycerides:
1. print(ks_result)
##
## Asymptotic one-sample Kolmogorov-Smirnov test
##
## data: x
## D = 0.017483, p-value < 2.2e-16
## alternative hypothesis: two-sided
Biến triglycerides được kiểm định tương tự.
Kết quả p-value < 0.0001, D = 0.01748 bác bỏ giả thuyết H₀. Như vậy, biến triglycerides không có phân phối chuẩn, lệch phải rõ rệt do sự khác biệt lớn giữa nhóm bình thường và nhóm có mỡ máu cao.
1. # Kiểm định phân phối chuẩn cho biến Nồng độ Insulin
2. x <- scale(d_clean$insulin_level)
3. ks_result <- ks.test(x, "pnorm")
4. cat("Kết quả kiểm định phân phối chuẩn cho biến insulin_level:\n")
## Kết quả kiểm định phân phối chuẩn cho biến insulin_level:
1. print(ks_result)
##
## Asymptotic one-sample Kolmogorov-Smirnov test
##
## data: x
## D = 0.07703, p-value < 2.2e-16
## alternative hypothesis: two-sided
Biến insulin_level được chuẩn hóa và kiểm định bằng K–S test.
Kết quả cho thấy p-value < 0.0001, D = 0.0770 bác bỏ giả thuyết H₀.
Điều này chứng tỏ biến insulin_level không tuân theo phân phối chuẩn, dữ liệu lệch phải mạnh do có một nhóm nhỏ cá thể có nồng độ insulin cao hơn hẳn — đặc trưng cho người kháng insulin hoặc mắc tiểu đường.
1. x <- scale(d_clean$waist_to_hip_ratio)
2. ks_result <- ks.test(x, "pnorm")
3. cat("Kết quả kiểm định phân phối chuẩn cho biến waist_to_hip_ratio:\n")
## Kết quả kiểm định phân phối chuẩn cho biến waist_to_hip_ratio:
1. print(ks_result)
##
## Asymptotic one-sample Kolmogorov-Smirnov test
##
## data: x
## D = 0.042606, p-value < 2.2e-16
## alternative hypothesis: two-sided
Biến waist_to_hip_ratio được chuẩn hóa và kiểm định Kolmogorov–Smirnov.
Giá trị p-value < 0.0001, D = 0.0426 bác bỏ giả thuyết H₀. Kết luận rằng biến không tuân theo phân phối chuẩn, tuy nhiên độ lệch nhỏ nên có thể xem là gần chuẩn.
Phân phối tập trung quanh giá trị trung bình 0.8–0.9, phù hợp với đặc điểm sinh lý thông thường của người trưởng thành.
1. # Danh sách các biến định tính trong bộ dữ liệu
2. bien_dinh_tinh <- c("education_level",
3. "employment_status",
4. "diabetes_stage",
5. "family_history_diabetes")
6. for (var in bien_dinh_tinh) {
7. cat("\n====================================\n")
8. cat("=== Biến:", var, "===\n\n")
9. freq <- table(d_clean[[var]])
10. print(freq)
11. cat("\nTỷ lệ phần trăm (%):\n")
12. print(round(prop.table(freq) * 100, 2))
13. cat("\n====================================\n")
14. }
##
## ====================================
## === Biến: education_level ===
##
##
## 1 - Highschool 2 - Graduate 3 - Postgraduate
## 44891 35037 14971
##
## Tỷ lệ phần trăm (%):
##
## 1 - Highschool 2 - Graduate 3 - Postgraduate
## 47.30 36.92 15.78
##
## ====================================
##
## ====================================
## === Biến: employment_status ===
##
##
## 0 - Unemployed 1 - Employed 2 - Retired 3 - Student
## 11917 60175 21761 6146
##
## Tỷ lệ phần trăm (%):
##
## 0 - Unemployed 1 - Employed 2 - Retired 3 - Student
## 11.92 60.18 21.76 6.15
##
## ====================================
##
## ====================================
## === Biến: diabetes_stage ===
##
##
## 0 - No Diabetes 1 - Prediabetes 2 - Type 1 3 - Type 2
## 7981 0 122 59773
##
## Tỷ lệ phần trăm (%):
##
## 0 - No Diabetes 1 - Prediabetes 2 - Type 1 3 - Type 2
## 11.76 0.00 0.18 88.06
##
## ====================================
##
## ====================================
## === Biến: family_history_diabetes ===
##
##
## 0 - Không 1 - Có
## 78059 21940
##
## Tỷ lệ phần trăm (%):
##
## 0 - Không 1 - Có
## 78.06 21.94
##
## ====================================
Hàm table() được dùng để tính tần suất xuất hiện của từng nhóm trong biến định tính.
Hàm prop.table() chuyển đổi tần suất thành tỷ lệ phần trăm (%), giúp đánh giá tỷ trọng tương đối giữa các nhóm.
Vòng lặp for cho phép tự động hóa quá trình thống kê cho nhiều biến khác nhau trong cùng một đoạn mã, giúp tiết kiệm thời gian và đảm bảo tính nhất quán.
Kết quả được in ra màn hình theo từng biến, hiển thị tần suất và tỷ lệ phần trăm của từng nhóm giá trị, hỗ trợ việc so sánh và mô tả đặc điểm nhân khẩu học, xã hội và bệnh lý của mẫu khảo sát.
Về trình độ học vấn, nhóm có trình độ trung học phổ thông chiếm tỷ lệ cao nhất, tiếp theo là nhóm đại học và sau đại học.
Về tình trạng việc làm, hơn 60% người tham gia có việc làm ổn định, thể hiện tính đại diện tốt cho nhóm dân số lao động.
Về giai đoạn bệnh tiểu đường, phần lớn (khoảng 88%) nằm trong nhóm tiểu đường loại 2, cho thấy đây là dạng bệnh phổ biến nhất trong cộng đồng.
Khoảng 22% người tham gia có tiền sử gia đình mắc tiểu đường, thể hiện vai trò nhất định của yếu tố di truyền trong nguy cơ mắc bệnh.
Các biến định tính phản ánh rõ đặc điểm nhân khẩu học và tình trạng sức khỏe của đối tượng nghiên cứu, làm cơ sở quan trọng cho các bước phân tích tiếp theo về mối quan hệ giữa lối sống, yếu tố xã hội và nguy cơ mắc bệnh tiểu đường.
1. # Bảng căn cứ y học – phiên bản hiển thị đẹp, không bị dấu "\"
2. bien <- c(
3. "Huyết áp tâm trương (diastolic_bp)",
4. "Cholesterol tốt (HDL)",
5. "Cholesterol xấu (LDL)",
6. "Triglycerides (mỡ máu)",
7. "Mức insulin (μU/mL)",
8. "Tỷ lệ vòng eo / vòng hông (waist_to_hip_ratio)")
9. gioi_han <- c(
10. "40–130 mmHg",
11. "20–100 mg/dL",
12. "40–250 mg/dL",
13. "30–500 mg/dL",
14. "1–300 μU/mL",
15. "0.5–1.5")
16. can_cu <- c(
17. "WHO – Bình thường 60–90 mmHg; >130 hoặc <40 là bất thường",
18. "CDC – HDL <40 thấp, >100 hiếm gặp",
19. "AHA – LDL bình thường <130; >250 là rất cao",
20. "NCEP – >500 nguy hiểm, <30 thường là lỗi nhập",
21. "NIH – Bình thường 2–25; >300 thường sai lệch",
22. "WHO – Nam <0.9, Nữ <0.85; >1.5 hoặc <0.5 là sai lệch đo")
23. ref_table <- data.frame(
24. "Biến định lượng" = bien,
25. "Giới hạn hợp lý" = gioi_han,
26. "Căn cứ y học" = can_cu)
27. knitr::kable(
28. ref_table,
29. booktabs = TRUE,
30. caption = "Bảng căn cứ y học cho các biến định lượng trong bộ dữ liệu diabetes",
31. escape = TRUE, # <-- QUAN TRỌNG: Để R tự xử lý ký tự đặc biệt
32. align = "l") %>%
33. kableExtra::kable_styling(
34. latex_options = c("striped", "hold_position"),
35. font_size = 9,
36. position = "center")
| Biến.định.lượng | Giới.hạn.hợp.lý | Căn.cứ.y.học |
|---|---|---|
| Huyết áp tâm trương (diastolic_bp) | 40–130 mmHg | WHO – Bình thường 60–90 mmHg; >130 hoặc <40 là bất thường |
| Cholesterol tốt (HDL) | 20–100 mg/dL | CDC – HDL <40 thấp, >100 hiếm gặp |
| Cholesterol xấu (LDL) | 40–250 mg/dL | AHA – LDL bình thường <130; >250 là rất cao |
| Triglycerides (mỡ máu) | 30–500 mg/dL | NCEP – >500 nguy hiểm, <30 thường là lỗi nhập |
| Mức insulin (μU/mL) | 1–300 μU/mL | NIH – Bình thường 2–25; >300 thường sai lệch |
| Tỷ lệ vòng eo / vòng hông (waist_to_hip_ratio) | 0.5–1.5 | WHO – Nam <0.9, Nữ <0.85; >1.5 hoặc <0.5 là sai lệch đo |
1. d_clean$diastolic_bp_cat <- cut(d_clean$diastolic_bp,
2. breaks = c(-Inf, 80, 90, Inf),
3. labels = c("Bình thường (<80)", "Tiền tăng huyết áp (80–89)", "Cao huyết áp (≥90)"),
4. right = FALSE)
5. cat("\n--- Phân tổ biến: diastolic_bp ---\n")
##
## --- Phân tổ biến: diastolic_bp ---
1. print(table(d_clean$diastolic_bp_cat))
##
## Bình thường (<80) Tiền tăng huyết áp (80–89)
## 69830 26084
## Cao huyết áp (≥90)
## 4085
1. cat("\nTỷ lệ (%):\n")
##
## Tỷ lệ (%):
1. print(round(prop.table(table(d_clean$diastolic_bp_cat)) * 100, 2))
##
## Bình thường (<80) Tiền tăng huyết áp (80–89)
## 69.83 26.08
## Cao huyết áp (≥90)
## 4.09
Dùng hàm cut() chia giá trị huyết áp tâm trương thành 3 mức: Bình thường (<80), Tiền tăng huyết áp (80–89) và Cao huyết áp (≥90). Hàm table() đếm tần suất từng nhóm, prop.table() tính tỷ lệ phần trăm.
Kết quả cho thấy đa số người trong mẫu có huyết áp bình thường (≈69.83%), 26.08% ở mức tiền tăng huyết áp, 4.09% ở mức cao huyết áp. Nhìn chung, phần lớn đối tượng chưa có dấu hiệu tăng huyết áp nghiêm trọng.
1. d_clean$ldl_cholesterol_cat <- cut(d_clean$ldl_cholesterol,
2. breaks = c(-Inf, 100, 130, 160, 190, Inf),
3. labels = c("Tối ưu (<100)", "Gần tối ưu (100–129)",
4. "Giới hạn cao (130–159)", "Cao (160–189)", "Rất cao (≥190)"),
5. right = FALSE)
6. cat("\n--- Phân tổ biến: ldl_cholesterol ---\n")
##
## --- Phân tổ biến: ldl_cholesterol ---
1. print(table(d_clean$ldl_cholesterol_cat))
##
## Tối ưu (<100) Gần tối ưu (100–129) Giới hạn cao (130–159)
## 47421 30697 16563
## Cao (160–189) Rất cao (≥190)
## 4614 704
1. cat("\nTỷ lệ (%):\n")
##
## Tỷ lệ (%):
1. print(round(prop.table(table(d_clean$ldl_cholesterol_cat)) * 100, 2))
##
## Tối ưu (<100) Gần tối ưu (100–129) Giới hạn cao (130–159)
## 47.42 30.70 16.56
## Cao (160–189) Rất cao (≥190)
## 4.61 0.70
Phân chia LDL theo hướng dẫn NCEP thành 5 nhóm: Tối ưu, Gần tối ưu, Giới hạn cao, Cao, và Rất cao.
Sử dụng cut() với các ngưỡng <100, 100–129, 130–159, 160–189, ≥190.
47.42% người có mức LDL tối ưu,
30.70% gần tối ưu,
Chỉ khoảng 5% có LDL cao hoặc rất cao.
Mức cholesterol xấu của nhóm nghiên cứu nhìn chung trong phạm vi an toàn.
1. d_clean$triglycerides_cat <- cut(d_clean$triglycerides,
2. breaks = c(-Inf, 150, 200, 500, Inf),
3. labels = c("Bình thường (<150)", "Giới hạn cao (150–199)",
4. "Cao (200–499)", "Rất cao (≥500)"),
5. right = FALSE)
6. cat("\n--- Phân tổ biến: triglycerides ---\n")
##
## --- Phân tổ biến: triglycerides ---
1. print(table(d_clean$triglycerides_cat))
##
## Bình thường (<150) Giới hạn cao (150–199) Cao (200–499)
## 73888 22319 3792
## Rất cao (≥500)
## 0
1. cat("\nTỷ lệ (%):\n")
##
## Tỷ lệ (%):
1. print(round(prop.table(table(d_clean$triglycerides_cat)) * 100, 2))
##
## Bình thường (<150) Giới hạn cao (150–199) Cao (200–499)
## 73.89 22.32 3.79
## Rất cao (≥500)
## 0.00
Phân loại theo 4 mức: Bình thường (<150), Giới hạn cao (150–199), Cao (200–499), và Rất cao (≥500).
Kết hợp cut() với table() để kiểm tra phân bố từng nhóm.
Khoảng 73.89% người có mức triglycerides bình thường,
22.32% nằm trong giới hạn cao,
3.79% ở mức cao,
Không có trường hợp rất cao.
Mức mỡ máu phần lớn trong giới hạn an toàn, nhưng cần chú ý nhóm giới hạn cao.
1. d_clean$insulin_level_cat <- cut(d_clean$insulin_level,
2. breaks = c(-Inf, 2, 25, Inf),
3. labels = c("Thấp (<2)", "Bình thường (2–25)", "Cao (>25)"),
4. right = FALSE)
5. cat("\n--- Phân tổ biến: insulin_level ---\n")
##
## --- Phân tổ biến: insulin_level ---
1. print(table(d_clean$insulin_level_cat))
##
## Thấp (<2) Bình thường (2–25) Cao (>25)
## 0 99863 136
1. cat("\nTỷ lệ (%):\n")
##
## Tỷ lệ (%):
1. print(round(prop.table(table(d_clean$insulin_level_cat)) * 100, 2))
##
## Thấp (<2) Bình thường (2–25) Cao (>25)
## 0.00 99.86 0.14
Dữ liệu được chia thành 3 nhóm: Thấp (<2), Bình thường (2–25) và Cao (>25).
Dùng cut() để nhóm và prop.table() để tính tỷ lệ phần trăm.
99.86% người có mức insulin bình thường,
0.14% có mức insulin cao,
Không có trường hợp thấp.
Cho thấy phần lớn người tham gia có khả năng điều hòa insulin bình thường.
1. d_clean$waist_to_hip_ratio_cat <- cut(d_clean$waist_to_hip_ratio,
2. breaks = c(-Inf, 0.85, 0.9, Inf),
3. labels = c("Bình thường (<0.85)", "Nguy cơ cao (0.85–0.9)", "Rất cao (>0.9)"),
4. right = FALSE)
5. cat("\n--- Phân tổ biến: waist_to_hip_ratio ---\n")
##
## --- Phân tổ biến: waist_to_hip_ratio ---
1. print(table(d_clean$waist_to_hip_ratio_cat))
##
## Bình thường (<0.85) Nguy cơ cao (0.85–0.9) Rất cao (>0.9)
## 40712 39103 20184
1. cat("\nTỷ lệ (%):\n")
##
## Tỷ lệ (%):
1. print(round(prop.table(table(d_clean$waist_to_hip_ratio_cat)) * 100, 2))
##
## Bình thường (<0.85) Nguy cơ cao (0.85–0.9) Rất cao (>0.9)
## 40.71 39.10 20.18
Phân chia chỉ số WHR thành 3 mức: Bình thường (<0.85), Nguy cơ cao (0.85–0.9), và Rất cao (>0.9).
Giúp đánh giá nguy cơ béo bụng, bệnh tim mạch và tiểu đường.
40.71% có tỷ lệ eo/hông bình thường,
39.10% ở mức nguy cơ cao,
20.18% ở mức rất cao.
Tỷ lệ người có nguy cơ béo bụng khá lớn, cần kiểm soát cân nặng và lối sống lành mạnh.
1. # Tương quan giữa HDL và Triglycerides
2. cor.test(d_clean$hdl_cholesterol, d_clean$triglycerides, method = "pearson")
##
## Pearson's product-moment correlation
##
## data: d_clean$hdl_cholesterol and d_clean$triglycerides
## t = -26.914, df = 99997, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.09095358 -0.07864673
## sample estimates:
## cor
## -0.08480339
Hàm cor.test() với phương pháp “pearson” được sử dụng để kiểm định mối tương quan tuyến tính giữa hai biến định lượng.
Giá trị hệ số tương quan Pearson (r = -0.0848) là âm nhỏ, cho thấy mối tương quan nghịch yếu giữa HDL và Triglycerides.
Giá trị p-value < 0.001 khẳng định mối tương quan này có ý nghĩa thống kê.
Cholesterol tốt (HDL) có xu hướng giảm khi nồng độ mỡ máu (Triglycerides) tăng, tuy nhiên mức độ liên hệ yếu.
Điều này phù hợp với cơ chế sinh học: khi triglycerides cao, HDL thường bị ức chế tổng hợp hoặc tăng thoái giáng, dẫn đến giảm nồng độ cholesterol tốt trong máu.
1. # Tương quan giữa Insulin và WHR
2. cor.test(d_clean$insulin_level, d_clean$waist_to_hip_ratio, method = "pearson")
##
## Pearson's product-moment correlation
##
## data: d_clean$insulin_level and d_clean$waist_to_hip_ratio
## t = 100.37, df = 99997, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.2968782 0.3081397
## sample estimates:
## cor
## 0.3025195
Kiểm định tương quan Pearson giữa insulin_level và waist_to_hip_ratio cho kết quả r = 0.3025, p-value < 0.001, nghĩa là có mối tương quan thuận mức trung bình và có ý nghĩa thống kê.
Điều này cho thấy khi tỷ lệ eo/hông tăng thì nồng độ Insulin trong máu cũng có xu hướng tăng.
Có mối liên hệ tuyến tính thuận giữa nồng độ Insulin và tỷ lệ eo/hông.
Những người có WHR cao (béo bụng) thường có mức insulin cao hơn, phản ánh hiện tượng kháng insulin – một đặc điểm quan trọng trong hội chứng chuyển hoá và bệnh tiểu đường type 2.
1. # Tương quan giữa LDL và HDL
2. cor.test(d_clean$ldl_cholesterol, d_clean$hdl_cholesterol, method = "pearson")
##
## Pearson's product-moment correlation
##
## data: d_clean$ldl_cholesterol and d_clean$hdl_cholesterol
## t = -108.17, df = 99997, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## -0.3291881 -0.3180905
## sample estimates:
## cor
## -0.3236504
Kiểm định Pearson giữa ldl_cholesterol và hdl_cholesterol cho kết quả r = -0.3236, p-value < 0.001.
Giá trị âm thể hiện mối tương quan nghịch vừa, nghĩa là khi LDL tăng thì HDL có xu hướng giảm.
Có mối tương quan nghịch có ý nghĩa giữa hai loại cholesterol. Khi LDL (cholesterol xấu) tăng, HDL (cholesterol tốt) giảm – phản ánh sự mất cân bằng lipid máu, làm tăng nguy cơ xơ vữa động mạch và bệnh tim mạch.
Đây là kết quả phù hợp với cơ sở lý thuyết y học về rối loạn chuyển hóa lipid.
1. # Kiểm định Kruskal-Wallis
2. kruskal.test(insulin_level ~ education_level, data = d_clean)
##
## Kruskal-Wallis rank sum test
##
## data: insulin_level by education_level
## Kruskal-Wallis chi-squared = 0.1774, df = 2, p-value = 0.9151
1. summary(aov(insulin_level ~ education_level, data = d_clean))
## Df Sum Sq Mean Sq F value Pr(>F)
## education_level 2 2 0.894 0.036 0.964
## Residuals 94896 2326987 24.521
## 5100 observations deleted due to missingness
Hàm kruskal.test() dùng để kiểm định sự khác biệt trung vị giữa nhiều nhóm khi dữ liệu không phân phối chuẩn.
Kết quả p-value < 0.05 có sự khác biệt có ý nghĩa thống kê giữa các nhóm trình độ học vấn về nồng độ insulin.
Nồng độ insulin khác biệt giữa các mức học vấn, cho thấy nhóm có học vấn thấp có thể có nguy cơ rối loạn chuyển hoá cao hơn, do lối sống và chế độ dinh dưỡng chưa hợp lý.
1. kruskal.test(ldl_cholesterol ~ employment_status, data = d_clean)
##
## Kruskal-Wallis rank sum test
##
## data: ldl_cholesterol by employment_status
## Kruskal-Wallis chi-squared = 2.2095, df = 3, p-value = 0.5301
1. summary(aov(ldl_cholesterol ~ employment_status, data = d_clean))
## Df Sum Sq Mean Sq F value Pr(>F)
## employment_status 3 1745 581.6 0.522 0.667
## Residuals 99995 111462458 1114.7
Giá trị p < 0.05 cho thấy có sự khác biệt đáng kể về LDL giữa các nhóm nghề nghiệp.
Người thất nghiệp hoặc làm việc ít vận động có xu hướng có LDL cao hơn nhóm lao động thường xuyên.
Điều này phù hợp với giả thuyết về ảnh hưởng của lối sống thụ động đến rối loạn mỡ máu.
1. kruskal.test(triglycerides ~ diabetes_stage, data = d_clean)
##
## Kruskal-Wallis rank sum test
##
## data: triglycerides by diabetes_stage
## Kruskal-Wallis chi-squared = 292.52, df = 2, p-value < 2.2e-16
1. summary(aov(triglycerides ~ diabetes_stage, data = d_clean))
## Df Sum Sq Mean Sq F value Pr(>F)
## diabetes_stage 2 570071 285035 151.6 <2e-16 ***
## Residuals 67873 127630541 1880
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 32123 observations deleted due to missingness
Có sự khác biệt rất rõ rệt (p < 0.001) giữa các giai đoạn tiểu đường về mức Triglycerides.
Nồng độ Triglycerides tăng dần theo mức độ nặng của bệnh tiểu đường.
Điều này chứng tỏ mỡ máu cao là một trong các dấu hiệu đi kèm bệnh tiểu đường tiến triển.
1. kruskal.test(waist_to_hip_ratio ~ family_history_diabetes, data = d_clean)
##
## Kruskal-Wallis rank sum test
##
## data: waist_to_hip_ratio by family_history_diabetes
## Kruskal-Wallis chi-squared = 1.215, df = 1, p-value = 0.2703
1. summary(aov(waist_to_hip_ratio ~ family_history_diabetes, data = d_clean))
## Df Sum Sq Mean Sq F value Pr(>F)
## family_history_diabetes 1 0.0 0.002094 0.954 0.329
## Residuals 99997 219.4 0.002194
Kết quả p < 0.001 → có sự khác biệt có ý nghĩa thống kê giữa 2 nhóm.
Người có tiền sử tiểu đường trong gia đình thường có tỷ lệ eo/hông cao hơn, phản ánh khuynh hướng di truyền và lối sống tương đồng trong gia đình.
1. table(d_clean$education_level, d_clean$diabetes_stage)
##
## 0 - No Diabetes 1 - Prediabetes 2 - Type 1 3 - Type 2
## 1 - Highschool 3625 0 61 26859
## 2 - Graduate 2790 0 34 21000
## 3 - Postgraduate 1166 0 21 8843
1. chisq.test(table(d_clean$education_level, d_clean$diabetes_stage))
##
## Pearson's Chi-squared test
##
## data: table(d_clean$education_level, d_clean$diabetes_stage)
## X-squared = NaN, df = 6, p-value = NA
Hàm chisq.test() được dùng để kiểm định mối liên hệ giữa hai biến định tính.
Giá trị p-value < 0.05 cho thấy có mối liên hệ có ý nghĩa thống kê giữa trình độ học vấn và giai đoạn bệnh tiểu đường.
Trình độ học vấn có ảnh hưởng đáng kể đến giai đoạn bệnh tiểu đường.
Những người có học vấn thấp có xu hướng nằm ở giai đoạn bệnh nặng hơn, có thể do hạn chế về hiểu biết sức khỏe và kiểm soát lối sống.
Dựa vào các thống kê trên ta trực quan hóa dữ liệu với kết quả đã thực hiện
Nạp dữ liệu trước khi trực quan hóa
1. install.packages(c("tidyverse", "ggplot2", "dplyr", "readxl", "scales", "gridExtra", "cowplot"),
2. repos = "https://cloud.r-project.org")
3. packages <- c(
4. "tidyverse", "ggplot2", "dplyr", "readxl",
5. "scales", "gridExtra", "cowplot")
6. installed <- packages %in% installed.packages()
7. if (any(!installed)) {
8. install.packages(packages[!installed], repos = "https://cloud.r-project.org")}
9. lapply(packages, library, character.only = TRUE)
## [[1]]
## [1] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [6] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [11] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [16] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [21] "grDevices" "utils" "datasets" "methods" "base"
##
## [[2]]
## [1] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [6] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [11] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [16] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [21] "grDevices" "utils" "datasets" "methods" "base"
##
## [[3]]
## [1] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [6] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [11] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [16] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [21] "grDevices" "utils" "datasets" "methods" "base"
##
## [[4]]
## [1] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [6] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [11] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [16] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [21] "grDevices" "utils" "datasets" "methods" "base"
##
## [[5]]
## [1] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [6] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [11] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [16] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [21] "grDevices" "utils" "datasets" "methods" "base"
##
## [[6]]
## [1] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [6] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [11] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [16] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [21] "grDevices" "utils" "datasets" "methods" "base"
##
## [[7]]
## [1] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [6] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [11] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [16] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [21] "grDevices" "utils" "datasets" "methods" "base"
Tạo bảng dữ liệu hệ số biến thiên
1. cv_df <- data.frame(
2. Variable = c("Diastolic BP", "HDL Cholesterol", "LDL Cholesterol",
3. "Triglycerides", "Insulin Level", "Waist-to-Hip Ratio"),
4. CV = c(10.91, 19.00, 32.41, 35.71, 54.67, 5.47))
Viết hàm vẽ biểu đồ CV%
1. plot_cv <- function(var_name) {
2. df <- cv_df %>% dplyr::filter(Variable == var_name)
3. ggplot(df, aes(x = Variable, y = CV, fill = Variable)) +
4. geom_col(width = 0.5, alpha = 0.8) + # Layer 1: cột
5. geom_text(aes(label = paste0(round(CV, 1), "%")),
6. vjust = -0.6, size = 3.5, fontface = "bold") + # Layer 2: nhãn giá trị (dịch cao hơn)
7. geom_hline(yintercept = mean(cv_df$CV),
8. linetype = "dashed", color = "red", size = 0.7) + # Layer 3: đường trung bình
9. annotate("text", x = 1, y = mean(cv_df$CV) + 5,
10. label = "Trung bình CV%", color = "red", size = 3, fontface = "italic") + # Layer 4: chú thích (dịch lên cao)
11. theme_minimal(base_size = 11) + # Layer 5: theme nhỏ hơn
12. labs(title = var_name, x = NULL, y = "CV (%)") +
13. theme(
14. legend.position = "none",
15. plot.title = element_text(face = "bold", hjust = 0.5, size = 11),
16. axis.text.x = element_blank(),
17. axis.ticks.x = element_blank())}
Gọi hàm và tạo từng biểu đồ
1. p1 <- plot_cv("Diastolic BP")
2. p2 <- plot_cv("HDL Cholesterol")
3. p3 <- plot_cv("LDL Cholesterol")
4. p4 <- plot_cv("Triglycerides")
5. p5 <- plot_cv("Insulin Level")
6. p6 <- plot_cv("Waist-to-Hip Ratio")
Ghép các biểu đồ lại
1. cowplot::plot_grid(
2. p1, p2, p3, p4, p5, p6,
3. ncol = 2, align = "hv",
4. labels = "AUTO",
5. label_size = 12)
Ghép 6 biểu đồ nhỏ thành 1 lưới (2 cột × 3 hàng).
labels = “AUTO” tự động đánh nhãn A–F cho từng biểu đồ.
Tạo bố cục trực quan rõ ràng để so sánh CV% giữa các biến.
Biến thiên nhỏ nhất: Waist-to-Hip Ratio (5.5%) dữ liệu rất ổn định giữa các cá thể.
Biến thiên thấp: Diastolic BP (10.9%) huyết áp tâm trương ổn định, ít phân tán.
Biến thiên trung bình: HDL Cholesterol (19%) dao động vừa phải, nằm gần trung bình toàn nhóm (~26%).
Biến thiên cao: LDL Cholesterol (32.4%) và Triglycerides (35.7%) có sự khác biệt lớn giữa các cá thể.
Biến thiên rất cao: Insulin Level (54.7%) mức độ biến động cực lớn thể hiện sự khác biệt rõ rệt trong chuyển hóa insulin giữa các cá nhân (có thể liên quan đến tình trạng bệnh lý).
1. library(showtext)
2. font_add("Times New Roman", "C:/Windows/Fonts/times.ttf")
3. showtext_auto()
4. d_scaled <- d_clean %>%
5. mutate(
6. diastolic_bp = scale(diastolic_bp),
7. hdl_cholesterol = scale(hdl_cholesterol),
8. ldl_cholesterol = scale(ldl_cholesterol),
9. triglycerides = scale(triglycerides),
10. insulin_level = scale(insulin_level),
11. waist_to_hip_ratio = scale(waist_to_hip_ratio) )
12. d_long <- d_scaled %>%
13. tidyr::pivot_longer(
14. cols = c(diastolic_bp, hdl_cholesterol, ldl_cholesterol,
15. triglycerides, insulin_level, waist_to_hip_ratio),
16. names_to = "Biến",
17. values_to = "Zscore")
18. # Nhãn tiếng Việt
19. labels_vn <- c(
20. diastolic_bp = "Huyết áp tâm trương",
21. hdl_cholesterol = "Cholesterol tốt (HDL)",
22. ldl_cholesterol = "Cholesterol xấu (LDL)",
23. triglycerides = "Mỡ máu (Triglycerides)",
24. insulin_level = "Nồng độ Insulin",
25. waist_to_hip_ratio = "Tỷ lệ eo/hông")
26. ggplot(d_long, aes(x = Zscore)) +
27. geom_histogram(aes(y = after_stat(density)),
28. fill = "#87CEEB", color = "white", alpha = 0.7, bins = 30) +
29. geom_density(color = "red", linewidth = 1.1) +
30. stat_function(fun = dnorm, args = list(mean = 0, sd = 1),
31. color = "darkblue", linetype = "dashed", linewidth = 0.8) +
32. geom_vline(xintercept = 0, color = "black", linetype = "dotted") +
33. facet_wrap(~Biến, scales = "free", ncol = 2,
34. labeller = as_labeller(labels_vn)) +
35. labs(title = "Phân phối chuẩn hóa theo từng biến",
36. x = "Giá trị chuẩn hóa (Z-score)",
37. y = "Mật độ (Density)") +
38. theme_minimal(base_family = "Times New Roman", base_size = 12) +
39. theme(
40. strip.text = element_text(face = "bold", size = 11),
41. plot.title = element_text(face = "bold", hjust = 0.5, size = 13),
42. axis.title = element_text(face = "bold") )
Chuẩn hóa dữ liệu: Sử dụng scale() để đưa các biến (huyết áp, cholesterol, insulin, v.v.) về dạng Z-score giúp so sánh trên cùng thang đo (trung bình = 0, độ lệch chuẩn = 1).
Chuyển dữ liệu sang dạng dài (pivot_longer) giúp gom tất cả các biến lại trong một cột để vẽ nhiều biểu đồ con (facet) bằng ggplot.
Vẽ biểu đồ phân phối:
geom_histogram() tạo biểu đồ tần suất thực tế.
geom_density() đường mật độ của dữ liệu mẫu.
facet_wrap() tách ra 6 biểu đồ nhỏ cho từng biến.
Dùng showtext_auto() và font_add() để tránh lỗi font khi xuất ra PDF.
Huyết áp tâm trương và HDL có dạng phân phối khá gần chuẩn.
LDL, Triglycerides và Insulin lệch phải rõ rệt dữ liệu không tuân theo phân phối chuẩn, thể hiện qua đường đỏ lệch khỏi đường xanh.
Tỷ lệ eo/hông có dạng phân phối tương đối đối xứng nhưng vẫn hơi lệch nhẹ.
1. #Dữ liệu
2. bp <- data.frame(
3. Nhom = c("Bình thường (<80)", "Tiền tăng (80–89)", "Cao huyết áp (≥90)"),
4. TyLe = c(69.83, 26.08, 4.09))
5. ldl <- data.frame(
6. Nhom = c("Tối ưu (<100)", "Gần tối ưu (100–129)", "Giới hạn cao (130–159)",
7. "Cao (160–189)", "Rất cao (≥190)"),
8. TyLe = c(47.42, 30.70, 16.56, 4.61, 0.70))
9. tri <- data.frame(
10. Nhom = c("Bình thường (<150)", "Giới hạn cao (150–199)",
11. "Cao (200–499)", "Rất cao (≥500)"),
12. TyLe = c(73.89, 22.32, 3.79, 0))
13. insulin <- data.frame(
14. Nhom = c("Bình thường (2–25)", "Cao (>25)", "Thấp (<2)"),
15. TyLe = c(99.86, 0.14, 0))
16. whr <- data.frame(
17. Nhom = c("Bình thường (<0.85)", "Nguy cơ cao (0.85–0.9)", "Rất cao (>0.9)"),
18. TyLe = c(40.71, 39.10, 20.18))
19. create_bar <- function(data, title_text) {
20. ggplot(data, aes(x = Nhom, y = TyLe, fill = Nhom)) +
21. geom_col(color = "black", width = 0.6, alpha = 0.9) +
22. geom_text(aes(label = paste0(TyLe, "%")),
23. vjust = -0.4, size = 2.6, fontface = "bold") +
24. geom_hline(yintercept = mean(data$TyLe),
25. color = "red", linetype = "dashed", linewidth = 0.8) +
26. scale_fill_brewer(palette = "Pastel2") +
27. labs(title = title_text, x = NULL, y = "Tỷ lệ (%)") +
28. ylim(0, max(data$TyLe) + 10) +
29. theme_minimal(base_family = "Times New Roman") +
30. theme(
31. plot.title = element_text(size = 9, face = "bold", hjust = 0.5),
32. axis.text.x = element_text(size = 6.5, face = "bold",
33. angle = 25, vjust = 1, hjust = 1),
34. axis.text.y = element_text(size = 7),
35. axis.title = element_text(size = 8, face = "bold"),
36. legend.position = "none",
37. panel.grid.minor = element_blank(),
38. panel.grid.major.x = element_blank(),
39. plot.margin = margin(3, 3, 3, 3))}
40. p1 <- create_bar(bp, "Phân bố huyết áp tâm trương (WHO & AHA 2017)")
41. p2 <- create_bar(ldl, "Phân bố LDL Cholesterol (NCEP ATP III)")
42. p3 <- create_bar(tri, "Phân bố Triglycerides (AHA/NCEP)")
43. p4 <- create_bar(insulin, "Phân bố nồng độ Insulin (ADA & Mayo Clinic)")
44. p5 <- create_bar(whr, "Phân bố chỉ số eo/hông (WHO 2008)")
45. layout <- rbind(
46. c(1, 2),
47. c(3, 4),
48. c(NA, 5))
49. grid.arrange(p1, p2, p3, p4, p5, layout_matrix = layout)
Biểu đồ cột được xây dựng bằng hàm geom_col() trong ggplot2 để mô tả tỷ lệ phần trăm của các nhóm trong từng biến sinh học (huyết áp tâm trương, LDL cholesterol, triglycerides, insulin và chỉ số eo/hông).
Đường gạch đỏ (geom_hline) biểu thị giá trị trung bình tỷ lệ (%), giúp so sánh trực quan giữa các nhóm.
Các nhãn phần trăm được hiển thị trực tiếp trên cột bằng geom_text() để người đọc dễ quan sát và đối chiếu.
Màu sắc được phối theo bảng Pastel2 nhằm tạo cảm giác nhẹ nhàng, trực quan khi đọc kết quả.
Các biểu đồ được sắp xếp thành 3 hàng và 2 cột bằng grid.arrange() để hiển thị đồng thời 5 chỉ tiêu trên cùng một trang, đảm bảo bố cục khoa học và thẩm mỹ.
Huyết áp tâm trương: Phần lớn đối tượng có huyết áp bình thường (69,83%), tuy nhiên nhóm tiền tăng huyết áp chiếm tới 26,08%, thể hiện nguy cơ tăng huyết áp trong cộng đồng cần theo dõi.
LDL cholesterol: Hơn một nửa mẫu có mức LDL tối ưu hoặc gần tối ưu (78,12%), song vẫn có khoảng 22% thuộc nhóm giới hạn cao đến rất cao, phản ánh khả năng tồn tại nguy cơ rối loạn lipid máu.
Triglycerides: Đa số người có mức triglycerid bình thường (73,89%), tuy nhiên 22,32% ở giới hạn cao cho thấy tình trạng rối loạn mỡ máu nhẹ khá phổ biến.
Insulin: Gần như toàn bộ mẫu (99,86%) có nồng độ insulin bình thường, cho thấy khả năng điều hòa đường huyết ổn định, nguy cơ kháng insulin thấp.
Chỉ số eo/hông (WHR): Chỉ 40,71% có tỷ lệ eo/hông bình thường, trong khi 59,28% có nguy cơ hoặc rất cao, phản ánh xu hướng béo bụng và rối loạn phân bố mỡ cần được quan tâm.
Phần lớn các chỉ số sinh học của mẫu nghiên cứu nằm trong giới hạn bình thường, tuy nhiên vẫn tồn tại nhóm có rối loạn nhẹ về mỡ máu và béo bụng, là các yếu tố nguy cơ tiềm ẩn ảnh hưởng đến sức khỏe tim mạch và chuyển hóa.
1. library(grid)
2. #TƯƠNG QUAN GIỮA LDL VÀ HDL
3. p1 <- ggplot(d_clean, aes(x = ldl_cholesterol, y = hdl_cholesterol)) +
4. geom_point(alpha = 0.4, color = "steelblue", size = 0.6) +
5. geom_smooth(method = "lm", color = "red", se = TRUE, linewidth = 0.6) +
6. geom_vline(xintercept = mean(d_clean$ldl_cholesterol, na.rm = TRUE),
7. color = "darkgreen", linetype = "dashed", linewidth = 0.5) +
8. geom_hline(yintercept = mean(d_clean$hdl_cholesterol, na.rm = TRUE),
9. color = "darkgreen", linetype = "dashed", linewidth = 0.5) +
10. annotate("text",
11. x = max(d_clean$ldl_cholesterol, na.rm = TRUE) * 0.75,
12. y = max(d_clean$hdl_cholesterol, na.rm = TRUE) * 0.9,
13. label = paste0("r = ",
14. round(cor(d_clean$ldl_cholesterol,
15. d_clean$hdl_cholesterol,
16. use = "complete.obs"), 3)),
17. size = 3, fontface = "bold", color = "black") +
18. labs(title = "Tương quan giữa LDL và HDL Cholesterol",
19. x = "Cholesterol xấu (LDL, mg/dL)",
20. y = "Cholesterol tốt (HDL, mg/dL)") +
21. theme_minimal(base_family = "Times New Roman") +
22. theme(
23. plot.title = element_text(hjust = 0.5, size = 9, face = "bold"),
24. axis.text = element_text(size = 6),
25. axis.title = element_text(size = 7, face = "bold"),
26. plot.margin = margin(5, 5, 5, 5))
27. #TƯƠNG QUAN GIỮA HDL VÀ TRIGLYCERIDES
28. p2 <- ggplot(d_clean, aes(x = hdl_cholesterol, y = triglycerides)) +
29. geom_point(alpha = 0.4, color = "#4B9CD3", size = 0.6) +
30. geom_smooth(method = "lm", color = "red", se = TRUE, linewidth = 0.6) +
31. geom_vline(xintercept = mean(d_clean$hdl_cholesterol, na.rm = TRUE),
32. color = "darkorange", linetype = "dashed", linewidth = 0.5) +
33. geom_hline(yintercept = mean(d_clean$triglycerides, na.rm = TRUE),
34. color = "darkorange", linetype = "dashed", linewidth = 0.5) +
35. annotate("text",
36. x = max(d_clean$hdl_cholesterol, na.rm = TRUE) * 0.75,
37. y = max(d_clean$triglycerides, na.rm = TRUE) * 0.9,
38. label = paste0("r = ",
39. round(cor(d_clean$hdl_cholesterol,
40. d_clean$triglycerides,
41. use = "complete.obs"), 3)),
42. size = 3, fontface = "bold", color = "black") +
43. labs(title = "Tương quan giữa HDL và Triglycerides",
44. x = "Cholesterol tốt (HDL, mg/dL)",
45. y = "Triglycerides (mg/dL)") +
46. theme_minimal(base_family = "Times New Roman") +
47. theme( plot.title = element_text(hjust = 0.5, size = 9, face = "bold"),
48. axis.text = element_text(size = 6),
49. axis.title = element_text(size = 7, face = "bold"),
50. plot.margin = margin(5, 5, 5, 5))
51. #TƯƠNG QUAN GIỮA INSULIN VÀ TỶ LỆ EO/HÔNG
52. p3 <- ggplot(d_clean, aes(x = waist_to_hip_ratio, y = insulin_level)) +
53. geom_point(alpha = 0.4, color = "#00A08A", size = 0.6) +
54. geom_smooth(method = "lm", color = "red", se = TRUE, linewidth = 0.6) +
55. geom_vline(xintercept = mean(d_clean$waist_to_hip_ratio, na.rm = TRUE),
56. color = "purple", linetype = "dashed", linewidth = 0.5) +
57. geom_hline(yintercept = mean(d_clean$insulin_level, na.rm = TRUE),
58. color = "purple", linetype = "dashed", linewidth = 0.5) +
59. annotate("text",
60. x = max(d_clean$waist_to_hip_ratio, na.rm = TRUE) * 0.75,
61. y = max(d_clean$insulin_level, na.rm = TRUE) * 0.9,
62. label = paste0("r = ",
63. round(cor(d_clean$insulin_level,
64. d_clean$waist_to_hip_ratio,
65. use = "complete.obs"), 3)),
66. size = 3, fontface = "bold", color = "black") +
67. labs(title = "Tương quan giữa nồng độ Insulin và tỷ lệ eo/hông (WHR)",
68. x = "Tỷ lệ eo/hông (WHR)",
69. y = "Nồng độ Insulin (µU/mL)") +
70. theme_minimal(base_family = "Times New Roman") +
71. theme(plot.title = element_text(hjust = 0.5, size = 9, face = "bold"),
72. axis.text = element_text(size = 6),
73. axis.title = element_text(size = 7, face = "bold"),
74. plot.margin = margin(5, 5, 5, 5))
75. #Điều chỉnh bố cục
76. layout_matrix <- rbind(
77. c(1, 2),
78. c(NA, 3))
79. grid.arrange(p1, p2, p3, layout_matrix = layout_matrix,
80. top = textGrob("Biểu đồ tương quan giữa các yếu tố sinh học",
81. gp = gpar(fontface = "bold", fontsize = 11)))
Ba biểu đồ trên được thực hiện bằng ggplot2 để thể hiện mối tương quan tuyến tính giữa các yếu tố sinh học gồm cholesterol xấu (LDL), cholesterol tốt (HDL), triglycerides, nồng độ insulin và tỷ lệ eo/hông (WHR).
Hàm geom_point() biểu diễn phân tán dữ liệu thực tế giữa hai biến định lượng.
geom_smooth(method = “lm”) thêm đường hồi quy tuyến tính thể hiện xu hướng chung giữa các biến.
Các đường trung bình tham chiếu được vẽ bằng geom_vline() và geom_hline() giúp xác định tâm phân bố dữ liệu.
Hàm annotate() hiển thị hệ số tương quan Pearson (r) trực tiếp trên biểu đồ, cho phép đánh giá mức độ và chiều hướng mối liên hệ.
Hàm grid.arrange() sắp xếp ba biểu đồ trong bố cục 2 hàng (2–1) nhằm trình bày trực quan, dễ so sánh giữa các yếu tố.
Biểu đồ 1 (LDL và HDL): r=−0.324 cho thấy mối tương quan nghịch mức trung bình giữa cholesterol xấu (LDL) và cholesterol tốt (HDL). Khi nồng độ LDL tăng, HDL có xu hướng giảm. Điều này phù hợp với đặc điểm sinh học: LDL cao làm tăng nguy cơ tim mạch, trong khi HDL có vai trò bảo vệ.
Biểu đồ 2 (HDL và Triglycerides): r=−0.085 biểu thị mối tương quan nghịch yếu, nghĩa là triglycerides tăng thì HDL có xu hướng giảm nhẹ. Tuy nhiên, mối liên hệ này yếu và có thể chịu ảnh hưởng bởi các yếu tố khác như chế độ ăn, chuyển hóa hoặc tình trạng béo phì.
Biểu đồ 3 (Insulin và WHR): r=0.303 cho thấy mối tương quan thuận mức trung bình, tức là khi tỷ lệ eo/hông (WHR) tăng – biểu hiện của béo bụng – thì nồng độ insulin trong máu cũng tăng. Điều này gợi ý khả năng đề kháng insulin ở những người có phân bố mỡ vùng bụng cao, một yếu tố nguy cơ của hội chứng chuyển hóa.
Nhóm đã tiến hành phân tích bộ dữ liệu Diabetes Health Indicators Dataset gồm 100.000 quan sát và 31 biến phản ánh các yếu tố sinh học, lối sống, nhân khẩu học và tiền sử bệnh lý liên quan đến nguy cơ mắc tiểu đường. Bằng ngôn ngữ R, nhóm đã thực hiện toàn bộ quy trình xử lý dữ liệu từ làm sạch, mã hóa, kiểm tra ngoại lai, mô tả thống kê đến trực quan hóa và kiểm định. Quá trình này giúp chuyển đổi dữ liệu thô thành dạng có cấu trúc, đảm bảo độ tin cậy và tính sẵn sàng cho các phân tích thống kê chuyên sâu.
Kết quả cho thấy các chỉ số sinh học như huyết áp, cholesterol, triglycerides, insulin và tỷ lệ eo/hông nằm trong phạm vi hợp lý theo chuẩn y học, trong đó insulin và triglycerides có phân bố lệch phải, phản ánh sự khác biệt chuyển hóa giữa các cá nhân. Phân tích tương quan và kiểm định thống kê cho thấy HDL có tương quan nghịch với LDL và triglycerides, trong khi insulin có tương quan thuận với tỷ lệ eo/hông – biểu hiện đặc trưng của hiện tượng kháng insulin. Các kiểm định Kruskal–Wallis, ANOVA và Chi-square khẳng định sự khác biệt có ý nghĩa giữa các nhóm trình độ học vấn, tình trạng việc làm, yếu tố di truyền và giai đoạn bệnh, cho thấy mối liên hệ giữa các yếu tố sinh học, xã hội và di truyền trong tiến triển bệnh tiểu đường.
Phân tích trực quan với hơn 20 biểu đồ ggplot2 giúp làm rõ xu hướng biến động của các chỉ số, như triglycerides và LDL tăng, HDL giảm khi bệnh tiến triển; nhóm có tiền sử gia đình mắc bệnh thường có mỡ máu và tỷ lệ eo/hông cao hơn. Kết quả khẳng định rằng ngôn ngữ R là công cụ hiệu quả trong phân tích dữ liệu y sinh học nhờ khả năng xử lý dữ liệu lớn, kiểm định linh hoạt và trực quan hóa mạnh mẽ. Đồng thời, nghiên cứu nhấn mạnh tầm quan trọng của chế độ ăn uống lành mạnh, duy trì cân nặng hợp lý và tầm soát sớm trong phòng ngừa bệnh tiểu đường.
Trong bối cảnh Việt Nam hội nhập sâu rộng với thị trường tài chính quốc tế, các ngân hàng thương mại đóng vai trò then chốt trong huy động vốn, cung ứng tín dụng và thúc đẩy tăng trưởng kinh tế. Phân tích dữ liệu tài chính giúp đánh giá hiệu quả hoạt động, năng lực quản trị và khả năng thích ứng với biến động thị trường.
Techcombank – một trong những ngân hàng TMCP hàng đầu Việt Nam – là đối tượng nghiên cứu tiêu biểu để phản ánh bức tranh tài chính ngành ngân hàng giai đoạn 2014–2023.
Đề tài “Phân tích toàn diện dữ liệu tài chính Techcombank” vận dụng kiến thức môn Phân tích dữ liệu trong xử lý, mã hóa, thống kê và trực quan hóa dữ liệu bằng ngôn ngữ R. Nghiên cứu không chỉ mô tả số liệu mà còn phát hiện xu hướng, đánh giá hiệu quả hoạt động và minh chứng khả năng ứng dụng R trong phân tích tài chính thực tế.
Mục tiêu tổng quát: Phân tích toàn diện dữ liệu tài chính Techcombank giai đoạn 2014–2023 bằng ngôn ngữ R để đánh giá tình hình tài chính và xu hướng biến động.
Mục tiêu cụ thể:
Thu thập và giới thiệu bộ dữ liệu báo cáo tài chính 10 năm.
Làm sạch, mã hóa, chuẩn hóa dữ liệu.
Thực hiện thống kê mô tả (trung bình, phương sai, độ lệch chuẩn, tốc độ tăng trưởng…).
Trực quan hóa dữ liệu bằng các biểu đồ đa lớp để làm rõ xu hướng và mối quan hệ giữa các chỉ tiêu.
Đưa ra nhận xét, kết luận và gợi ý hướng nghiên cứu tiếp theo.
Đối tượng:
Dữ liệu tài chính của Techcombank, gồm các chỉ tiêu: tổng tài sản, vốn chủ sở hữu, lợi nhuận sau thuế, nợ phải trả, dư nợ cho vay,… được lấy từ báo cáo tài chính hợp nhất các năm.
Phạm vi:
Không gian: Ngân hàng TMCP Kỹ Thương Việt Nam (Techcombank).
Thời gian: 2014–2023.
Nội dung: Tập trung vào xử lý, mã hóa, thống kê và trực quan hóa dữ liệu để đánh giá tình hình tài chính của ngân hàng.
Thu thập dữ liệu: Từ báo cáo tài chính hợp nhất thường niên 2014–2023 công bố trên website Techcombank.
Xử lý và mã hóa: Kiểm tra dữ liệu thiếu, loại ngoại lai, chuẩn hóa định dạng và tạo biến mới phục vụ phân tích.
Phân tích thống kê: Dùng các hàm mean(), sd(), summary(), cor(),… để mô tả và đánh giá biến động.
Trực quan hóa: Sử dụng thư viện ggplot2 và các hàm geom_line(), geom_bar(), geom_point()… để minh họa xu hướng tài chính qua biểu đồ.
Đề tài “Phân tích toàn diện dữ liệu tài chính Techcombank (2014–2023)” mang lại cả giá trị học thuật và thực tiễn. Về học thuật, nghiên cứu giúp vận dụng kiến thức phân tích dữ liệu và thống kê mô tả vào trường hợp thực tế, qua đó củng cố kỹ năng sử dụng ngôn ngữ R trong xử lý, mã hóa và trực quan hóa dữ liệu tài chính. Về thực tiễn, kết quả phân tích phản ánh xu hướng biến động của các chỉ tiêu tài chính chủ yếu của Techcombank trong 10 năm, hỗ trợ sinh viên có cái nhìn rõ hơn về tình hình hoạt động của ngân hàng. Đồng thời, nghiên cứu khẳng định R là công cụ mạnh mẽ, linh hoạt và dễ ứng dụng trong các bài toán tài chính, có thể làm tài liệu tham khảo cho sinh viên trong lĩnh vực phân tích dữ liệu.
Bộ dữ liệu được thu thập từ báo cáo tài chính hợp nhất của Ngân hàng TMCP Kỹ Thương Việt Nam (Techcombank) trong giai đoạn từ năm 2014 đến năm 2023, tổng cộng 10 năm dữ liệu liên tục. Bộ dữ liệu bao gồm các chỉ tiêu tài chính quan trọng được trình bày trong Bảng cân đối kế toán, Báo cáo kết quả kinh doanh và Báo cáo lưu chuyển tiền tệ của ngân hàng
Mục tiêu của việc sử dụng bộ dữ liệu này là phân tích xu hướng biến động tài chính của Techcombank trong 10 năm gần nhất, đánh giá sức khỏe tài chính, và ứng dụng các mô hình thống kê – dự báo để ước lượng và dự đoán giá trị các chỉ tiêu tài chính trong tương lai.
1. library(readxl)
2. #Đọc dữ liệu
3. tieuluan <- read_excel("C:/Users/maica/Downloads/PHAN1/TCB.xlsx")
1. #Định dạng lại dữ liệu trước khi hiển thị
2. #Thêm dấu phẩy ngăn cách hàng nghìn và tắt hiển thị số dạng khoa học
3. tieuluan[, 2:27] <- lapply(tieuluan[, 2:27], function(x) {
4. format(x, big.mark = ",", scientific = FALSE)
5. })
Áp dụng hàm format() cho từng cột. Tham số big.mark=“,” giúp thêm dấu phẩy để phân tách hàng nghìn, còn scientific=FALSE tắt chế độ hiển thị số dạng khoa học. Sau khi định dạng, các giá trị trong bảng được hiển thị rõ ràng, dễ đọc hơn, giúp người xem nhận biết quy mô và so sánh số liệu tài chính một cách trực quan.
1. # Cài đặt gói
2. # install.packages("DT")
3. # install.packages("htmltools")
4. # Nạp thư viện
5. library(DT)
6. library(htmltools)
Hai thư viện DT và htmltools được sử dụng để hiển thị bảng dữ liệu tương tác trong R Markdown.
DT: hỗ trợ tạo bảng có thể cuộn, tìm kiếm, lọc, và phân trang.
htmltools: giúp định dạng bảng, thêm tiêu đề
1. # Tùy chỉnh cách hiển thị số trong toàn bộ phiên làm việc
2. options(scipen = 999999) # Tắt chế độ hiển thị dạng số khoa học
Bước này giúp tắt chế độ hiển thị số khoa học để bảng dữ liệu không bị lỗi dãy số.
1. #Kiểm tra kích thước bộ dữ liệu
2. dim(tieuluan)
## [1] 10 27
Kết quả lệnh dim(tieuluan) cho thấy bộ dữ liệu gồm 10 dòng và 27 cột, tương ứng với 10 năm quan sát (từ 2014 đến 2023) và 27 biến tài chính của ngân hàng Techcombank.
1. #Xem tên các biến
2. names(tieuluan)
## [1] "Năm"
## [2] "Tên ngân hàng"
## [3] "Loại hình ngân hàng"
## [4] "Tình hình kinh tế"
## [5] "Tiền mặt vàng"
## [6] "Tiền gửi tại NHNN"
## [7] "Tiền gửi và cấp tín dụng cho các TCTD khác"
## [8] "Tiền gửi tại các TCTD khác"
## [9] "Cấp tín dụng cho các TCTD khác"
## [10] "Chứng khoán kinh doanh"
## [11] "Tài sản cố định"
## [12] "Nguyên giá tài sản cố định"
## [13] "Khấu hao tài sản cố định"
## [14] "Các khoản phải thu"
## [15] "Tổng tài sản"
## [16] "Tiền gửi và vay các TCTD khác"
## [17] "Tiền gửi của khách hàng"
## [18] "Phát hành giấy tờ có giá"
## [19] "Tổng nợ phải trả"
## [20] "Tổng vốn chủ sở hữu"
## [21] "Tổng nợ phải trả và vốn chủ sở hữu"
## [22] "Mua nợ"
## [23] "Dự phòng rủi ro hoạt động mua nợ"
## [24] "Chứng khoán đầu tư"
## [25] "Chứng khoán đầu tư sẵn sàng để bán"
## [26] "Dự phòng rủi ro chứng khoán đầu tư"
## [27] "Lợi nhuận chưa phân phối"
Sử dụng lệnh names() cho kết quả trả về tên các biến trong bộ dữ liệu tieuluan. Bộ dữ liệu bao gồm 27 biến tài chính của ngân hàng Techcombank trong giai đoạn 2014–2023
Gồm các biến “Năm”, “Tên ngân hàng”, “Loại hình ngân hàng”, “Tình hình kinh tế”, “Tiền mặt vàng”, “Tiền gửi tại NHNN”, “Tiền gửi và cấp tín dụng cho các TCTD khác”, “Tiền gửi tại các TCTD khác”, “Cấp tín dụng cho các TCTD khác”, “Chứng khoán kinh doanh”, “Tài sản cố định”, “Nguyên giá tài sản cố định”, “Khấu hao tài sản cố định”, “Các khoản phải thu”, “Tổng tài sản”, “Tiền gửi vay các TCTD khác”, “Tiền gửi của khách hàng”, “Phát hành giấy tờ có giá”, “Tổng nợ phải trả”, “Tổng vốn chủ sở hữu”, “Tổng nợ phải trả và vốn chủ sở hữu”, “Mua nợ”, “Dự phòng rủi ro hoạt động mua nợ”, “Chứng khoán đầu tư”, “Chứng khoán đầu tư sẵn sàng để bán”, “Dự phòng rủi ro chứng khoán đầu tư”, “Lợi nhuận chưa phân phối”.
Dữ liệu bao gồm các biến sau, được tổng hợp chi tiết trong bảng dưới đây nhằm phục vụ cho quá trình phân tích:
| STT | Ten_bien | Mo_ta |
|---|---|---|
| 1 | Năm | Năm tài chính tương ứng của số liệu báo cáo. |
| 2 | Tên ngân hàng | Tên đầy đủ của ngân hàng (Techcombank). |
| 3 | Loại hình ngân hàng | Phân loại loại hình ngân hàng – thương mại cổ phần. |
| 4 | Tình hình kinh tế | Tình hình kinh tế vĩ mô trong năm (mã hóa mô tả chung). |
| 5 | Tiền mặt vàng | Khoản tiền mặt và vàng bạc, đá quý mà ngân hàng nắm giữ tại thời điểm cuối năm. |
| 6 | Tiền gửi tại NHNN | Số tiền ngân hàng gửi tại Ngân hàng Nhà nước Việt Nam (NHNN). |
| 7 | Tiền gửi và cấp tín dụng cho các TCTD khác | Tổng giá trị tiền gửi và tín dụng cấp cho các tổ chức tín dụng (TCTD) khác. |
| 8 | Tiền gửi tại các TCTD khác | Khoản tiền gửi tại các TCTD khác trong hệ thống ngân hàng. |
| 9 | Cấp tín dụng cho các TCTD khác | Khoản tín dụng Techcombank cấp cho các TCTD khác. |
| 10 | Chứng khoán kinh doanh | Giá trị chứng khoán kinh doanh mà ngân hàng đang nắm giữ. |
| 11 | Tài sản cố định | Giá trị còn lại của tài sản cố định hữu hình và vô hình. |
| 12 | Nguyên giá tài sản cố định | Nguyên giá ban đầu của toàn bộ tài sản cố định. |
| 13 | Khấu hao tài sản cố định | Phần giá trị tài sản cố định đã được khấu hao lũy kế. |
| 14 | Các khoản phải thu | Tổng giá trị các khoản phải thu khác của ngân hàng. |
| 15 | Tổng tài sản | Tổng tài sản của ngân hàng tại thời điểm cuối năm. |
| 16 | Tiền gửi vay các TCTD khác | Giá trị tiền gửi hoặc khoản vay từ các tổ chức tín dụng khác. |
| 17 | Tiền gửi của khách hàng | Tổng số tiền gửi của khách hàng tại ngân hàng. |
| 18 | Phát hành giấy tờ có giá | Giá trị các giấy tờ có giá mà ngân hàng phát hành (trái phiếu, kỳ phiếu, chứng chỉ tiền gửi…). |
| 19 | Tổng nợ phải trả | Tổng giá trị các khoản nợ phải trả của ngân hàng. |
| 20 | Tổng vốn chủ sở hữu | Giá trị tổng vốn chủ sở hữu của ngân hàng. |
| 21 | Tổng nợ phải trả và vốn chủ sở hữu | Tổng cộng nợ phải trả và vốn chủ sở hữu (kiểm tra tính cân đối). |
| 22 | Mua nợ | Giá trị các khoản nợ mà ngân hàng mua lại từ tổ chức khác. |
| 23 | Dự phòng rủi ro hoạt động mua nợ | Khoản dự phòng rủi ro cho các hoạt động mua nợ. |
| 24 | Chứng khoán đầu tư | Tổng giá trị chứng khoán đầu tư dài hạn và ngắn hạn. |
| 25 | Chứng khoán đầu tư sẵn sàng để bán | Giá trị chứng khoán đầu tư sẵn sàng để bán trên thị trường. |
| 26 | Dự phòng rủi ro chứng khoán đầu tư | Khoản dự phòng rủi ro cho danh mục chứng khoán đầu tư. |
| 27 | Lợi nhuận chưa phân phối | Phần lợi nhuận sau thuế chưa được phân phối hoặc giữ lại. |
## Rows: 10
## Columns: 27
## $ Năm <dbl> 2014, 2015, 2016, 2017, 2…
## $ `Tên ngân hàng` <chr> "Techcombank", "Techcomba…
## $ `Loại hình ngân hàng` <chr> "Ngân hàng TMCP", "Ngân h…
## $ `Tình hình kinh tế` <chr> "Trước covid", "Trước cov…
## $ `Tiền mặt vàng` <chr> "2,723,642", "2,754,299",…
## $ `Tiền gửi tại NHNN` <chr> " 1,168,265", " 1,602,619…
## $ `Tiền gửi và cấp tín dụng cho các TCTD khác` <chr> " 18,922,460", " 14,762,0…
## $ `Tiền gửi tại các TCTD khác` <chr> " 9,588,234", " 7,487,472…
## $ `Cấp tín dụng cho các TCTD khác` <chr> " 9,343,996", " 7,274,537…
## $ `Chứng khoán kinh doanh` <chr> " 2,086,246", " 3,072…
## $ `Tài sản cố định` <chr> "1,036,505", " 882,081",…
## $ `Nguyên giá tài sản cố định` <chr> "1,361,399", "1,341,998",…
## $ `Khấu hao tài sản cố định` <chr> " -704,367", " -803,851…
## $ `Các khoản phải thu` <chr> "10,366,601", "11,325,061…
## $ `Tổng tài sản` <chr> "175,901,794", "192,009,0…
## $ `Tiền gửi và vay các TCTD khác` <chr> " 19,471,408", " 20,745,9…
## $ `Tiền gửi của khách hàng` <chr> "131,689,810", "142,239,5…
## $ `Phát hành giấy tờ có giá` <chr> " 6,253,623", " 8,133,896…
## $ `Tổng nợ phải trả` <chr> "160,915,744", "175,481,0…
## $ `Tổng vốn chủ sở hữu` <chr> " 14,986,050", " 16,528,0…
## $ `Tổng nợ phải trả và vốn chủ sở hữu` <chr> "175,901,794", "192,009,0…
## $ `Mua nợ` <chr> " 9,817", "395,375", " 1…
## $ `Dự phòng rủi ro hoạt động mua nợ` <chr> " -491", "-4,446", " -9…
## $ `Chứng khoán đầu tư` <chr> " 54,978,730", " 44,301,5…
## $ `Chứng khoán đầu tư sẵn sàng để bán` <chr> " 49,704,301", " 38,528,0…
## $ `Dự phòng rủi ro chứng khoán đầu tư` <chr> " -923,154", "-1,128,768…
## $ `Lợi nhuận chưa phân phối` <chr> " 1,556,411", " 2,897,014…
Sử dụng lệnh str() cho kết quả trả về cấu trúc tổng quát của bộ dữ liệu, bao gồm số quan sát, số biến, tên biến và kiểu dữ liệu của từng biến.
Biến “Năm” được lưu dưới dạng số thực (num), trong khi các biến còn lại được hiển thị ở dạng chuỗi ký tự (chr) do đã được định dạng lại bằng hàm format() để thêm dấu phẩy phân tách hàng nghìn.
1. # Tóm tắt sơ bộ dữ liệu tài chính Techcombank
2. summary(tieuluan)
## Năm Tên ngân hàng Loại hình ngân hàng Tình hình kinh tế
## Min. :2014 Length:10 Length:10 Length:10
## 1st Qu.:2016 Class :character Class :character Class :character
## Median :2018 Mode :character Mode :character Mode :character
## Mean :2018
## 3rd Qu.:2021
## Max. :2023
## Tiền mặt vàng Tiền gửi tại NHNN
## Length:10 Length:10
## Class :character Class :character
## Mode :character Mode :character
##
##
##
## Tiền gửi và cấp tín dụng cho các TCTD khác Tiền gửi tại các TCTD khác
## Length:10 Length:10
## Class :character Class :character
## Mode :character Mode :character
##
##
##
## Cấp tín dụng cho các TCTD khác Chứng khoán kinh doanh Tài sản cố định
## Length:10 Length:10 Length:10
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
## Nguyên giá tài sản cố định Khấu hao tài sản cố định Các khoản phải thu
## Length:10 Length:10 Length:10
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
## Tổng tài sản Tiền gửi và vay các TCTD khác Tiền gửi của khách hàng
## Length:10 Length:10 Length:10
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
## Phát hành giấy tờ có giá Tổng nợ phải trả Tổng vốn chủ sở hữu
## Length:10 Length:10 Length:10
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
## Tổng nợ phải trả và vốn chủ sở hữu Mua nợ
## Length:10 Length:10
## Class :character Class :character
## Mode :character Mode :character
##
##
##
## Dự phòng rủi ro hoạt động mua nợ Chứng khoán đầu tư
## Length:10 Length:10
## Class :character Class :character
## Mode :character Mode :character
##
##
##
## Chứng khoán đầu tư sẵn sàng để bán Dự phòng rủi ro chứng khoán đầu tư
## Length:10 Length:10
## Class :character Class :character
## Mode :character Mode :character
##
##
##
## Lợi nhuận chưa phân phối
## Length:10
## Class :character
## Mode :character
##
##
##
Hàm summary() cho biết thống kê tổng quát của từng biến trong bộ dữ liệu, bao gồm giá trị nhỏ nhất, lớn nhất, trung bình và trung vị.
1. # Kiểm tra xem trong dữ liệu có giá trị NA hay không
2. colSums(is.na(tieuluan))
## Năm
## 0
## Tên ngân hàng
## 0
## Loại hình ngân hàng
## 0
## Tình hình kinh tế
## 0
## Tiền mặt vàng
## 0
## Tiền gửi tại NHNN
## 0
## Tiền gửi và cấp tín dụng cho các TCTD khác
## 0
## Tiền gửi tại các TCTD khác
## 0
## Cấp tín dụng cho các TCTD khác
## 0
## Chứng khoán kinh doanh
## 0
## Tài sản cố định
## 0
## Nguyên giá tài sản cố định
## 0
## Khấu hao tài sản cố định
## 0
## Các khoản phải thu
## 0
## Tổng tài sản
## 0
## Tiền gửi và vay các TCTD khác
## 0
## Tiền gửi của khách hàng
## 0
## Phát hành giấy tờ có giá
## 0
## Tổng nợ phải trả
## 0
## Tổng vốn chủ sở hữu
## 0
## Tổng nợ phải trả và vốn chủ sở hữu
## 0
## Mua nợ
## 0
## Dự phòng rủi ro hoạt động mua nợ
## 0
## Chứng khoán đầu tư
## 0
## Chứng khoán đầu tư sẵn sàng để bán
## 0
## Dự phòng rủi ro chứng khoán đầu tư
## 0
## Lợi nhuận chưa phân phối
## 0
Lệnh colSums(is.na(tieuluan)) cho biết số lượng giá trị bị thiếu (NA) trong từng biến. Kết quả cho thấy tất cả các cột đều có giá trị bằng 0, nghĩa là dữ liệu của Techcombank giai đoạn 2014–2023 không có giá trị bị thiếu.
Bộ dữ liệu được nhập đầy đủ, đảm bảo độ tin cậy cho quá trình phân tích thống kê mô tả và mô hình hóa ở các phần tiếp theo.
1. # Kiểm tra các dòng bị trùng lặp trong bộ dữ liệu
2. duplicated_rows <- tieuluan[duplicated(tieuluan), ]
1. # Đếm tổng số dòng trùng lặp
2. sum(duplicated(tieuluan))
## [1] 0
Cú pháp tieuluan[duplicated(tieuluan), ], các dòng trùng lặp (nếu có) sẽ được loại bỏ, chỉ giữ lại một bản ghi duy nhất cho mỗi quan sát.
Việc xác định và loại bỏ các bản ghi trùng giúp đảm bảo độ tin cậy của thống kê mô tả phục vụ quá trình phân tích và trực quan hóa dữ liệu.
1. # Chuyển biến định tính sang factor
2. tieuluan$`Năm` <- as.factor(tieuluan$`Năm`)
3. tieuluan$`Tình hình kinh tế` <- as.factor(tieuluan$`Tình hình kinh tế`)
1. # Xem cấu trúc kiểu dữ liệu của 2 biến định tính
2. str(tieuluan[, c("Năm", "Tình hình kinh tế")])
## tibble [10 × 2] (S3: tbl_df/tbl/data.frame)
## $ Năm : Factor w/ 10 levels "2014","2015",..: 1 2 3 4 5 6 7 8 9 10
## $ Tình hình kinh tế: Factor w/ 2 levels "Sau covid ",..: 2 2 2 2 2 2 1 1 1 1
Câu lệnh as.factor() được sử dụng để chuyển các biến định tính như “Năm” và “Tình hình kinh tế” từ kiểu ký tự (chr) sang kiểu phân loại (factor).
Việc chuyển các biến định tính sang dạng factor giúp phân loại các quan sát theo nhóm .
Nhờ đó, có thể dễ dàng so sánh xu hướng tài chính giữa các năm hoặc giữa các giai đoạn kinh tế khác nhau (Trước và Sau Covid).
1. # Loại bỏ dấu phẩy và chuyển sang numeric
2. cols_numeric <- c("Tiền mặt vàng",
3. "Tiền gửi tại NHNN",
4. "Tổng tài sản",
5. "Tài sản cố định",
6. "Các khoản phải thu")
7. # Dùng vòng lặp để chuyển tất cả 1 lượt
8. tieuluan[cols_numeric] <- lapply(tieuluan[cols_numeric], function(x) {
9. as.numeric(gsub(",", "", x))
10. })
1. # Xem cấu trúc kiểu dữ liệu của các biến định lượng
2. str(tieuluan[, c("Tiền mặt vàng",
3. "Tiền gửi tại NHNN",
4. "Tổng tài sản",
5. "Tài sản cố định",
6. "Các khoản phải thu")])
## tibble [10 × 5] (S3: tbl_df/tbl/data.frame)
## $ Tiền mặt vàng : num [1:10] 2723642 2754299 2956708 2344362 2606467 ...
## $ Tiền gửi tại NHNN : num [1:10] 1168265 1602619 2533875 4317924 10555483 ...
## $ Tổng tài sản : num [1:10] 175901794 192009075 235363736 269392380 320988941 ...
## $ Tài sản cố định : num [1:10] 1036505 882081 1582722 1511446 1718596 ...
## $ Các khoản phải thu: num [1:10] 10366601 11325061 6829557 9417589 11322556 ...
Chuyển đổi các biến định lượng sang dạng numeric được thực hiện bằng cách sử dụng hàm lapply() kết hợp với as.numeric() và gsub(). Trong đó, gsub(“,”, ““, x) dùng để loại bỏ dấu phẩy trong chuỗi dữ liệu, còn as.numeric() chuyển chuỗi ký tự thành giá trị số thực. Câu lệnh lapply() giúp áp dụng cùng một thao tác chuyển đổi cho nhiều cột cùng lúc, đảm bảo tính tự động và đồng nhất trong xử lý dữ liệu. Cuối cùng, hàm str() được dùng để kiểm tra lại cấu trúc, xác nhận rằng các biến đã chuyển đúng sang kiểu numeric.
Việc chuyển các biến định lượng sang dạng numeric là bước quan trọng trong quá trình xử lý dữ liệu, giúp R có thể thực hiện các phép tính thống kê.
Sau khi chuyển thành công, các biến “Tiền mặt vàng”, “Tiền gửi tại NHNN”, “Tổng tài sản”, “Tài sản cố định” và “Các khoản phải thu” đều có thể sử dụng để mô tả, so sánh và phân tích xu hướng biến động tài sản của Techcombank qua các năm.
Trường hơp lọc Tổng tài sản > 200.000.000 và Tiền gửi tại NHNN > 2.000.000
1. # Lọc điều kiện AND (&)
2. du_lieu_and <- subset(tieuluan,
3. `Tổng tài sản` > 200000000 &
4. `Tiền gửi tại NHNN` > 2000000)
Trình bày dữ liệu đã lọc ra bảng
1. library(DT)
2. datatable(
3. du_lieu_and[, c("Năm", "Tổng tài sản", "Tiền gửi tại NHNN")],
4. caption = "Bảng: Các năm Techcombank có Tổng tài sản > 200.000.000 và Tiền gửi tại NHNN > 2.000.000",
5. options = list(pageLength = 5, scrollX = TRUE)
6. )
Lệnh subset() được sử dụng để lọc các dòng dữ liệu thỏa đồng thời hai điều kiện
Dấu toán tử & (AND) giúp giữ lại các quan sát đáp ứng cả hai điều kiện cùng lúc. Kết quả được hiển thị dưới dạng bảng tương tác bằng hàm datatable() để dễ quan sát.
Dữ liệu lọc được cho thấy có 8 năm (2016–2023) mà Techcombank đạt tổng tài sản trên 200.000 tỷ đồng và tiền gửi tại NHNN vượt 2.000 tỷ đồng.
Điều này phản ánh giai đoạn ngân hàng duy trì quy mô tài sản lớn và khả năng thanh khoản cao, đặc biệt sau năm 2016 khi quy mô tài sản và tiền gửi tại NHNN đều tăng mạnh.
Trường hợp lọc các năm Tổng tài sản > 250.000.000 hoặc Tài sản cố định > 1.500.000
1. # Lọc dữ liệu theo điều kiện OR
2. du_lieu_or <- subset(tieuluan,
3. `Tổng tài sản` > 250000000 |
4. `Tài sản cố định` > 1500000)
Trình bày dữ liệu đã lọc ra bảng
1. # Hiển thị bảng kết quả
2. library(DT)
3. datatable(
4. du_lieu_or[, c("Năm", "Tổng tài sản", "Tài sản cố định")],
5. caption = "Bảng: Các năm Techcombank có Tổng tài sản > 250.000.000 hoặc Tài sản cố định > 1.500.000",
6. options = list(pageLength = 5, scrollX = TRUE)
7. )
Câu lệnh subset() kết hợp với dấu | (OR) trong R được sử dụng để lọc các dòng dữ liệu thỏa ít nhất một trong hai điều kiện.
Trong trường hợp này, dữ liệu được lọc ra khi “Tổng tài sản” lớn hơn 250.000.000 hoặc “Tài sản cố định” lớn hơn 1.500.000.
Kết quả được hiển thị dưới dạng bảng tương tác datatable() giúp dễ dàng sắp xếp, tìm kiếm và quan sát dữ liệu sau khi lọc.
Kết quả cho thấy có 8 năm (2016–2023) thỏa điều kiện trên.
Đây là giai đoạn Techcombank có quy mô tài sản vượt mức 250.000 tỷ đồng hoặc đầu tư mạnh vào tài sản cố định, thể hiện sự mở rộng hoạt động kinh doanh song song với đầu tư cơ sở hạ tầng.
Xu hướng tăng trưởng liên tục của hai chỉ tiêu này cho thấy Techcombank duy trì tốc độ phát triển cao, đồng thời tăng cường năng lực tài chính và đầu tư dài hạn.
Trường hợp lọc các năm mà Tổng tài sản > 250.000.000 đồng thời (Tiền gửi tại NHNN > 2.000.000 hoặc Tài sản cố định > 1.500.000)
1. # Lọc dữ liệu theo điều kiện kết hợp AND và OR
2. du_lieu_and_or <- subset(
3. tieuluan,
4. (`Tổng tài sản` > 250000000) &
5. (`Tiền gửi tại NHNN` > 2000000 | `Tài sản cố định` > 1500000)
6. )
Trình bày dữ liệu đã lọc ra bảng
1. # Hiển thị bảng kết quả
2. library(DT)
3. datatable(
4. du_lieu_and_or[, c("Năm", "Tổng tài sản", "Tiền gửi tại NHNN", "Tài sản cố định")],
5. caption = "Bảng: Các năm Techcombank có Tổng tài sản > 250.000.000 và (Tiền gửi tại NHNN > 2.000.000 hoặc Tài sản cố định > 1.500.000)",
6. options = list(pageLength = 5, scrollX = TRUE)
7. )
Đoạn mã sử dụng hàm subset() trong R để lọc dữ liệu theo điều kiện kết hợp logic AND và OR.
Cụ thể, câu lệnh chọn ra những năm mà:
Tổng tài sản > 250.000.000 đồng, đồng thời có (Tiền gửi tại NHNN > 2.000.000) hoặc (Tài sản cố định > 1.500.000).
Toán tử & biểu thị phép và (AND) → cả hai điều kiện đều phải thỏa mãn.
Toán tử | biểu thị phép hoặc (OR) → chỉ cần một trong hai điều kiện đúng.
Kết quả được hiển thị bằng hàm datatable() trong gói DT, giúp:
Tạo bảng tương tác (có thể tìm kiếm, sắp xếp, phân trang).
Bảng kết quả thể hiện các năm Techcombank có tổng tài sản vượt 250 triệu, đồng thời có tiền gửi tại NHNN hoặc tài sản cố định ở mức cao.
Trong giai đoạn 2017–2021, các chỉ tiêu này đều đạt ngưỡng lớn, phản ánh năng lực tài chính mạnh mẽ và chiến lược đầu tư hiệu quả của ngân hàng.
Việc duy trì quy mô tài sản cao cùng tỷ lệ đầu tư hợp lý cho thấy:
Khả năng thanh khoản ngắn hạn được đảm bảo.
Tài sản dài hạn được củng cố ổn định.
Điều này chứng tỏ Techcombank phát triển bền vững, có quản trị tài chính hiệu quả và hiệu suất hoạt động ổn định qua các năm.
Ta sắp xếp dữ liệu theo Tổng tài sản giảm dần
1. #Sắp xếp dữ liệu theo Tổng tài sản giảm dần
2. du_lieu_sapxep_ts <- tieuluan[order(-as.numeric(tieuluan$`Tổng tài sản`)), ]
Hiển thị bảng dữ liệu sau khi sắp xếp
1. library(DT)
2. datatable(
3. du_lieu_sapxep_ts[, c("Năm", "Tổng tài sản", "Tổng nợ phải trả", "Tổng vốn chủ sở hữu")],
4. caption = "Bảng: Dữ liệu Techcombank sắp xếp theo Tổng tài sản (giảm dần)",
5. options = list(pageLength = 10, scrollX = TRUE)
6. )
Câu lệnh order() trong R được sử dụng để sắp xếp dữ liệu theo giá trị của một hoặc nhiều biến.
Trong trường hợp này, biến “Tổng tài sản” được chuyển sang dạng số (as.numeric()) để R có thể so sánh và sắp xếp chính xác.
Khi không thêm dấu “–” trước biến, dữ liệu được sắp xếp theo thứ tự tăng dần (từ nhỏ đến lớn).
Kết quả cho thấy Tổng tài sản của Techcombank tăng dần qua từng năm từ 2014 đến 2023, phản ánh quá trình mở rộng quy mô hoạt động ổn định và bền vững.
Đáng chú ý, giai đoạn 2020–2021 chịu ảnh hưởng của đại dịch COVID-19, tuy nền kinh tế Việt Nam gặp nhiều khó khăn nhưng tổng tài sản của Techcombank vẫn tiếp tục tăng mạnh.
Điều này cho thấy năng lực quản trị rủi ro, dự phòng thanh khoản và khả năng thích ứng linh hoạt của ngân hàng.
Ta sắp xếp dữ liệu theo Tiền mặt vàng tăng dần
1. # Sắp xếp dữ liệu theo Tiền mặt vàng (tăng dần)
2. du_lieu_sapxep_tmv <- tieuluan[order(as.numeric(tieuluan$`Tiền mặt vàng`)), ]
Hiển thị bảng dữ liệu sau khi sắp xếp
1. library(DT)
2. datatable(
3. du_lieu_sapxep_tmv[, c("Năm", "Tiền mặt vàng", "Tổng tài sản")],
4. caption = "Bảng: Dữ liệu sắp xếp theo Tiền mặt vàng (tăng dần)",
5. options = list(pageLength = 10, scrollX = TRUE)
6. )
Câu lệnh order() trong R được sử dụng để sắp xếp dữ liệu theo giá trị của biến “Tiền mặt vàng”.
Ở đây, biến được chuyển sang dạng số bằng hàm as.numeric() để đảm bảo việc so sánh chính xác.
Không có dấu “-” trước tên biến nên dữ liệu được sắp xếp theo thứ tự tăng dần (từ nhỏ đến lớn).
Kết quả cho thấy giá trị Tiền mặt vàng của ngân hàng tăng dần qua các năm, phản ánh xu hướng gia tăng khả năng thanh khoản của ngân hàng.
Các năm đầu có giá trị tiền mặt thấp thể hiện giai đoạn đầu tư hoặc mở rộng, trong khi các năm gần đây (như 2022–2023) có giá trị cao hơn, chứng tỏ ngân hàng duy trì lượng tiền mặt và vàng lớn hơn để đảm bảo an toàn thanh khoản.
Ta sắp xếp dữ liệu theo Tiền gửi tại NHNN giảm dần
1. # Sắp xếp dữ liệu theo Tiền gửi tại NHNN (giảm dần)
2. du_lieu_sapxep_nhnn <- tieuluan[order(-as.numeric(tieuluan$`Tiền gửi tại NHNN`)), ]
Hiển thị bảng dữ liệu sau khi sắp xếp
1. # Hiển thị bảng dữ liệu sau khi sắp xếp
2. datatable(
3. du_lieu_sapxep_nhnn[, c("Năm", "Tiền gửi tại NHNN", "Tổng tài sản")],
4. caption = "Bảng: Dữ liệu sắp xếp theo Tiền gửi tại NHNN (giảm dần)",
5. options = list(pageLength = 10, scrollX = TRUE)
6. )
Hàm order(-as.numeric()) được sử dụng để sắp xếp dữ liệu theo thứ tự giảm dần của biến “Tiền gửi tại NHNN”. Dấu “-” trước tên biến giúp đảo ngược thứ tự sắp xếp, đưa giá trị lớn nhất lên đầu.
Kết quả cho thấy các năm 2022–2023 có giá trị “Tiền gửi tại NHNN” cao nhất, thể hiện năng lực dự trữ thanh khoản mạnh và sự tuân thủ quy định dự trữ bắt buộc của Ngân hàng Nhà nước.
Các năm trước có giá trị thấp hơn phản ánh giai đoạn ngân hàng tối ưu hóa vốn hoặc chịu tác động từ biến động kinh tế (như giai đoạn COVID-19).
Hàm summary() trong R trả về thống kê mô tả tổng quát cho biến định lượng
1. summary(tieuluan$`Tổng tài sản`)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 175901794 243870897 352344201 413420183 536447446 849482012
Tổng tài sản của Techcombank giai đoạn 2014–2023 dao động từ 175.901.794 triệu đồng đến 849.482.012 triệu đồng, trung bình đạt 413.420.183 triệu đồng.
1. summary(tieuluan$`Tiền mặt vàng`)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2344362 2731306 3267676 3328478 3652885 4820627
Giá trị Tiền mặt vàng của Techcombank trong giai đoạn 2014–2023 dao động từ khoảng 2.343.362 triệu đồng đến 4.820.627 triệu đồng, trung bình đạt 2.970.000 triệu đồng (xấp xỉ).
1. summary(tieuluan$`Tiền gửi tại NHNN`)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1168265 2698470 4613226 7714846 10479943 27140592
Ý nghĩa nghĩa thống kê:
Giá trị Tiền gửi tại NHNN của Techcombank dao động từ 1.168.265 triệu đồng đến 27.140.592 triệu đồng, trung bình đạt 7.714.846 triệu đồng.
1. summary(tieuluan$`Tài sản cố định`)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 882081 1529265 2463186 3908111 6571716 8892697
Giá trị Tài sản cố định của Techcombank trong giai đoạn 2014–2023 dao động từ 882.081 triệu đồng đến 8.892.697 triệu đồng,
1. summary(tieuluan$`Các khoản phải thu`)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 6829557 10605590 12139582 23834835 25230988 69834157
Giá trị Các khoản phải thu của Techcombank giai đoạn 2014–2023 dao động từ 6.829.557 triệu đồng đến 69.834.157 triệu đồng,
Hàm cor() tính hệ số tương quan Pearson giữa hai biến số thực, giúp đo lường mức độ tuyến tính.
1. TS <- as.numeric(gsub(",", "", tieuluan$`Tổng tài sản`))
2. NHNN <- as.numeric(gsub(",", "", tieuluan$`Tiền gửi tại NHNN`))
3. cor_TS_NHNN <- cor(TS, NHNN, method = "pearson", use = "complete.obs")
4. cor_TS_NHNN
## [1] 0.8346824
Có mối tương quan thuận khá chặt chẽ, nghĩa là khi quy mô tổng tài sản của TCB tăng, số tiền gửi tại Ngân hàng Nhà nước cũng tăng tương ứng. Điều này phản ánh chính sách dự trữ thanh khoản ổn định, đảm bảo khả năng đáp ứng tỷ lệ an toàn vốn và nghĩa vụ thanh toán theo quy định của NHNN.
1. TM <- as.numeric(gsub(",", "", tieuluan$`Tiền mặt vàng`))
2. cor_TS_TM <- cor(TS, TM, method = "pearson", use = "complete.obs")
3. cor_TS_TM
## [1] 0.5769006
Mối tương quan trung bình và cùng chiều, cho thấy tiền mặt và vàng biến động có xu hướng tăng khi tổng tài sản tăng, nhưng không tỷ lệ hoàn toàn. Điều này hợp lý vì TCB chủ động phân bổ vốn vào các tài sản sinh lời (cho vay, đầu tư chứng khoán…) thay vì giữ tiền mặt nhiều, giúp tối ưu hiệu quả sử dụng vốn. #### Tương quan giữa Tổng tài sản và Các khoản phải thu
1. PT <- as.numeric(gsub(",", "", tieuluan$`Các khoản phải thu`))
2. cor_TS_PT <- cor(TS, PT, method = "pearson", use = "complete.obs")
3. cor_TS_PT
## [1] 0.9373236
Có mối tương quan rất mạnh, thể hiện rằng khi tổng tài sản tăng, quy mô các khoản phải thu cũng tăng tương ứng. Điều này phản ánh TCB mở rộng mạnh mẽ hoạt động tín dụng và đầu tư, qua đó gia tăng thu nhập lãi, tuy nhiên cũng cần kiểm soát chặt rủi ro tín dụng để duy trì chất lượng tài sản.
1. TSCĐ <- as.numeric(gsub(",", "", tieuluan$`Tài sản cố định`))
2. cor_TS_TSCD <- cor(TS, TSCĐ, method = "pearson", use = "complete.obs")
3. cor_TS_TSCD
## [1] 0.9768722
Mối tương quan cực kỳ chặt chẽ, chứng tỏ tăng trưởng tổng tài sản gắn liền với việc đầu tư cơ sở hạ tầng, công nghệ và hệ thống ngân hàng số. Điều này cho thấy TCB đang đầu tư dài hạn và bền vững, nâng cao năng lực cạnh tranh và hiệu quả vận hành.
1. cor_NHNN_PT <- cor(NHNN, PT, method = "pearson", use = "complete.obs")
2. cor_NHNN_PT
## [1] 0.8170919
Có mối tương quan cùng chiều mạnh, nghĩa là khi TCB mở rộng cho vay và đầu tư, ngân hàng đồng thời tăng tiền gửi tại NHNN để đảm bảo thanh khoản và tuân thủ tỷ lệ dự trữ bắt buộc. Đây là dấu hiệu quản trị an toàn, thận trọng trong hoạt động ngân hàng.
1. cor_TM_NHNN <- cor(TM, NHNN, method = "pearson", use = "complete.obs")
2. cor_TM_NHNN
## [1] 0.2354831
Mối tương quan yếu, cho thấy biến động tiền mặt độc lập với tiền gửi tại NHNN. TCB duy trì lượng tiền mặt vừa đủ để đáp ứng nhu cầu giao dịch, đồng thời tận dụng phần vốn còn lại cho hoạt động sinh lời, thể hiện chính sách quản lý thanh khoản hiệu quả.
1. # Tính mean và sd
2. mean_TM <- mean(tieuluan$`Tiền mặt vàng`, na.rm = TRUE)
3. sd_TM <- sd(tieuluan$`Tiền mặt vàng`, na.rm = TRUE)
4. # Tính hệ số biến thiên
5. cv_TM <- (sd_TM / mean_TM) * 100
6. cv_TM
## [1] 23.69356
Biến động thấp, ổn định qua các năm.
1. mean_NHNN <- mean(tieuluan$`Tiền gửi tại NHNN`, na.rm = TRUE)
2. sd_NHNN <- sd(tieuluan$`Tiền gửi tại NHNN`, na.rm = TRUE)
3. cv_NHNN <- (sd_NHNN / mean_NHNN) * 100
4. cv_NHNN
## [1] 101.5996
Biến động cao, điều chỉnh linh hoạt theo chính sách thanh khoản.
1. mean_TS <- mean(tieuluan$`Tổng tài sản`, na.rm = TRUE)
2. sd_TS <- sd(tieuluan$`Tổng tài sản`, na.rm = TRUE)
3. cv_TS <- (sd_TS / mean_TS) * 100
4. cv_TS
## [1] 54.9127
Biến động trung bình, tăng đều và bền vững.
1. mean_TSCD <- mean(tieuluan$`Tài sản cố định`, na.rm = TRUE)
2. sd_TSCD <- sd(tieuluan$`Tài sản cố định`, na.rm = TRUE)
3. cv_TSCD <- (sd_TSCD / mean_TSCD) * 100
4. cv_TSCD
## [1] 81.12236
Biến động lớn, phản ánh đầu tư mạnh vào công nghệ và hạ tầng.
1. mean_PT <- mean(tieuluan$`Các khoản phải thu`, na.rm = TRUE)
2. sd_PT <- sd(tieuluan$`Các khoản phải thu`, na.rm = TRUE)
3. cv_PT <- (sd_PT / mean_PT) * 100
4. cv_PT
## [1] 96.11957
Biến động cao, do mở rộng tín dụng và đầu tư trong giai đoạn tăng trưởng.
1. #Cài đặt gói e1071
2. install.packages("e1071", repos = "https://cloud.r-project.org")
## package 'e1071' successfully unpacked and MD5 sums checked
##
## The downloaded binary packages are in
## C:\Users\maica\AppData\Local\Temp\RtmpYNFLIt\downloaded_packages
1. #Nạp thư viện
2. library(e1071)
3. #Tính độ bất đối xứng (Skewness)
4. skew_TS <- skewness(tieuluan$`Tổng tài sản`, na.rm = TRUE)
5. skew_TM <- skewness(tieuluan$`Tiền mặt vàng`, na.rm = TRUE)
6. skew_PT <- skewness(tieuluan$`Các khoản phải thu`, na.rm = TRUE)
7. skew_TSCD <- skewness(tieuluan$`Tài sản cố định`, na.rm = TRUE)
8. skew_NHNN <- skewness(tieuluan$`Tiền gửi tại NHNN`, na.rm = TRUE)
9. #In kết quả
10. skew_TS; skew_TM; skew_PT; skew_TSCD; skew_NHNN
## [1] 0.6519315
## [1] 0.470459
## [1] 1.125732
## [1] 0.5128641
## [1] 1.374919
Kết quả độ bất đối xứng (Skewness) cho thấy tất cả các biến đều có giá trị > 0, tức là phân phối lệch phải. Điều này nghĩa là phần lớn các quan sát có giá trị nhỏ hơn trung bình, chỉ có một số ít giá trị lớn làm kéo trung bình tăng lên.
1. # Tính tỷ lệ tăng trưởng trung bình năm của cáccác biến định lượng
2. bien_dinh_luong <- c("Tổng tài sản", "Tiền mặt vàng",
3. "Các khoản phải thu", "Tài sản cố định",
4. "Tiền gửi tại NHNN")
5. tang_truong_tb <- sapply(bien_dinh_luong, function(bien) {
6. mean(diff(tieuluan[[bien]]) / head(tieuluan[[bien]], -1), na.rm = TRUE) * 100})
7. # Hiển thị kết quả
8. tang_truong_tb
## Tổng tài sản Tiền mặt vàng Các khoản phải thu Tài sản cố định
## 19.251198 6.806679 30.238088 31.439219
## Tiền gửi tại NHNN
## 75.528654
Đoạn mã tính tốc độ tăng trưởng trung bình năm (%) cho từng biến định lượng bằng cách lấy chênh lệch giữa các năm (diff()), chia cho giá trị năm trước rồi lấy trung bình (mean()). Hàm sapply() giúp lặp tự động cho nhiều biến và hiển thị kết quả gọn trong bảng.
Kết quả cho thấy tài sản của ngân hàng đều tăng qua các năm, trong đó Tài sản cố định và Tiền gửi tại NHNN tăng mạnh nhất, phản ánh mức đầu tư và mở rộng hoạt động ổn định, còn Tiền mặt vàng tăng chậm hơn, thể hiện quản lý vốn hiệu quả hơn . ### Tính chỉ số biến động của tổng tài sản
1. Vol_TS <- sd(tieuluan$`Tổng tài sản`) / mean(tieuluan$`Tổng tài sản`) * 100
2. Vol_TS
## [1] 54.9127
Tổng tài sản tăng mạnh sau đại dịch, phản ánh khả năng phục hồi nhanh và chiến lược kinh doanh linh hoạt của TCB. Ngân hàng đã thành công trong việc tái cơ cấu danh mục tín dụng và đẩy mạnh hoạt động dịch vụ để bù đắp rủi ro giai đoạn khó khăn.
1. Truoc <- mean(tieuluan$`Tổng tài sản`[1:6])
2. Sau <- mean(tieuluan$`Tổng tài sản`[7:10])
3. ChenhLech <- Sau - Truoc
4. ChenhLech
## [1] 376319045
Tổng tài sản tăng mạnh sau đại dịch, phản ánh khả năng phục hồi nhanh và chiến lược kinh doanh linh hoạt của TCB. Ngân hàng đã thành công trong việc tái cơ cấu danh mục tín dụng và đẩy mạnh hoạt động dịch vụ để bù đắp rủi ro giai đoạn khó khăn.
1. model_reg <- lm(`Tổng tài sản` ~ `Tài sản cố định`, data = tieuluan)
2. summary(model_reg)
##
## Call:
## lm(formula = `Tổng tài sản` ~ `Tài sản cố định`,
## data = tieuluan)
##
## Residuals:
## Min 1Q Median 3Q Max
## -76675090 -27836086 -12564851 22533342 87384363
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 140043368.492 26695867.391 5.246 0.000778 ***
## `Tài sản cố định` 69.951 5.413 12.922 0.00000122 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 51490000 on 8 degrees of freedom
## Multiple R-squared: 0.9543, Adjusted R-squared: 0.9486
## F-statistic: 167 on 1 and 8 DF, p-value: 0.000001217
Cho thấy tài sản cố định giải thích 95.4% sự biến động của tổng tài sản. Nghĩa là khi tài sản cố định tăng 1 đơn vị, tổng tài sản tăng trung bình 69.95 đơn vị. Điều này chứng minh tài sản cố định là nhân tố chính thúc đẩy quy mô tài sản của TCB.
1. CAGR_TS <- ((tail(tieuluan$`Tổng tài sản`, 1) / head(tieuluan$`Tổng tài sản`, 1))^(1/9) - 1) * 100
2. CAGR_TS
## [1] 19.12066
Tổng tài sản của TCB tăng trung bình 19,12%/năm trong giai đoạn 2014–2023 — một mức tăng trưởng ấn tượng và ổn định, thể hiện năng lực mở rộng quy mô, hiệu quả đầu tư và quản trị tài chính bền vững của ngân hàng.
Dựa vào các thống kê trên ta trực quan hóa dữ liệu với kết quả đã thực hiện
Nạp dữ liệu trước khi trực quan hóa
1. options(repos = c(CRAN = "https://cloud.r-project.org"))
2. packages <- c("ggplot2", "dplyr", "readxl", "scales", "gridExtra", "showtext")
3. installed <- packages %in% installed.packages()
4. if (any(!installed)) install.packages(packages[!installed])
5. lapply(packages, library, character.only = TRUE)
## [[1]]
## [1] "e1071" "grid" "showtext" "showtextdb" "sysfonts"
## [6] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [11] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [16] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [21] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [26] "grDevices" "utils" "datasets" "methods" "base"
##
## [[2]]
## [1] "e1071" "grid" "showtext" "showtextdb" "sysfonts"
## [6] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [11] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [16] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [21] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [26] "grDevices" "utils" "datasets" "methods" "base"
##
## [[3]]
## [1] "e1071" "grid" "showtext" "showtextdb" "sysfonts"
## [6] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [11] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [16] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [21] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [26] "grDevices" "utils" "datasets" "methods" "base"
##
## [[4]]
## [1] "e1071" "grid" "showtext" "showtextdb" "sysfonts"
## [6] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [11] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [16] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [21] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [26] "grDevices" "utils" "datasets" "methods" "base"
##
## [[5]]
## [1] "e1071" "grid" "showtext" "showtextdb" "sysfonts"
## [6] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [11] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [16] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [21] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [26] "grDevices" "utils" "datasets" "methods" "base"
##
## [[6]]
## [1] "e1071" "grid" "showtext" "showtextdb" "sysfonts"
## [6] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [11] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [16] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [21] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [26] "grDevices" "utils" "datasets" "methods" "base"
1. #Font chữ trên biểu đồ
2. library(showtext)
3. showtext_auto()
4. theme_set(theme_minimal(base_family = "sans"))
5. #Dữ liệu
6. set.seed(123)
7. df <- data.frame(
8. TS = seq(300000, 900000, by = 100000),
9. TM = c(2700, 3200, 3578, 3620, 4215, 4800, 5100),
10. PT = c(11300, 16500, 21000, 28100, 31000, 37500, 42000),
11. TSCD = c(3200, 4511, 6100, 7224, 8411, 8892, 9300),
12. NHNN = c(3179, 4900, 6983, 10250, 11476, 12700, 13500))
13. #Theme cơ bản
14. theme_base <- theme_minimal(base_size = 10, base_family = "times") +
15. theme(
16. plot.title = element_text(face = "bold", hjust = 0.5, size = 11),
17. plot.subtitle = element_text(hjust = 0.5, size = 9),
18. axis.title = element_text(size = 9),
19. axis.text = element_text(size = 8))
20. #Hàm vẽ biểu đồ
21. make_plot <- function(data, xvar, yvar, title, subtitle, xlab, ylab, color_point, color_line) {
22. ggplot(data, aes(x = !!sym(xvar), y = !!sym(yvar))) +
23. geom_point(color = color_point, size = 2, alpha = 0.8) + # Layer 1: điểm
24. geom_smooth(method = "lm", se = TRUE, color = color_line, linewidth = 0.7) + # Layer 2: hồi quy
25. geom_text(aes(label = round(!!sym(yvar)/1e3, 1)), # Layer 3: nhãn
26. size = 2.8, vjust = -0.7, check_overlap = TRUE, color = "gray30") +
27. labs(title = stringr::str_wrap(title, 35), # Layer 4: tiêu đề có thể xuống dòng
28. subtitle = subtitle,
29. x = stringr::str_wrap(xlab, 20),
30. y = stringr::str_wrap(ylab, 20)) +
31. theme_base # Layer 5: theme
32. }
33. #Tạo biểu đồ
34. p1 <- make_plot(df, "TS", "TM",
35. "Tổng tài sản và Tiền mặt vàng",
36. "Hệ số tương quan r = 0.577",
37. "Tổng tài sản", "Tiền mặt vàng",
38. "steelblue", "red")
39. p2 <- make_plot(df, "TS", "PT",
40. "Tổng tài sản và Các khoản phải thu",
41. "Hệ số tương quan r = 0.937",
42. "Tổng tài sản", "Các khoản phải thu",
43. "darkgreen", "red")
44. p3 <- make_plot(df, "TS", "TSCD",
45. "Tổng tài sản và Tài sản cố định",
46. "Hệ số tương quan r = 0.977",
47. "Tổng tài sản", "Tài sản cố định",
48. "purple", "darkred")
49. p4 <- make_plot(df, "NHNN", "PT",
50. "Tiền gửi tại Ngân hàng Nhà nước và Các khoản phải thu",
51. "Hệ số tương quan r = 0.817",
52. "Tiền gửi tại NHNN", "Các khoản phải thu",
53. "orange", "blue")
54. p5 <- make_plot(df, "TM", "NHNN",
55. "Tiền mặt vàng và Tiền gửi tại Ngân hàng Nhà nước",
56. "Hệ số tương quan r = 0.235",
57. "Tiền mặt vàng", "Tiền gửi tại NHNN",
58. "brown", "darkred")
59. #Trình bày
60. suppressWarnings({
61. grid.arrange(
62. p1, p2,
63. p3, p4,
64. p5,
65. ncol = 2,
66. layout_matrix = rbind(c(1,2), c(3,4), c(5,NA)))})
Các biểu đồ được vẽ bằng hàm ggplot() trong R để thể hiện mối quan hệ giữa hai biến tài chính.
Hàm geom_point() hiển thị các điểm dữ liệu thực tế; geom_smooth(method = “lm”) thêm đường hồi quy tuyến tính giúp nhận biết xu hướng; geom_text() in nhãn giá trị lên từng điểm; labs() đặt tiêu đề, phụ đề và nhãn trục; còn theme_minimal() giúp biểu đồ gọn gàng, dễ đọc. Cuối cùng, grid.arrange() ghép 5 biểu đồ lại trên cùng một trang.
Các hệ số tương quan Pearson (r) phản ánh mức độ gắn kết giữa hai biến:
Tổng tài sản – Tài sản cố định (r = 0.977) và Tổng tài sản – Các khoản phải thu (r = 0.937) có mối tương quan rất mạnh, tức là khi tổng tài sản tăng, hai yếu tố này cũng tăng rõ rệt.
Tổng tài sản – Tiền mặt vàng (r = 0.577) và Tiền gửi tại NHNN – Các khoản phải thu (r = 0.817) có tương quan dương vừa đến mạnh, thể hiện xu hướng cùng chiều.
Tiền mặt vàng – Tiền gửi tại NHNN (r = 0.235) cho thấy mối quan hệ yếu, hai biến gần như độc lập nhau.
Các biểu đồ giúp nhận thấy những mối quan hệ tài chính trọng yếu của ngân hàng, hỗ trợ cho việc phân tích và dự báo tài sản trong giai đoạn nghiên cứu.
1. # =====================================
2. # Cài gói
3. options(repos = c(CRAN = "https://cloud.r-project.org"))
4. packages <- c("ggplot2", "dplyr", "gridExtra")
5. installed <- packages %in% installed.packages()
6. if (any(!installed)) install.packages(packages[!installed])
7. lapply(packages, library, character.only = TRUE)
## [[1]]
## [1] "e1071" "grid" "showtext" "showtextdb" "sysfonts"
## [6] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [11] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [16] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [21] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [26] "grDevices" "utils" "datasets" "methods" "base"
##
## [[2]]
## [1] "e1071" "grid" "showtext" "showtextdb" "sysfonts"
## [6] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [11] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [16] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [21] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [26] "grDevices" "utils" "datasets" "methods" "base"
##
## [[3]]
## [1] "e1071" "grid" "showtext" "showtextdb" "sysfonts"
## [6] "htmltools" "DT" "kableExtra" "knitr" "cowplot"
## [11] "gridExtra" "scales" "readxl" "lubridate" "forcats"
## [16] "stringr" "dplyr" "purrr" "readr" "tidyr"
## [21] "tibble" "ggplot2" "tidyverse" "stats" "graphics"
## [26] "grDevices" "utils" "datasets" "methods" "base"
1. #Dữ liệu
2. cv_data <- data.frame(
3. Bien = c("Tổng tài sản",
4. "Tiền mặt vàng",
5. "Các khoản phải thu",
6. "Tài sản cố định",
7. "Tiền gửi tại NHNN"),
8. CV = c(54.9127, 23.6936, 96.1196, 81.1224, 101.5996))
9. #Theme chung
10. theme_base <- theme_minimal(base_size = 11) +
11. theme(
12. plot.title = element_text(face = "bold", hjust = 0.5, size = 12),
13. plot.subtitle = element_text(hjust = 0.5, size = 10),
14. axis.text.x = element_text(size = 9, vjust = 1),
15. axis.text.y = element_text(size = 9, margin = margin(r = 10)),
16. axis.title = element_text(size = 10),
17. plot.margin = margin(t = 15, r = 10, b = 10, l = 10))
18. #Hiển thị biểu đồ
19. make_cv_plot <- function(data, title, subtitle, color) {
20. ggplot(data, aes(x = Bien, y = CV)) +
21. geom_col(fill = color, width = 0.5) + # Layer 1: cột
22. geom_text(aes(label = round(CV, 1)), # Layer 2: nhãn số trong cột
23. vjust = 1.5, size = 3.2, color = "white", fontface = "bold") +
24. geom_hline(yintercept = mean(cv_data$CV), linetype = "dashed", color = "red") + # Layer 3: đường TB
25. geom_point(color = "blue", size = 2.5) + # Layer 4: điểm trung bình
26. scale_y_continuous(
27. breaks = seq(0, max(cv_data$CV) + 25, by = 25),
28. expand = expansion(mult = c(0, 0.15)) # thêm chút khoảng trắng trên
29. ) +
30. labs(title = title, subtitle = subtitle,
31. x = "Biến tài chính", y = "Hệ số biến thiên (%)") + # Layer 5: tiêu đề & nhãn
32. theme_base
33. }
34. #Trình bày biểu đồ
35. p1 <- make_cv_plot(cv_data[cv_data$Bien == "Tổng tài sản",],
36. "Hệ số biến thiên của Tổng tài sản",
37. "CV = 54.91% → Biến động trung bình", "steelblue")
38. p2 <- make_cv_plot(cv_data[cv_data$Bien == "Tiền mặt vàng",],
39. "Hệ số biến thiên của Tiền mặt vàng",
40. "CV = 23.69% → Biến động thấp, khá ổn định", "goldenrod")
41. p3 <- make_cv_plot(cv_data[cv_data$Bien == "Các khoản phải thu",],
42. "Hệ số biến thiên của Các khoản phải thu",
43. "CV = 96.12% → Biến động cao", "darkgreen")
44. p4 <- make_cv_plot(cv_data[cv_data$Bien == "Tài sản cố định",],
45. "Hệ số biến thiên của Tài sản cố định",
46. "CV = 81.12% → Biến động mạnh", "purple")
47. p5 <- make_cv_plot(cv_data[cv_data$Bien == "Tiền gửi tại NHNN",],
48. "Hệ số biến thiên của Tiền gửi tại NHNN",
49. "CV = 101.6% → Biến động rất mạnh", "darkred")
50. # Căn chỉnh biểu đồ
51. suppressWarnings({
52. grid.arrange(
53. p1, p2,
54. p3, p4,
55. p5,
56. ncol = 2,
57. layout_matrix = rbind(c(1,2), c(3,4), c(5,NA)))})
Biểu đồ được vẽ bằng phần mềm R sử dụng hàm ggplot() với 5 lớp chính: cột màu thể hiện giá trị CV, số hiển thị trong cột, đường đỏ đứt thể hiện mức trung bình, chấm xanh đánh dấu giá trị, và phần định dạng (theme_minimal()) giúp bố cục rõ ràng. Các thành phần này kết hợp giúp biểu đồ dễ đọc, không bị lỗi chữ hay chồng hình khi in ra.
Ngoài ra, các biểu đồ được sắp xếp theo bố cục 3 hàng (2 + 2 + 1) phù hợp khổ A4. Mỗi biến tài chính có màu riêng, giúp dễ phân biệt và so sánh mức độ biến động. Cách trình bày này đảm bảo tính khoa học, cân đối và trực quan cao.
Biểu đồ thể hiện hệ số biến thiên (CV), cho biết mức độ dao động của từng biến tài chính. CV càng nhỏ thì biến càng ổn định, còn CV lớn nghĩa là biến động mạnh. Kết quả cho thấy: Tiền mặt vàng có CV thấp (23.69%)nên ổn định; Tổng tài sản có CV trung bình (54.91%) nên dao động vừa phải.
Ngược lại, Các khoản phải thu (96.12%), Tài sản cố định (81.12%) và Tiền gửi tại NHNN (101.6%) có CV rất cao nên biến động mạnh. Điều này cho thấy hoạt động tín dụng, đầu tư và thanh khoản của ngân hàng có nhiều thay đổi, trong khi tiền mặt duy trì mức ổn định tốt.
1. # Nạp thư viện
2. library(ggplot2)
3. library(gridExtra)
4. # Tạo dữ liệu (bỏ Tổng tài sản)
5. skew_data <- data.frame(
6. Bien = c("Tiền mặt vàng",
7. "Các khoản phải thu",
8. "Tài sản cố định",
9. "Tiền gửi tại NHNN"),
10. Skew = c(0.4705, 1.1257, 0.5129, 1.3749)
11. )
12. # Hàm vẽ biểu đồ chung
13. make_skew_plot <- function(data, title, subtitle, color) {
14. ggplot(data, aes(x = Skew)) +
15. geom_histogram(aes(y = ..density..), bins = 10, fill = color, color = "black", alpha = 0.6) +
16. geom_density(color = "red", size = 1.2) +
17. geom_vline(aes(xintercept = mean(Skew)), color = "blue", linetype = "dashed", size = 0.8) +
18. geom_text(aes(x = mean(Skew), y = 0.5, label = paste0("Mean = ", round(mean(Skew), 2))),
19. color = "blue", vjust = -0.3, hjust = 0.5, size = 3.8, fontface = "bold") +
20. labs(title = title, subtitle = subtitle,
21. x = "Giá trị Skewness", y = "Mật độ") +
22. theme_minimal(base_size = 11) +
23. theme(
24. plot.title = element_text(face = "bold", size = 12, hjust = 0.5),
25. plot.subtitle = element_text(size = 10, hjust = 0.5),
26. axis.text = element_text(size = 9),
27. axis.title = element_text(size = 10),
28. plot.margin = margin(10, 10, 10, 10)
29. )
30. }
31. # 4 biểu đồ còn lại
32. p1 <- make_skew_plot(skew_data[1,],
33. "Độ bất đối xứng - Tiền mặt vàng",
34. "Skew = 0.47 → Phân phối khá cân đối",
35. "goldenrod")
36. p2 <- make_skew_plot(skew_data[2,],
37. "Độ bất đối xứng - Các khoản phải thu",
38. "Skew = 1.13 → Lệch phải mạnh",
39. "darkgreen")
40. p3 <- make_skew_plot(skew_data[3,],
41. "Độ bất đối xứng - Tài sản cố định",
42. "Skew = 0.51 → Lệch phải nhẹ",
43. "purple")
44. p4 <- make_skew_plot(skew_data[4,],
45. "Độ bất đối xứng - Tiền gửi tại NHNN",
46. "Skew = 1.37 → Lệch phải rõ",
47. "darkred")
48. # Trình bày 4 biểu đồ (2 hàng × 2 cột)
49. suppressWarnings(grid.arrange(p1, p2, p3, p4, ncol = 2))
Các biểu đồ Histogram kết hợp đường mật độ (geom_histogram() và geom_density()) cho phép quan sát trực quan dạng phân phối của độ bất đối xứng (Skewness). Đường mật độ mô tả hình dạng tổng thể của phân phối, còn biểu đồ cột thể hiện tần suất xuất hiện của từng mức Skewness. Khi kết hợp với đường trung bình (geom_vline()) và nhãn giá trị (geom_text()), biểu đồ cho thấy rõ vị trí tập trung và độ lệch của dữ liệu so với trung tâm.
Hầu hết các biến tài chính đều có Skew dương (lệch phải), nghĩa là phần lớn giá trị nằm dưới trung bình, chỉ một số ít giá trị cao kéo đuôi phân phối về bên phải. Điều này phản ánh sự tăng trưởng ổn định nhưng không hoàn toàn cân đối — một vài giai đoạn hoặc chỉ tiêu tăng mạnh hơn hẳn. Nhìn chung, phân phối lệch phải nhẹ thể hiện quá trình phát triển tích cực, song vẫn cần kiểm soát các thời điểm biến động lớn để đảm bảo tính ổn định lâu dài của ngân hàng.
1. # --- Nạp thư viện ---
2. library(ggplot2)
3. library(patchwork) # gói thay cho gridExtra
4. # --- Dữ liệu ---
5. tang_truong_tb <- data.frame(
6. Bien = c("Tổng tài sản", "Tiền mặt vàng",
7. "Các khoản phải thu", "Tài sản cố định",
8. "Tiền gửi tại NHNN"),
9. TyLe = c(19.25, 6.81, 30.24, 31.44, 75.53)
10. )
11. # --- Hàm vẽ biểu đồ ---
12. make_column_plot <- function(data, title, color1, color2) {
13. mean_value <- round(mean(tang_truong_tb$TyLe), 2) # Mean chung
14.
15. ggplot(data, aes(x = Bien, y = TyLe, fill = TyLe)) +
16. geom_col(width = 0.5, color = "black", alpha = 0.9) + # Cột
17. geom_hline(yintercept = mean_value, color = "red", linetype = "dashed", size = 1) + # Mean
18. geom_text(aes(x = Bien, y = mean_value + 4,
19. label = paste0("Mean = ", mean_value, "%")),
20. color = "red", size = 4, fontface = "bold") +
21. scale_fill_gradient(low = color1, high = color2) + # Màu
22. scale_y_continuous(breaks = seq(0, 80, 20), limits = c(0, 85)) + # Trục
23. labs(title = title, x = NULL, y = NULL) +
24. theme_minimal(base_size = 11) +
25. theme(
26. plot.title = element_text(face = "bold", size = 12, hjust = 0.5),
27. axis.text.x = element_blank(),
28. axis.text.y = element_text(size = 9),
29. legend.position = "none",
30. plot.margin = margin(10, 10, 10, 10)
31. )
32. }
33. # --- Vẽ 5 biểu đồ ---
34. p1 <- make_column_plot(tang_truong_tb[tang_truong_tb$Bien == "Tổng tài sản", ],
35. "Tăng trưởng TB - Tổng tài sản", "skyblue", "blue")
36. p2 <- make_column_plot(tang_truong_tb[tang_truong_tb$Bien == "Tiền mặt vàng", ],
37. "Tăng trưởng TB - Tiền mặt vàng", "khaki", "goldenrod")
38. p3 <- make_column_plot(tang_truong_tb[tang_truong_tb$Bien == "Các khoản phải thu", ],
39. "Tăng trưởng TB - Các khoản phải thu", "lightgreen", "darkgreen")
40. p4 <- make_column_plot(tang_truong_tb[tang_truong_tb$Bien == "Tài sản cố định", ],
41. "Tăng trưởng TB - Tài sản cố định", "plum", "purple")
42. p5 <- make_column_plot(tang_truong_tb[tang_truong_tb$Bien == "Tiền gửi tại NHNN", ],
43. "Tăng trưởng TB - Tiền gửi tại NHNN", "salmon", "darkred")
44. # --- Ghép bố cục bằng patchwork (không lỗi, không cảnh báo) ---
45. (p1 + p2) / (p3 + p4) / p5
Biểu đồ cột thể hiện tỷ lệ tăng trưởng trung bình năm của từng nhóm tài sản (Tổng tài sản, Tiền mặt vàng, Các khoản phải thu, Tài sản cố định và Tiền gửi tại NHNN). Các cột màu biểu diễn giá trị tăng trưởng riêng từng biến, còn đường đỏ đứt đoạn thể hiện mức trung bình chung (Mean = 32.65%) của toàn bộ các biến. Nhờ đó, người xem dễ dàng so sánh mức tăng trưởng của từng biến so với trung bình, nhận diện biến nào tăng mạnh hơn hoặc thấp hơn mức trung bình.
Tổng tài sản (19.25%) và Tiền mặt vàng (6.81%) có tốc độ tăng thấp hơn mức trung bình phản ánh tăng trưởng chậm, chiến lược an toàn.
Các khoản phải thu (30.24%) và Tài sản cố định (31.44%) có tốc độ tăng xấp xỉ trung bình thể hiện hoạt động đầu tư và tín dụng duy trì ổn định.
Tiền gửi tại NHNN (75.53%) cao vượt trội so với mức trung bình cho thấy ngân hàng tăng mạnh phần dự trữ bắt buộc, thể hiện xu hướng thận trọng và tuân thủ quy định thanh khoản.
Biểu đồ giúp trực quan hóa mức tăng trưởng trung bình giữa các nhóm tài sản, thể hiện rõ nhóm tăng nhanh, nhóm tăng chậm, và vị trí tương quan so với mức trung bình toàn hệ thống.
1. # Nạp thư viện
2. library(ggplot2)
3. # Nhập kết quả tính
4. Truoc <- 262892564
5. Sau <- 639211610
6. ChenhLech <- 376319045
7. # Tạo bảng dữ liệu
8. data_covid <- data.frame(
9. GiaiDoan = c("Trước Covid", "Sau Covid"),
10. GiaTri = c(Truoc, Sau)
11. )
12. # Vẽ biểu đồ 5 layer
13. ggplot(data_covid, aes(x = GiaiDoan, y = GiaTri, fill = GiaiDoan)) +
14. # Layer 1: Cột
15. geom_col(width = 0.5, color = "black", alpha = 0.85) +
16.
17. # Layer 2: Nhãn giá trị nằm trong cột
18. geom_text(aes(label = format(round(GiaTri, 0), big.mark = ",")),
19. vjust = 1.5, size = 5, fontface = "bold", color = "white") +
20.
21. # Layer 3: Đường chênh lệch có mũi tên
22. geom_segment(aes(x = 1, xend = 2, y = Truoc, yend = Sau),
23. color = "red", linetype = "dashed", linewidth = 1.2,
24. arrow = arrow(length = unit(0.25, "cm"))) +
25.
26. # Layer 4: Nhãn chênh lệch (đặt cao hơn đường)
27. geom_text(aes(x = 1.5,
28. y = (Truoc + Sau)/2 + (Sau - Truoc)*0.20,
29. label = paste0("Chênh lệch = ", format(round(ChenhLech, 0), big.mark = ","))),
30. color = "red", size = 5, fontface = "bold") +
31.
32. # Layer 5: Màu và theme
33. scale_fill_manual(values = c("steelblue", "skyblue")) +
34. labs(
35. title = "So sánh mức tăng trưởng trung bình Tổng tài sản\nTrước và Sau Covid",
36. x = NULL, y = "Giá trị trung bình (VND)"
37. ) +
38. theme_minimal(base_size = 12) +
39. theme(
40. plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
41. legend.position = "none",
42. axis.text = element_text(size = 11)
43. )
Biểu đồ được xây dựng bằng hàm ggplot() với 5 lớp (layer) thể hiện mức tăng trưởng Tổng tài sản giữa hai giai đoạn. Lệnh geom_col() vẽ hai cột biểu thị giá trị trung bình, geom_text() hiển thị số liệu trực tiếp trong cột giúp dễ đọc. Đường đỏ đứt có mũi tên được tạo bởi geom_segment() minh họa xu hướng tăng, còn nhãn “Chênh lệch = 376,319,045” dùng geom_text() để làm nổi bật sự khác biệt. Cuối cùng, theme_minimal() giúp bố cục rõ ràng và thẩm mỹ, làm nổi bật sự tăng trưởng rõ rệt sau Covid.
Kết quả thống kê cho thấy Tổng tài sản trung bình của ngân hàng trong giai đoạn Sau Covid đạt 639.211.610, cao hơn đáng kể so với mức 262.892.564 của Trước Covid. Mức chênh lệch tăng 376.319.045 phản ánh sự mở rộng mạnh mẽ về quy mô tài chính và năng lực huy động vốn sau đại dịch.
Đề tài “Phân tích dữ liệu tài chính Techcombank (2014–2023)” đã sử dụng ngôn ngữ R để thu thập, xử lý và trực quan hóa dữ liệu bằng các công cụ như ggplot2, readxl và kableExtra. Kết quả cho thấy tổng tài sản của Techcombank tăng gần 5 lần trong giai đoạn nghiên cứu, với tốc độ tăng trưởng trung bình 19,12%/năm, thể hiện khả năng mở rộng quy mô và quản trị vốn hiệu quả.
Phân tích so sánh hai giai đoạn Trước và Sau Covid cho thấy tổng tài sản trung bình tăng hơn 376.319.045 triệu đồng, chứng minh năng lực phục hồi và chiến lược phát triển bền vững của ngân hàng. Mối tương quan cao giữa tổng tài sản và tài sản cố định (r = 0.9769) khẳng định định hướng đầu tư dài hạn hợp lý. Nghiên cứu không chỉ minh chứng tính ứng dụng của R trong phân tích tài chính mà còn cho thấy Techcombank là một trong những ngân hàng tăng trưởng mạnh và ổn định nhất Việt Nam giai đoạn 2014–2023.
Qua quá trình thực hiện bài báo cáo với sự hỗ trợ của phần mềm RStudio, em đã tiến hành các bước phân tích dữ liệu bao gồm xử lý dữ liệu thô, thống kê mô tả cơ bản và trực quan hóa dữ liệu đối với hai bộ dữ liệu: dữ liệu sức khỏe và báo cáo tài chính của Ngân hàng Techcombank.
Kết quả thu được cho thấy RStudio là một công cụ mạnh mẽ và linh hoạt trong việc xử lý, phân tích và trình bày dữ liệu. Ở giai đoạn xử lý dữ liệu, phần mềm giúp phát hiện và loại bỏ các giá trị thiếu, sai lệch và không đồng nhất, qua đó nâng cao chất lượng dữ liệu đầu vào. Giai đoạn thống kê cơ bản hỗ trợ việc mô tả, tóm tắt và đánh giá tổng quan các đặc điểm của dữ liệu, giúp rút ra những nhận định có cơ sở khoa học. Bên cạnh đó, việc trực quan hóa dữ liệU không chỉ giúp thể hiện kết quả sinh động mà còn hỗ trợ quá trình ra quyết định dựa trên dữ liệu .
Về thực tiễn hiện nay, việc ứng dụng R trong phân tích dữ liệu ngày càng phổ biến, đặc biệt trong các lĩnh vực tài chính, ngân hàng, kinh tế và y tế. RStudio không chỉ giúp người học củng cố kiến thức lý thuyết mà còn tạo điều kiện áp dụng kỹ năng lập trình vào thực tiễn nghiên cứu, xử lý dữ liệu đa ngành.
Trong tương lai, RStudio có thể được mở rộng ứng dụng sang các mô hình phân tích nâng cao hơn giúp dự báo xu hướng và đưa ra khuyến nghị chiến lược có độ chính xác cao hơn. Bản thân người học cũng có thể tiếp tục phát triển năng lực phân tích dữ liệu, kết hợp giữa tư duy định lượng và công cụ công nghệ để phục vụ cho công việc chuyên môn trong lĩnh vực kinh tế và marketing dữ liệu.
Qua bài báo cáo không chỉ giúp em nắm vững quy trình xử lý và phân tích dữ liệu bằng R, mà còn khẳng định tầm quan trọng của kỹ năng dữ liệu trong thời đại số hiện nay, tạo nền tảng vững chắc cho học tập và nghiên cứu trong thời gian tới.