CHƯƠNG 1: TRÌNH BÀY BỘ DỮ LIỆU VỀ HIỆU SUẤT VÀ NĂNG SUẤT CỦA NHÂN VIÊN

Bộ dữ liệu này được chúng em lấy từ Kaggle chứa 100.000 hàng dữ liệu, ghi lại các khía cạnh chính về hiệu suất, năng suất và nhân khẩu học của nhân viên trong môi trường doanh nghiệp. Bộ dữ liệu bao gồm các thông tin chi tiết liên quan đến công việc, thói quen làm việc, trình độ học vấn, hiệu suất và mức độ hài lòng của nhân viên.

I. GIỚI THIỆU VỀ BỘ DỮ LIỆU

1. Đọc dữ liệu

Data <- read_excel("Data.xlsx")

Câu lệnh ở dòng 1 giúp nhập toàn bộ bộ dữ liệu nhân sự (gồm các thông tin như lương, tuổi, giới tính, phòng ban, điểm hài lòng, v.v..) vào R để bắt đầu phân tích.

2. Xem qua dữ liệu

head(Data)
## # A tibble: 6 × 20
##   Employee_ID Department       Gender   Age Job_Title Hire_Date Years_At_Company
##         <dbl> <chr>            <chr>  <dbl> <chr>     <chr>                <dbl>
## 1           1 IT               Male      55 Speciali… 2022-01-…                2
## 2           2 Finance          Male      29 Developer 2024-04-…                0
## 3           3 Finance          Male      55 Speciali… 2015-10-…                8
## 4           4 Customer Support Female    48 Analyst   2016-10-…                7
## 5           5 Engineering      Female    36 Analyst   2021-07-…                3
## 6           6 IT               Male      43 Manager   2016-08-…                8
## # ℹ 13 more variables: Education_Level <chr>, Performance_Score <dbl>,
## #   Monthly_Salary <chr>, Work_Hours_Per_Week <dbl>, Projects_Handled <dbl>,
## #   Overtime_Hours <dbl>, Sick_Days <dbl>, Remote_Work_Frequency <dbl>,
## #   Team_Size <dbl>, Training_Hours <dbl>, Promotions <dbl>,
## #   Employee_Satisfaction_Score <chr>, Resigned <lgl>

Lệnh này giúp nhanh chóng kiểm tra dữ liệu nhập có đúng hay chưa, đồng thời hình dung cấu trúc tổng quan của bộ dữ liệu nhân viên trước khi bắt đầu các bước xử lý tiếp theo.

3. Kiểm tra kích thước dữ liệu

dim(Data)
## [1] 100000     20

Dòng 1 trả về kích thước của đối tượng dữ liệu — cụ thể là số dòng và số cột của Data. Từ kết quả cho thấy, dữ liệu thô có 100000 quan sát và 20 biến (tương đương với số dòng và số cột của bảng dữ liệu).

4. Kiểm tra tên biến

names(Data)
##  [1] "Employee_ID"                 "Department"                 
##  [3] "Gender"                      "Age"                        
##  [5] "Job_Title"                   "Hire_Date"                  
##  [7] "Years_At_Company"            "Education_Level"            
##  [9] "Performance_Score"           "Monthly_Salary"             
## [11] "Work_Hours_Per_Week"         "Projects_Handled"           
## [13] "Overtime_Hours"              "Sick_Days"                  
## [15] "Remote_Work_Frequency"       "Team_Size"                  
## [17] "Training_Hours"              "Promotions"                 
## [19] "Employee_Satisfaction_Score" "Resigned"

Hàm này dùng để lấy ra tên các cột (tên biến) của một data frame, list, hoặc ma trận. Ở đây, lệnh giúp xác định rõ các biến có trong bộ dữ liệu nhân sự, kết quả là danh sách các tên biến trong dữ liệu gốc Data.

5. Giải thích ý nghĩa các biến trong bộ dữ liệu Data

variable_meaning <- tibble(
  Variable = names(Data),
  Meaning = c(
    "Mã định danh duy nhất của mỗi nhân viên",
    "Phòng ban mà nhân viên đang làm việc (như IT, HR, Sales,...)",
    "Giới tính của nhân viên",
    "Tuổi của nhân viên",
    "Chức danh công việc hiện tại của nhân viên",
    "Ngày bắt đầu làm việc tại công ty",
    "Số năm nhân viên đã làm việc tại công ty",
    "Trình độ học vấn cao nhất của nhân viên",
    "Điểm đánh giá hiệu suất làm việc (từ 1 đến 5)",
    "Mức lương hàng tháng của nhân viên",
    "Số giờ làm việc trung bình mỗi tuần của nhân viên",
    "Số dự án mà nhân viên đã hoặc đang phụ trách",
    "Số giờ làm thêm trung bình mỗi tháng",
    "Số ngày nghỉ ốm của nhân viên trong năm",
    "Tần suất làm việc từ xa",
    "Quy mô nhóm hoặc đội mà nhân viên tham gia",
    "Tổng số giờ tham gia các khóa đào tạo",
    "Số lần được thăng chức của nhân viên",
    "Mức độ hài lòng của nhân viên (từ 0 đến 5)",
    "Trạng thái nghỉ việc của nhân viên (TRUE = đã nghỉ, FALSE = còn làm)"
  )
)
kable(variable_meaning, booktabs = TRUE, caption = "Giải thích ý nghĩa các biến trong bộ dữ liệu nhân sự") %>%
  kable_styling(full_width = FALSE)
Giải thích ý nghĩa các biến trong bộ dữ liệu nhân sự
Variable Meaning
Employee_ID Mã định danh duy nhất của mỗi nhân viên
Department Phòng ban mà nhân viên đang làm việc (như IT, HR, Sales,…)
Gender Giới tính của nhân viên
Age Tuổi của nhân viên
Job_Title Chức danh công việc hiện tại của nhân viên
Hire_Date Ngày bắt đầu làm việc tại công ty
Years_At_Company Số năm nhân viên đã làm việc tại công ty
Education_Level Trình độ học vấn cao nhất của nhân viên
Performance_Score Điểm đánh giá hiệu suất làm việc (từ 1 đến 5)
Monthly_Salary Mức lương hàng tháng của nhân viên
Work_Hours_Per_Week Số giờ làm việc trung bình mỗi tuần của nhân viên
Projects_Handled Số dự án mà nhân viên đã hoặc đang phụ trách
Overtime_Hours Số giờ làm thêm trung bình mỗi tháng
Sick_Days Số ngày nghỉ ốm của nhân viên trong năm
Remote_Work_Frequency Tần suất làm việc từ xa
Team_Size Quy mô nhóm hoặc đội mà nhân viên tham gia
Training_Hours Tổng số giờ tham gia các khóa đào tạo
Promotions Số lần được thăng chức của nhân viên
Employee_Satisfaction_Score Mức độ hài lòng của nhân viên (từ 0 đến 5)
Resigned Trạng thái nghỉ việc của nhân viên (TRUE = đã nghỉ, FALSE = còn làm)

Dòng 1: tạo một bảng dữ liệu (data frame) gồm 2 cột: + Variable: Tên biến trong bộ dữ liệu + Meaning: Ý nghĩa tương ứng của từng biến

Dòng 26 giúp tạo bảng định dạng đẹp trong file báo cáo, thêm viền bảng và thêm tiêu đề (chú thích) cho bảng.

Kết quả trả về bảng mô tả chi tiết ý nghĩa tất cả các biến có trong dữ liệu.

6. Xem kiểu dữ liệu của từng cột

str(Data)
## tibble [100,000 × 20] (S3: tbl_df/tbl/data.frame)
##  $ Employee_ID                : num [1:100000] 1 2 3 4 5 6 7 8 9 10 ...
##  $ Department                 : chr [1:100000] "IT" "Finance" "Finance" "Customer Support" ...
##  $ Gender                     : chr [1:100000] "Male" "Male" "Male" "Female" ...
##  $ Age                        : num [1:100000] 55 29 55 48 36 43 37 55 55 45 ...
##  $ Job_Title                  : chr [1:100000] "Specialist" "Developer" "Specialist" "Analyst" ...
##  $ Hire_Date                  : chr [1:100000] "2022-01-19 08:03:05.556036" "2024-04-18 08:03:05.556036" "2015-10-26 08:03:05.556036" "2016-10-22 08:03:05.556036" ...
##  $ Years_At_Company           : num [1:100000] 2 0 8 7 3 8 1 9 1 7 ...
##  $ Education_Level            : chr [1:100000] "High School" "High School" "High School" "Bachelor" ...
##  $ Performance_Score          : num [1:100000] 5 5 3 2 2 3 5 2 2 1 ...
##  $ Monthly_Salary             : chr [1:100000] "6750.0" "7500.0" "5850.0" "4800.0" ...
##  $ Work_Hours_Per_Week        : num [1:100000] 33 34 37 52 38 46 55 42 51 41 ...
##  $ Projects_Handled           : num [1:100000] 32 34 27 10 11 31 20 46 23 33 ...
##  $ Overtime_Hours             : num [1:100000] 22 13 6 28 29 8 29 7 21 2 ...
##  $ Sick_Days                  : num [1:100000] 2 14 3 12 13 0 2 8 14 6 ...
##  $ Remote_Work_Frequency      : num [1:100000] 0 100 50 100 100 100 0 100 0 75 ...
##  $ Team_Size                  : num [1:100000] 14 12 10 10 15 15 16 7 1 4 ...
##  $ Training_Hours             : num [1:100000] 66 61 1 0 9 95 27 64 0 53 ...
##  $ Promotions                 : num [1:100000] 0 2 0 1 1 0 0 0 1 2 ...
##  $ Employee_Satisfaction_Score: chr [1:100000] "2.63" "1.72" "3.17" "1.86" ...
##  $ Resigned                   : logi [1:100000] FALSE FALSE FALSE FALSE FALSE FALSE ...

Dòng 1 cho ta cái nhìn tổng quan về cấu trúc và kiểu dữ liệu của bộ nhân sự. Các kiểu dữ liệu có trong Data gồm: dữ liệu dạng số num (numeric),dữ liệu dạng văn bản chr (character) và dữ liệu dạng logic như True hoặc False logi (logical). Tuy nhiên có thể thấy một vài biến trong bộ dữ liệu là dạng chr nhưng thực chất là dạng số num và biến Hire_Date chưa được chuyển về dạng data, chúng ta sẽ xử lý những vấn đề này ở phần xử lý dữ liệu thô và mã hóa dữ liệu.

7. Kiểm tra dữ liệu bị thiếu

colSums(is.na(Data))
##                 Employee_ID                  Department 
##                           0                           0 
##                      Gender                         Age 
##                           0                           0 
##                   Job_Title                   Hire_Date 
##                           0                           0 
##            Years_At_Company             Education_Level 
##                           0                           0 
##           Performance_Score              Monthly_Salary 
##                           0                           0 
##         Work_Hours_Per_Week            Projects_Handled 
##                           0                           0 
##              Overtime_Hours                   Sick_Days 
##                           0                           0 
##       Remote_Work_Frequency                   Team_Size 
##                           0                           0 
##              Training_Hours                  Promotions 
##                           0                           0 
## Employee_Satisfaction_Score                    Resigned 
##                           0                           0

Dòng 1 kiểm tra trong toàn bộ bảng Data xem có giá trị nào bị thiếu (NA) hay không. Kết quả trả về tất cả giá trị đều bằng 0, tức là: Không có giá trị nào bị thiếu trong toàn bộ 20 biến và 100.000 dòng.

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

sum(duplicated(Data))
## [1] 0

Lệnh này cho biết có bao nhiêu quan sát bị trùng lặp trong dữ liệu. Kết quả = 0 có nghĩa là bộ dữ liệu nhân sự sạch, không trùng lặp.

9.Thống kê tổng quan nhanh

summary(Data)
##   Employee_ID      Department           Gender               Age       
##  Min.   :     1   Length:100000      Length:100000      Min.   :22.00  
##  1st Qu.: 25001   Class :character   Class :character   1st Qu.:31.00  
##  Median : 50001   Mode  :character   Mode  :character   Median :41.00  
##  Mean   : 50001                                         Mean   :41.03  
##  3rd Qu.: 75000                                         3rd Qu.:51.00  
##  Max.   :100000                                         Max.   :60.00  
##   Job_Title          Hire_Date         Years_At_Company Education_Level   
##  Length:100000      Length:100000      Min.   : 0.000   Length:100000     
##  Class :character   Class :character   1st Qu.: 2.000   Class :character  
##  Mode  :character   Mode  :character   Median : 4.000   Mode  :character  
##                                        Mean   : 4.476                     
##                                        3rd Qu.: 7.000                     
##                                        Max.   :10.000                     
##  Performance_Score Monthly_Salary     Work_Hours_Per_Week Projects_Handled
##  Min.   :1.000     Length:100000      Min.   :30.00       Min.   : 0.00   
##  1st Qu.:2.000     Class :character   1st Qu.:37.00       1st Qu.:12.00   
##  Median :3.000     Mode  :character   Median :45.00       Median :24.00   
##  Mean   :2.995                        Mean   :44.96       Mean   :24.43   
##  3rd Qu.:4.000                        3rd Qu.:53.00       3rd Qu.:37.00   
##  Max.   :5.000                        Max.   :60.00       Max.   :49.00   
##  Overtime_Hours    Sick_Days      Remote_Work_Frequency   Team_Size    
##  Min.   : 0.00   Min.   : 0.000   Min.   :  0.00        Min.   : 1.00  
##  1st Qu.: 7.00   1st Qu.: 3.000   1st Qu.: 25.00        1st Qu.: 5.00  
##  Median :15.00   Median : 7.000   Median : 50.00        Median :10.00  
##  Mean   :14.51   Mean   : 7.009   Mean   : 50.09        Mean   :10.01  
##  3rd Qu.:22.00   3rd Qu.:11.000   3rd Qu.: 75.00        3rd Qu.:15.00  
##  Max.   :29.00   Max.   :14.000   Max.   :100.00        Max.   :19.00  
##  Training_Hours    Promotions     Employee_Satisfaction_Score  Resigned      
##  Min.   : 0.00   Min.   :0.0000   Length:100000               Mode :logical  
##  1st Qu.:25.00   1st Qu.:0.0000   Class :character            FALSE:89990    
##  Median :49.00   Median :1.0000   Mode  :character            TRUE :10010    
##  Mean   :49.51   Mean   :0.9997                                              
##  3rd Qu.:75.00   3rd Qu.:2.0000                                              
##  Max.   :99.00   Max.   :2.0000

Lệnh này giúp hiểu rõ cấu trúc và đặc điểm chung của toàn bộ bộ dữ liệu nhân sự. Với biến numeric: trả về Min, 1st Qu., Median, Mean, 3rd Qu., Max. Với biến character hoặc factor: trả về Length, Class, Mode. Ý nghĩa từ biến Sick_Days: Min = 0 → nhân viên không nghỉ ốm ngày nào Median = 7 → mức nghỉ ốm phổ biến nhất Mean = 7.009 → trung bình mỗi nhân viên nghỉ khoảng 7 ngày/năm. Max = 14 → người nghỉ nhiều nhất là 14 ngày

10. Phân loại biến theo kiểu dữ liệu

num_vars <- sapply(Data, is.numeric)
sum(num_vars)
## [1] 12

Dòng 1 này kiểm tra tất cả các cột trong Data để xác định số biến định lượng (kiểu số numeric).

cat_vars <- sapply(Data, function(x) is.character(x) | is.factor(x))
sum(cat_vars)
## [1] 7

Dòng 1 kiểm tra tất cả các cột trong Data để xác định số biến định tính (là kiểu ký tự (character) hoặc hạng mục (factor)).

date_vars <- sapply(Data, function(x) inherits(x, "Date") | inherits(x, "POSIXct"))
sum(date_vars)
## [1] 0

Dòng 1 kiểm tra tất cả các cột trong Data để xác định số biến thời gian (là kiểu ngày (Date) hoặc ngày-giờ (POSIXct)).

names(Data)[num_vars]    # Định lượng
##  [1] "Employee_ID"           "Age"                   "Years_At_Company"     
##  [4] "Performance_Score"     "Work_Hours_Per_Week"   "Projects_Handled"     
##  [7] "Overtime_Hours"        "Sick_Days"             "Remote_Work_Frequency"
## [10] "Team_Size"             "Training_Hours"        "Promotions"
names(Data)[cat_vars]    # Định tính
## [1] "Department"                  "Gender"                     
## [3] "Job_Title"                   "Hire_Date"                  
## [5] "Education_Level"             "Monthly_Salary"             
## [7] "Employee_Satisfaction_Score"
names(Data)[date_vars]   # Kiểu thời gian
## character(0)

Dòng 1 sẽ trả về tên các cột trong Data từng loại: định lượng, định tính và kiểu thời gian. Biến định lượng (12 biến): Là các biến đo lường bằng con số, có thể dùng cho phân tích thống kê, tính trung bình, phương sai,…Ví dụ: Tuổi, Số năm làm việc, Số giờ làm thêm, Lương,… Biến định tính (7 biến): Biểu diễn đặc điểm, phân loại, hoặc danh mục của nhân viên. Ví dụ: Phòng ban, Giới tính, Trình độ học vấn,… Biến thời gian (0 biến): Hiện tại chưa có biến nào là kiểu ngày — nhưng biến “Hire_Date” nên được chuyển về dạng thời gian để thuận tiện cho phân tích.

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

1. Chuyển kiểu dữ liệu từ character sang factor

Data$Department <- as.factor(Data$Department)
Data$Gender <- as.factor(Data$Gender)

Dòng lệnh 1 và 2 này chuyển các cột Department và Gender trong bảng Data từ kiểu ký tự (character) sang kiểu nhân tố (factor), giúp R hiểu đây là biến phân loại thay vì chuỗi văn bản thông thường. Trong quá trình xử lý dữ liệu, hai biến Department (phòng ban) và Gender (giới tính) ban đầu có kiểu dữ liệu character. Để đảm bảo việc phân tích nhóm và trực quan hóa dữ liệu được chính xác, hai biến này được chuyển đổi sang kiểu factor.

2. Chuyển đổi biến character sang muberic

Data$Monthly_Salary <- as.numeric(Data$Monthly_Salary)
str(Data$Monthly_Salary)
##  num [1:100000] 6750 7500 5850 4800 4800 7800 5250 7200 4200 6050 ...

Dòng lệnh 1 chuyển các cột Monthly_Salary trong bảng Data sang kiểu số (numeric). Dòng lệnh 2 hiển thị cấu trúc và kiểu dữ liệu của cột Monthly_Salary, giúp kiểm tra xem cột này đã được chuyển sang kiểu numeric thành công hay chưa.

Data$Employee_Satisfaction_Score <- as.numeric(Data$Employee_Satisfaction_Score)
str(Data$Employee_Satisfaction_Score)
##  num [1:100000] 2.63 1.72 3.17 1.86 1.25 2.77 4.46 2.09 1.44 2.93 ...

Dòng lệnh 1 chuyển các cột Employee_Satisfaction_Score trong bảng Data sang kiểu số (numeric). Dòng lệnh 2 hiển thị cấu trúc và kiểu dữ liệu của cột Employee_Satisfaction_Score, giúp kiểm tra xem cột này đã được chuyển sang kiểu numeric thành công hay chưa.

Trong dữ liệu ban đầu, Hai biến “Mức lương hàng tháng” (Monthly_Salary) và “Mức độ hài lòng của nhân viên” (Employee_Satisfaction_Score) ban đầu được lưu ở dạng ký tự (character), khiến việc tính toán thống kê bị hạn chế. Sau khi chuyển đổi sang dạng số (numeric), các biến này có thể được sử dụng trong các phép phân tích thống kê mô tả, kiểm định, hồi quy và trực quan hóa dữ liệu một cách chính xác hơn.

3. Chuyển đổi biến character sang dạng date

Data$Hire_Date <- (Data$Hire_Date)
Data$Hire_Date <- as.Date(Data$Hire_Date)
class(Data$Hire_Date)
## [1] "Date"
head(Data$Hire_Date)
## [1] "2022-01-19" "2024-04-18" "2015-10-26" "2016-10-22" "2021-07-23"
## [6] "2016-08-14"

Dòng 1: giữ nguyên giá trị cột Hire_Date. Dòng 2: chuyển cột Hire_Date sang kiểu ngày (Date). Dòng 3: kiểm tra xem cột này hiện có kiểu dữ liệu là Date hay không. Dòng 4: kiểm tra lại kết quả sau khi chuẩn hóa.

Biến Hire_Date chứa thông tin về ngày nhân viên bắt đầu làm việc tại công ty. Ban đầu, dữ liệu lưu dưới dạng ký tự có chứa cả thông tin giờ phút, gây khó khăn trong việc phân tích thời gian. Biến Hire_Date ban đầu trong dữ liệu có kiểu chuỗi ký tự (character) như: “2022-01-19 08:03:05.556036” “2016-10-22 08:03:05.556036” Sau khi chuyển chuỗi ký tự này sang kiểu dữ liệu ngày tháng (Date), có một điểm kỹ thuật quan trọng: as.Date() chỉ đọc được ngày theo định dạng “YYYY-MM-DD”. Trong dữ liệu, phần 08:03:05.556036 là giờ/phút/giây, nên tự động bỏ qua phần thời gian và chỉ giữ lại ngày.

4. Loại bỏ biến không cần thiết

Data <- Data %>% select(-Employee_ID)
names(Data)
##  [1] "Department"                  "Gender"                     
##  [3] "Age"                         "Job_Title"                  
##  [5] "Hire_Date"                   "Years_At_Company"           
##  [7] "Education_Level"             "Performance_Score"          
##  [9] "Monthly_Salary"              "Work_Hours_Per_Week"        
## [11] "Projects_Handled"            "Overtime_Hours"             
## [13] "Sick_Days"                   "Remote_Work_Frequency"      
## [15] "Team_Size"                   "Training_Hours"             
## [17] "Promotions"                  "Employee_Satisfaction_Score"
## [19] "Resigned"

Dòng 1 dùng để bỏ cột trong một bảng dữ liệu. Dấu trừ (-) trước tên biến có nghĩa là loại bỏ cột đó. Vậy R sẽ giữ lại toàn bộ các cột khác ngoài Employee_ID. Dòng 2 xác nhận việc loại bỏ đã thành công bằng cách liệt kê lại các biến. Biến Employee_ID là mã định danh duy nhất cho từng nhân viên, không mang giá trị phân tích. Do đó, biến này được loại bỏ khỏi bộ dữ liệu để đảm bảo chỉ giữ lại các biến có ý nghĩa thống kê.

5. Phát hiện giá trị ngoại lai

num_vars <- sapply(Data, is.numeric)
for (var in names(Data)[num_vars]) {
  Q1 <- quantile(Data[[var]], 0.25, na.rm = TRUE)
  Q3 <- quantile(Data[[var]], 0.75, na.rm = TRUE)
  IQR_val <- Q3 - Q1
  
  lower_bound <- Q1 - 1.5 * IQR_val
  upper_bound <- Q3 + 1.5 * IQR_val
  outliers <- sum(Data[[var]] < lower_bound | Data[[var]] > upper_bound, na.rm = TRUE)
  cat("Biến:", var, "- Số lượng ngoại lai:", outliers, "\n")
}
## Biến: Age - Số lượng ngoại lai: 0 
## Biến: Years_At_Company - Số lượng ngoại lai: 0 
## Biến: Performance_Score - Số lượng ngoại lai: 0 
## Biến: Monthly_Salary - Số lượng ngoại lai: 0 
## Biến: Work_Hours_Per_Week - Số lượng ngoại lai: 0 
## Biến: Projects_Handled - Số lượng ngoại lai: 0 
## Biến: Overtime_Hours - Số lượng ngoại lai: 0 
## Biến: Sick_Days - Số lượng ngoại lai: 0 
## Biến: Remote_Work_Frequency - Số lượng ngoại lai: 0 
## Biến: Team_Size - Số lượng ngoại lai: 0 
## Biến: Training_Hours - Số lượng ngoại lai: 0 
## Biến: Promotions - Số lượng ngoại lai: 0 
## Biến: Employee_Satisfaction_Score - Số lượng ngoại lai: 0

Dòng 1 xác định các cột có kiểu số trong Data. Dòng 2 là lệnh lặp qua từng biến số. Dòng 3 tính tứ phân vị thứ nhất (Q1). Dòng 4 tính tứ phân vị thứ ba (Q3). Dòng 5 tính khoảng tứ phân vị (IQR). Dòng 7 và dòng 8 là giới hạn dưới/trên để phát hiện ngoại lai. Dòng 9 đếm số giá trị ngoại lai trong biến. Dòng 10 in ra từng tên biến và số ngoại lai.

Ta có giới hạn phát hiện ngoại lai: \[ \text{Lower bound} = Q_1 - 1.5 \times IQR \]

\[ \text{Upper bound} = Q_3 + 1.5 \times IQR \]

Bất kỳ giá trị nào nhỏ hơn Lower bound hoặc lớn hơn Upper bound đều được xem là ngoại lai.

Việc phát hiện giá trị ngoại lai giúp nhận diện các quan sát không bình thường — ví dụ: Nhân viên có mức lương quá cao hoặc quá thấp so với mặt bằng chung, nhân viên có số giờ làm việc cực lớn hoặc cực nhỏ, các điểm số hiệu suất vượt xa trung bình chung,… Các giá trị này có thể là dữ liệu sai lệch hoặc nhập nhầm, cần phải được loại bỏ.

Kết quả kiểm tra ngoại lai cho thấy không có giá trị nào vượt quá ngưỡng 1.5×IQR ở tất cả các biến định lượng. Điều này chứng tỏ bộ dữ liệu được chuẩn hóa tốt, không xuất hiện các giá trị bất thường cực đoan ảnh hưởng đến phân tích thống kê. Do đó, không cần thực hiện bước loại bỏ hoặc xử lý ngoại lai.

6. Chuẩn hóa dữ liệu về cùng thang đo

Phương pháp Z-Score giúp đưa dữ liệu về cùng thang đo có trung bình bằng 0độ lệch chuẩn bằng 1, được tính theo công thức: \[ Z = \frac{X - \mu}{\sigma} \]

num_vars <- names(Data)[sapply(Data, is.numeric)]
Data_scaled <- Data %>%
  select(all_of(num_vars)) %>%
  mutate(across(everything(), scale)) %>%
  pivot_longer(cols = everything(), names_to = "Variable", values_to = "Value")

Dòng 1 lấy tên các cột trong Data có kiểu số và lưu vào num_vars. Dòng 2 bắt đầu tạo bảng mới Data_scaled. Dòng 3 chọn các cột số (num_vars) từ Data. Dòng 4 chuẩn hóa mọi biến số (đưa về dạng z-score). Dòng 5 chuyển dữ liệu từ dạng rộng sang dạng dài, gom hai cột: Variable: tên biến Value: giá trị chuẩn hóa

Sau bước này, toàn bộ các biến số được chuẩn hóa về cùng thang đo.

7. Trực quan hóa ngoại lai bằng Boxlot

num_vars <- names(Data)[sapply(Data, is.numeric)]
ggplot(Data_scaled, aes(x = Variable, y = Value)) +
  geom_boxplot(fill = "skyblue", color = "darkblue", outlier.colour = "red") +
  labs(title = "Biểu đồ Boxplot sau khi chuẩn hóa (Z-score)",
       x = "Tên biến", y = "Giá trị chuẩn hóa (Z-score)") +
  theme_minimal(base_size = 13) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(hjust = 0.5, face = "bold"))

Dòng 1 lấy tên các cột trong Data mà kiểu dữ liệu là số (numeric). Dòng 2 khởi tạo biểu đồ với dữ liệu Data_scaled; trục X là biến, trục Y là giá trị chuẩn hóa.

Dòng 3 vẽ biểu đồ hộp (boxplot) với: Màu nền hộp: xanh nhạt Viền: xanh đậm Điểm ngoại lai: màu đỏ

Dòng 4 và 5 thêm tiêu đề và nhãn cho các trục. Dòng 6 dùng giao diện tối giản (minimal) và cỡ chữ 13. Dòng 7 và 8 xoay nhãn trục X 45°, căn chỉnh cho dễ đọc; căn giữa và in đậm tiêu đề biểu đồ.

Biểu đồ Boxplot sau khi chuẩn hóa Z-score cho thấy phần lớn các biến có trung vị xấp xỉ 0 và độ phân tán tương đối đồng đều. Điều này chứng tỏ việc chuẩn hóa dữ liệu đã được thực hiện đúng. Một số biến như PromotionsRemote_Work_Frequency có độ biến động lớn hơn, cho thấy phạm vi giá trị rộng. Nhìn chung, dữ liệu đạt trạng thái cân bằng và sẵn sàng cho các bước phân tích tiếp theo.

8. Định dạng số thập phân cho dữ liệu

Data$Monthly_Salary        <- round(Data$Monthly_Salary, 0)
Data$Work_Hours_Per_Week   <- round(Data$Work_Hours_Per_Week, 0)
Data$Overtime_Hours        <- round(Data$Overtime_Hours, 0)
Data$Training_Hours        <- round(Data$Training_Hours, 0)
Data$Employee_Satisfaction_Score <- round(Data$Employee_Satisfaction_Score, 2)

Dòng 1, 2, 3, 4 lần lượt làm tròn các biến lương tháng, số giờ làm việc, số giờ làm thêm và số giờ đào tạo thành số nguyên. Dòng 5 làm tròn biến điểm hài lòng của nhân viên đến 2 chữ số thập phân.

9. Tạo biến phân loại nhân viên theo kinh nghiệm

Data$Experience_Level <- cut(
  Data$Years_At_Company,
  breaks = c(0, 2, 5, 10, Inf),
  labels = c("Fresher", "Junior", "Senior", "Expert"),
  right = FALSE
)
table(Data$Experience_Level)
## 
## Fresher  Junior  Senior  Expert 
##   20101   30310   49545      44

Dòng 1 tạo biến mới Experience_Level. Dòng 2, 3 và 4 dựa trên số năm làm việc Years_At_Company, chia khoảng: 0–2, 2–5, 5–10, và từ 10 trở lên. Sau đó gán nhãn tương ứng với các khoảng: Fresher, Junior, Senior, Expert.

Dòng 7 kiểm tra kết quả ta được bảng số lượng nhân viên theo kinh nghiệm.

Đa số nhân viên thuộc nhóm Senior (49.545 người), cho thấy lực lượng có kinh nghiệm chiếm tỷ trọng lớn. Nhóm Fresher và Junior cũng khá đông (tổng hơn 50.000 người), thể hiện công ty vẫn tuyển nhiều nhân viên mới. Nhóm Expert rất ít (44 người), chứng tỏ số nhân sự có thâm niên cao còn hạn chế.

10. Tạo biến nhân viên theo nhóm tuổi

Data$Age_Group <- cut(Data$Age,
                      breaks = c(22, 30, 40, 50, 60),  
                      labels = c("22–30", "31–40", "41–50", "51–60"),
                      include.lowest = TRUE)
table(Data$Age_Group)
## 
## 22–30 31–40 41–50 51–60 
## 23031 25535 25721 25713

Dòng 1 tạo biến mới Age_Group. Dòng 2, 3, 4 chia độ tuổi thành các khoảng: 22–30, 31–40, 41–50, 51–60. Gán nhãn tương ứng cho từng nhóm tuổi và đảm bảo giá trị nhỏ nhất (22 tuổi) được tính vào nhóm đầu tiên. Dòng 5 kiểm tra bảng số lượng nhân viên theo nhóm tuổi.

Kết quả cho thấy, phân bố tuổi khá đồng đều giữa các nhóm.

11. Tạo biến nhân viên theo mức lương hàng tháng

Data$Salary_Level <- cut(Data$Monthly_Salary,
                         breaks = c(3850, 5500, 7000, 9000),
                         labels = c("Thấp", "Trung bình", "Cao"),
                         include.lowest = TRUE)
table(Data$Salary_Level)
## 
##       Thấp Trung bình        Cao 
##      31604      34264      34132

Dòng 1 tạo biến mới Salary_Level để phân loại mức lương. Dòng 2, 3, 4 chia khoảng lương: 3.850–5.500, 5.500–7.000, và 7.000–9.000. Gán nhãn tương ứng: Thấp, Trung bình, Cao và đảm bảo mức lương thấp nhất được tính vào nhóm đầu tiên. Dòng 5 kiểm tra bảng số lượng nhân viên theo mức lương hàng tháng.

Từ bảng kết quả cho thấy 3 nhóm lương có số lượng khá cân bằng, chênh lệch không lớn. Nhóm Trung bình và Cao chiếm tỷ lệ tương đương, cho thấy thu nhập của nhân viên được phân bổ tương đối đồng đều.

12. Tạo biến năm

Data$Hire_Year <- year(Data$Hire_Date)
head(Data[, c("Hire_Date", "Hire_Year")])
## # A tibble: 6 × 2
##   Hire_Date  Hire_Year
##   <date>         <dbl>
## 1 2022-01-19      2022
## 2 2024-04-18      2024
## 3 2015-10-26      2015
## 4 2016-10-22      2016
## 5 2021-07-23      2021
## 6 2016-08-14      2016

Dòng 1 trích năm tuyển dụng từ biến Hire_Date và lưu vào cột mới Hire_Year. Dòng 2 hiển thị 6 dòng đầu gồm hai cột Hire_Date và Hire_Year để kiểm tra kết quả.

III. THỐNG KÊ CƠ BẢN

1. Thống kê mô tả chi tiết các biến định lượng

describe(Data[num_vars])
## Data[num_vars] 
## 
##  13  Variables      100000  Observations
## --------------------------------------------------------------------------------
## Age 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##    1e+05        0       39    0.999    41.03       41    12.98       23 
##      .10      .25      .50      .75      .90      .95 
##       25       31       41       51       57       59 
## 
## lowest : 22 23 24 25 26, highest: 56 57 58 59 60
## --------------------------------------------------------------------------------
## Years_At_Company 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##    1e+05        0       11     0.99    4.476      4.5    3.297        0 
##      .10      .25      .50      .75      .90      .95 
##        0        2        4        7        8        9 
##                                                                             
## Value          0     1     2     3     4     5     6     7     8     9    10
## Frequency  10083 10018 10272  9935 10103  9892 10068  9892  9961  9732    44
## Proportion 0.101 0.100 0.103 0.099 0.101 0.099 0.101 0.099 0.100 0.097 0.000
## --------------------------------------------------------------------------------
## Performance_Score 
##        n  missing distinct     Info     Mean  pMedian      Gmd 
##    1e+05        0        5     0.96    2.995        3    1.601 
##                                         
## Value          1     2     3     4     5
## Frequency  20120 20013 19999 19940 19928
## Proportion 0.201 0.200 0.200 0.199 0.199
## --------------------------------------------------------------------------------
## Monthly_Salary 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##    1e+05        0       28    0.998     6403     6375     1575     4200 
##      .10      .25      .50      .75      .90      .95 
##     4550     5250     6500     7500     8400     9000 
## 
## lowest : 3850 4200 4400 4550 4800, highest: 7700 7800 8250 8400 9000
## --------------------------------------------------------------------------------
## Work_Hours_Per_Week 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##    1e+05        0       31    0.999    44.96       45    10.32       31 
##      .10      .25      .50      .75      .90      .95 
##       33       37       45       53       57       59 
## 
## lowest : 30 31 32 33 34, highest: 56 57 58 59 60
## --------------------------------------------------------------------------------
## Projects_Handled 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##    1e+05        0       50        1    24.43     24.5     16.7        2 
##      .10      .25      .50      .75      .90      .95 
##        4       12       24       37       45       47 
## 
## lowest :  0  1  2  3  4, highest: 45 46 47 48 49
## --------------------------------------------------------------------------------
## Overtime_Hours 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##    1e+05        0       30    0.999    14.51     14.5    9.999        1 
##      .10      .25      .50      .75      .90      .95 
##        2        7       15       22       27       28 
## 
## lowest :  0  1  2  3  4, highest: 25 26 27 28 29
## --------------------------------------------------------------------------------
## Sick_Days 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##    1e+05        0       15    0.996    7.009        7    4.991        0 
##      .10      .25      .50      .75      .90      .95 
##        1        3        7       11       13       14 
##                                                                             
## Value          0     1     2     3     4     5     6     7     8     9    10
## Frequency   6715  6669  6763  6617  6587  6585  6563  6712  6633  6671  6671
## Proportion 0.067 0.067 0.068 0.066 0.066 0.066 0.066 0.067 0.066 0.067 0.067
##                                   
## Value         11    12    13    14
## Frequency   6659  6632  6794  6729
## Proportion 0.067 0.066 0.068 0.067
## --------------------------------------------------------------------------------
## Remote_Work_Frequency 
##        n  missing distinct     Info     Mean  pMedian      Gmd 
##    1e+05        0        5     0.96    50.09       50       40 
##                                         
## Value          0    25    50    75   100
## Frequency  19837 20235 19706 20173 20049
## Proportion 0.198 0.202 0.197 0.202 0.200
## --------------------------------------------------------------------------------
## Team_Size 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##    1e+05        0       19    0.997    10.01       10    6.337        1 
##      .10      .25      .50      .75      .90      .95 
##        2        5       10       15       18       19 
##                                                                             
## Value          1     2     3     4     5     6     7     8     9    10    11
## Frequency   5287  5272  5298  5309  5279  5164  5218  5242  5159  5251  5323
## Proportion 0.053 0.053 0.053 0.053 0.053 0.052 0.052 0.052 0.052 0.053 0.053
##                                                           
## Value         12    13    14    15    16    17    18    19
## Frequency   5244  5233  5210  5214  5356  5149  5324  5468
## Proportion 0.052 0.052 0.052 0.052 0.054 0.051 0.053 0.055
## --------------------------------------------------------------------------------
## Training_Hours 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##    1e+05        0      100        1    49.51     49.5    33.36        4 
##      .10      .25      .50      .75      .90      .95 
##        9       25       49       75       90       94 
## 
## lowest :  0  1  2  3  4, highest: 95 96 97 98 99
## --------------------------------------------------------------------------------
## Promotions 
##        n  missing distinct     Info     Mean  pMedian      Gmd 
##    1e+05        0        3    0.889   0.9997        1   0.8882 
##                             
## Value          0     1     2
## Frequency  33296 33436 33268
## Proportion 0.333 0.334 0.333
## --------------------------------------------------------------------------------
## Employee_Satisfaction_Score 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##    1e+05        0      401        1    2.999        3    1.329     1.20 
##      .10      .25      .50      .75      .90      .95 
##     1.40     2.01     3.00     3.99     4.60     4.80 
## 
## lowest : 1    1.01 1.02 1.03 1.04, highest: 4.96 4.97 4.98 4.99 5   
## --------------------------------------------------------------------------------

Dùng hàm ở dòng 1 để thống kê mô tả các biến định lượng trong Data

Kết quả từng biến cho thấy: Age: Trung vị 41 tuổi, đa số nhân viên ở độ tuổi trung niên (31–51): lực lượng lao động có kinh nghiệm, độ tuổi ổn định.

Years_At_Company: Trung vị 4,5 năm, tập trung mạnh ở nhóm dưới 5 năm, cho thấy nhiều người mới vào hoặc đang trong giai đoạn đầu sự nghiệp.

Performance_Score: Tập trung đều quanh mức 3, thể hiện phần lớn nhân viên hoàn thành tốt nhiệm vụ ở mức trung bình khá.

Monthly_Salary: Trung vị 6.375, phần lớn nhân viên nhận lương 6.000–7.000, cho thấy mức thu nhập ổn định, chênh lệch không lớn.

Work_Hours_Per_Week: Trung vị 45 giờ, phổ biến nhất là 40–50 giờ/tuần, phản ánh cường độ làm việc chuẩn và hợp lý.

Projects_Handled: Trung vị 24–25 dự án, đa số nhân viên thực hiện 20–40 dự án, cho thấy mức độ tham gia công việc tương đối cao.

Overtime_Hours: Trung vị 14–15 giờ/tháng, phần lớn tập trung ở 10–20 giờ, chứng tỏ làm thêm có nhưng không quá tải.

Sick_Days: Trung vị 7 ngày, phân bố khá đều, thể hiện tình trạng sức khỏe và nghỉ phép ổn định giữa các nhân viên.

Remote_Work_Frequency: Phổ biến nhất là 50% thời gian làm việc từ xa, cho thấy mô hình làm việc hybrid (kết hợp tại nhà và tại công ty) rất phổ biến.

Team_Size: Trung vị 10 người, đa số nhóm có 5–15 thành viên, phản ánh quy mô nhóm vừa phải, dễ quản lý.

Training_Hours: Trung vị 49–50 giờ/năm, phần lớn tập trung quanh mức này: cho thấy chính sách đào tạo được chuẩn hóa và đồng đều giữa nhân viên.

Promotions: Giá trị phổ biến nhất là 1 lần thăng chức

Employee_Satisfaction_Score: Trung vị 3 điểm, đa số nhân viên hài lòng ở mức trung bình.

2. Kiểm định sự khác biệt về lương theo giới tính

Data_gender2 <- Data %>% filter(Gender %in% c("Male", "Female"))
t_test_result <- t.test(Monthly_Salary ~ Gender, data = Data_gender2)
print(t_test_result)
## 
##  Welch Two Sample t-test
## 
## data:  Monthly_Salary by Gender
## t = 0.50877, df = 96030, p-value = 0.6109
## alternative hypothesis: true difference in means between group Female and group Male is not equal to 0
## 95 percent confidence interval:
##  -12.84842  21.85717
## sample estimates:
## mean in group Female   mean in group Male 
##             6404.986             6400.482

Dòng 1 tạo tập dữ liệu Data_gender2 chứa các dòng có giới tính thuộc hai nhóm Male và Female. Dòng 2 thực hiện kiểm định t-test độc lập, so sánh Monthly_Salary giữa Male và Female. Dòng 3 hiển thị kết quả kiểm định (trung bình, p-value, và kết luận về sự khác biệt lương theo giới).

Ta có: t = 0.50877: Giá trị thống kê t. Càng xa 0 thì khác biệt càng lớn. Ở đây rất nhỏ nên khác biệt không đáng kể. df = 96030: Bậc tự do. Số liệu càng lớn, ước lượng càng chính xác. p-value = 0.6109: Xác suất để có được kết quả như quan sát nếu không có khác biệt thực sự (theo H₀).

Kết quả kiểm định Welch’s t-test cho thấy không có sự khác biệt có ý nghĩa thống kê về mức lương trung bình giữa nam và nữ (t = 0.509, df = 96030, ta có: p = 0.6109 > 0.05 (Bác bỏ H1)) Mức lương trung bình của nhân viên nam (6,400) và nữ (6,405) gần như tương đương.

# --- 4. Tính hiệu ứng (Effect size) ---
gender_salary_effect <- cohens_d(Monthly_Salary ~ Gender, data = Data_gender2)
print(gender_salary_effect)
## Cohen's d |        95% CI
## -------------------------
## 3.28e-03  | [-0.01, 0.02]
## 
## - Estimated using pooled SD.

Dòng 1 tính hiệu ứng Cohen’s d để đo mức độ khác biệt lương giữa hai giới tính trong Data_gender2. Dòng 2 in kết quả ra màn hình — giá trị d cho biết mức độ chênh lệch thực tế: khoảng 0.2 = nhỏ 0.5 = trung bình 0.8 trở lên = lớn

Hiệu ứng thực tế theo Cohen’s d = 0.003, cho thấy mức chênh lệch không đáng kể về mặt thống kê và thực tế.

3. Kiểm định ANOVA cho lương theo phòng ban

anova_salary_dept <- aov(Monthly_Salary ~ Department, data = Data)
summary(anova_salary_dept)
##                Df    Sum Sq Mean Sq F value Pr(>F)
## Department      8 1.475e+07 1844344   0.979   0.45
## Residuals   99991 1.884e+11 1883783

Dòng 1 thực hiện phân tích phương sai (ANOVA) để xem lương khác nhau thế nào giữa các phòng ban. Dùng hàm aov() để mô hình hóa Monthly_Salary theo Department. Dòng 2 hiển thị giá trị F và p-value, giúp xác định có sự khác biệt ý nghĩa về lương giữa các phòng ban hay không.

Kết quả phân tích phương sai một yếu tố (ANOVA) cho thấy sự khác biệt về lương trung bình giữa các phòng ban không có ý nghĩa thống kê (F(8, 99991) = 0.979, p = 0.45) cho thấy lương trung bình giữa các phòng ban không khác biệt đáng kể trong dữ liệu này.

Ta xem chi tiết hơn (so sáng từng cặp) như sau:

TukeyHSD(anova_salary_dept)
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = Monthly_Salary ~ Department, data = Data)
## 
## $Department
##                                     diff       lwr      upr     p adj
## Engineering-Customer Support  13.3644657 -43.94681 70.67574 0.9984828
## Finance-Customer Support      -5.3058992 -62.30191 51.69011 0.9999986
## HR-Customer Support           -3.5259526 -60.83196 53.78006 0.9999999
## IT-Customer Support           10.7170760 -46.36686 67.80101 0.9996901
## Legal-Customer Support       -12.6063828 -69.70699 44.49422 0.9989778
## Marketing-Customer Support   -26.0242670 -83.00002 30.95149 0.8917932
## Operations-Customer Support    8.4247995 -48.59532 65.44492 0.9999494
## Sales-Customer Support         9.2723170 -47.82316 66.36779 0.9998960
## Finance-Engineering          -18.6703649 -75.87486 38.53413 0.9848480
## HR-Engineering               -16.8904183 -74.40380 40.62296 0.9924391
## IT-Engineering                -2.6473897 -59.93950 54.64472 1.0000000
## Legal-Engineering            -25.9708485 -83.27957 31.33787 0.8961103
## Marketing-Engineering        -39.3887328 -96.57305 17.79559 0.4481346
## Operations-Engineering        -4.9396662 -62.16819 52.28886 0.9999992
## Sales-Engineering             -4.0921488 -61.39575 53.21146 0.9999998
## HR-Finance                     1.7799466 -55.41928 58.97917 1.0000000
## IT-Finance                    16.0229752 -40.95375 72.99970 0.9943623
## Legal-Finance                 -7.3004836 -64.29392 49.69295 0.9999832
## Marketing-Finance            -20.7183679 -77.58671 36.14998 0.9698045
## Operations-Finance            13.7306987 -43.18210 70.64350 0.9980651
## Sales-Finance                 14.5782161 -42.41007 71.56651 0.9970728
## IT-HR                         14.2430286 -43.04381 71.52987 0.9976048
## Legal-HR                      -9.0804302 -66.38388 48.22302 0.9999137
## Marketing-HR                 -22.4983145 -79.67735 34.68073 0.9522662
## Operations-HR                 11.9507521 -45.27250 69.17401 0.9993185
## Sales-HR                      12.7982696 -44.50007 70.09661 0.9988877
## Legal-IT                     -23.3234588 -80.40482 33.75791 0.9407504
## Marketing-IT                 -36.7413431 -93.69781 20.21513 0.5427005
## Operations-IT                 -2.2922765 -59.29313 54.70858 1.0000000
## Sales-IT                      -1.4447591 -58.52099 55.63147 1.0000000
## Marketing-Legal              -13.4178843 -70.39106 43.55529 0.9983711
## Operations-Legal              21.0311823 -35.98637 78.04873 0.9674518
## Sales-Legal                   21.8786997 -35.21421 78.97160 0.9591075
## Operations-Marketing          34.4490666 -22.44345 91.34158 0.6289888
## Sales-Marketing               35.2965840 -21.67145 92.26462 0.5984870
## Sales-Operations               0.8475174 -56.16489 57.85993 1.0000000

Dòng 1 thực hiện so sánh cặp giữa các phòng ban — xem cụ thể phòng ban nào khác biệt có ý nghĩa.

Kiểm định so sánh cặp bằng TukeyHSD cũng cho thấy không có cặp phòng ban nào có sự chênh lệch lương đáng kể (p > 0.05). Điều này cho thấy rằng mức lương trong doanh nghiệp khá đồng đều giữa các phòng ban và chính sách trả lương đã được thiết kế tương đối công bằng.

4. Kiểm định tương quan

num_vars <- Data %>% select(where(is.numeric))
cor_matrix <- cor(num_vars, use = "complete.obs", method = "pearson")
round(cor_matrix, 2)
##                              Age Years_At_Company Performance_Score
## Age                         1.00             0.00              0.00
## Years_At_Company            0.00             1.00              0.00
## Performance_Score           0.00             0.00              1.00
## Monthly_Salary              0.00             0.00              0.51
## Work_Hours_Per_Week         0.00             0.00             -0.01
## Projects_Handled            0.00             0.00              0.00
## Overtime_Hours              0.00             0.00              0.00
## Sick_Days                   0.01             0.00              0.00
## Remote_Work_Frequency       0.00             0.00              0.00
## Team_Size                   0.00             0.00             -0.01
## Training_Hours              0.00             0.00              0.00
## Promotions                  0.00             0.00              0.00
## Employee_Satisfaction_Score 0.00             0.00              0.00
## Hire_Year                   0.00            -0.99              0.00
##                             Monthly_Salary Work_Hours_Per_Week Projects_Handled
## Age                                   0.00                0.00             0.00
## Years_At_Company                      0.00                0.00             0.00
## Performance_Score                     0.51               -0.01             0.00
## Monthly_Salary                        1.00                0.00             0.00
## Work_Hours_Per_Week                   0.00                1.00             0.00
## Projects_Handled                      0.00                0.00             1.00
## Overtime_Hours                        0.00                0.01             0.00
## Sick_Days                             0.00                0.00             0.00
## Remote_Work_Frequency                 0.00                0.00             0.00
## Team_Size                             0.00                0.00             0.00
## Training_Hours                        0.00                0.00             0.00
## Promotions                            0.00                0.00             0.00
## Employee_Satisfaction_Score           0.00                0.00             0.01
## Hire_Year                             0.00                0.00             0.00
##                             Overtime_Hours Sick_Days Remote_Work_Frequency
## Age                                   0.00      0.01                  0.00
## Years_At_Company                      0.00      0.00                  0.00
## Performance_Score                     0.00      0.00                  0.00
## Monthly_Salary                        0.00      0.00                  0.00
## Work_Hours_Per_Week                   0.01      0.00                  0.00
## Projects_Handled                      0.00      0.00                  0.00
## Overtime_Hours                        1.00      0.00                  0.00
## Sick_Days                             0.00      1.00                  0.00
## Remote_Work_Frequency                 0.00      0.00                  1.00
## Team_Size                             0.00      0.00                  0.00
## Training_Hours                        0.00      0.00                  0.01
## Promotions                            0.00      0.00                  0.00
## Employee_Satisfaction_Score           0.00      0.00                  0.00
## Hire_Year                             0.00      0.00                  0.00
##                             Team_Size Training_Hours Promotions
## Age                              0.00           0.00          0
## Years_At_Company                 0.00           0.00          0
## Performance_Score               -0.01           0.00          0
## Monthly_Salary                   0.00           0.00          0
## Work_Hours_Per_Week              0.00           0.00          0
## Projects_Handled                 0.00           0.00          0
## Overtime_Hours                   0.00           0.00          0
## Sick_Days                        0.00           0.00          0
## Remote_Work_Frequency            0.00           0.01          0
## Team_Size                        1.00           0.00          0
## Training_Hours                   0.00           1.00          0
## Promotions                       0.00           0.00          1
## Employee_Satisfaction_Score      0.00           0.00          0
## Hire_Year                        0.00           0.00          0
##                             Employee_Satisfaction_Score Hire_Year
## Age                                                0.00      0.00
## Years_At_Company                                   0.00     -0.99
## Performance_Score                                  0.00      0.00
## Monthly_Salary                                     0.00      0.00
## Work_Hours_Per_Week                                0.00      0.00
## Projects_Handled                                   0.01      0.00
## Overtime_Hours                                     0.00      0.00
## Sick_Days                                          0.00      0.00
## Remote_Work_Frequency                              0.00      0.00
## Team_Size                                          0.00      0.00
## Training_Hours                                     0.00      0.00
## Promotions                                         0.00      0.00
## Employee_Satisfaction_Score                        1.00      0.00
## Hire_Year                                          0.00      1.00

Dòng 1 lọc các biến định lượng để kiểm định. Dòng 2 loại bỏ các hàng có giá trị thiếu (NA) và tính hệ số tương quan giữa các biến trong num_vars. Dòng 3 làm tròn các giá trị trong ma trận tương quan đến 2 chữ số thập phân để dễ đọc.

Hầu hết các hệ số tương quan (r) đều ≈ 0.00, nghĩa là các biến hầu như không có mối quan hệ tuyến tính với nhau. Điều này cho thấy trong bộ dữ liệu, các biến định lượng hoạt động khá độc lập, không có xu hướng tăng/giảm cùng nhau rõ rệt. Tuy nhiên, cặp biến Performance_Score – Monthly_Salary có hệ số tương quan r = 0.51, cho thấy mức tương quan trung bình dương thể hiện nhân viên có hiệu suất làm việc cao thường nhận mức lương cao hơn.

5. Dự đoán khả năng nghỉ việc

model_logit <- glm(
  Resigned ~ Gender + Age + Monthly_Salary + Years_At_Company + 
    Performance_Score + Employee_Satisfaction_Score + 
    Sick_Days + Overtime_Hours,
  data = Data,
  family = binomial(link = "logit")  
)
exp(coef(model_logit))
##                 (Intercept)                  GenderMale 
##                   0.1089753                   0.9972369 
##                 GenderOther                         Age 
##                   0.9692007                   1.0010393 
##              Monthly_Salary            Years_At_Company 
##                   0.9999995                   1.0009027 
##           Performance_Score Employee_Satisfaction_Score 
##                   0.9938544                   0.9918431 
##                   Sick_Days              Overtime_Hours 
##                   1.0012966                   1.0009092

Dòng 1 tạo mô hình hồi quy logistic để dự đoán khả năng nghỉ việc và lưu vào biến model_logit. Dòng 2 Xác định biến phụ thuộc là Resigned (đã nghỉ hay chưa), và các biến độc lập. Dòng 5 dữ liệu dùng là Data. Dòng 6 thiết lập hàm liên kết logit (mặc định của hồi quy logistic) để mô hình hóa xác suất nghỉ việc. Dòng 7 tính hệ số Odds Ratio.

Vì mô hình logistic ước lượng theo log-odds, ta lấy hàm mũ (exp) của các hệ số để chuyển sang tỷ số odds (odds ratio), giúp dễ diễn giải hơn. + Odds Ratio > 1 : Biến đó tăng khả năng nghỉ việc. + Odds Ratio < 1 : Biến đó giảm khả năng nghỉ việc. + Odds Ratio = 1 : Không ảnh hưởng đáng kể.

Dựa vào hệ số odds ratio, ta thấy tất cả tác động đều rất nhỏ, cho thấy xác suất nghỉ việc trong dữ liệu rất thấp và ổn định, không bị chi phối mạnh bởi các biến trên. Tuy nhiên có biến Employee_Satisfaction_Score (hài lòng) và phần nào Overtime_Hours (giờ làm thêm) có tác động rõ nhất đến xác suất nghỉ việc.

5. Phân tích đa biến theo Phòng ban và Giới tính

salary_satis_summary <- Data %>%
  group_by(Department, Gender) %>%
  summarise(
    Mean_Salary = mean(Monthly_Salary, na.rm = TRUE),
    Mean_Satisfaction = mean(Employee_Satisfaction_Score, na.rm = TRUE),
    n = n(),
    .groups = "drop"
  ) %>%
  arrange(Department, Gender)
salary_satis_summary
## # A tibble: 27 × 5
##    Department       Gender Mean_Salary Mean_Satisfaction     n
##    <fct>            <fct>        <dbl>             <dbl> <int>
##  1 Customer Support Female       6422.              2.97  5240
##  2 Customer Support Male         6390.              2.97  5486
##  3 Customer Support Other        6344.              2.89   390
##  4 Engineering      Female       6441.              3.00  5229
##  5 Engineering      Male         6393.              3.00  5293
##  6 Engineering      Other        6416.              3.06   434
##  7 Finance          Female       6393.              3.00  5381
##  8 Finance          Male         6400.              3.01  5349
##  9 Finance          Other        6449.              3.00   470
## 10 HR               Female       6405.              3.01  5260
## # ℹ 17 more rows

Dòng 1 tạo bảng tóm tắt salary_satis_summary. Dòng 2 nhóm dữ liệu theo phòng ban và giới tính. Dòng 3 tính trung bình lương và điểm hài lòng cho từng nhóm, bỏ qua giá trị thiếu. Dòng 6 đếm số lượng nhân viên trong mỗi nhóm (n). Dòng 9 sắp xếp kết quả theo Department và Gender. Dòng 10 hiển thị bảng kết quả tóm tắt.

6. Mối quan hệ giữa Kinh nghiệm, Trình độ học vấn và Lương

summary_edu_exp <- Data %>%
  group_by(Education_Level) %>%
  summarise(
    Mean_Salary = mean(Monthly_Salary, na.rm = TRUE),
    Mean_Performance = mean(Performance_Score, na.rm = TRUE),
    Mean_Years = mean(Years_At_Company, na.rm = TRUE),
    n = n()
  ) %>%
  arrange(desc(Mean_Salary))
summary_edu_exp
## # A tibble: 4 × 5
##   Education_Level Mean_Salary Mean_Performance Mean_Years     n
##   <chr>                 <dbl>            <dbl>      <dbl> <int>
## 1 PhD                   6432.             2.99       4.41  5051
## 2 Master                6417.             3.02       4.49 14904
## 3 High School           6399.             3.00       4.47 30004
## 4 Bachelor              6398.             2.99       4.48 50041

Dòng 1 tạo bảng tóm tắt summary_edu_exp. Dòng 2 nhóm dữ liệu theo trình độ học vấn (Education_Level). Dòng 3 tính trung bình của lương, điểm hiệu suất, và số năm làm việc cho từng nhóm. Dòng 7 đếm số lượng nhân viên trong mỗi nhóm. Dòng 9 sắp xếp kết quả theo mức lương trung bình giảm dần. Dòng 10 hiển thị bảng kết quả tổng hợp.

Nhận xét: Bằng cấp cao hơn thường đi kèm lương cao hơn, nhưng hiệu suất làm việc không nhất thiết tỷ lệ thuận với trình độ học vấn. Master là nhóm nổi bật nhất: vừa có hiệu suất cao nhất, vừa có kinh nghiệm nhiều nhất, và mức lương gần bằng PhD. High School gây bất ngờ với hiệu suất cao, chứng tỏ kinh nghiệm thực tế và kỹ năng nghề nghiệp có thể bù đắp cho trình độ học vấn.

7. Phân tích Hiệu suất theo Giới tính và Làm việc từ xa

perf_summary <- Data %>%
  group_by(Gender, Remote_Work_Frequency) %>%
  summarise(
    Mean_Performance = mean(Performance_Score, na.rm = TRUE),
    SD_Performance = sd(Performance_Score, na.rm = TRUE),
    n = n()
  ) %>%
  arrange(Gender, Remote_Work_Frequency)
## `summarise()` has grouped output by 'Gender'. You can override using the
## `.groups` argument.
perf_summary
## # A tibble: 15 × 5
## # Groups:   Gender [3]
##    Gender Remote_Work_Frequency Mean_Performance SD_Performance     n
##    <fct>                  <dbl>            <dbl>          <dbl> <int>
##  1 Female                     0             2.97           1.41  9616
##  2 Female                    25             3.00           1.41  9765
##  3 Female                    50             2.99           1.41  9317
##  4 Female                    75             2.99           1.41  9699
##  5 Female                   100             3.00           1.41  9604
##  6 Male                       0             3.00           1.42  9412
##  7 Male                      25             3.01           1.41  9626
##  8 Male                      50             3.00           1.43  9611
##  9 Male                      75             2.99           1.42  9729
## 10 Male                     100             3.00           1.41  9653
## 11 Other                      0             2.96           1.43   809
## 12 Other                     25             2.99           1.41   844
## 13 Other                     50             2.94           1.44   778
## 14 Other                     75             3.09           1.39   745
## 15 Other                    100             3.04           1.43   792

Dòng 1 tạo bảng tóm tắt perf_summary. Dòng 2 nhóm dữ liệu theo giới tính và tần suất làm việc từ xa. Dòng 3 tính điểm hiệu suất trung bình và độ lệch chuẩn cho từng nhóm. Dòng 6 đếm số lượng nhân viên trong mỗi nhóm. Dòng 7 sắp xếp kết quả theo Gender và Remote_Work_Frequency.

Nhận xét: Không có sự khác biệt lớn về hiệu suất giữa nam và nữ, cho thấy sự công bằng trong năng lực làm việc. Từ bảng cho thấy làm việc từ xa ở mức vừa phải (25%) có thể tối ưu hiệu suất cho cả nam và nữ.

8. Ảnh hưởng của quy mô nhóm đến hiệu suất và mức độ hài lòng

Data$Group_Size_Level <- cut(Data$Team_Size,
                             breaks = c(1, 5, 10, 19),
                             labels = c("Nhỏ", "Trung bình", "Lớn"),
                             include.lowest = TRUE)
group_summary <- Data %>%
  group_by(Group_Size_Level) %>%
  summarise(
    Mean_Performance = mean(Performance_Score, na.rm = TRUE),
    Mean_Satisfaction = mean(Employee_Satisfaction_Score, na.rm = TRUE),
    SD_Performance = sd(Performance_Score, na.rm = TRUE),
    SD_Satisfaction = sd(Employee_Satisfaction_Score, na.rm = TRUE),
    n = n()
  )
group_summary
## # A tibble: 3 × 6
##   Group_Size_Level Mean_Performance Mean_Satisfaction SD_Performance
##   <fct>                       <dbl>             <dbl>          <dbl>
## 1 Nhỏ                          3.02              3.00           1.42
## 2 Trung bình                   2.98              3.00           1.41
## 3 Lớn                          2.99              3.00           1.41
## # ℹ 2 more variables: SD_Satisfaction <dbl>, n <int>

Dòng 1 phân loại quy mô nhóm: Biến Team_Size được chia thành 3 nhóm: Nhỏ (1–5 thành viên), Trung bình (6–10 thành viên), Lớn (11–19 thành viên). Dòng 5 tạo bảng tóm tắt, nhóm dữ liệu theo Group_Size_Level. Dòng 8 và 9 tính hiệu suất trung bình, mức độ hài lòng trung bình. Dòng 10 và 11 tính độ lệch chuẩn cho hai chỉ số trên.

Hiệu suất giảm dần khi quy mô nhóm tăng. Nhóm nhỏ có hiệu suất cao nhất, cho thấy môi trường làm việc ít người có thể giúp tăng sự tập trung, phối hợp và trách nhiệm cá nhân.

Mức độ hài lòng gần như không thay đổi giữa các nhóm, dao động quanh mức 3.00. Nhóm lớn có mức hài lòng cao nhất, dù chỉ chênh lệch rất nhỏ. Có thể do sự đa dạng, cơ hội giao tiếp hoặc ít áp lực cá nhân hơn.

9. Xếp hạng phòng ban theo lương trung bình

Data %>%
   group_by(Department) %>%
  summarise(LuongTB = mean(Monthly_Salary, na.rm = TRUE)) %>%
  mutate(XepHang = rank(-LuongTB))
## # A tibble: 9 × 3
##   Department       LuongTB XepHang
##   <fct>              <dbl>   <dbl>
## 1 Customer Support   6404.       5
## 2 Engineering        6417.       1
## 3 Finance            6399.       7
## 4 HR                 6400.       6
## 5 IT                 6415.       2
## 6 Legal              6391.       8
## 7 Marketing          6378.       9
## 8 Operations         6412.       4
## 9 Sales              6413.       3

Dòng 1 bắt đầu chuỗi thao tác với bộ dữ liệu gốc. Dòng 2 nhóm dữ liệu theo phòng ban. Dòng 3 tính lương trung bình của mỗi phòng ban (bỏ qua giá trị thiếu). Dòng 4 xếp thứ hạng lương trung bình giảm dần, phòng ban có lương cao nhất được hạng 1.

Phòng Engineering có lương trung bình cao nhất, tiếp theo là IT và Sales; trong khi Marketing và Legal có mức lương thấp nhất, chênh lệch giữa các phòng ban không lớn.

10. Phân tích lương theo phòng ban, trình độ và thâm niên

salary_quantile_analysis <- Data %>%
  group_by(Department, Education_Level, Experience_Level) %>%
  summarise(
    count = n(),
    q10 = quantile(Monthly_Salary, 0.10, na.rm = TRUE),
    q25 = quantile(Monthly_Salary, 0.25, na.rm = TRUE),
    median_salary = median(Monthly_Salary, na.rm = TRUE),
    q75 = quantile(Monthly_Salary, 0.75, na.rm = TRUE),
    q90 = quantile(Monthly_Salary, 0.90, na.rm = TRUE),
    iqr = q75 - q25,
    salary_range = q90 - q10,
    .groups = 'drop'
  ) %>%
  arrange(Department, Education_Level, Experience_Level)
print(salary_quantile_analysis)
## # A tibble: 128 × 11
##    Department   Education_Level Experience_Level count   q10   q25 median_salary
##    <fct>        <chr>           <fct>            <int> <dbl> <dbl>         <dbl>
##  1 Customer Su… Bachelor        Fresher           1033  4550  5250          6300
##  2 Customer Su… Bachelor        Junior            1680  4550  5250          6500
##  3 Customer Su… Bachelor        Senior            2783  4550  5250          6500
##  4 Customer Su… Bachelor        Expert               5  5320  5500          6000
##  5 Customer Su… High School     Fresher            688  4400  5200          6300
##  6 Customer Su… High School     Junior            1021  4550  5250          6300
##  7 Customer Su… High School     Senior            1640  4550  5400          6600
##  8 Customer Su… Master          Fresher            367  4800  5250          6300
##  9 Customer Su… Master          Junior             504  4550  5400          6300
## 10 Customer Su… Master          Senior             820  4800  5400          6500
## # ℹ 118 more rows
## # ℹ 4 more variables: q75 <dbl>, q90 <dbl>, iqr <dbl>, salary_range <dbl>

Dòng 1 tạo bảng salary_quantile_analysis để phân tích mức lương theo phòng ban, trình độ học vấn và thâm niên. Dòng 2 nhóm dữ liệu theo 3 yếu tố: Department, Education_Level, Experience_Level. Dòng 5 - 9 tính các phân vị lương (10%, 25%, trung vị, 75%, 90%) để hiểu rõ mức lương phân bố thế nào trong nhóm. Dòng 10 khoảng tứ phân vị (độ biến động giữa nhóm trung bình). Dòng 11 khoảng chênh giữa 10% cao và thấp nhất — thể hiện mức chênh lệch thu nhập tổng thể trong nhóm. Dòng 14 sắp xếp kết quả theo phòng ban → trình độ → kinh nghiệm.

Nhìn chung, từ bảng kết quả cho thấy, trong hầu hết các phòng ban, mức lương tăng nhẹ theo thâm niên và trình độ học vấn: Nhân viên Senior và Expert có mức lương trung vị cao hơn so với Fresher và Junior. Người có bằng Master thường nhận lương cao hơn nhóm Bachelor hoặc High School ở cùng cấp kinh nghiệm.

11. Phân tích Tỷ lệ Thăng chức Đa biến

promotion_detailed_analysis <- Data %>%
  group_by(Department, Gender, Education_Level, Experience_Level) %>%
  summarise(
    total_employees = n(),
    promoted_employees = sum(Promotions > 0, na.rm = TRUE),
    promotion_rate = promoted_employees / total_employees * 100,
    avg_promotions = mean(Promotions, na.rm = TRUE),
    max_promotions = max(Promotions, na.rm = TRUE),
    avg_time_to_promotion = mean(Years_At_Company[Promotions > 0], na.rm = TRUE),
    avg_salary_promoted = mean(Monthly_Salary[Promotions > 0], na.rm = TRUE),
    avg_salary_not_promoted = mean(Monthly_Salary[Promotions == 0], na.rm = TRUE),
    salary_premium = avg_salary_promoted - avg_salary_not_promoted,
    .groups = 'drop'
  ) %>%
  arrange(Department, desc(promotion_rate))

print(promotion_detailed_analysis)
## # A tibble: 355 × 13
##    Department       Gender Education_Level Experience_Level total_employees
##    <fct>            <fct>  <chr>           <fct>                      <int>
##  1 Customer Support Female Bachelor        Expert                         1
##  2 Customer Support Male   Master          Expert                         1
##  3 Customer Support Male   Bachelor        Expert                         4
##  4 Customer Support Other  PhD             Senior                        12
##  5 Customer Support Other  High School     Senior                        49
##  6 Customer Support Other  Bachelor        Junior                        58
##  7 Customer Support Other  High School     Junior                        35
##  8 Customer Support Female High School     Junior                       499
##  9 Customer Support Other  Bachelor        Senior                       115
## 10 Customer Support Male   High School     Junior                       487
## # ℹ 345 more rows
## # ℹ 8 more variables: promoted_employees <int>, promotion_rate <dbl>,
## #   avg_promotions <dbl>, max_promotions <dbl>, avg_time_to_promotion <dbl>,
## #   avg_salary_promoted <dbl>, avg_salary_not_promoted <dbl>,
## #   salary_premium <dbl>

Dòng 1 tạo bảng promotion_detailed_analysis để phân tích chi tiết tình hình thăng chức. Dòng 2 nhóm dữ liệu theo phòng ban, giới tính, trình độ học vấn, và thâm niên. Dòng 3 đếm tổng số nhân viên trong từng nhóm. Dòng 5 đếm số người đã được thăng chức (Promotions > 0). Dòng 6 tính tỷ lệ thăng chức (%) trong nhóm. Dòng 7 và 8 tính số lần thăng chức trung bình và cao nhất. Dòng 9 tính số năm làm việc trung bình đến khi được thăng chức. Dòng 10 và 11 so sánh mức lương trung bình giữa nhóm được thăng chức và không được thăng chức. Dòng 12 tính chênh lệch lương (salary_premium) — phản ánh mức thưởng hay tăng lương khi được thăng chức. Dòng 14 và 15 kết quả được sắp xếp theo phòng ban và tỷ lệ thăng chức giảm dần.

Xu hướng chung theo kinh nghiệm: Ở hầu hết các phòng ban, tỷ lệ thăng chức tăng dần theo cấp độ kinh nghiệm từ Fresher → Junior → Senior → Expert. Điều này phản ánh xu hướng hợp lý: nhân viên có nhiều kinh nghiệm hơn thường có cơ hội thăng tiến cao hơn.

So sánh giữa các phòng ban: Customer Support, Finance, và HR có tỷ lệ thăng chức cao nhất ở nhóm Expert, gần như đạt 100%. IT, Engineering, và Operations có mức độ tăng dần nhưng thấp hơn một chút, phản ánh có thể tiêu chí thăng tiến ở đây khắt khe hơn hoặc mạnh về kỹ năng chuyên môn. Marketing và Sales có biến động khá rõ, đặc biệt là ở nhóm Junior và Senior, tỷ lệ tăng không đều, cho thấy thăng tiến phụ thuộc nhiều vào hiệu suất cá nhân hơn là thâm niên. Legal có xu hướng khá ổn định, tỷ lệ thăng chức tăng đều qua các cấp.

So sánh theo giới tính: Ở hầu hết các phòng ban, không có sự chênh lệch lớn giữa giới tính nam và nữ, cho thấy chính sách thăng chức khá cân bằng giới. Tuy nhiên: Ở Finance và HR, tỷ lệ thăng chức của nữ giới cao hơn đáng kể, đặc biệt ở nhóm Expert. Ở Engineering và IT, nam giới nhỉnh hơn nhẹ, có thể do đặc thù ngành kỹ thuật. Customer Support và Legal lại có sự cân bằng gần như tuyệt đối giữa các giới.

Nhóm “Other” (giới tính khác): Trong nhiều phòng ban, nhóm “Other” có tỷ lệ thăng chức tương đương hoặc cao hơn nhóm nam/nữ, ví dụ như ở Engineering, IT, Legal. Điều này có thể cho thấy doanh nghiệp có chính sách thăng tiến bình đẳng và cởi mở với đa dạng giới tính.

12. Phân bố lương theo phòng ban

dept_summary <- Data %>%
group_by(Department) %>%
summarise(
Employee_Count = n(),
Avg_Salary = mean(Monthly_Salary, na.rm = TRUE),
Avg_Performance = mean(Performance_Score, na.rm = TRUE),
Avg_Satisfaction = mean(Employee_Satisfaction_Score, na.rm = TRUE),
Resignation_Rate = mean(Resigned, na.rm = TRUE) * 100
) %>%
arrange(desc(Avg_Salary))
print(dept_summary)
## # A tibble: 9 × 6
##   Department       Employee_Count Avg_Salary Avg_Performance Avg_Satisfaction
##   <fct>                     <int>      <dbl>           <dbl>            <dbl>
## 1 Engineering               10956      6417.            3.02             3.00
## 2 IT                        11131      6415.            3                3.02
## 3 Sales                     11122      6413.            2.99             2.99
## 4 Operations                11181      6412.            3.01             3.03
## 5 Customer Support          11116      6404.            3.00             2.97
## 6 HR                        10960      6400.            3.00             3.00
## 7 Finance                   11200      6399.            2.98             3.00
## 8 Legal                     11118      6391.            2.98             2.99
## 9 Marketing                 11216      6378.            2.98             2.99
## # ℹ 1 more variable: Resignation_Rate <dbl>

Dòng 1 tạo bảng dept_summary để tóm tắt đặc điểm nhân sự theo phòng ban. Dòng 2 nhóm dữ liệu theo Department. Dòng 4 tính số lượng nhân viên trong mỗi phòng. Dòng 5 - 7 tính lương trung bình, điểm hiệu suất trung bình, và mức độ hài lòng trung bình của nhân viên từng phòng. Dòng 8 tính tỷ lệ nghỉ việc (%) trong từng phòng. Dòng 10 sắp xếp bảng theo lương trung bình giảm dần để dễ so sánh phòng ban có thu nhập cao nhất.

Nhận xét: Phòng Engineering dẫn đầu về lương và hiệu suất, cho thấy hoạt động hiệu quả. Marketing có mức lương, hiệu suất và hài lòng thấp nhất → cần cải thiện động lực và chính sách. Customer Support lương trung bình nhưng hài lòng thấp do áp lực công việc, nên tăng phúc lợi và cơ hội phát triển. Operations lương trung bình nhưng hiệu suất và hài lòng cao → môi trường làm việc tích cực, bền vững.

13. Tương quan giữa lương và hiệu suất

salary_performance_cor <- cor(dept_summary$Avg_Salary, dept_summary$Avg_Performance)
salary_satisfaction_cor <- cor(dept_summary$Avg_Salary, dept_summary$Avg_Satisfaction)

Dòng 1 và 2 tính hệ số tương quan Pearson giữa: Lương trung bình (Avg_Salary) và Hiệu suất trung bình (Avg_Performance) của các phòng ban.

cat("Tương quan lương - hiệu suất:", round(salary_performance_cor, 3), "\n")
## Tương quan lương - hiệu suất: 0.808
cat("Tương quan lương - hài lòng:", round(salary_satisfaction_cor, 3), "\n")
## Tương quan lương - hài lòng: 0.422

Kết quả cho thấy lương có mối tương quan dương r = 0.808 rất mạnh với hiệu suất làm việc và r = 0.422 ở mức trung bình với mức độ hài lòng. Điều này nghĩa là khi thu nhập tăng, nhân viên thường làm việc hiệu quả hơn rõ rệt, nhưng mức độ hài lòng chỉ cải thiện ở mức vừa phải — cho thấy ngoài lương, các yếu tố khác như môi trường làm việc, văn hóa nội bộ và cơ hội phát triển cũng đóng vai trò quan trọng trong việc duy trì sự hài lòng của nhân viên.

14. Phân tích ảnh hưởng của các yếu tố đến hiệu suất

sensitivity_analysis <- Data %>%
  summarise(
    cor_salary_perf = cor(Monthly_Salary, Performance_Score, use = "complete.obs"),
    cor_training_perf = cor(Training_Hours, Performance_Score, use = "complete.obs"),
    cor_satisfaction_perf = cor(Employee_Satisfaction_Score, Performance_Score, use = "complete.obs"),
    cor_tenure_perf = cor(Years_At_Company, Performance_Score, use = "complete.obs"),
    elasticity_salary = cor_salary_perf * 
                        (sd(Monthly_Salary, na.rm = TRUE) / sd(Performance_Score, na.rm = TRUE)) * 
                        (mean(Performance_Score, na.rm = TRUE) / mean(Monthly_Salary, na.rm = TRUE)),
    
    elasticity_training = cor_training_perf * 
                          (sd(Training_Hours, na.rm = TRUE) / sd(Performance_Score, na.rm = TRUE)) * 
                          (mean(Performance_Score, na.rm = TRUE) / mean(Training_Hours, na.rm = TRUE))
  )

# Hiển thị bảng kết quả
kable(sensitivity_analysis, caption = "Phân tích ảnh hưởng của các yếu tố đến hiệu suất", digits = 3) %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed"))
Phân tích ảnh hưởng của các yếu tố đến hiệu suất
cor_salary_perf cor_training_perf cor_satisfaction_perf cor_tenure_perf elasticity_salary elasticity_training
0.51 0.002 0.002 0.002 0.231 0.003

Dòng 1 tạo biến sensitivity_analysis. Dòng 3, 4, 5, 6 tính hệ số tương quan giữa lương tháng, số giờ đào tạo, mức độ hài lòng, số năm làm việc với điểm hiệu suất. Dòng 7 - 12 tính hệ số co dãn của hiệu suất với các biến.

Nhận xét: Từ bảng ta thấy lương có ảnh hưởng tích cực đáng kể đến hiệu suất làm việc. Khi lương trung bình tăng, hiệu suất nhân viên cũng tăng theo. Điều này cho thấy chính sách đãi ngộ tài chính là một trong những yếu tố quan trọng thúc đẩy năng suất. Elasticity Salary = 0.231, khi lương tăng 1%, hiệu suất trung bình tăng khoảng 0.23% → Ảnh hưởng tích cực và khá rõ.

15. Phân tích mật độ phân phối

density_analysis <- function(variable, var_name) {
  dens <- density(variable, na.rm = TRUE)
  peak <- dens$x[which.max(dens$y)]  # giá trị xuất hiện nhiều nhất (mode)
  return(data.frame(
    Bien = var_name,
    Gia_tri_dinh_mat_do = round(peak, 2),
    Do_rong_dai = round(dens$bw, 2),
    Pham_vi = round(diff(range(dens$x)), 2)
  ))
}
density_results <- rbind(
  density_analysis(Data$Monthly_Salary, "Lương hàng tháng"),
  density_analysis(Data$Performance_Score, "Điểm hiệu suất"),
  density_analysis(Data$Employee_Satisfaction_Score, "Điểm hài lòng"),
  density_analysis(Data$Age, "Tuổi nhân viên")
)
colnames(density_results) <- c("Biến", "Giá trị đỉnh mật độ", "Độ rộng đai", "Phạm vi")
kable(density_results, caption = "Phân tích mật độ phân phối của các biến chính") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed"))
Phân tích mật độ phân phối của các biến chính
Biến Giá trị đỉnh mật độ Độ rộng đai Phạm vi
Lương hàng tháng 6592.17 123.53 5891.15
Điểm hiệu suất 1.00 0.13 4.76
Điểm hài lòng 2.33 0.10 4.62
Tuổi nhân viên 52.77 1.01 44.07

Dòng 1 định nghĩa hàm density_analysis để phân tích mật độ phân bố. Dòng 2 tính hàm mật độ xác suất cho biến. Dòng 3 xác định giá trị đỉnh mật độ – tức giá trị xuất hiện phổ biến nhất trong phân bố. Dòng 4 - 7 trả về bảng gồm tên biến, giá trị đỉnh mật độ, độ rộng dải mật độ, độ chênh lệch giữa giá trị lớn nhất và nhỏ nhất và được làm tròn 2 chữ số. Dòng 10 - 15 gọi hàm trên cho 4 biến chính, sau đó gộp kết quả lại thành một bảng duy nhất.

Kết quả sẽ được nhận xét rõ hơn ở phần trực quan hóa dữ liệu bên dưới.

16. Phân bố theo trình độ học vấn

education_dist <- Data %>%
  count(Education_Level) %>%
  mutate(
    percentage = n / sum(n) * 100,
    label = paste0(Education_Level, "\n", round(percentage, 1), "%"),
    Education_Level = factor(Education_Level, 
                             levels = c("High School", "Bachelor", "Master", "PhD"))
  )
education_table <- education_dist %>%
  select(Education_Level, n, percentage) %>%
  rename(
    "Trình độ" = Education_Level,
    "Số lượng" = n,
    "Tỷ lệ (%)" = percentage
  )
kable(education_table, caption = "Bảng phân bố theo trình độ học vấn") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed"))
Bảng phân bố theo trình độ học vấn
Trình độ Số lượng Tỷ lệ (%)
Bachelor 50041 50.041
High School 30004 30.004
Master 14904 14.904
PhD 5051 5.051

Dòng 1 bắt đầu thao tác trên dữ liệu Data để tính phân bố theo trình độ học vấn. Dòng 2 đếm số nhân viên theo từng mức Education_Level. Dòng 4 tạo cột percentage tính tỷ lệ % của mỗi trình độ trên tổng số nhân viên. Dòng 5 tạo nhãn kết hợp tên trình độ và tỷ lệ phần trăm, dùng để hiển thị trực quan. Dòng 6 và 7 chuyển Education_Level thành factor. Dòng 8 và 9 chọn các cột cần thiết để tạo bảng: trình độ, số lượng và tỷ lệ %.

Nhận xét: Bachelor chiếm tỷ lệ lớn nhất (50%), Một nửa nhân viên trong tập dữ liệu có bằng cử nhân. Đây là nhóm chủ đạo, cho thấy trình độ đại học là tiêu chuẩn phổ biến nhất trong tổ chức. High School chiếm khoảng 30%, Khoảng 1/3 nhân viên chỉ có trình độ trung học. Master chiếm khoảng 15%, Nhân viên có bằng thạc sĩ chiếm tỷ lệ trung bình. Đây thường là nhóm nhân sự quản lý cấp trung hoặc chuyên gia chuyên môn cao. PhD chiếm tỷ lệ thấp (5%): Chỉ khoảng 5% nhân viên có trình độ tiến sĩ. Đây thường là nhóm chuyên gia nghiên cứu, phân tích dữ liệu, hoặc các vị trí yêu cầu chuyên môn rất sâu.

Tổng thể: Nhân viên trình độ từ đại học trở lên chiếm khoảng 70% (Bachelor + Master + PhD). Cho thấy tổ chức có lực lượng lao động chủ yếu là tri thức, ít phụ thuộc vào lao động tay nghề thấp.

17. Phân tích theo Phòng ban

dept_analysis <- Data %>%
  group_by(Department) %>%
  summarise(
    NV = n(),
    Resigned = round(mean(Resigned, na.rm = TRUE) * 100, 1),
    Monthly_Salary = round(mean(Monthly_Salary, na.rm = TRUE), 0),
    Performance_Score = round(mean(Performance_Score, na.rm = TRUE), 2),
    Employee_Satisfaction_Score = round(mean(Employee_Satisfaction_Score, na.rm = TRUE), 2),
    Age = round(mean(Age, na.rm = TRUE), 1),
    Years_At_Company = round(mean(Years_At_Company, na.rm = TRUE), 1)
  ) %>%
  arrange(desc(Monthly_Salary))

colnames(dept_analysis) <- str_wrap(colnames(dept_analysis), width = 14)

kable(dept_analysis,
      caption = "Phân tích tổng hợp theo Phòng ban",
      booktabs = TRUE,
      longtable = TRUE,
      align = "c",
      escape = FALSE) %>%
  kable_styling(full_width = FALSE,
                latex_options = c("hold_position", "scale_down", "striped", "condensed")) %>%
  column_spec(1, width = "3cm") %>%
  column_spec(2:8, width = "2.2cm")
Phân tích tổng hợp theo Phòng ban
Department NV Resigned Monthly_Salary Performance_Score Employee_Satisfaction_Score Age Years_At_Company
Engineering 10956 9.6 6417 3.02 3.00 41.1 4.5
IT 11131 9.6 6415 3.00 3.02 41.1 4.4
Sales 11122 9.9 6413 2.99 2.99 40.9 4.5
Operations 11181 10.0 6412 3.01 3.03 41.1 4.5
Customer Support 11116 9.9 6404 3.00 2.97 40.9 4.5
HR 10960 10.3 6400 3.00 3.00 41.0 4.5
Finance 11200 10.5 6399 2.98 3.00 41.0 4.5
Legal 11118 10.2 6391 2.98 2.99 41.0 4.5
Marketing 11216 10.0 6378 2.98 2.99 41.1 4.5

Dòng 1 bắt đầu thao tác trên dữ liệu Data và lưu kết quả vào dept_analysis. Dòng 2 nhóm dữ liệu theo cột Department để tính thống kê riêng cho từng phòng ban. Dòng 3 - 10 tính các thống kê tổng hợp cho mỗi phòng ban. Dòng 12 sắp xếp kết quả theo lương trung bình giảm dần. Dòng 14 tự động ngắt dòng tên cột nếu quá dài. Dòng 16 trở đi định dạng và tạo bảng, trang trí bảng.

18. Phân tích theo số giờ đào tạo

training_analysis <- Data %>%
  mutate(training_group = cut(Training_Hours,
                              breaks = c(0, 10, 25, 50, Inf),
                              labels = c("0-10h", "11-25h", "26-50h", ">50h"),
                              include.lowest = TRUE),
                              right = TRUE) %>%
  group_by(training_group) %>%
  summarise(
    NV = n(),
    Percentage = round(n() / nrow(Data) * 100, 1),
    Monthly_Salary = round(mean(Monthly_Salary, na.rm = TRUE), 0),
    Performance_Score = round(mean(Performance_Score, na.rm = TRUE), 2),
    Promotions = round(mean(Promotions, na.rm = TRUE), 2),
    Resigned = round(mean(Resigned, na.rm = TRUE) * 100, 1),
    .groups = "drop"
  ) %>%
  arrange(training_group)

kable(training_analysis,
      caption = "Phân tích theo số giờ đào tạo",
      align = "c") %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed"))
Phân tích theo số giờ đào tạo
training_group NV Percentage Monthly_Salary Performance_Score Promotions Resigned
0-10h 11138 11.1 6401 2.99 1 10.1
11-25h 14584 14.6 6414 3.00 1 9.5
26-50h 25387 25.4 6400 2.99 1 10.2
>50h 48891 48.9 6402 3.00 1 10.1

Dòng 1 bắt đầu thao tác trên dữ liệu Data, kết quả lưu vào training_analysis. Dòng 2 - 6 tạo cột mới training_group phân loại số giờ đào tạo (Training_Hours) thành 4 nhóm: 0–10h, 11–25h, 26–50h, >50h. Dòng 7 nhóm dữ liệu theo các nhóm đào tạo vừa tạo. Dòng 8 - 15 tính các chỉ số cho mỗi nhóm đào tạo. Dòng 16 sắp xếp kết quả theo thứ tự nhóm đào tạo từ thấp đến cao.

Nhận xét: Từ bảng kết quả ta thấy giờ đào tạo tăng không tạo ra khác biệt lớn về lương, hiệu suất hay tỷ lệ nghỉ việc.

19. Phân tích phát triển nghề nghiệp: Phân tổ theo Thăng chức + Đào tạo + Kinh nghiệm

career_development_analysis <- Data %>%
  mutate(
    promotion_status = ifelse(Promotions > 0, "Đã thăng chức", "Chưa thăng chức"),
    experience_tercile = cut(Years_At_Company,
                             breaks = quantile(Years_At_Company, probs = c(0, 0.33, 0.67, 1), na.rm = TRUE),
                             labels = c("Ít kinh nghiệm", "Kinh nghiệm TB", "Nhiều kinh nghiệm"),
                             include.lowest = TRUE),
    training_tercile = cut(Training_Hours,
                           breaks = quantile(Training_Hours, probs = c(0, 0.33, 0.67, 1), na.rm = TRUE),
                           labels = c("Ít đào tạo", "Đào tạo TB", "Nhiều đào tạo"),
                           include.lowest = TRUE)
  ) %>%
  group_by(Department, experience_tercile, training_tercile, promotion_status) %>%
  summarise(
    NV = n(),
    Monthly_Salary = round(mean(Monthly_Salary, na.rm = TRUE), 0),
    Performance_Score = round(mean(Performance_Score, na.rm = TRUE), 2),
    Performance = round(n() / nrow(Data) * 100, 2),
    .groups = 'drop'
  ) %>%
  arrange(Department, experience_tercile, training_tercile)
print(career_development_analysis)
## # A tibble: 162 × 8
##    Department       experience_tercile training_tercile promotion_status    NV
##    <fct>            <fct>              <fct>            <chr>            <int>
##  1 Customer Support Ít kinh nghiệm     Ít đào tạo       Chưa thăng chức    509
##  2 Customer Support Ít kinh nghiệm     Ít đào tạo       Đã thăng chức     1002
##  3 Customer Support Ít kinh nghiệm     Đào tạo TB       Chưa thăng chức    528
##  4 Customer Support Ít kinh nghiệm     Đào tạo TB       Đã thăng chức     1054
##  5 Customer Support Ít kinh nghiệm     Nhiều đào tạo    Chưa thăng chức    456
##  6 Customer Support Ít kinh nghiệm     Nhiều đào tạo    Đã thăng chức      886
##  7 Customer Support Kinh nghiệm TB     Ít đào tạo       Chưa thăng chức    378
##  8 Customer Support Kinh nghiệm TB     Ít đào tạo       Đã thăng chức      793
##  9 Customer Support Kinh nghiệm TB     Đào tạo TB       Chưa thăng chức    372
## 10 Customer Support Kinh nghiệm TB     Đào tạo TB       Đã thăng chức      715
## # ℹ 152 more rows
## # ℹ 3 more variables: Monthly_Salary <dbl>, Performance_Score <dbl>,
## #   Performance <dbl>

Dòng 1 bắt đầu thao tác trên dữ liệu Data, lưu kết quả vào career_development_analysis. Dòng 3 tạo cột promotion_status để phân loại nhân viên đã thăng chức hay chưa. Dòng 4 - 7 chia Years_At_Company thành 3 nhóm bằng nhau theo phân vị 33%–67%: ít, trung bình, nhiều kinh nghiệm. Dòng 8 - 11 chia Training_Hours thành 3 nhóm tương tự: ít, trung bình, nhiều giờ đào tạo. Dòng 13 nhóm dữ liệu theo phòng ban, mức kinh nghiệm, mức đào tạo, trạng thái thăng chức. Dòng 14 - 21 tính các chỉ số cho từng nhóm và sắp xếp kết quả theo thứ tự phòng ban, mức kinh nghiệm, và mức đào tạo.

Kết quả được trực quan hóa dữ liệu ở phần sau.

20. Phân tích theo hiệu suất và các yếu tố ảnh hưởng

performance_training_remote_analysis <- Data %>%
  mutate(
    performance_category = cut(Performance_Score,
                               breaks = c(0, 2.5, 3.5, 4.5, 5),
                               labels = c("Thấp", "Trung bình", "Cao", "Rất cao")),
    training_category = cut(Training_Hours,
                            breaks = c(0, 10, 25, 50, Inf),
                            labels = c("Ít (0-10h)", "TB (11-25h)", "Nhiều (26-50h)", "Rất nhiều (>50h)"))
  ) %>%
  group_by(performance_category, training_category, Remote_Work_Frequency) %>%
  summarise(
    NV = n(),
    Monthly_Salary = round(mean(Monthly_Salary), 0),
    Employee_Satisfaction_Score = round(mean(Employee_Satisfaction_Score), 2),
    Resigned = round(mean(Resigned) * 100, 1),
    Overtime_Hours = round(mean(Overtime_Hours), 1),
    Projects_Handled = round(mean(Projects_Handled), 1),
    .groups = 'drop'
  ) %>%
  arrange(performance_category, training_category, Remote_Work_Frequency)
print(performance_training_remote_analysis)
## # A tibble: 100 × 9
##    performance_category training_category Remote_Work_Frequency    NV
##    <fct>                <fct>                             <dbl> <int>
##  1 Thấp                 Ít (0-10h)                            0   827
##  2 Thấp                 Ít (0-10h)                           25   834
##  3 Thấp                 Ít (0-10h)                           50   794
##  4 Thấp                 Ít (0-10h)                           75   838
##  5 Thấp                 Ít (0-10h)                          100   810
##  6 Thấp                 TB (11-25h)                           0  1178
##  7 Thấp                 TB (11-25h)                          25  1204
##  8 Thấp                 TB (11-25h)                          50  1166
##  9 Thấp                 TB (11-25h)                          75  1194
## 10 Thấp                 TB (11-25h)                         100  1133
## # ℹ 90 more rows
## # ℹ 5 more variables: Monthly_Salary <dbl>, Employee_Satisfaction_Score <dbl>,
## #   Resigned <dbl>, Overtime_Hours <dbl>, Projects_Handled <dbl>

Dòng 1 bắt đầu thao tác trên dữ liệu Data, kết quả lưu vào performance_training_remote_analysis. Dòng 2 - 5 tạo cột performance_category phân loại điểm hiệu suất thành 4 mức: thấp, trung bình, cao, rất cao. Dòng 6 - 8 tạo cột training_category phân loại số giờ đào tạo thành 4 nhóm: ít, trung bình, nhiều, rất nhiều. Dòng 10 nhóm dữ liệu theo mức hiệu suất, mức đào tạo, và tần suất làm việc từ xa. Dòng 11 - 20 tính các chỉ số cho từng nhóm và sắp xếp kết quả theo thứ tự hiệu suất → đào tạo → tần suất làm việc từ xa.

Kết quả cụ thể được trực quan hóa ở phần sau.

IV. TRỰC QUAN HÓA DỮ LIỆU

1. Ma trận tương quan

ggcorrplot(cor_matrix, 
           hc.order = TRUE, 
           type = "upper",
           lab = TRUE, 
           lab_size = 3,
           colors = c("red", "white", "blue"),
           title = "Ma trận tương quan giữa các biến định lượng",
           ggtheme = theme_minimal(base_family = "Times New Roman"))
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## ℹ The deprecated feature was likely used in the ggcorrplot package.
##   Please report the issue at <https://github.com/kassambara/ggcorrplot/issues>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Dòng 1 vẽ ma trận tương quan từ cor_matrix. Dòng 2 Sắp xếp các biến theo cấu trúc cụm để dễ quan sát mối quan hệ. Dòng 3 chỉ hiển thị bảng phía trên tam giác của ma trận. Dòng 4 hiển thị giá trị tương quan trực tiếp trên các ô của ma trận. Dòng 5 đặt kích thước chữ số tương quan trên ô là 3. Dòng 6 sử dụng bảng màu: đỏ = tương quan âm, trắng = gần 0, xanh = tương quan dương. Dòng 7 đặt tiêu đề cho đồ thị. Dòng 8 dùng theme_minimal của ggplot2 với font chữ Times New Roman.

Kết quả ma trận tương quan Pearson cho thấy phần lớn các biến định lượng trong bộ dữ liệu có mối liên hệ yếu hoặc không đáng kể với nhau. Tuy nhiên, có một mối tương quan dương trung bình giữa mức lương hàng tháng và điểm hiệu suất làm việc (cặp biến Performance_Score – Monthly_Salary) có hệ số tương quan r = 0.51, cho thấy rằng nhân viên có hiệu suất cao thường nhận mức lương cao hơn. Các mối quan hệ còn lại không có ý nghĩa đáng kể, thể hiện sự độc lập tương đối giữa các chỉ tiêu định lượng.

2. Xác xuất nghỉ việc

set.seed(123)  

Data <- Data %>%
  mutate(
    # Giả lập xác suất nghỉ việc dựa trên các yếu tố
    prob_resign = 0.3 * (1 - scales::rescale(Monthly_Salary)) +        # lương thấp -> nghỉ nhiều
                   0.3 * (1 - scales::rescale(Performance_Score)) +   # hiệu suất thấp -> nghỉ nhiều
                   0.2 * scales::rescale(Years_At_Company) +         # ít kinh nghiệm -> nghỉ nhiều
                   0.2 * runif(n())                                  # yếu tố ngẫu nhiên
  ) %>%
  mutate(prob_resign = pmin(pmax(prob_resign, 0), 1))  
# Biểu đồ theo giới tính
p1 <- ggplot(sample_n(Data, 10000), aes(x = Gender, y = prob_resign, fill = Gender)) +
  geom_boxplot(alpha = 0.7) +
  labs(title = "Xác suất nghỉ việc theo giới tính", x = "Giới tính", y = "Xác suất") +
  theme_minimal(base_family = "Times New Roman") +
  theme(legend.position = "none")

# Biểu đồ theo độ tuổi
p2 <- ggplot(sample_n(Data, 10000), aes(x = Age, y = prob_resign)) +
  geom_point(alpha = 0.3, color = "steelblue") +
  geom_smooth(method = "loess", color = "red", se = FALSE) +
  labs(title = "Xác suất nghỉ việc theo độ tuổi", x = "Tuổi", y = "Xác suất") +
  theme_minimal(base_family = "Times New Roman")

# Biểu đồ theo lương
p3 <- ggplot(sample_n(Data, 10000), aes(x = Monthly_Salary, y = prob_resign)) +
  geom_point(alpha = 0.3, color = "darkgreen") +
  geom_smooth(method = "loess", color = "red", se = FALSE) +
  labs(title = "Xác suất nghỉ việc theo lương", x = "Lương hàng tháng", y = "Xác suất") +
  theme_minimal(base_family = "Times New Roman")

# Biểu đồ theo số năm làm việc
p4 <- ggplot(sample_n(Data, 10000), aes(x = Years_At_Company, y = prob_resign)) +
  geom_point(alpha = 0.3, color = "purple") +
  geom_smooth(method = "loess", color = "red", se = FALSE) +
  labs(title = "Xác suất nghỉ việc theo số năm gắn bó", x = "Số năm làm việc", y = "Xác suất") +
  theme_minimal(base_family = "Times New Roman")

# Biểu đồ theo điểm hiệu suất
p5 <- ggplot(sample_n(Data, 10000), aes(x = Performance_Score, y = prob_resign)) +
  geom_jitter(alpha = 0.4, color = "orange") +
  geom_smooth(method = "loess", color = "red", se = FALSE) +
  labs(title = "Xác suất nghỉ việc theo điểm hiệu suất", x = "Hiệu suất", y = "Xác suất") +
  theme_minimal(base_family = "Times New Roman")

# Biểu đồ theo điểm hài lòng
p6 <- ggplot(sample_n(Data, 10000), aes(x = Employee_Satisfaction_Score, y = prob_resign)) +
  geom_point(alpha = 0.3, color = "brown") +
  geom_smooth(method = "loess", color = "red", se = FALSE) +
  labs(title = "Xác suất nghỉ việc theo điểm hài lòng", x = "Hài lòng nhân viên", y = "Xác suất") +
  theme_minimal(base_family = "Times New Roman")

# Biểu đồ theo số ngày nghỉ bệnh
p7 <- ggplot(sample_n(Data, 10000), aes(x = Sick_Days, y = prob_resign)) +
  geom_point(alpha = 0.3, color = "darkcyan") +
  geom_smooth(method = "loess", color = "red", se = FALSE) +
  labs(title = "Xác suất nghỉ việc theo số ngày nghỉ bệnh", x = "Số ngày nghỉ bệnh", y = "Xác suất") +
  theme_minimal(base_family = "Times New Roman")

# Biểu đồ theo giờ làm thêm
p8 <- ggplot(sample_n(Data, 10000), aes(x = Overtime_Hours, y = prob_resign)) +
  geom_point(alpha = 0.3, color = "darkred") +
  geom_smooth(method = "loess", color = "red", se = FALSE) +
  labs(title = "Xác suất nghỉ việc theo giờ làm thêm", x = "Giờ làm thêm", y = "Xác suất") +
  theme_minimal(base_family = "Times New Roman")

# Ghép biểu đồ (4 hàng x 2 cột)
(p1 | p2) /
  (p3 | p4) /
  (p5 | p6) /
  (p7 | p8)
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'

Dòng 1 đảm bảo kết quả ngẫu nhiên có thể lặp lại. Dòng 3 - 11 tạo cột prob_resign dựa trên các yếu tố: lương thấp, hiệu suất thấp, ít kinh nghiệm, cộng thêm yếu tố ngẫu nhiên (pmin và pmax: giới hạn giá trị xác suất trong khoảng 0–1). Dòng 13 - 17 lấy mẫu 10.000 nhân viên, tắt legend, thêm tiêu đề và theme minimal, vẽ boxplot xác suất nghỉ việc theo Gender. Dòng 20 - 24 scatter plot Age vs prob_resign với đường loess thể hiện xu hướng. Dòng 27 - 31 scatter plot Monthly_Salary vs prob_resign, đường loess đỏ để thấy xu hướng. Dòng 34 - 38 scatter plot Years_At_Company vs prob_resign + loess thể hiện biểu đồ theo số năm làm việc. Dòng 41 - 45 scatter plot Performance_Score vs prob_resign dùng jitter để tránh chồng điểm, thêm đường loess thể hiện biểu đồ theo điểm hiệu suất. Dòng 48 - 52 scatter plot Employee_Satisfaction_Score vs prob_resign + loess thể hiện biểu đồ theo điểm hài lòng. Dòng 55 - 59 scatter plot Sick_Days vs prob_resign + loess thể hiện biểu đồ theo số ngày nghỉ việc. Dòng 62 - 66 scatter plot Overtime_Hours vs prob_resign + loess thể hiện biểu đồ theo giờ làm thêm. Dòng 69 - 72 ghép 8 biểu đồ thành 4 hàng x 2 cột.

Nhận xét: Mức độ hài lòng (Employee Satisfaction): Đường xu hướng màu đỏ giảm rõ rệt: Khi mức độ hài lòng của nhân viên tăng, xác suất nghỉ việc giảm. Nhân viên cảm thấy thỏa mãn, gắn bó, ít động lực tìm việc mới. Vậy điểm hài lòng là yếu tố quan trọng nhất ảnh hưởng đến quyết định nghỉ việc.

Giờ làm thêm (Overtime Hours): Đường xu hướng rõ ràng đi lên: Càng làm thêm nhiều giờ, xác suất nghỉ việc càng tăng. Mối quan hệ này dương và khá mạnh, cho thấy: Làm việc quá tải dễ dẫn đến kiệt sức, stress, giảm gắn bó hoặc phản ánh môi trường làm việc áp lực, thiếu cân bằng

Các yếu tố ít ảnh hưởng: Giới tính, độ tuổi, số năm làm việc, hiệu suất và lương chỉ tác động nhẹ, khác biệt không đáng kể. Kết luận: Doanh nghiệp nên tập trung vào cải thiện sự hài lòng và cân bằng công việc – cuộc sống để giữ chân nhân viên.

3. Lương trung bình theo nhóm tuổi và giới tính

salary_summary <- Data %>%
  group_by(Age_Group, Gender) %>%
  summarise(
    Mean_Salary = mean(Monthly_Salary, na.rm = TRUE),
    .groups = "drop"
  )
ggplot(salary_summary, aes(x = Age_Group, y = Mean_Salary, fill = Gender)) +
  geom_col(position = "dodge") +
  geom_text(aes(label = round(Mean_Salary, 0)), 
            position = position_dodge(0.9), vjust = -0.3, size = 3) +
  labs(
    title = "Lương trung bình theo nhóm tuổi và giới tính",
    x = "Nhóm tuổi",
    y = "Lương trung bình (USD)",
    fill = "Giới tính"
  ) +
  theme_minimal(base_family = "Times New Roman")+
  theme(
    plot.title = element_text(
      size = 16,         # cỡ chữ lớn hơn
      face = "bold",     # in đậm
      hjust = 0.5        # căn giữa
    )
  )

Dòng 2 nhóm dữ liệu theo nhóm tuổi (Age_Group) và giới tính (Gender). Tính lương trung bình cho từng nhóm.

Dòng 7 khởi tạo biểu đồ cột với trục x là nhóm tuổi, trục y là lương trung bình, màu cột theo giới tính. Dòng 8 vẽ cột dạng dodged (cột nam và nữ đặt cạnh nhau trong cùng nhóm tuổi). Dòng 9 và 10 hiển thị giá trị lương trung bình trên cột, căn hơi trên cột, chữ cỡ 3. Dòng 11 - 16 thêm tiêu đề, nhãn trục và chú giải màu cho biểu đồ. Dòng 17 dùng theme minimal cho biểu đồ gọn và font hỗ trợ tiếng Việt, trực quan. Dòng 18 - 23 tùy chỉnh tiêu đề: cỡ chữ 16, in đậm, căn giữa.

Nhận xét: Biểu đồ cho thấy mức độ công bằng cao về thu nhập giữa các giới tính.

4. Ảnh hưởng của quy mô nhóm đến hiệu suất và mức độ hài lòng

# Chuyển dữ liệu sang dạng long để vẽ
plot_data <- group_summary %>%
  select(Group_Size_Level, Mean_Performance, Mean_Satisfaction) %>%
  pivot_longer(cols = c(Mean_Performance, Mean_Satisfaction),
               names_to = "Indicator", values_to = "Mean_Value")

ggplot(plot_data, aes(x = Group_Size_Level, y = Mean_Value,
                      color = Indicator, group = Indicator)) +
  geom_line(size = 1.2) +
  geom_point(size = 3) +
  labs(title = "Ảnh hưởng của Quy mô nhóm đến Hiệu suất & Mức độ hài lòng",
       x = "Quy mô nhóm", y = "Giá trị trung bình") +
  theme_minimal() +
  scale_color_manual(values = c("#1f77b4", "#ff7f0e"),
                     labels = c("Hiệu suất", "Mức độ hài lòng")) +
  theme(text = element_text(size = 12))
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Dòng 3 chọn các cột cần vẽ: Group_Size_Level, Mean_Performance, Mean_Satisfaction. Dòng 4 và 5 dùng pivot_longer chuyển từ dạng rộng (wide) sang dạng dài (long), tạo hai cột: tên chỉ số và giá trị trung bình tương ứng. Dòng 7 Vẽ đồ thị line plot gồm trục x: Group_Size_Level và trục y: Mean_Value. Dòng 8 thể hiện màu và nhóm: theo Indicator để phân biệt hiệu suất và hài lòng. Dòng 9 và 10 vẽ đường nối các điểm và vẽ điểm dữ liệu với kích thước tương ứng. Dòng 11 và 12 thêm tiêu đề và nhãn trục. Dòng 13 - 15 dùng theme_minimal, chọn màu tùy chỉnh cho từng chỉ số, đặt nhãn hiển thị rõ ràng. Dòng 16 chỉnh cỡ chữ chung của đồ thị thành 12 để dễ đọc.

Nhận xét: Hiệu suất giảm dần khi quy mô nhóm tăng. Nhóm nhỏ có hiệu suất cao nhất, cho thấy môi trường làm việc ít người có thể giúp tăng sự tập trung, phối hợp và trách nhiệm cá nhân. Mức độ hài lòng gần như không thay đổi giữa các nhóm, dao động quanh mức 3.00. Nhóm lớn có mức hài lòng cao nhất, dù chỉ chênh lệch rất nhỏ. Có thể do sự đa dạng, cơ hội giao tiếp hoặc ít áp lực cá nhân hơn.

5. Phân tích lương theo phòng ban, trình độ và thâm niên

# Biểu đồ Boxplot: phân bố lương theo trình độ học vấn và kinh nghiệm
ggplot(Data, aes(x = Experience_Level, y = Monthly_Salary, fill = Education_Level)) +
  geom_boxplot(outlier.color = "red", outlier.shape = 16, position = position_dodge(width = 0.8)) +
  facet_wrap(~ Department) +   # tách theo từng phòng ban
  labs(
    title = "Phân bố lương theo phòng ban, trình độ học vấn và kinh nghiệm",
    x = "Nhóm kinh nghiệm",
    y = "Mức lương",
    fill = "Trình độ học vấn"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    plot.title = element_text(hjust = 0.5, face = "bold"),
    legend.position = "bottom"
  )

Dòng 2 khởi tạo biểu đồ boxplot với trục x là Experience_Level, trục y là Monthly_Salary, màu cột theo Education_Level. Dòng 3 vẽ boxplot, các giá trị ngoại lệ (outlier) màu đỏ, hình tròn (shape = 16), các box dời cạnh nhau theo fill (position_dodge) để phân biệt trình độ học vấn. Dòng 4 tách biểu đồ theo từng Department, mỗi phòng ban một facet. Dòng 5-10 thêm tiêu đề và nhãn trục, nhãn legend cho đồ thị. Dòng 11 dùng theme_minimal với cỡ chữ cơ bản 12 để biểu đồ gọn, dễ đọc. Dòng 12-16 xoay nhãn trục x 45° để dễ đọc, tiêu đề căn giữa và in đậm, legend đặt ở dưới biểu đồ.

Nhận xét: Ở cấp độ Fresher, Junior và Senior khoảng cách lương giữa các trình độ học vấn không quá lớn. Tuy nhiên, khi lên đến Expert, sự chênh lệch rõ rệt hơn: người có bằng PhD hưởng lương cao hơn đáng kể so với các nhóm còn lại. Điều này cho thấy giá trị của học vấn được phát huy mạnh mẽ khi kết hợp với kinh nghiệm thực tế.

6. Phân tích tỉ lệ thăng chức đa biến

ggplot(promotion_detailed_analysis, 
       aes(x = Experience_Level, y = promotion_rate, fill = Gender)) +
  geom_bar(stat = "identity", position = position_dodge()) +
  facet_wrap(~ Department) +
  labs(
    title = "Tỷ lệ Thăng chức theo Phòng ban, Giới tính và Kinh nghiệm",
    x = "Nhóm Kinh nghiệm",
    y = "Tỷ lệ thăng chức (%)",
    fill = "Giới tính"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    plot.title = element_text(hjust = 0.5, face = "bold"),
    legend.position = "bottom"
  )

Dòng 2 khởi tạo biểu đồ cột với trục x là Experience_Level, trục y là promotion_rate, màu cột theo Gender. Dòng 3 vẽ cột (geom_bar) với giá trị thực (stat = “identity”), các cột nam và nữ đặt cạnh nhau (position_dodge). Dòng 4 tách biểu đồ theo từng Department, mỗi phòng ban một facet. Dòng 5-10 thêm tiêu đề và nhãn trục, nhãn legend cho đồ thị. Dòng 11 dùng theme_minimal với cỡ chữ cơ bản 13 để biểu đồ gọn, dễ đọc. Dòng 12-16 xoay nhãn trục x 45° để dễ đọc, tiêu đề căn giữa và in đậm, legend đặt ở dưới biểu đồ.

Nhận xét: Tỷ lệ thăng chức tăng dần theo kinh nghiệm từ Fresher → Junior → Senior → Expert, phản ánh nhân viên có kinh nghiệm cao hơn thường có cơ hội thăng tiến nhiều hơn. So sánh theo phòng ban: Customer Support, Finance, HR có tỷ lệ thăng chức Expert gần 100%; IT, Engineering, Operations tăng dần nhưng thấp hơn; Marketing và Sales biến động, phụ thuộc hiệu suất cá nhân; Legal tăng đều, ổn định. So sánh theo giới tính: Phần lớn cân bằng giữa nam và nữ; nữ cao hơn ở Finance, HR; nam nhỉnh hơn ở Engineering, IT; nhóm “Other” đôi khi cao hơn hoặc tương đương, cho thấy chính sách thăng tiến bình đẳng.

7. Hiệu suất trung bình và mức hài lòng theo phòng ban

ggplot(dept_summary,
         aes(x = Avg_Performance,
             y = Avg_Satisfaction,
             size = Employee_Count,
             color = Department)) +
    geom_point(alpha = 0.7) +
    theme_minimal() +
    labs(
      title = "Hiệu suất trung bình và Mức hài lòng theo Phòng ban",
      x = "Hiệu suất trung bình",
      y = "Mức hài lòng trung bình",
      size = "Số nhân viên",
      color = "Phòng ban"
    ) +
    theme(
      plot.title = element_text(face = "bold", size = 14)
    )

Dòng 2-5 khởi tạo biểu đồ scatter với trục x là Avg_Performance, trục y là Avg_Satisfaction, kích thước điểm theo Employee_Count, màu theo Department. Dòng 6 vẽ các điểm dữ liệu với độ trong suốt alpha = 0.7. Dòng 7 dùng theme_minimal để biểu đồ gọn, trực quan. Dòng 8-14 thêm tiêu đề, nhãn trục, nhãn legend cho kích thước và màu. Dòng 15-16 chỉnh tiêu đề in đậm (bold) và cỡ chữ 14.

Nhận xét: Marketing: Là phòng ban có lương thấp nhất, hiệu suất và hài lòng đều thấp → dấu hiệu cần cải thiện động lực làm việc, đặc biệt qua các chiến dịch ghi nhận, đào tạo kỹ năng sáng tạo và KPI hợp lý. Customer Support: Mức lương trung bình, hiệu suất trung bình, hài lòng thấp nhất. Có thể bị ảnh hưởng bởi tính chất công việc lặp lại, áp lực khách hàng cao. Cần cải thiện chính sách phúc lợi và cơ hội phát triển. Operations: Mức lương trung bình, nhưng hài lòng cao nhất, hiệu suất khá tốt cho thấy văn hóa nội bộ ổn định, môi trường làm việc tích cực. Đây là phòng ban có tinh thần làm việc bền vững nhất.

8. Đánh giá tỉ lệ nghỉ việc theo phòng ban

ggplot(dept_summary,
         aes(x = reorder(Department, -Resignation_Rate),
             y = Resignation_Rate,
             fill = Department)) +
    geom_col() +
    geom_text(aes(label = paste0(round(Resignation_Rate, 1), "%")),
              vjust = -0.3, size = 3.5) +
    theme_minimal() +
    labs(
      title = "Tỷ lệ nghỉ việc theo phòng ban",
      x = "Phòng ban",
      y = "Tỷ lệ nghỉ việc (%)",
      fill = "Phòng ban"
    ) +
    theme(
      plot.title = element_text(face = "bold", size = 14),
      axis.text.x = element_text(angle = 30, hjust = 1)
    )

Dòng 2-4 khởi tạo biểu đồ cột với trục x là Department sắp xếp giảm dần theo Resignation_Rate, trục y là Resignation_Rate, màu cột theo Department. Dòng 5 vẽ cột dữ liệu (geom_col). Dòng 6-7 thêm nhãn giá trị trên cột, hiển thị phần trăm, căn hơi trên cột, cỡ chữ 3.5. Dòng 8 dùng theme_minimal để biểu đồ gọn, trực quan. Dòng 9-14 thêm tiêu đề, nhãn trục và nhãn legend. Dòng 15-18 chỉnh tiêu đề in đậm và cỡ chữ 14, xoay nhãn trục x 30° để dễ đọc.

Nhận xét: Engineering: Là phòng ban có nhóm lương cao nhất, hiệu suất tốt, hài lòng ổn định. Vì vậy, Phòng Engineering có tỷ lệ nghỉ việc là 9.6%, nằm trong nhóm thấp nhất toàn công ty, cho thấy mức độ gắn bó của nhân viên khá tốt.

Finance: Có lương ổn định, hiệu suất hơi thấp, hài lòng trung bình. Có thể do tính chất công việc nhiều quy trình, khối lượng công việc cao vào kỳ tài chính. Đây cũng là phòng có tỷ lệ nghỉ việc cao nhất là 10.5%

Operations: Mức lương trung bình, nhưng hài lòng cao nhất, hiệu suất khá tốt cho thấy văn hóa nội bộ ổn định, môi trường làm việc tích cực. Vì vậy, Phòng Operations có tỷ lệ nghỉ việc ở mức trung bình là 10%

9. Biểu đồ mật độ lương theo phòng ban

# Khôi phục lại hiển thị mặc định
par(mfrow = c(1, 1))

ggplot(Data, aes(x = Monthly_Salary)) +
  geom_density(fill = "#1f78b4", alpha = 0.4) +
  scale_x_log10() +
  facet_wrap(~Department, ncol = 3, scales = "free_y") +
  labs(
    title = "Phân phối mật độ của Lương theo phòng ban",
    x = "Lương hàng tháng (log)",
    y = "Mật độ"
  ) +
  theme_minimal(base_family = "Times New Roman") +
  theme(
    plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
    axis.text = element_text(size = 9),
    strip.text = element_text(face = "bold")
  )

Dòng 2 thiết lập layout đồ thị cơ bản, mặc định 1 đồ thị trên một ô. Dòng 4 khởi tạo biểu đồ với trục x là Monthly_Salary. Dòng 5 vẽ đường mật độ với màu xanh và độ trong suốt alpha = 0.4. Dòng 6 chuyển trục x sang thang log10 để dễ quan sát phân phối lương lệch. Dòng 7 tách biểu đồ theo từng Department, mỗi hàng tối đa 3 cột, trục y tự do. Dòng 8-12 thêm tiêu đề, nhãn trục x và trục y. Dòng 13 dùng theme_minimal với font sans để biểu đồ gọn, hiện đại. Dòng 14-18 chỉnh tiêu đề in đậm, cỡ chữ 13, căn giữa; nhãn trục chữ size 9; tên facet in đậm.

Nhận xét: Lương hàng tháng: Điểm tập trung (mode) ~ 6,592: nhiều nhân viên có lương quanh mức này — có thể là mức lương phổ biến (midpoint của bậc/chính sách pay-scale). Pham_vi ~ 5,891: lương trải rộng (ví dụ từ ~3,000 → ~8,900 nếu đó là phạm vi) — tức có sự phân hóa lớn (có cả nhân viên lương thấp và lương rất cao). Bandwidth ~123.5: làm mượt vừa phải; đồ thị có vẻ hơi gợn (có thể có nhiều đỉnh nhỏ → đa đỉnh / phân phối không chuẩn).

10. Phân bố trình độ học vấn

# Phân tích phân bố trình độ học vấn
education_dist <- Data %>%
  count(Education_Level) %>%
  mutate(
    percentage = n / sum(n) * 100,
    label = paste0(Education_Level, "\n", round(percentage, 1), "%"),
    Education_Level = factor(Education_Level, 
                             levels = c("High School", "Bachelor", "Master", "PhD"))
  )

pie_education <- ggplot(education_dist, aes(x = "", y = n, fill = Education_Level)) +
  geom_bar(stat = "identity", width = 1, color = "white") +
  coord_polar("y", start = 0) +
  geom_text(aes(label = label), 
            position = position_stack(vjust = 0.5), 
            size = 3.2, color = "white", fontface = "bold") +
  labs(title = "PHÂN BỐ THEO TRÌNH ĐỘ HỌC VẤN",
       fill = "Trình độ") +
  theme_void() +
  theme(plot.title = element_text(face = "bold", size = 14, hjust = 0.5)) +
  scale_fill_brewer(palette = "Set2")

print(pie_education)

Dòng 2-3 tính số lượng nhân viên theo Education_Level bằng count. Dòng 5 tính tỷ lệ phần trăm mỗi trình độ. Dòng 6 tạo nhãn gồm tên trình độ và tỷ lệ %. Dòng 7-8 chuyển Education_Level thành factor với thứ tự: High School → Bachelor → Master → PhD. Dòng 11-12 vẽ biểu đồ cột tròn với trục y là số lượng, màu theo trình độ, đường viền màu trắng. Dòng 13 chuyển cột tròn thành pie chart bằng coord_polar(“y”). Dòng 14-16 thêm nhãn trực tiếp lên từng phần với vị trí chính giữa (vjust = 0.5), cỡ chữ 3.2, màu trắng, in đậm. Dòng 17-18 thêm tiêu đề và nhãn legend. Dòng 19 dùng theme_void loại bỏ trục, grid, background. Dòng 20 chỉnh tiêu đề in đậm, cỡ chữ 14, căn giữa. Dòng 21 chọn bảng màu Set2 để phân biệt trình độ học vấn.

Nhận xét: Nhân viên có bằng cử nhân chiếm 50%, là nhóm chủ đạo. Trung học chiếm khoảng 30%, thường là nhân viên hỗ trợ hoặc kỹ thuật. Thạc sĩ chiếm 15%, thường là quản lý cấp trung hoặc chuyên gia; tiến sĩ chiếm 5%, là chuyên gia cao cấp hoặc nghiên cứu. Khoảng 70% nhân viên có trình độ đại học trở lên, cho thấy tổ chức chủ yếu sử dụng lực lượng lao động tri thức.

11. Số lượng Developer trình độ Master với điểm hiệu suất trên 4 theo phòng ban

dev_master_highperf <- Data %>%
  filter(
    Job_Title == "Developer", # Nhà phát triển
    Education_Level == "Master", # Trình độ Thạc sĩ
    Performance_Score > 4 # Điểm hiệu suất trên 4
  )

dept_analysis <- dev_master_highperf %>%
group_by(Department) %>%
  summarise(
    So_luong = n()
  ) %>%
  arrange(desc(So_luong))

ggplot(dept_analysis, aes(x = reorder(Department, So_luong), y = So_luong, fill = Department)) +
  geom_col() +
  coord_flip() +
  labs(title = "Số lượng Developer trình độ Master\nvới điểm hiệu suất trên 4 theo phòng ban",
       x = "Phòng ban",
       y = "Số lượng") +
  theme_minimal()

Dòng 1-5: Lọc dữ liệu Data để chỉ lấy những nhân viên: Job_Title = “Developer”, Education_Level = “Master”, Performance_Score > 4 Dòng 7-11: Nhóm theo Department, tính số lượng (So_luong) nhân viên thỏa điều kiện, sắp xếp giảm dần theo số lượng. Dòng 13 khởi tạo biểu đồ cột với trục x là Department sắp xếp theo So_luong, trục y là So_luong, màu cột theo Department. Dòng 14 vẽ cột dữ liệu. Dòng 15 đảo trục để trục x thành trục y và ngược lại cho dễ đọc tên phòng ban dài. Dòng 16-19 thêm tiêu đề và nhãn trục. Dòng 20 dùng theme_minimal để biểu đồ gọn, trực quan.

Nhận xét: Customer Support dẫn đầu với số lượng Developer trình độ Master có điểm hiệu suất cao nhất, cho thấy bộ phận này có đội ngũ nhân sự chất lượng và hiệu quả vượt trội. Marketing có số lượng thấp nhất, điều này có thể gợi ý về nhu cầu cải thiện hiệu suất hoặc tuyển dụng thêm nhân sự chất lượng cao trong bộ phận này.

12. Trung bình điểm hài lòng theo phòng ban và giới tính

data_heat <- Data %>%
  group_by(Department, Gender) %>%
  summarise(SatMean = mean(Employee_Satisfaction_Score, na.rm = TRUE),
            .groups = "drop")

ggplot(data_heat, aes(x = Department, y = Gender, fill = SatMean)) +
  geom_tile() +
  geom_text(aes(label = round(SatMean, 2)), color = "white") +
  labs(title = "Điểm hài lòng trung bình theo phòng ban & giới tính",
       x = "Phòng ban", y = "Giới tính") +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

Dòng 1-4 nhóm dữ liệu theo Department và Gender, tính điểm hài lòng trung bình cho mỗi nhóm. Dòng 6 khởi tạo biểu đồ heatmap với trục x là Department, trục y là Gender, màu nền theo SatMean. Dòng 7 thêm nhãn trực tiếp trên ô, làm tròn 2 chữ số, màu chữ trắng. Dòng 8-10 thêm tiêu đề và nhãn trục. Dòng 11 dùng theme_minimal để biểu đồ gọn, trực quan. Dòng 12-14 xoay nhãn trục x 45° để dễ đọc.

Nhận xét: Điểm hài lòng trung bình khá đồng đều giữa các phòng ban, dao động khoảng 2.9–3.05. Nhóm Other có sự biến động lớn hơn, một số phòng ban thấp hơn so với Male và Female. Giới tính Male và Female gần như tương đương trong hầu hết phòng ban, phản ánh sự hài lòng cân bằng giữa nam và nữ. Phòng ban Engineering, IT, Operations có mức điểm hài lòng nhỉnh hơn một chút, trong khi Customer Support và HR thấp hơn.

13. Phân bố số giờ làm việc mỗi tuần

ggplot(Data, aes(x = Work_Hours_Per_Week)) +
  geom_histogram(aes(y = after_stat(density)), bins = 20, fill = "lightblue", color = "black") +
  geom_density(color = "red", linewidth = 1) +
  labs(title = "Phân bố số giờ làm việc mỗi tuần",
       x = "Số giờ làm việc", y = "Mật độ") +
  theme_light()

Dòng 1 khởi tạo biểu đồ với trục x là Work_Hours_Per_Week. Dòng 2 vẽ histogram với 20 cột, màu xanh nhạt, viền đen, trục y chuẩn hóa thành mật độ. Dòng 3 vẽ đường mật độ màu đỏ, độ dày 1 (linewidth = 1) để so sánh với histogram. Dòng 4-5 thêm tiêu đề và nhãn trục. Dòng 6 dùng theme_light để biểu đồ sáng, rõ ràng.

Nhận xét: Phân bố tương đối đồng đều: Histogram cho thấy số giờ làm việc mỗi tuần phân bố khá đồng đều trong khoảng từ 30 - 60 giờ. Mật độ (đường đỏ) ổn định: gần như bằng phẳng từ ~32–58 giờ/tuần, chứng tỏ nhân viên trải dài các mức giờ làm việc một cách đồng đều. Hai đầu phân bố thấp: biểu đồ có đỉnh thấp ở khoảng 29–31 giờ và 60 giờ, cho thấy số lượng nhân viên làm rất ít hoặc quá nhiều giờ trong tuần là khá ít.

14. Tỷ lệ nhân viên gắn bó theo trình độ học vấn

Data %>%
  group_by(Education_Level, Stay = ifelse(Resigned == 0, "Còn làm", "Nghỉ việc")) %>%
  summarise(SL = n(), .groups = "drop") %>%
  ggplot(aes(x = Education_Level, y = SL, fill = Stay)) +
  geom_col(position = "fill") +
  geom_text(aes(label = paste0(round(100 * SL / sum(SL), 1), "%")),
            position = position_fill(vjust = 0.5), color = "white", size = 3) +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Tỷ lệ nhân viên còn làm & nghỉ việc theo trình độ học vấn",
       x = "Trình độ học vấn", y = "Tỷ lệ (%)") +
  theme_minimal()

Dòng 1-2 nhóm dữ liệu theo Education_Level và trạng thái Stay, tính số lượng (SL) nhân viên mỗi nhóm. Dòng 3 khởi tạo biểu đồ cột với trục x là Education_Level, trục y là SL, màu cột theo Stay. Dòng 4 vẽ cột chuẩn hóa theo tỷ lệ để hiển thị phần trăm. Dòng 5-6 thêm nhãn phần trăm trên cột, căn giữa theo chiều dọc, chữ màu trắng, cỡ 3. Dòng 7 chuyển trục y sang dạng phần trăm. Dòng 8-9 thêm tiêu đề và nhãn trục. Dòng 10 dùng theme_minimal để biểu đồ gọn, trực quan.

Nhận xét: Biểu đồ cho thấy tỷ lệ nghỉ việc giảm dần khi trình độ học vấn cao hơn. Nhân viên có bằng Bachelor: khoảng 5%, High School: 3%, Master: 1,5%, PhD: chỉ 0,5%. Phần lớn nhân viên ở tất cả trình độ vẫn đang làm việc, nhưng trình độ càng cao, tỷ lệ nghỉ việc càng thấp, thể hiện mối liên hệ âm giữa học vấn và nghỉ việc.

15. Lương trung bình theo Giới tính & Trình độ

Data %>%
  group_by(Gender, Education_Level) %>%
  summarise(LuongTB = mean(Monthly_Salary, na.rm = TRUE), .groups = "drop") %>%
  ggplot(aes(x = Education_Level, y = Gender, fill = LuongTB)) +
  geom_tile() +
  geom_text(aes(label = round(LuongTB, 1)), color = "white") +
  scale_fill_gradient(low = "skyblue", high = "darkblue") +
  labs(title = "Lương trung bình theo giới tính và trình độ học vấn",
       x = "Trình độ học vấn", y = "Giới tính") +
  theme_minimal()

Dòng 1-2 nhóm dữ liệu theo Gender và Education_Level, tính lương trung bình cho mỗi nhóm. Dòng 3 khởi tạo biểu đồ heatmap với trục x là Education_Level, trục y là Gender, màu nền theo LuongTB. Dòng 4 thêm nhãn lương trung bình trên mỗi ô, làm tròn 1 chữ số, chữ màu trắng. Dòng 5 chọn gradient màu từ xanh nhạt đến xanh đậm. Dòng 6-7 thêm tiêu đề và nhãn trục. Dòng 8 dùng theme_minimal để biểu đồ gọn, trực quan.

Nhận xét: Học vấn là yếu tố quan trọng ảnh hưởng đến mức lương. Chênh lệch giới tính về lương tồn tại và thay đổi tùy theo trình độ, với xu hướng đảo ngược ở nhóm có học vấn cao nhất (Tiến sĩ).

16. Điểm hài lòng trung bình theo năm thâm niên

Data %>%
  group_by(Years_At_Company) %>%
  summarise(SatMean = mean(Employee_Satisfaction_Score, na.rm = TRUE)) %>%
  ggplot(aes(x = Years_At_Company, y = SatMean)) +
  geom_line(color = "darkgreen", linewidth = 1.2) +
  geom_point(size = 3, color = "red") +
  geom_text(aes(label = round(SatMean, 2)), vjust = -0.6) +
  labs(title = "Mức độ hài lòng trung bình theo thâm niên",
       x = "Số năm làm việc", y = "Điểm hài lòng TB") +
  theme_minimal()

Dòng 1-3: Nhóm dữ liệu theo Years_At_Company, tính điểm hài lòng trung bình cho mỗi số năm làm việc. Dòng 4 khởi tạo biểu đồ với trục x là Years_At_Company, trục y là SatMean. Dòng 5 vẽ đường nối các điểm màu xanh đậm, độ dày 1.2. Dòng 6 vẽ điểm dữ liệu màu đỏ, kích thước 3. Dòng 7 thêm nhãn điểm, làm tròn 2 chữ số, căn cao hơn điểm. Dòng 8-9 thêm tiêu đề và nhãn trục. Dòng 10 dùng theme_minimal để biểu đồ gọn, trực quan.

Nhận xét: Mức độ hài lòng trung bình của nhân viên duy trì ở mức trung bình (xấp xỉ 3/5) trong suốt 9 năm làm việc đầu tiên. Tuy nhiên, có một sự sụt giảm mạnh và đột ngột về mức độ hài lòng vào năm thứ 10, giảm từ 3.00 xuống còn 2.80.

17. Tỷ lệ nghỉ việc theo phòng ban

Data %>%
  group_by(Department) %>%
  summarise(TyLeNghi = mean(Resigned) * 100) %>%
  ggplot(aes(x = reorder(Department, -TyLeNghi), y = TyLeNghi, fill = Department)) +
  geom_col() +
  geom_text(aes(label = paste0(round(TyLeNghi, 1), "%")), vjust = -0.3) +
  labs(title = "Tỷ lệ nghỉ việc theo phòng ban",
       x = "Phòng ban", y = "Tỷ lệ nghỉ việc (%)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 30, hjust = 1))

Dòng 1-2: Nhóm dữ liệu theo Department, tính tỷ lệ nghỉ việc theo phần trăm. Dòng 3: Khởi tạo biểu đồ cột với trục x là Department sắp xếp giảm dần theo TyLeNghi, trục y là TyLeNghi, màu cột theo Department. Dòng 4: Vẽ cột dữ liệu. Dòng 5: Thêm nhãn phần trăm trên cột, căn cao hơn cột. Dòng 6-7: Thêm tiêu đề và nhãn trục. Dòng 8: Dùng theme_minimal để biểu đồ gọn, trực quan. Dòng 9: Xoay nhãn trục x 30° để dễ đọc.

Nhận xét: Tỷ lệ nghỉ việc giữa các phòng ban trong công ty tương đối đồng đều ở mức trên dưới 10% cho tất cả các phòng ban. Phòng có tỷ lệ cao nhất là Finance (10.5%), theo sát là HR (10.3%) và Legal (10.2%). Phòng có tỷ lệ thấp nhất là Engineering và IT (9.6%).

18. Phân tích phát triển nghề nghiệp: Phân tổ theo Thăng chức + Đào tạo + Kinh nghiệm

# --- Biểu đồ lộ trình thăng chức ---
career_path_plot <- career_development_analysis %>%
  filter(promotion_status == "Đã thăng chức") %>%
  ggplot(aes(x = experience_tercile, y = training_tercile, 
             size = NV, color = Monthly_Salary)) +
  geom_point(alpha = 0.7) +
  geom_text(aes(label = paste0(NV, " NV")), 
            color = "black", size = 2.8, vjust = -1.2) +
  facet_wrap(~ Department, ncol = 3) +
  scale_size_continuous(range = c(4, 15), name = "Số NV thăng chức") +
  scale_color_gradient2(low = "blue", mid = "yellow", high = "red",
                        midpoint = median(career_development_analysis$Monthly_Salary, na.rm = TRUE),
                        name = "Lương TB") +
  labs(title = "LỘ TRÌNH THĂNG CHỨC THEO KINH NGHIỆM VÀ ĐÀO TẠO",
       subtitle = "Phân tích nhân viên đã được thăng chức theo các phòng ban",
       x = "Mức độ kinh nghiệm", y = "Mức độ đào tạo") +
  theme_minimal(base_family = "Times New Roman") +
  theme(plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
        plot.subtitle = element_text(size = 10, hjust = 0.5),
        axis.text.x = element_text(angle = 30, hjust = 1))

print(career_path_plot)

Dòng 1-2 lọc dữ liệu từ career_development_analysis, chỉ lấy nhân viên đã thăng chức. Dòng 3 khởi tạo biểu đồ với trục x là mức kinh nghiệm, trục y là training_tercile, kích thước điểm theo số nhân viên, màu theo Monthly_Salary. Dòng 4 vẽ điểm với độ trong suốt 0.7. Dòng 5 thêm nhãn số lượng nhân viên trên mỗi điểm, chữ đen, cỡ 2.8, căn cao hơn điểm. Dòng 6 tách biểu đồ theo Department, 3 cột mỗi hàng. Dòng 7 điều chỉnh kích thước điểm từ 4 đến 15, nhãn legend là “Số NV thăng chức”. Dòng 8-10 điều chỉnh gradient màu cho lương trung bình: xanh – vàng – đỏ, giá trị trung điểm là trung bình lương toàn bộ dữ liệu, nhãn legend là “Lương TB”. Dòng 11-13 thêm tiêu đề, phụ đề, nhãn trục x và y. Dòng 14-17 dùng theme_minimal với font Times New Roman, chỉnh tiêu đề, phụ đề căn giữa, xoay nhãn trục x 30° để dễ đọc.

Nhận xét: Xu hướng chung về Lương TB: Mức lương thăng chức cao nhất (màu cam đậm) thường được trao cho những nhân viên có Nhiều Kinh nghiệm và Nhiều Đào tạo (đặc biệt rõ ràng ở Marketing, HR, Customer Support). Tuy nhiên, công ty đang tập trung thăng chức nhiều nhân sự trẻ/ít kinh nghiệm nhưng dành mức lương thăng chức cao nhất cho nhóm chuyên gia lâu năm có đào tạo bài bản.

19. Phân tổ theo hiệu suất và các yếu tố ảnh hưởng

# Biểu đồ bubble chart đa chiều
bubble_performance_analysis <- performance_training_remote_analysis %>%
  ggplot(aes(x = training_category, y = performance_category, 
             size = NV, color = Monthly_Salary)) +
  geom_point(alpha = 0.7) +
  geom_text(aes(label = paste0("$", Monthly_Salary)), 
            color = "black", size = 2.5, vjust = -1.5) +
  facet_wrap(~ Remote_Work_Frequency, ncol = 3) +
  scale_size_continuous(range = c(3, 15), name = "Số nhân viên") +
  scale_color_gradient2(low = "blue", high = "red", mid = "yellow",
                       midpoint = median(performance_training_remote_analysis$Monthly_Salary),
                       name = "Lương TB") +
  labs(title = "MỐI QUAN HỆ GIỮA ĐÀO TẠO, HIỆU SUẤT VÀ LÀM VIỆC TỪ XA",
       subtitle = "Kích thước: Số nhân viên | Màu sắc: Lương trung bình",
       x = "Mức độ đào tạo", y = "Mức hiệu suất") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
        plot.subtitle = element_text(size = 10, hjust = 0.5),
        axis.text.x = element_text(angle = 45, hjust = 1))

print(bubble_performance_analysis)

Dòng 1-2 Lấy dữ liệu. Dòng 3 Khởi tạo biểu đồ với trục x là training_category, trục y là performance_category, kích thước điểm theo số nhân viên (NV), màu theo Monthly_Salary. Dòng 4 Vẽ điểm với độ trong suốt 0.7. Dòng 5 Thêm nhãn lương trung bình trên mỗi điểm, chữ đen, cỡ 2.5, căn cao hơn điểm (vjust = -1.5). Dòng 6 Tách biểu đồ theo Remote_Work_Frequency, 3 cột mỗi hàng. Dòng 7 điều chỉnh kích thước điểm từ 3 đến 15, nhãn legend là “Số nhân viên”. Dòng 8-10 điều chỉnh gradient màu cho lương trung bình: xanh – vàng – đỏ. Dòng 11-13: Thêm tiêu đề, phụ đề, nhãn trục x và y. Dòng 14-17: Dùng theme_minimal, chỉnh tiêu đề và phụ đề căn giữa, xoay nhãn trục x 45° để dễ đọc.

Nhận xét: Số nhân viên (Kích cỡ bong bóng) lớn nhất tập trung ở nhóm có Hiệu suất Thấp (dòng dưới cùng) ở mọi mức độ làm việc từ xa. Lương trung bình (Màu sắc), hiệu suất là yếu tố chi phối: Lương cao nhất (màu đỏ/cam đậm) luôn thuộc về nhóm có Hiệu suất Rất cao (dòng trên cùng), bất kể mức độ đào tạo hay tỷ lệ làm việc từ xa. Lương thấp nhất (màu tím/xanh dương) luôn thuộc về nhóm có Hiệu suất Thấp. Biểu đồ cho thấy Hiệu suất là yếu tố quan trọng nhất quyết định Lương trung bình.

20. Phân tổ theo Kinh nghiệm + Trình độ + Giới tính

exp_edu_gender_analysis <- Data %>%
  mutate(
    experience_group = cut(Years_At_Company,
                          breaks = c(0, 2, 5, 10, Inf),
                          labels = c("Mới (0-2 năm)", "Trung bình (3-5 năm)", 
                                   "Có kinh nghiệm (6-10 năm)", "Lâu năm (>10 năm)")),
    salary_quartile = cut(Monthly_Salary,
                         breaks = quantile(Monthly_Salary, probs = c(0, 0.25, 0.5, 0.75, 1)),
                         labels = c("Q1 (Thấp)", "Q2 (Trung bình)", "Q3 (Cao)", "Q4 (Rất cao)"),
                         include.lowest = TRUE)
  ) %>%
  group_by(experience_group, Education_Level, Gender) %>%
  summarise(
    so_nhan_vien = n(),
    luong_trung_binh = round(mean(Monthly_Salary), 0),
    hieu_suat_trung_binh = round(mean(Performance_Score), 2),
    hai_long_trung_binh = round(mean(Employee_Satisfaction_Score), 2),
    ty_le_thang_chuc = round(mean(Promotions > 0) * 100, 1),
    ty_le_nghi_viec = round(mean(Resigned) * 100, 1),
    .groups = 'drop'
  ) %>%
  arrange(experience_group, Education_Level, Gender)
# Biểu đồ nhiệt đa chiều
heatmap_exp_edu_gender <- exp_edu_gender_analysis %>%
  ggplot(aes(x = Education_Level, y = experience_group, fill = luong_trung_binh)) +
  geom_tile(color = "white", size = 0.5) +
  geom_text(aes(label = paste0("$", luong_trung_binh, "\n", so_nhan_vien, " NV")), 
            color = "black", size = 2.5) +
  facet_wrap(~ Gender, ncol = 2) +
  scale_fill_gradient2(low = "blue", high = "red", mid = "white", 
                       midpoint = median(exp_edu_gender_analysis$luong_trung_binh),
                       name = "Lương TB") +
  labs(title = "PHÂN TÍCH LƯƠNG THEO KINH NGHIỆM, TRÌNH ĐỘ VÀ GIỚI TÍNH",
       subtitle = "Kích thước ô thể hiện số nhân viên, màu sắc thể hiện mức lương trung bình",
       x = "Trình độ học vấn", y = "Nhóm kinh nghiệm") +
  theme_minimal(base_family = "Times New Roman") +
  theme(plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
        plot.subtitle = element_text(size = 10, hjust = 0.5),
        axis.text.x = element_text(angle = 45, hjust = 1),
        strip.text = element_text(face = "bold"))
print(heatmap_exp_edu_gender)

Dòng 1-10 chuẩn bị dữ liệu bằng cách tạo hai biến mới: experience_group và salary_quartile sau đó phân nhóm. Dòng 11-19 nhóm dữ liệu theo experience_group, Education_Level, Gender và tính các chỉ số. Dòng 21-38: Vẽ biểu đồ nhiệt (heatmap): Trục x: Education_Level, trục y: experience_group, màu ô: luong_trung_binh, vẽ ô màu, viền trắng, độ dày 0.5. Thêm nhãn hiển thị lương trung bình và số nhân viên, tách theo giới tính, 2 cột.Thêm tiêu đề, phụ đề, nhãn trục x/y. Dùng font Times New Roman, tiêu đề in đậm, căn giữa, xoay nhãn trục x 45°, nhãn facet in đậm.

Nhận xét: mặc dù trình độ học vấn và kinh nghiệm là yếu tố chung quyết định mức lương, nhóm giới tính Other đang được trả lương trung bình cao hơn đáng kể so với Female và Male, đặc biệt là ở những vị trí yêu cầu trình độ học vấn cao.

CHƯƠNG 2: PHÂN TÍCH DỮ LIỆU MÃ CHỨNG KHOÁN DBC

Mục tiêu chính là phân tích cấu trúc và biến động nguồn vốn của Công ty CP Tập đoàn Dabaco Việt Nam thông qua dữ liệu từ bảng cân đối kế toán trong giai đoạn nghiên cứu từ năm 2015 - 2024. Cụ thể, bài tiểu luận tập trung vào hai nhóm chỉ tiêu chính của Nguồn Vốn, bao gồm: Nợ phải trả và Vốn chủ sở hữu.

I. GIỚI THIỆU BỘ DỮ LIỆU

1. Đọc dữ liệu

dataDBC <- read_excel("dataDBC.xlsx")

Lệnh đọc dữ liệu từ file dataDBC.

2. Xem qua dữ liệu

head(dataDBC)
## # A tibble: 6 × 18
##     Năm `NỢ PHẢI TRẢ` `Nợ ngắn hạn` `Phải trả người bán ngắn hạn`
##   <dbl>         <dbl>         <dbl>                         <dbl>
## 1  2024 7355476127696 6420694102809                  762647490938
## 2  2023 8345469400426 7141605465752                  795600820770
## 3  2022 8332876258119 7213028754790                 2129218054781
## 4  2021 6176631172021 5171698802616                 1392462971688
## 5  2020 5894311104553 4254585526684                 1012195989287
## 6  2019 6565967444140 4819677610567                  911471772009
## # ℹ 14 more variables: `Người mua trả tiền trước ngắn hạn` <dbl>,
## #   `Thuế và các khoản phải nộp Nhà nước` <dbl>,
## #   `Phải trả người lao động` <dbl>, `Chi phí phải trả ngắn hạn` <dbl>,
## #   `Phải trả ngắn hạn khác` <dbl>, `Vay và nợ thuê tài chính ngắn hạn` <dbl>,
## #   `Quỹ khen thưởng, phúc lợi` <dbl>, `Nợ dài hạn` <dbl>,
## #   `VỐN CHỦ SỞ HỮU` <dbl>, `Vốn góp của chủ sở hữu` <dbl>,
## #   `Thặng dư vốn cổ phần` <dbl>, `Quỹ đầu tư phát triển` <dbl>, …

Sử dụng lệnh này hiển thị 6 dòng đầu để xác định có đọc đúng và dữ liệu có bị lệch dòng, lệch cột hay không.

3. Số dòng và số cột

dim(dataDBC)
## [1] 10 18

Lệnh dùng để xác định kích thước của bảng dữ liệu.

Kết quả cho thấy: 10 18 nghĩa là bảng dataDBC có 10 hàng (quan sát) và 18 cột (biến). Đây là bước kiểm tra cơ bản, đảm bảo dữ liệu đã được đọc đúng và có đủ số lượng biến cần phân tích.

4. Kiểm tra tên các biến

names(dataDBC)
##  [1] "Năm"                                 "NỢ PHẢI TRẢ"                        
##  [3] "Nợ ngắn hạn"                         "Phải trả người bán ngắn hạn"        
##  [5] "Người mua trả tiền trước ngắn hạn"   "Thuế và các khoản phải nộp Nhà nước"
##  [7] "Phải trả người lao động"             "Chi phí phải trả ngắn hạn"          
##  [9] "Phải trả ngắn hạn khác"              "Vay và nợ thuê tài chính ngắn hạn"  
## [11] "Quỹ khen thưởng, phúc lợi"           "Nợ dài hạn"                         
## [13] "VỐN CHỦ SỞ HỮU"                      "Vốn góp của chủ sở hữu"             
## [15] "Thặng dư vốn cổ phần"                "Quỹ đầu tư phát triển"              
## [17] "Lợi nhuận sau thuế chưa phân phối"   "TỔNG CỘNG NGUỒN VỐN"
dataDBC <- clean_names(dataDBC)

Dòng 1 và 2 giúp người dùng kiểm tra nhanh toàn bộ cấu trúc tên biến trong bảng dữ liệu và chuẩn hóa tên cột. Kết quả dữ liệu cho thấy gồm 18 biến mô tả cấu trúc nguồn vốn của doanh nghiệp.

5. Xác định phạm vi thời gian

nam_bat_dau <- min(dataDBC$nam, na.rm = TRUE)
nam_ket_thuc <- max(dataDBC$nam, na.rm = TRUE)
cat("Phạm vi thời gian của bộ dữ liệu từ năm", nam_bat_dau, "đến năm", nam_ket_thuc, "\n")
## Phạm vi thời gian của bộ dữ liệu từ năm 2015 đến năm 2024

Dòng 1 và 2 xác định năm sớm nhất và năm muộn nhất trong cột “nam”

Bộ dữ liệu bao gồm 10 năm liên tiếp (2015–2024). Điều này cho phép quan sát xu hướng biến động dài hạn của các khoản nợ phải trả, vốn chủ sở hữu, và tổng nguồn vốn.

6. Phân loại biến theo nhóm

phan_loai_bien <- data.frame(
  Nhom = c(
    rep("NỢ PHẢI TRẢ", 1),
    rep("NỢ PHẢI TRẢ - NỢ NGẮN HẠN", 7),
    rep("NỢ PHẢI TRẢ - NỢ DÀI HẠN", 1),
    rep("VỐN CHỦ SỞ HỮU", 5),
    "NGUỒN VỐN"
  ),
  Bien = c(
    "Nợ Phải Trả",
    "Nợ Ngắn Hạn",
    "Phải Trả Người Bán Ngắn Hạn",
    "Người Mua Trả Tiền Trước Ngắn Hạn",
    "Thuế Và Các Khoản Phải Nộp Nhà Nước",
    "Phải Trả Người Lao Động",
    "Chi Phí Phải Trả Ngắn Hạn",
    "Phải Trả Ngắn Hạn Khác",
    "Nợ Dài Hạn",
    "Vốn Chủ Sở Hữu",
    "Vốn Góp Của Chủ Sở Hữu",
    "Thặng Dư Vốn Cổ Phần",
    "Quỹ Đầu Tư Phát Triển",
    "Lợi Nhuận Sau Thuế Chưa Phân Phối",
    "Tổng Cộng Nguồn Vốn"
  )
)
print(phan_loai_bien)
##                         Nhom                                Bien
## 1                NỢ PHẢI TRẢ                         Nợ Phải Trả
## 2  NỢ PHẢI TRẢ - NỢ NGẮN HẠN                         Nợ Ngắn Hạn
## 3  NỢ PHẢI TRẢ - NỢ NGẮN HẠN         Phải Trả Người Bán Ngắn Hạn
## 4  NỢ PHẢI TRẢ - NỢ NGẮN HẠN   Người Mua Trả Tiền Trước Ngắn Hạn
## 5  NỢ PHẢI TRẢ - NỢ NGẮN HẠN Thuế Và Các Khoản Phải Nộp Nhà Nước
## 6  NỢ PHẢI TRẢ - NỢ NGẮN HẠN             Phải Trả Người Lao Động
## 7  NỢ PHẢI TRẢ - NỢ NGẮN HẠN           Chi Phí Phải Trả Ngắn Hạn
## 8  NỢ PHẢI TRẢ - NỢ NGẮN HẠN              Phải Trả Ngắn Hạn Khác
## 9   NỢ PHẢI TRẢ - NỢ DÀI HẠN                          Nợ Dài Hạn
## 10            VỐN CHỦ SỞ HỮU                      Vốn Chủ Sở Hữu
## 11            VỐN CHỦ SỞ HỮU              Vốn Góp Của Chủ Sở Hữu
## 12            VỐN CHỦ SỞ HỮU                Thặng Dư Vốn Cổ Phần
## 13            VỐN CHỦ SỞ HỮU               Quỹ Đầu Tư Phát Triển
## 14            VỐN CHỦ SỞ HỮU   Lợi Nhuận Sau Thuế Chưa Phân Phối
## 15                 NGUỒN VỐN                 Tổng Cộng Nguồn Vốn

Dòng 1 giúp tạo bảng phan_loai_bien sẽ có 2 cột: Nhom: nhóm phân loại chính (bài báo cáo này phân tích Nguồn vốn của doanh nghiệp gồm 2 chỉ tiêu chính: Nợ phải trả và Vốn chủ sở hữu) và Bien: tên biến tương ứng trong dữ liệu

7. Cấu trúc dữ liệu

str(dataDBC)
## tibble [10 × 18] (S3: tbl_df/tbl/data.frame)
##  $ nam                                : num [1:10] 2024 2023 2022 2021 2020 ...
##  $ no_phai_tra                        : num [1:10] 7.36e+12 8.35e+12 8.33e+12 6.18e+12 5.89e+12 ...
##  $ no_ngan_han                        : num [1:10] 6.42e+12 7.14e+12 7.21e+12 5.17e+12 4.25e+12 ...
##  $ phai_tra_nguoi_ban_ngan_han        : num [1:10] 7.63e+11 7.96e+11 2.13e+12 1.39e+12 1.01e+12 ...
##  $ nguoi_mua_tra_tien_truoc_ngan_han  : num [1:10] 2.07e+11 2.21e+11 8.87e+11 5.88e+11 5.52e+11 ...
##  $ thue_va_cac_khoan_phai_nop_nha_nuoc: num [1:10] 1.00e+11 3.25e+10 4.54e+10 7.96e+10 1.39e+11 ...
##  $ phai_tra_nguoi_lao_dong            : num [1:10] 8.63e+10 7.63e+10 6.49e+10 1.09e+11 1.07e+11 ...
##  $ chi_phi_phai_tra_ngan_han          : num [1:10] 5.31e+10 1.04e+11 6.45e+10 7.65e+10 6.35e+10 ...
##  $ phai_tra_ngan_han_khac             : num [1:10] 2.69e+11 1.04e+12 2.21e+11 2.38e+11 2.00e+11 ...
##  $ vay_va_no_thue_tai_chinh_ngan_han  : num [1:10] 4.93e+12 4.84e+12 3.70e+12 2.60e+12 2.16e+12 ...
##  $ quy_khen_thuong_phuc_loi           : num [1:10] 1.35e+10 3.34e+10 9.55e+10 8.97e+10 2.21e+10 ...
##  $ no_dai_han                         : num [1:10] 9.35e+11 1.20e+12 1.12e+12 1.00e+12 1.64e+12 ...
##  $ von_chu_so_huu                     : num [1:10] 6.77e+12 4.67e+12 4.64e+12 4.69e+12 4.21e+12 ...
##  $ von_gop_cua_chu_so_huu             : num [1:10] 3.35e+12 2.42e+12 2.42e+12 1.15e+12 1.05e+12 ...
##  $ thang_du_von_co_phan               : num [1:10] 8.22e+11 4.18e+11 4.18e+11 4.18e+11 4.18e+11 ...
##  $ quy_dau_tu_phat_trien              : num [1:10] 1.82e+12 1.80e+12 1.79e+12 2.52e+12 1.50e+12 ...
##  $ loi_nhuan_sau_thue_chua_phan_phoi  : num [1:10] 7.72e+11 2.79e+10 8.10e+09 5.95e+11 1.24e+12 ...
##  $ tong_cong_nguon_von                : num [1:10] 1.41e+13 1.30e+13 1.30e+13 1.09e+13 1.01e+13 ...

Dòng 1 giúp mô tả cấu trúc dữ liệu tài chính: Là tibble(bảng dữ liệu) có 10 dòng × 18 cột. Từ kết quả cho thấy các biến đều là kiểu dữ liệu số (numeric). Mỗi biến biểu diễn một chỉ tiêu trong phần “Nguồn vốn” của bảng cân đối kế toán.

8. Ý nghĩa các biến

Bộ dữ liệu được thu thập từ Báo cáo tài chính hợp nhất của Công ty Cổ phần Tập đoàn Dabaco Việt Nam (mã chứng khoán: DBC) giai đoạn 2015–2024, bao gồm 18 biến phản ánh cơ cấu Nguồn vốn. Các biến được chia thành 2 nhóm chính: Nợ phải trả và Vốn chủ sở hữu. Ý nghĩa chi tiết của từng biến được trình bày trong bảng dưới đây.

giai_thich_bien <- data.frame(
  Bien = names(dataDBC),
  Y_nghia = c(
    "Năm tài chính",
    "Tổng nợ phải trả",
    "Nợ ngắn hạn (<1 năm)",
    "Phải trả nhà cung cấp ngắn hạn",
    "Khách hàng trả trước ngắn hạn",
    "Thuế & các khoản nộp Nhà nước",
    "Phải trả người lao động",
    "Chi phí phải trả ngắn hạn",
    "Các khoản phải trả khác",
    "Vay & nợ thuê tài chính ngắn hạn",
    "Quỹ khen thưởng & phúc lợi",
    "Nợ dài hạn (>1 năm)",
    "Tổng vốn chủ sở hữu",
    "Vốn góp của chủ sở hữu",
    "Thặng dư vốn cổ phần",
    "Quỹ đầu tư phát triển",
    "Lợi nhuận sau thuế chưa phân phối",
    "Tổng nguồn vốn"
  )
)

# --- Tạo bảng PDF đẹp ---
giai_thich_bien %>%
  kable("latex", booktabs = TRUE, longtable = TRUE, 
        caption = "Bảng giải thích các biến trong dữ liệu") %>%
  kable_styling(latex_options = c("striped", "repeat_header"), 
                full_width = FALSE, font_size = 10) %>%
  column_spec(1, width = "6cm") %>%
  column_spec(2, width = "8cm")

Dòng 1 tạo bảng dữ liệu giai_thich_bien gồm hai cột: Bien và Y_nghia. Dòng 23 chuyển bảng sang định dạng LaTeX, giúp xuất bảng đẹp trong file PDF. Dòng 24–26 định dạng bảng: tạo nền xen kẽ, lặp lại tiêu đề khi sang trang mới, giữ độ rộng hợp lý và chỉnh cỡ chữ 10. Dòng 27 đặt độ rộng cột Bien là 4cm để tên biến gọn gàng. Dòng 28 đặt độ rộng cột Y_nghia là 10cm giúp mô tả hiển thị rõ ràng.

9. Đánh giá sơ bộ các chỉ tiêu chính

# PHÂN TÍCH XU HƯỚNG 3 CHỈ TIÊU CHÍNH (2015–2024)

# 1. Tổng NỢ PHẢI TRẢ
cat("Xu hướng tổng NỢ PHẢI TRẢ (2015–2024):\n")
## Xu hướng tổng NỢ PHẢI TRẢ (2015–2024):
liabilities_trend <- dataDBC %>%
  arrange(nam) %>%
  select(nam, no_phai_tra)

for (i in 1:nrow(liabilities_trend)) {
  year <- liabilities_trend$nam[i]
  value <- liabilities_trend$no_phai_tra[i]
  cat("  ", year, ": ", format(value, big.mark = ",", scientific = FALSE), "\n", sep = "")
}
##   2015: 2,668,763,190,851
##   2016: 3,190,129,918,957
##   2017: 4,486,599,351,977
##   2018: 5,603,485,031,551
##   2019: 6,565,967,444,140
##   2020: 5,894,311,104,553
##   2021: 6,176,631,172,021
##   2022: 8,332,876,258,119
##   2023: 8,345,469,400,426
##   2024: 7,355,476,127,696
trend_direction_liab <- ifelse(tail(liabilities_trend$no_phai_tra, 1) > head(liabilities_trend$no_phai_tra, 1),
                               "Tăng", "Giảm")
cat("\nNhận xét tổng quan: Xu hướng tổng NỢ PHẢI TRẢ là", trend_direction_liab, "qua giai đoạn 2015–2024.\n\n")
## 
## Nhận xét tổng quan: Xu hướng tổng NỢ PHẢI TRẢ là Tăng qua giai đoạn 2015–2024.
# 2. VỐN CHỦ SỞ HỮU
cat("Xu hướng VỐN CHỦ SỞ HỮU (2015–2024):\n")
## Xu hướng VỐN CHỦ SỞ HỮU (2015–2024):
equity_trend <- dataDBC %>%
  arrange(nam) %>%
  select(nam, von_chu_so_huu)

for (i in 1:nrow(equity_trend)) {
  year <- equity_trend$nam[i]
  value <- equity_trend$von_chu_so_huu[i]
  cat("  ", year, ": ", format(value, big.mark = ",", scientific = FALSE), "\n", sep = "")
}
##   2015: 1,946,447,536,231
##   2016: 2,339,141,904,502
##   2017: 2,502,616,605,237
##   2018: 2,746,528,417,636
##   2019: 3,025,957,478,860
##   2020: 4,206,960,190,688
##   2021: 4,685,923,120,134
##   2022: 4,641,227,653,231
##   2023: 4,666,234,857,446
##   2024: 6,766,079,699,901
trend_direction_equity <- ifelse(tail(equity_trend$von_chu_so_huu, 1) > head(equity_trend$von_chu_so_huu, 1),
                                 "Tăng", "Giảm")
cat("\nNhận xét tổng quan: Xu hướng VỐN CHỦ SỞ HỮU là", trend_direction_equity, "qua giai đoạn 2015–2024.\n\n")
## 
## Nhận xét tổng quan: Xu hướng VỐN CHỦ SỞ HỮU là Tăng qua giai đoạn 2015–2024.
# 3. TỔNG CỘNG NGUỒN VỐN
cat("Xu hướng TỔNG CỘNG NGUỒN VỐN (2015–2024):\n")
## Xu hướng TỔNG CỘNG NGUỒN VỐN (2015–2024):
total_capital_trend <- dataDBC %>%
  arrange(nam) %>%
  select(nam, tong_cong_nguon_von)

for (i in 1:nrow(total_capital_trend)) {
  year <- total_capital_trend$nam[i]
  value <- total_capital_trend$tong_cong_nguon_von[i]
  cat("  ", year, ": ", format(value, big.mark = ",", scientific = FALSE), "\n", sep = "")
}
##   2015: 4,615,210,727,082
##   2016: 5,529,271,823,459
##   2017: 6,989,215,957,214
##   2018: 8,350,013,449,187
##   2019: 9,591,924,923,000
##   2020: 10,101,271,295,241
##   2021: 10,862,564,292,155
##   2022: 12,974,103,921,350
##   2023: 13,011,704,257,872
##   2024: 14,121,555,827,597
trend_direction_total <- ifelse(tail(total_capital_trend$tong_cong_nguon_von, 1) > head(total_capital_trend$tong_cong_nguon_von, 1),
                                "Tăng", "Giảm")
cat("\nNhận xét tổng quan: Xu hướng TỔNG CỘNG NGUỒN VỐN là", trend_direction_total, "qua giai đoạn 2015–2024.\n")
## 
## Nhận xét tổng quan: Xu hướng TỔNG CỘNG NGUỒN VỐN là Tăng qua giai đoạn 2015–2024.

10. Đánh giá các chỉ tiêu chính qua biểu đồ

dataDBC %>%
  select(nam, no_phai_tra, von_chu_so_huu, tong_cong_nguon_von) %>%
  pivot_longer(-nam, names_to = "Chi_tieu", values_to = "Gia_tri") %>%
  mutate(nam = as.factor(nam)) %>% 
  ggplot(aes(x = nam, y = Gia_tri, color = Chi_tieu, group = Chi_tieu)) +
  geom_line(linewidth = 1.2) +  
  geom_point(size = 2) +
  theme_minimal() +
  labs(
    title = "Xu hướng Nợ phải trả, Vốn chủ sở hữu và Tổng nguồn vốn (2015–2024)",
    x = "Năm",
    y = "Giá trị (tỷ VND)"
  )

Dòng 1 lọc các cột cần phân tích từ dataDBC, gồm: nam, no_phai_tra, von_chu_so_huu, tong_cong_nguon_von. Dòng 2 chuyển dữ liệu từ dạng rộng sang dài và tạo hai cột mới: Chi_tieu và Gia_tri. Dòng 3 chuyển nam sang dạng factor để hiển thị theo thứ tự rời rạc trên trục x. Dòng 4 khởi tạo biểu đồ với trục x là nam, trục y là Gia_tri, phân nhóm và tô màu theo Chi_tieu. Dòng 5–6 vẽ đường xu hướng rõ nét giữa các năm và thêm các điểm dữ liệu để dễ nhận diện từng năm. Dòng 8–11 thêm tiêu đề, nhãn trục x–y để mô tả rõ nội dung.

Nhận xét: Biểu đồ cho thấy doanh nghiệp cả 3 chỉ tiêu (nợ phải trả, vốn chủ sở hữu và tổng nguồn vốn) có xu hướng tăng qua các năm.

II. XỬ LÝ DỮ LIỆU

1. Xử lý tên biến

dataDBC <- clean_names(dataDBC)

Dòng 1 loại bỏ dấu và khoảng trắng có trong biến để trong quá trình gọi biến trong code không bị lỗi.

2. Chuyển đổi biến Năm từ dạng num qua dạng date

dataDBC$nam <- as.numeric(as.character(dataDBC$nam))
str(dataDBC$nam)
##  num [1:10] 2024 2023 2022 2021 2020 ...

Dòng 1 chuyển cột nam từ factor (hoặc character) sang số (numeric). Dòng 2 kiểm tra cấu trúc của biến nam sau khi chuyển đổi.

3. Kiểm tra số quan sát bị thiếu

so_thieu <- sum(is.na(dataDBC))
print(so_thieu)
## [1] 0

Dòng 1 và 2 kiểm tra số quan sát bị thiếu và in kết quả.

4. Kiểm tra số quan sát trùng lặp

so_trung_lap <- sum(duplicated(dataDBC))
print(so_trung_lap)
## [1] 0

Dòng 1 và 2 kiểm tra số quan sát trùng lặp và in kết quả.

5. Bảng tổng hợp thông tin cơ bản

so_bien <- ncol(dataDBC)
so_quan_sat <- nrow(dataDBC)
so_trung_lap <- sum(duplicated(dataDBC))
so_thieu <- sum(is.na(dataDBC))
ty_le_thieu <- round(so_thieu / (so_bien * so_quan_sat) * 100, 2)

thong_tin_co_ban <- data.frame(
Chi_tieu = c(
"Số biến (cột)",
"Số quan sát (dòng)",
"Số quan sát trùng lặp",
"Số quan sát bị thiếu",
"Tỷ lệ quan sát bị thiếu (%)"
),
Gia_tri = c(so_bien, so_quan_sat, so_trung_lap, so_thieu, ty_le_thieu)
)
print(thong_tin_co_ban)
##                      Chi_tieu Gia_tri
## 1               Số biến (cột)      18
## 2          Số quan sát (dòng)      10
## 3       Số quan sát trùng lặp       0
## 4        Số quan sát bị thiếu       0
## 5 Tỷ lệ quan sát bị thiếu (%)       0

Dòng 1–2 xác định kích thước dữ liệu — số biến (cột) và quan sát (dòng) trong bảng dataDBC. Dòng 3 tính số quan sát trùng lặp trong dữ liệu. Dòng 4 đếm tổng số giá trị bị thiếu (NA). Dòng 5 tính tỷ lệ phần trăm giá trị thiếu so với tổng số ô dữ liệu. Dòng 7–13 tạo bảng tóm tắt thông tin cơ bản gồm các chỉ tiêu và giá trị tương ứng để mô tả tổng quan chất lượng dữ liệu.

Kết quả cho thấy số quan sát trùng lặp và số quan sát bị thiếu đều là 0, do đó tỉ lệ quan sát bị thiếu là không có.

6. Kiểm tra và xử lý giá trị ngoại lai

bien <- c("no_phai_tra", "von_chu_so_huu", "tong_cong_nguon_von")
data_long <- dataDBC %>%
  select(all_of(bien)) %>%
  pivot_longer(cols = everything(), names_to = "Bien", values_to = "GiaTri")

ggplot(data_long, aes(x = Bien, y = GiaTri, fill = Bien)) +
  geom_boxplot(alpha = 0.6) +
  labs(title = "Kiểm tra ngoại lai cho các biến",
       x = "Biến",
       y = "Giá trị") +
  theme_minimal() +
  theme(legend.position = "none",
        plot.title = element_text(face = "bold", hjust = 0.5))

Dòng 1 xác định các biến quan tâm để kiểm tra ngoại lai. Dòng 2–4 chọn các biến từ dữ liệu và chuyển sang dạng dài. Dòng 6–8 vẽ boxplot hiển thị phân bố giá trị theo từng biến, màu theo biến, độ trong suốt alpha = 0.6. Dòng 9–11 thêm tiêu đề và nhãn trục cho biểu đồ. Dòng 12–14 theme tối giản, ẩn legend, căn giữa và in đậm tiêu đề.

Nhận xét: Nợ phải trả không có điểm ngoại lai. Dữ liệu phân bố đều, trung vị nằm giữa hộp, biến động ổn định qua các năm. Vốn chủ sở hữu không có ngoại lai. Giá trị dao động vừa phải (khoảng 2.000–6.700 tỷ đồng), trung vị khoảng 3.600–3.800, phân bố cân đối, tăng trưởng ổn định. Tổng cộng nguồn vốn không có điểm ngoại lai. Phân bố cân đối, trung vị nằm giữa hộp, giá trị dao động từ ~6.000 đến 13.000 tỷ đồng, biến động ổn định qua các năm.

7. Chuẩn hóa đơn vị

dataDBC <- dataDBC %>%
mutate(across(
.cols = -nam,
.fns = ~ round(.x / 1e9, 3)
))
head(dataDBC)
## # A tibble: 6 × 18
##     nam no_phai_tra no_ngan_han phai_tra_nguoi_ban_ngan…¹ nguoi_mua_tra_tien_t…²
##   <dbl>       <dbl>       <dbl>                     <dbl>                  <dbl>
## 1  2024       7355.       6421.                      763.                   207.
## 2  2023       8345.       7142.                      796.                   221.
## 3  2022       8333.       7213.                     2129.                   887.
## 4  2021       6177.       5172.                     1392.                   588.
## 5  2020       5894.       4255.                     1012.                   552.
## 6  2019       6566.       4820.                      911.                   410.
## # ℹ abbreviated names: ¹​phai_tra_nguoi_ban_ngan_han,
## #   ²​nguoi_mua_tra_tien_truoc_ngan_han
## # ℹ 13 more variables: thue_va_cac_khoan_phai_nop_nha_nuoc <dbl>,
## #   phai_tra_nguoi_lao_dong <dbl>, chi_phi_phai_tra_ngan_han <dbl>,
## #   phai_tra_ngan_han_khac <dbl>, vay_va_no_thue_tai_chinh_ngan_han <dbl>,
## #   quy_khen_thuong_phuc_loi <dbl>, no_dai_han <dbl>, von_chu_so_huu <dbl>,
## #   von_gop_cua_chu_so_huu <dbl>, thang_du_von_co_phan <dbl>, …

Dòng 1 bắt đầu thao tác với dataDBC dùng mutate để thay đổi giá trị các cột. Dòng 2–4 áp dụng cho tất cả cột trừ nam, chia giá trị cho 1 tỷ và làm tròn 3 chữ số thập phân. Dòng 5 hiển thị 6 dòng đầu của dữ liệu sau khi đã xử lý.

Mục đích: Chia các cột số (ngoại trừ date) cho 1 tỷ, làm tròn 3 chữ số, giúp số liệu dễ đọc.

8. Sắp xếp theo thời gian

dataDBC <- dataDBC[order(dataDBC$nam), ]
head(dataDBC)
## # A tibble: 6 × 18
##     nam no_phai_tra no_ngan_han phai_tra_nguoi_ban_ngan…¹ nguoi_mua_tra_tien_t…²
##   <dbl>       <dbl>       <dbl>                     <dbl>                  <dbl>
## 1  2015       2669.       2411.                      534.                   94.5
## 2  2016       3190.       2630.                      318.                  147. 
## 3  2017       4487.       3462.                      564.                  132. 
## 4  2018       5603.       4075.                      923.                  207. 
## 5  2019       6566.       4820.                      911.                  410. 
## 6  2020       5894.       4255.                     1012.                  552. 
## # ℹ abbreviated names: ¹​phai_tra_nguoi_ban_ngan_han,
## #   ²​nguoi_mua_tra_tien_truoc_ngan_han
## # ℹ 13 more variables: thue_va_cac_khoan_phai_nop_nha_nuoc <dbl>,
## #   phai_tra_nguoi_lao_dong <dbl>, chi_phi_phai_tra_ngan_han <dbl>,
## #   phai_tra_ngan_han_khac <dbl>, vay_va_no_thue_tai_chinh_ngan_han <dbl>,
## #   quy_khen_thuong_phuc_loi <dbl>, no_dai_han <dbl>, von_chu_so_huu <dbl>,
## #   von_gop_cua_chu_so_huu <dbl>, thang_du_von_co_phan <dbl>, …

Dữ liệu được sắp xếp từ năm 2015 đến năm 2024.

9. Đặt nhãn cho các biến (Label encoding)

labels <- c(
  no_phai_tra = "Nợ phải trả",
  no_ngan_han = "Nợ ngắn hạn",
  phai_tra_nguoi_ban_ngan_han = "Phải trả người bán NH",
  nguoi_mua_tra_tien_truoc_ngan_han = "Người mua trả tiền trước NH",
  thue_va_cac_khoan_phai_nop_nha_nuoc = "Thuế và khoản nộp NN",
  phai_tra_nguoi_lao_dong = "Phải trả NLĐ",
  chi_phi_phai_tra_ngan_han = "Chi phí phải trả NH",
  phai_tra_ngan_han_khac = "Phải trả NH khác",
  vay_va_no_thue_tai_chinh_ngan_han = "Vay và nợ thuê TC NH",
  quy_khen_thuong_phuc_loi = "Quỹ KTPL",
  no_dai_han = "Nợ dài hạn",
  von_chu_so_huu = "Vốn chủ sở hữu",
  von_gop_cua_chu_so_huu = "Vốn góp CSH",
  thang_du_von_co_phan = "Thặng dư VCP",
  quy_dau_tu_phat_trien = "Quỹ ĐTPT",
  loi_nhuan_sau_thue_chua_phan_phoi = "LNST chưa PP",
  tong_cong_nguon_von = "Tổng nguồn vốn"
)
attr(dataDBC, "variable_labels") <- labels

Dòng 1 tạo vector đặt nhãn tiếng Việt cho từng biến trong dữ liệu, gán tên biến làm tên phần tử và giá trị là nhãn hiển thị. Dòng 20 gán vector labels làm thuộc tính variable_labels cho dataDBC.

10. Tạo biến hệ số nợ trên vốn chủ sở hữu

dataDBC <- dataDBC %>%
  mutate(
    he_so_no_von = round(no_phai_tra / von_chu_so_huu, 3))

Dòng 1 bắt đầu thao tác với dataDBC dùng mutate để tạo biến mới. Dòng 2 tạo biến he_so_no_von bằng cách lấy Nợ phải trả chia cho Vốn chủ sở hữu, làm tròn 3 chữ số thập phân.

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

1. Thống kê mô tả cơ bản

describe(dataDBC[ , !names(dataDBC) %in% c("nam")])
## dataDBC[, !names(dataDBC) %in% c("nam")] 
## 
##  18  Variables      10  Observations
## --------------------------------------------------------------------------------
## no_phai_tra 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1     5862     5894     2325     2903 
##      .10      .25      .50      .75      .90      .95 
##     3138     4766     6035     7158     8334     8340 
##                                                                          
## Value      2668.763 3190.130 4486.599 5603.485 5894.311 6176.631 6565.967
## Frequency         1        1        1        1        1        1        1
## Proportion      0.1      0.1      0.1      0.1      0.1      0.1      0.1
##                                      
## Value      7355.476 8332.876 8345.469
## Frequency         1        1        1
## Proportion      0.1      0.1      0.1
## --------------------------------------------------------------------------------
## no_ngan_han 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1     4760     4776     2077     2509 
##      .10      .25      .50      .75      .90      .95 
##     2608     3616     4537     6108     7149     7181 
##                                                                          
## Value      2410.964 2629.727 3462.415 4075.303 4254.586 4819.678 5171.699
## Frequency         1        1        1        1        1        1        1
## Proportion      0.1      0.1      0.1      0.1      0.1      0.1      0.1
##                                      
## Value      6420.694 7141.605 7213.029
## Frequency         1        1        1
## Proportion      0.1      0.1      0.1
## --------------------------------------------------------------------------------
## phai_tra_nguoi_ban_ngan_han 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1    934.3    855.5    558.8    415.4 
##      .10      .25      .50      .75      .90      .95 
##    512.3    613.8    853.5    989.9   1466.1   1797.7 
##                                                                          
## Value       318.466  533.869  564.134  762.647  795.601  911.472  923.066
## Frequency         1        1        1        1        1        1        1
## Proportion      0.1      0.1      0.1      0.1      0.1      0.1      0.1
##                                      
## Value      1012.196 1392.463 2129.218
## Frequency         1        1        1
## Proportion      0.1      0.1      0.1
## --------------------------------------------------------------------------------
## nguoi_mua_tra_tien_truoc_ngan_han 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1    344.6    323.1    288.3    111.5 
##      .10      .25      .50      .75      .90      .95 
##    128.5    161.8    214.4    516.2    617.8    752.7 
##                                                                           
## Value       94.493 132.251 146.773 207.002 207.418 221.365 409.519 551.700
## Frequency        1       1       1       1       1       1       1       1
## Proportion     0.1     0.1     0.1     0.1     0.1     0.1     0.1     0.1
##                           
## Value      587.883 887.481
## Frequency        1       1
## Proportion     0.1     0.1
## --------------------------------------------------------------------------------
## thue_va_cac_khoan_phai_nop_nha_nuoc 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1    58.11    54.11    43.34    22.20 
##      .10      .25      .50      .75      .90      .95 
##    27.45    30.81    44.27    75.93   104.17   121.82 
##                                                                           
## Value       16.947  28.616  30.261  32.466  43.162  45.386  64.929  79.595
## Frequency        1       1       1       1       1       1       1       1
## Proportion     0.1     0.1     0.1     0.1     0.1     0.1     0.1     0.1
##                           
## Value      100.251 139.469
## Frequency        1       1
## Proportion     0.1     0.1
## --------------------------------------------------------------------------------
## phai_tra_nguoi_lao_dong 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1    72.03    70.59    27.13    43.14 
##      .10      .25      .50      .75      .90      .95 
##    49.96    60.00    66.43    83.78   107.37   107.95 
##                                                                           
## Value       36.330  51.473  59.356  61.933  64.859  68.009  76.319  86.273
## Frequency        1       1       1       1       1       1       1       1
## Proportion     0.1     0.1     0.1     0.1     0.1     0.1     0.1     0.1
##                           
## Value      107.242 108.528
## Frequency        1       1
## Proportion     0.1     0.1
## --------------------------------------------------------------------------------
## chi_phi_phai_tra_ngan_han 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1       68    66.55    30.19    36.05 
##      .10      .25      .50      .75      .90      .95 
##    43.37    50.88    64.01    89.02   101.27   102.82 
##                                                                           
## Value       28.732  44.993  50.130  53.127  63.514  64.514  76.535  93.182
## Frequency        1       1       1       1       1       1       1       1
## Proportion     0.1     0.1     0.1     0.1     0.1     0.1     0.1     0.1
##                           
## Value      100.928 104.359
## Frequency        1       1
## Proportion     0.1     0.1
## --------------------------------------------------------------------------------
## phai_tra_ngan_han_khac 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1    269.3      219    246.1    43.71 
##      .10      .25      .50      .75      .90      .95 
##    55.53   169.04   227.98   242.13   345.84   691.61 
##                                                                          
## Value        31.896   58.155  158.578  200.408  221.417  234.543  237.509
## Frequency         1        1        1        1        1        1        1
## Proportion      0.1      0.1      0.1      0.1      0.1      0.1      0.1
##                                      
## Value       243.673  268.999 1037.388
## Frequency         1        1        1
## Proportion      0.1      0.1      0.1
## --------------------------------------------------------------------------------
## vay_va_no_thue_tai_chinh_ngan_han 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1     2974     2919     1400     1622 
##      .10      .25      .50      .75      .90      .95 
##     1734     2192     2655     3588     4849     4889 
##                                                                          
## Value      1509.505 1758.905 2157.941 2293.804 2599.459 2710.567 3237.819
## Frequency         1        1        1        1        1        1        1
## Proportion      0.1      0.1      0.1      0.1      0.1      0.1      0.1
##                                      
## Value      3704.610 4840.721 4928.462
## Frequency         1        1        1
## Proportion      0.1      0.1      0.1
## --------------------------------------------------------------------------------
## quy_khen_thuong_phuc_loi 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1    39.49     32.6    33.15    13.91 
##      .10      .25      .50      .75      .90      .95 
##    14.31    18.03    27.75    45.49    90.30    92.92 
##                                                                          
## Value      13.516 14.398 17.639 19.195 22.115 33.387 43.089 46.293 89.716
## Frequency       1      1      1      1      1      1      1      1      1
## Proportion    0.1    0.1    0.1    0.1    0.1    0.1    0.1    0.1    0.1
##                  
## Value      95.533
## Frequency       1
## Proportion    0.1
## --------------------------------------------------------------------------------
## no_dai_han 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1     1102     1100    546.9    394.0 
##      .10      .25      .50      .75      .90      .95 
##    530.1    952.3   1072.0   1447.1   1650.4   1698.3 
##                                                                          
## Value       257.799  560.403  934.782 1004.932 1024.184 1119.848 1203.864
## Frequency         1        1        1        1        1        1        1
## Proportion      0.1      0.1      0.1      0.1      0.1      0.1      0.1
##                                      
## Value      1528.182 1639.726 1746.290
## Frequency         1        1        1
## Proportion      0.1      0.1      0.1
## --------------------------------------------------------------------------------
## von_chu_so_huu 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1     3753     3594     1722     2123 
##      .10      .25      .50      .75      .90      .95 
##     2300     2564     3616     4660     4894     5830 
##                                                                          
## Value      1946.448 2339.142 2502.617 2746.528 3025.957 4206.960 4641.228
## Frequency         1        1        1        1        1        1        1
## Proportion      0.1      0.1      0.1      0.1      0.1      0.1      0.1
##                                      
## Value      4666.235 4685.923 6766.080
## Frequency         1        1        1
## Proportion      0.1      0.1      0.1
## --------------------------------------------------------------------------------
## von_gop_cua_chu_so_huu 
##        n  missing distinct     Info     Mean  pMedian      Gmd 
##       10        0        9    0.994     1433     1152     1005 
##                                                                          
## Value       627.419  752.900  828.185  910.998 1047.639 1152.394 2420.017
## Frequency         1        1        2        1        1        1        1
## Proportion      0.1      0.1      0.2      0.1      0.1      0.1      0.1
##                             
## Value      2420.019 3346.691
## Frequency         1        1
## Proportion      0.1      0.1
## --------------------------------------------------------------------------------
## thang_du_von_co_phan 
##        n  missing distinct     Info     Mean 
##       10        0        2    0.273    458.7 
##                           
## Value      418.433 821.521
## Frequency        9       1
## Proportion     0.9     0.1
## --------------------------------------------------------------------------------
## quy_dau_tu_phat_trien 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1     1441     1429    664.3    712.4 
##      .10      .25      .50      .75      .90      .95 
##    745.7   1078.1   1423.0   1798.6   1894.4   2207.0 
##                                                                          
## Value       679.131  753.115 1057.575 1139.675 1348.360 1497.738 1794.677
## Frequency         1        1        1        1        1        1        1
## Proportion      0.1      0.1      0.1      0.1      0.1      0.1      0.1
##                                      
## Value      1799.871 1824.879 2519.656
## Frequency         1        1        1
## Proportion      0.1      0.1      0.1
## --------------------------------------------------------------------------------
## loi_nhuan_sau_thue_chua_phan_phoi 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1      419    381.4      420    17.01 
##      .10      .25      .50      .75      .90      .95 
##    25.93   204.18   354.20   550.25   819.10  1031.13 
##                                                                          
## Value         8.098   27.912  198.424  221.465  348.166  360.235  414.694
## Frequency         1        1        1        1        1        1        1
## Proportion      0.1      0.1      0.1      0.1      0.1      0.1      0.1
##                                      
## Value       595.440  771.988 1243.150
## Frequency         1        1        1
## Proportion      0.1      0.1      0.1
## --------------------------------------------------------------------------------
## tong_cong_nguon_von 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1     9615     9606     3909     5027 
##      .10      .25      .50      .75      .90      .95 
##     5438     7329     9847    12446    13123    13622 
##                                                                       
## Value       4615.211  5529.272  6989.216  8350.013  9591.925 10101.271
## Frequency          1         1         1         1         1         1
## Proportion       0.1       0.1       0.1       0.1       0.1       0.1
##                                                   
## Value      10862.564 12974.104 13011.704 14121.556
## Frequency          1         1         1         1
## Proportion       0.1       0.1       0.1       0.1
## --------------------------------------------------------------------------------
## he_so_no_von 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1    1.613    1.583   0.4135    1.191 
##      .10      .25      .50      .75      .90      .95 
##    1.295    1.366    1.595    1.794    2.053    2.111 
##                                                                       
## Value      1.087 1.318 1.364 1.371 1.401 1.788 1.793 1.795 2.040 2.170
## Frequency      1     1     1     1     1     1     1     1     1     1
## Proportion   0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1   0.1
## --------------------------------------------------------------------------------

Hàm này tóm tắt thống kê cơ bản của các cột dữ liệu.

2. Phân tích chi tiết xu hướng tổng nợ phải trả

dataDBC <- dataDBC %>% arrange(nam) %>% 
  mutate(nam = as.factor(nam))

ggplot(dataDBC, aes(x = nam, y = no_phai_tra, group = 1)) +
  geom_line(color = "#0072B2", size = 1.2) +             
  geom_point(color = "#D55E00", size = 3) +              
  geom_smooth(method = "lm", se = FALSE, color = "gray40", linetype = "dashed") +  
  theme_minimal(base_size = 13) +
  labs(title = "Xu hướng Tổng nợ phải trả qua các năm",
       x = "Năm",
       y = "Tổng nợ phải trả (Tỷ đồng)") +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5, size = 15),
    axis.title = element_text(face = "bold")
  )
## `geom_smooth()` using formula = 'y ~ x'

Dòng 1 sắp xếp dữ liệu theo nam và chuyển nam thành factor để biểu đồ trục x hiển thị tuần tự. Dòng 4 - 6 vẽ đường xu hướng của no_phai_tra theo năm và các điểm dữ liệu với màu sắc và kích thước tùy chỉnh. Dòng 7 thêm đường hồi quy tuyến tính dưới dạng đường đứt nét màu xám, không hiển thị khoảng tin cậy. Dòng 8 - 11 sử dụng theme tối giản và thêm tiêu đề, nhãn trục. Dòng 13 - 15 tùy chỉnh font in đậm cho tiêu đề, căn giữa tiêu đề, và in đậm nhãn trục.

Nhận xét xu hướng tổng nợ phải trả: 2015–2018: Nợ tăng mạnh do doanh nghiệp mở rộng quy mô (2.800 → 5.500 tỷ đồng). 2018–2020: Nợ tiếp tục tăng, đạt ~6.800 tỷ đồng năm 2019, sau đó giảm nhẹ (~5.900 tỷ đồng năm 2020) do tác động COVID-19. 2020–2023: Nợ tăng trở lại, đạt đỉnh >8.500 tỷ đồng năm 2022 và duy trì mức cao đến 2023, phản ánh sự phục hồi và mở rộng sau dịch.

3. Phân tích cơ cấu nợ

co_cau_no <- dataDBC %>%
  mutate(
    ty_trong_no_ngan_han = no_ngan_han / no_phai_tra * 100,
    ty_trong_no_dai_han  = no_dai_han  / no_phai_tra * 100,
    ty_le_no_tren_von    = no_phai_tra / tong_cong_nguon_von * 100
  )
co_cau_long <- co_cau_no %>%
  select(nam, ty_trong_no_ngan_han, ty_trong_no_dai_han) %>%
  pivot_longer(-nam, names_to = "Loai_no", values_to = "Ty_trong")

ggplot(co_cau_long, aes(x = factor(nam), y = Ty_trong, fill = Loai_no)) +
  geom_bar(stat = "identity", position = "stack") +
  labs(title = "Cơ cấu nợ qua các năm",
       x = "Năm", y = "Tỷ trọng (%)") +
  scale_fill_manual(values = c("#0073C2", "#E69F00"),
                    name = "Loại nợ",
                    labels = c("Nợ dài hạn", "Nợ ngắn hạn")) +
  theme_minimal(base_size = 13)

Dòng 1–6 tạo dữ liệu co_cau_no với các biến mới: ty_trong_no_ngan_han, ty_trong_no_dai_han, ty_le_no_tren_von. Dòng 7–10 chuyển dữ liệu sang dạng dài chỉ lấy năm và hai loại nợ, tạo cột Loai_no và Ty_trong. Dòng 12–18: Vẽ biểu đồ cột chồng gồm trục x là năm, trục y là tỷ trọng nợ, phân biệt nợ ngắn hạn và dài hạn. Dùng màu sắc tùy chỉnh và thêm nhãn cho legend. Sử dụng Theme tối giản, cỡ chữ cơ bản 13.

Nhận xét cơ cấu nợ: Nợ ngắn hạn chiếm ưu thế: Luôn duy trì 70–90% tổng nợ, chủ yếu phục vụ vốn lưu động và hoạt động ngắn hạn. Nợ dài hạn thấp và dao động nhẹ: Chiếm 10–30%, biến động ngược chiều nợ ngắn hạn. Cơ cấu nợ mất cân đối (nợ ngắn hạn chiếm tỷ trọng lớn) → rủi ro thanh toán cao hơn, đặc biệt nếu dòng tiền ngắn hạn bị gián đoạn. Tuy nhiên, chiến lược sử dụng nợ ngắn hạn cũng giúp doanh nghiệp tận dụng lãi suất thấp, tăng hiệu quả sử dụng vốn trong ngắn hạn.

4. Phân tích thành phần nợ ngắn hạn

co_cau_no_ngan_han <- dataDBC %>%
  mutate(
    tong_no_ngan_han = phai_tra_nguoi_ban_ngan_han +
                       nguoi_mua_tra_tien_truoc_ngan_han +
                       thue_va_cac_khoan_phai_nop_nha_nuoc +
                       phai_tra_nguoi_lao_dong +
                       chi_phi_phai_tra_ngan_han +
                       phai_tra_ngan_han_khac
  ) %>%
  select(nam, phai_tra_nguoi_ban_ngan_han, nguoi_mua_tra_tien_truoc_ngan_han,
         thue_va_cac_khoan_phai_nop_nha_nuoc, phai_tra_nguoi_lao_dong,
         chi_phi_phai_tra_ngan_han, phai_tra_ngan_han_khac, tong_no_ngan_han) %>%

  pivot_longer(
    cols = -c(nam, tong_no_ngan_han),
    names_to = "khoan_muc",
    values_to = "gia_tri"
  ) %>%
  
  mutate(
    ty_trong = gia_tri / tong_no_ngan_han * 100,
    khoan_muc = recode(khoan_muc,
                       phai_tra_nguoi_ban_ngan_han = "Phải trả người bán NH",
                       nguoi_mua_tra_tien_truoc_ngan_han = "Người mua trả tiền trước NH",
                       thue_va_cac_khoan_phai_nop_nha_nuoc = "Thuế và khoản nộp NN",
                       phai_tra_nguoi_lao_dong = "Phải trả NLĐ",
                       chi_phi_phai_tra_ngan_han = "Chi phí phải trả NH",
                       phai_tra_ngan_han_khac = "Phải trả NH khác")
  )
ggplot(co_cau_no_ngan_han, aes(x = nam, y = ty_trong, fill = khoan_muc)) +
  geom_bar(stat = "identity") +
  scale_fill_brewer(palette = "Set2") +
  labs(
    title = "Khoản mục trong Nợ ngắn hạn qua các năm",
    x = "Năm",
    y = "Tỷ trọng (%)",
    fill = "Khoản mục"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    legend.position = "right",
    axis.text.x = element_text(angle = 30, hjust = 1)
  )

Dòng 1–9 tạo biến tong_no_ngan_han là tổng các khoản mục nợ ngắn hạn, rồi chọn các cột liên quan để phân tích. Dòng 10–14 chuyển dữ liệu sang dạng dài với cột khoan_muc là tên khoản mục và gia_tri là giá trị tương ứng. Dòng 15–22 tạo cột ty_trong tính tỷ trọng mỗi khoản mục trên tổng nợ ngắn hạn, đồng thời đổi nhãn các khoản mục sang tiếng Việt dễ đọc bằng recode. Dòng 23–32 vẽ biểu đồ cột phân loại (stacked bar) gồm trục x là năm, trục y là tỷ trọng %. Màu sắc theo khoan_muc dùng palette Set2. Thêm tiêu đề, nhãn trục và nhãn legend. Sử dụng Theme tối giản, cỡ chữ 14, tiêu đề in đậm, căn giữa, legend bên phải, nghiêng trục x 30 độ.

Phân tích từng khoản mục:

Phải trả người bán NH (màu vàng): Luôn chiếm tỷ trọng lớn nhất qua các năm, đặc biệt nổi bật từ 2015 đến 2024. Điều này cho thấy doanh nghiệp phụ thuộc nhiều vào công nợ với nhà cung cấp, có thể là do chính sách thanh toán chậm hoặc quy mô mua hàng lớn.

Người mua trả tiền trước NH (màu hồng): Tỷ trọng tăng mạnh từ 2021 đến 2024. Đây là tín hiệu tích cực, phản ánh niềm tin của khách hàng và dòng tiền vào trước từ hoạt động kinh doanh.

Thuế và khoản nộp NN (màu xanh lá cây): Tỷ trọng ổn định.

Phải trả NLD (màu tím): Tỷ trọng khá nhỏ và ổn định, cho thấy chi phí nhân sự không phải là gánh nặng lớn trong nợ ngắn hạn.

Chi phí phải trả NH (màu cam): Biến động nhẹ qua các năm, nhưng không chiếm tỷ trọng lớn.

Phải trả NH khác (màu xanh dương): Xuất hiện không đều, có năm gần như không có. Điều này cho thấy doanh nghiệp ít phụ thuộc vào các khoản vay ngắn hạn từ ngân hàng khác.

Doanh nghiệp đang có xu hướng giảm phụ thuộc vào nhà cung cấp và tăng dòng tiền từ khách hàng, đây là dấu hiệu tích cực về quản trị tài chính. Nên tiếp tục duy trì sự cân bằng giữa các khoản mục để giảm rủi ro thanh khoản.

5. Phân tích cơ cấu Vốn chủ sở hữu

labels <- attr(dataDBC, "variable_labels")
co_cau_von_chu_so_huu <- dataDBC %>%
  mutate(
    tong_von_csh = von_gop_cua_chu_so_huu +
      thang_du_von_co_phan +
      quy_dau_tu_phat_trien +
      loi_nhuan_sau_thue_chua_phan_phoi
  ) %>%
  select(nam, von_gop_cua_chu_so_huu, thang_du_von_co_phan,
         quy_dau_tu_phat_trien, loi_nhuan_sau_thue_chua_phan_phoi, tong_von_csh) %>%
  pivot_longer(
    cols = -c(nam, tong_von_csh),
    names_to = "khoan_muc",
    values_to = "gia_tri"
  ) %>%
  mutate(
    ty_trong = gia_tri / tong_von_csh * 100,
    khoan_muc = labels[khoan_muc]
  )
ggplot(co_cau_von_chu_so_huu, aes(x = nam, y = ty_trong, fill = khoan_muc)) +
  geom_bar(stat = "identity") +
  scale_fill_brewer(palette = "Pastel1") +
  labs(
    title = "Cơ cấu vốn chủ sở hữu qua các năm",
    x = "Năm", y = "Tỷ trọng (%)",
    fill = "Khoản mục"
  ) +
  theme_minimal(base_size = 14, base_family = "Times New Roman") +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5),
    legend.position = "right"
  )

Dòng 1 lấy nhãn biến tiếng Việt từ thuộc tính variable_labels của dataDBC. Dòng 2–9 tạo biến tong_von_csh là tổng các khoản mục vốn chủ sở hữu, chọn các cột liên quan để phân tích. Dòng 10–14 chuyển dữ liệu sang dạng dài với cột khoan_muc và gia_tri. Dòng 15–18 tính tỷ trọng mỗi khoản mục trên tổng vốn chủ sở hữu và thay khoan_muc bằng nhãn tiếng Việt từ labels. Dòng 19–29 vẽ biểu đồ cột phân loại gồm trục x là năm, trục y là tỷ trọng %. Màu sắc theo khoan_muc dùng palette Pastel1. Thêm tiêu đề, nhãn trục và legend. Sử dụng Theme tối giản, cỡ chữ 14, tiêu đề in đậm, căn giữa, legend bên phải.

Nhận xét cơ cấu vốn chủ sở hữu:

Vốn góp CSH: Chiếm tỷ trọng chính, ổn định 30–35% giai đoạn 2015–2019, tăng mạnh lên ~50% từ 2021–2023, duy trì vai trò chủ đạo đến 2024.

Thặng dư vốn cổ phần (VCP): Tỷ trọng giảm dần, từ 15–20% xuống ~10%, phản ánh ít phát hành cổ phiếu mới hoặc đã dùng thặng dư cho các quỹ khác.

Quỹ đầu tư phát triển (ĐTPT): Chiếm tỷ trọng lớn giai đoạn 2016–2019 (~40–45%), giảm dần còn ~30% năm 2024 do trích lập ít hơn hoặc sử dụng để tái đầu tư.

Lợi nhuận sau thuế chưa phân phối (LNST chưa PP): Biến động nhẹ quanh 10–15%, tăng nhẹ một số năm (2020, 2023), giảm nhẹ năm 2024 do phân phối hoặc trích lập quỹ.

Tổng kết: 2015–2019 cơ cấu cân bằng, Quỹ ĐTPT lớn nhất; 2020–2024 Vốn góp CSH tăng mạnh, trở thành yếu tố chính, phản ánh chiến lược củng cố vốn điều lệ và ổn định nền tảng vốn chủ sở hữu.

6. Tính hệ số nợ trên vốn chủ sở hữu (D/E)

\[ D/E = \frac{\text{Tổng nợ phải trả}}{\text{Vốn chủ sở hữu}} \]

dataDBC <- dataDBC %>%
mutate(he_so_no_tren_von_csh = no_phai_tra / von_chu_so_huu)

ggplot(dataDBC, aes(x = nam, y = he_so_no_tren_von_csh, group = 1)) +
geom_line(color = "steelblue", linewidth = 1.2) +
geom_point(color = "darkred", size = 3) +
geom_text(aes(label = round(he_so_no_tren_von_csh, 2)),
vjust = -1, size = 3.5, color = "black") +
labs(
title = "Hệ số nợ trên vốn chủ sở hữu (D/E) qua các năm",
x = "Năm",
y = "Hệ số D/E"
) +
ylim(0.5, 2.25) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
axis.title = element_text(face = "bold")
)

Dòng 1 tạo biến he_so_no_tren_von_csh bằng Nợ phải trả chia cho Vốn chủ sở hữu (hệ số D/E). Dòng 3 vẽ đường nối các giá trị D/E theo năm với màu xanh thép và độ dày 1.2. Dòng 4 vẽ các điểm dữ liệu riêng lẻ màu đỏ sẫm, kích thước 3. Dòng 5–6 thêm nhãn giá trị D/E trên mỗi điểm, làm tròn 2 chữ số, đặt phía trên điểm. Dòng 7–11 thêm tiêu đề và nhãn trục, giới hạn trục y từ 0.5 đến 2.25. Dòng 12–15 theme tối giản, cỡ chữ 13, tiêu đề in đậm và căn giữa, nhãn trục in đậm.

Đánh giá: 2017–2019: Doanh nghiệp sử dụng đòn bẩy tài chính cao, tiềm ẩn rủi ro. 2020–2021: Cải thiện rõ rệt, D/E giảm xuống mức an toàn (~1.3). 2024: Mức D/E chỉ còn 1.09, thể hiện cơ cấu vốn ổn định và lành mạnh hơn.

→ Sau giai đoạn biến động, doanh nghiệp đang giảm dần phụ thuộc vào nợ, tăng khả năng tự chủ tài chính.

7. Phân tích tốc độ tăng trưởng LNST chưa phân phối

\[ Tốc~độ~tăng~trưởng~(\%) = \frac{X_t - X_{t-1}}{X_{t-1}} \times 100 \]

tang_truong_vcsh <- dataDBC %>%
  arrange(nam) %>%
  mutate(
    tang_truong_von_csh = ((von_chu_so_huu - lag(von_chu_so_huu)) / lag(von_chu_so_huu)) * 100,
    tang_truong_ln_chua_pp = ((loi_nhuan_sau_thue_chua_phan_phoi - lag(loi_nhuan_sau_thue_chua_phan_phoi)) / lag(loi_nhuan_sau_thue_chua_phan_phoi)) * 100
  ) %>%
  select(nam, starts_with("tang_truong"))

labels_vcsh <- c(
  tang_truong_von_csh = "Vốn chủ sở hữu",
  tang_truong_ln_chua_pp = "LNST chưa phân phối"
)
tang_truong_long <- melt(tang_truong_vcsh, id.vars = "nam",
                         variable.name = "Khoan_muc", value.name = "Tang_truong")
ggplot(tang_truong_long, aes(x = nam, y = Tang_truong, color = Khoan_muc, group = Khoan_muc)) +
  geom_line(size = 1.2) +
  geom_point(size = 2.5) +
  scale_color_manual(
    values = c("steelblue", "orange"),
    labels = labels_vcsh
  ) +
  labs(
    title = "Tốc độ tăng trưởng các khoản mục trong VCSH",
    x = "Năm",
    y = "Tốc độ tăng trưởng (%)",
    color = "Khoản mục"
  ) +
  theme_minimal(base_size = 13) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5))+
  scale_x_discrete(breaks = unique(tang_truong_long$nam))
## Warning: Removed 2 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 2 rows containing missing values or values outside the scale range
## (`geom_point()`).

Dòng 1–9 sắp xếp dữ liệu theo nam, tạo hai biến tăng trưởng theo năm: tang_truong_von_csh và tang_truong_ln_chua_pp. Tính theo phần trăm so với năm trước và giữ các cột liên quan. Dòng 11–15: Đặt nhãn tiếng Việt cho hai khoản mục tăng trưởng. Chuyển dữ liệu sang dạng dà để dễ vẽ biểu đồ với cột Khoan_muc và Tang_truong. Dòng 16–31: Vẽ biểu đồ đường gồm trục x là năm, trục y là tốc độ tăng trưởng %. Mỗi khoản mục là một đường riêng với màu sắc tùy chỉnh. Thêm các điểm dữ liệu, tiêu đề, nhãn trục, legend với nhãn tiếng Việt. Sử dụng Theme tối giản, cỡ chữ 13, tiêu đề in đậm và căn giữa. Đảm bảo trục x hiển thị đầy đủ các năm.

Biểu đồ trên thể hiện tốc độ tăng trưởng (%) của hai khoản mục trong Vốn chủ sở hữu giai đoạn 2015–2024, gồm: Vốn chủ sở hữu tổng thể (đường màu xanh dương) Lợi nhuận sau thuế chưa phân phối (LNST chưa PP) (đường màu cam)

Vốn chủ sở hữu: 2015–2023: Tăng ổn định, mức tăng thấp, không có biến động đột biến, phản ánh chính sách vốn thận trọng. 2023–2024: Tăng nhẹ, nền tảng vốn vẫn ổn định.

LNST chưa phân phối: 2015–2021: Biến động mạnh, có năm âm do chia cổ tức, trích quỹ hoặc bù lỗ, tích lũy không ổn định. 2022–2024: Năm 2022 giảm sâu do COVID-19; 2023 tăng mạnh; 2024 tăng đột biến (>2500%), phản ánh lợi nhuận bất thường hoặc cơ sở so sánh thấp trước đó.

8. Phân tích tương quan giữa các biến

correlation_data <- dataDBC %>%
  select(where(is.numeric))  

correlation_matrix <- cor(correlation_data, use = "complete.obs")

cor_long <- as.data.frame(as.table(correlation_matrix))
colnames(cor_long) <- c("Var1", "Var2", "Correlation")
ggplot(cor_long, aes(x = Var1, y = Var2, fill = Correlation)) +
  geom_tile(color = "white") +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red",
                       midpoint = 0, limit = c(-1, 1), space = "Lab",
                       name="Tương quan") +
  theme_minimal(base_size = 12) +
  theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) +
  labs(title = "Tương quan giữa các biến trong nguồn vốn",
       x = "", y = "")

Dòng 1–2 chọn tất cả các biến số trong dataDBC để tính tương quan. Dòng 3 tính ma trận tương quan dùng các quan sát đầy đủ. Dòng 4–6 chuyển ma trận tương quan sang dạng dài. Dòng 7–14 vẽ heatmap tương quan: tô màu theo hệ số tương quan: xanh – trắng – đỏ, midpoint = 0, giới hạn từ -1 đến 1. Sử dụng Theme tối giản, cỡ chữ 12, xoay nhãn trục x 45° để dễ đọc. Thêm tiêu đề, không hiển thị nhãn trục x/y.

  1. Tương quan dương mạnh (màu đỏ đậm) Các cặp biến sau có tương quan gần 1.0, cho thấy mối quan hệ tuyến tính rất mạnh: von_gop_cua_chu_so_huu - von_chu_so_huu: Hai biến này gần như trùng nhau về bản chất, đều phản ánh vốn chủ sở hữu. von_chu_so_huu - von_dieu_le: Vốn điều lệ là một phần của vốn chủ sở hữu, nên mối tương quan cao là hợp lý. tong_cong_nguon_von - no_phai_tra và von_chu_so_huu: Tổng nguồn vốn thường bằng nợ phải trả + vốn chủ sở hữu, nên mối tương quan cao là tất yếu.

  2. Tương quan âm đáng chú ý (màu xanh dương) he_so_no_tren_von_csh có tương quan âm với von_chu_so_huu và von_dieu_le: Điều này phản ánh rằng khi vốn chủ sở hữu tăng, tỷ lệ nợ trên vốn giảm – một dấu hiệu tích cực về tài chính. he_so_no_tren_von_csh ↔︎ quy_dau_tu_phat_trien: Có thể cho thấy rằng doanh nghiệp có tỷ lệ nợ cao thì ít đầu tư phát triển hơn.

Nhóm nợ phải trả: phai_tra, phai_tra_no_ngan_han, phai_tra_nguoi_ban, phai_tra_nguon_khac có xu hướng tương quan cao, cho thấy sự liên kết giữa các khoản nợ ngắn hạn và tổng nợ.

9. Tính biến động theo thời gian

df_melted <- dataDBC %>%
  pivot_longer(
    cols = -nam,          
    names_to = "Variable",
    values_to = "Value"
  )

volatility_analysis <- df_melted %>%
  group_by(nam) %>%
  summarise(
    Volatility = sd(Value, na.rm = TRUE) / mean(Value, na.rm = TRUE) * 100,  
    CV = sd(Value, na.rm = TRUE) / mean(Value, na.rm = TRUE)                  
  )
ggplot(volatility_analysis, aes(x = nam, group = 1)) +
  geom_line(aes(y = CV, color = "CV"), size = 1.2) +
  geom_point(aes(y = CV), size = 2, color = "red") +
  scale_y_continuous(limits = c(0, 1.6)) +   # trục tung 0 → 1.6
  labs(
    title = "Hệ số biến động (CV) của các biến tài chính theo năm",
    x = "Năm",
    y = "CV",
    color = ""
  ) +
  theme_minimal(base_size = 14) +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        legend.position = "none")

Dòng 1–6 chuyển dữ liệu dataDBC sang dạng dài với cột Variable và Value, giữ nguyên nam. Dòng 7–13 tính hệ số biến động (CV) theo năm: Volatility = độ lệch chuẩn / trung bình × 100 (%). CV = độ lệch chuẩn / trung bình (không nhân 100). Dòng 14–25 vẽ biểu đồ đường của CV theo năm: vẽ đường CV và đánh dấu điểm dữ liệu. Giới hạn trục y từ 0 đến 1.6 để quan sát rõ biến động. Thêm tiêu đề, nhãn trục, theme tối giản, tiêu đề in đậm căn giữa, không hiển thị legend.

Nhận xét: Volatility dao động khoảng 144% – 149% và CV khoảng 1.44 – 1.49. Đây là mức biến động khá cao, phản ánh rằng giữa các biến số tài chính (nợ, vốn chủ sở hữu, tổng nguồn vốn…) có sự chênh lệch lớn về giá trị, vì các khoản mục khác nhau có quy mô rất khác nhau. Nhìn chung, biến động có dao động nhẹ nhưng không quá lớn, nghĩa là cơ cấu tài chính của doanh nghiệp vẫn tương đối ổn định qua các năm, chỉ thay đổi nhỏ theo các năm kinh tế hoặc các quyết định tài chính của công ty.

10. Phân tích chuỗi thời gian với dự báo

ts_data <- ts(dataDBC$no_phai_tra, start = 2015, frequency = 1)  

forecast_model <- forecast(auto.arima(ts_data), h = 2)  # dự báo 2025-2026
autoplot(forecast_model) +
  labs(
    title = "DỰ BÁO NỢ PHẢI TRẢ (2025-2026)",
    x = "Năm",
    y = "Giá trị (tỷ VND)"
  ) +
  scale_x_continuous(
    breaks = seq(2015, 2026, by = 1)  
  ) +
  theme_minimal(base_size = 14)
## Scale for x is already present.
## Adding another scale for x, which will replace the existing scale.

Dòng 1 chuyển biến no_phai_tra thành dữ liệu chuỗi thời gian (ts) bắt đầu từ năm 2015, tần suất 1 năm. Dòng 3 dự báo 2 năm tiếp theo (2025-2026) bằng mô hình auto.arima. Dòng 4–12 vẽ biểu đồ dự báo: hiển thị giá trị thực và dự báo với khoảng tin cậy. Thêm tiêu đề, nhãn trục, đảm bảo trục x hiển thị các năm từ 2015 đến 2026. Sử dụng Theme tối giản, cỡ chữ 14.

Nhận xét: 2015–2019: Nợ phải trả tăng liên tục, từ mức khoảng 2.500 tỷ VND (2015) lên gần 6.500 tỷ VND (2019). Đây là giai đoạn tăng trưởng nhanh. 2019–2020: Có sự sụt giảm nhẹ, nợ giảm xuống còn khoảng 6.000 tỷ VND. 2020–2023: Nợ tăng mạnh trở lại, đạt đỉnh khoảng 8.000–8.500 tỷ VND và giữ ổn định trong hai năm. 2024: Nợ giảm nhẹ còn khoảng 7.000–7.500 tỷ VND, thể hiện xu hướng ổn định hoặc giảm nhẹ sau đỉnh.

Kết quả dự báo: Giá trị trung bình dự báo năm 2025: khoảng 7.000 tỷ VND. Giá trị trung bình dự báo năm 2026: gần 7.000–7.200 tỷ VND. Khoảng dao động có thể xảy ra: từ khoảng 5.000 tỷ đến 10.000 tỷ VND, cho thấy mức độ bất định tương đối cao trong hai năm tới.

11. Biểu đồ mật độ phân phối

df_long <- dataDBC %>%
  select(no_phai_tra, von_chu_so_huu) %>%
  pivot_longer(
    cols = everything(),
    names_to = "metric",
    values_to = "value"
  ) %>%
  mutate(
    metric_clean = ifelse(metric == "no_phai_tra", "Nợ phải trả", "Vốn chủ sở hữu")
  )
stats <- df_long %>%
  group_by(metric_clean) %>%
  summarise(
    Mean = mean(value, na.rm = TRUE),
    Median = median(value, na.rm = TRUE),
    .groups = "drop"
  )
p11 <- ggplot(df_long, aes(x = value, fill = metric_clean)) +
  geom_density(alpha = 0.5) +
  geom_vline(data = stats, aes(xintercept = Mean, color = metric_clean),
             linetype = "dashed", size = 1) +   # đường trung bình
  geom_vline(data = stats, aes(xintercept = Median, color = metric_clean),
             linetype = "solid", size = 1) +    # đường trung vị
  labs(
    title = "Phân phối mật độ Nợ phải trả và Vốn chủ sở hữu",
    x = "Giá trị (tỷ VND)",
    y = "Mật độ",
    fill = "Chỉ tiêu",
    color = "Chỉ tiêu"
  ) +
  theme_minimal(base_size = 14)
print(p11)

Dòng 1–7 chọn hai biến no_phai_tra và von_chu_so_huu. Chuyển dữ liệu sang dạng dài với cột metric và value. Tạo cột metric_clean với nhãn tiếng Việt cho dễ đọc. Dòng 8–13 tính trung bình (Mean) và trung vị (Median) cho mỗi biến, bỏ giá trị thiếu. Dòng 14–28 vẽ biểu đồ mật độ (density plot): hiển thị phân phối giá trị từng biến, màu theo biến, alpha = 0.5. Thêm đường trung bình và trung vị, màu theo biến. Thêm tiêu đề, nhãn trục, legend cho fill và color. Theme tối giản, cỡ chữ 14.

Nhận xét: Vốn chủ sở hữu (xanh lam): Tập trung chủ yếu 2.000–5.000 tỷ VND, đỉnh khoảng 3.000–3.500 tỷ; phân phối lệch phải nhẹ, phần lớn ở mức thấp–trung bình, doanh nghiệp duy trì vốn tự có vừa phải.

Nợ phải trả (hồng): Tập trung 5.000–7.000 tỷ VND, ít trường hợp <4.000 tỷ; phân phối lệch trái nhẹ, hầu hết nợ cao hơn vốn chủ sở hữu, phản ánh doanh nghiệp phụ thuộc nhiều vào nợ để tài trợ hoạt động.

So sánh tương quan giữa hai phân phối Điểm giao nhau giữa hai đường cong nằm khoảng 4.800–5.000 tỷ VND, đây có thể xem là ngưỡng cân bằng tương đối giữa nợ và vốn chủ sở hữu. Ở vùng dưới 5.000 tỷ, vốn chủ sở hữu chiếm ưu thế → thể hiện giai đoạn/tình huống tự chủ tài chính tốt hơn. Ở vùng trên 5.000 tỷ, nợ phải trả chiếm ưu thế → giai đoạn tăng sử dụng đòn bẩy tài chính, rủi ro có thể cao hơn.

12. Phân tích mối quan hệ nợ - vốn

dataDBC <- dataDBC %>%
  mutate(
    debt_to_equity = no_phai_tra / von_chu_so_huu,         # Tỷ lệ nợ/vốn
    equity_ratio  = von_chu_so_huu / tong_cong_nguon_von, # Tỷ trọng vốn chủ sở hữu
    debt_ratio    = no_phai_tra / tong_cong_nguon_von      # Tỷ trọng nợ phải trả
  )
debt_equity_stats <- dataDBC %>%
  summarise(
    Mean_Debt = mean(no_phai_tra),
    Mean_Equity = mean(von_chu_so_huu),
    Mean_DebtToEquity = mean(debt_to_equity),
    Max_DebtToEquity = max(debt_to_equity),
    Min_DebtToEquity = min(debt_to_equity)
  )

debt_equity_long <- dataDBC %>%
  select(nam, no_phai_tra, von_chu_so_huu) %>%
  pivot_longer(cols = c(no_phai_tra, von_chu_so_huu), 
               names_to = "metric", 
               values_to = "value")

ggplot(debt_equity_long, aes(x = nam, y = value, color = metric, group = metric)) +
  geom_line(size = 1.2) +
  geom_point(size = 2) +
  labs(
    title = "Mối quan hệ Nợ - Vốn chủ sở hữu (2015-2024)",
    x = "Năm",
    y = "Giá trị (tỷ VND)",
    color = "Chỉ tiêu"
  ) +
  theme_minimal(base_size = 14)

Dòng 1–6 tạo các biến mới: debt_to_equity, equity_ratio, debt_ratio. Dòng 7–14 tính một số thống kê tóm tắt: trung bình nợ, trung bình vốn, trung bình tỷ lệ nợ/vốn, giá trị tối đa và tối thiểu của tỷ lệ nợ/vốn. Dòng 15–19 chuyển dữ liệu no_phai_tra và von_chu_so_huu sang dạng dài để dễ vẽ biểu đồ, giữ cột năm. Dòng 20–29 vẽ biểu đồ đường thể hiện mối quan hệ Nợ – Vốn chủ sở hữu theo năm với trục x là năm, trục y là giá trị (tỷ VND). Mỗi chỉ tiêu là một đường riêng với màu sắc khác nhau. Thêm điểm dữ liệu, tiêu đề, nhãn trục, legend, theme tối giản, cỡ chữ 14.

Nhìn chung, cả hai chỉ tiêu đều có xu hướng tăng theo thời gian, nhưng nợ phải trả luôn cao hơn vốn chủ sở hữu, cho thấy doanh nghiệp sử dụng đòn bẩy tài chính đáng kể.

Giai đoạn 2015–2018: Nợ phải trả tăng mạnh từ khoảng 2.500 tỷ lên gần 6.000 tỷ VND, tức tăng hơn 2,4 lần. Vốn chủ sở hữu tăng chậm hơn, từ 2.000 tỷ lên khoảng 3.000 tỷ VND. Hệ số nợ/vốn chủ sở hữu (D/E) tăng nhanh, rủi ro tài chính có thể gia tăng.

Giai đoạn 2019–2020: Nợ phải trả đạt đỉnh khoảng 6.500 tỷ năm 2019 rồi giảm nhẹ xuống ~6.000 tỷ năm 2020. Vốn chủ sở hữu lại tăng mạnh từ 3.000 lên hơn 4.000 tỷ.

Giai đoạn 2021–2023: Nợ bứt phá mạnh. Nợ phải trả tăng mạnh từ 6.000 tỷ lên gần 8.500 tỷ VND, duy trì mức cao suốt 2022–2023. Vốn chủ sở hữu chỉ tăng nhẹ và gần như đi ngang quanh 4.500–4.800 tỷ VND.

Năm 2024: Tín hiệu tích cực. Nợ phải trả giảm nhẹ từ mức đỉnh, còn khoảng 7.000–7.500 tỷ VND. Vốn chủ sở hữu tăng mạnh lên gần 6.000 tỷ VND — mức tăng ấn tượng nhất trong 10 năm. Cho thấy doanh nghiệp đang cải thiện cơ cấu tài chính, giảm nợ và tăng vốn chủ, hướng đến sự bền vững và an toàn hơn.

13. So sánh các khoản vay qua các năm

loan_data <- dataDBC %>%
  mutate(nam = as.numeric(as.character(nam))) %>%
  select(nam, vay_va_no_thue_tai_chinh_ngan_han, no_dai_han) %>%
  pivot_longer(
    cols = c(vay_va_no_thue_tai_chinh_ngan_han, no_dai_han),
    names_to = "loan_type",
    values_to = "value"
  ) %>%
  mutate(
    loan_type_clean = case_when(
      loan_type == "vay_va_no_thue_tai_chinh_ngan_han" ~ "Vay ngắn hạn",
      loan_type == "no_dai_han" ~ "Nợ dài hạn"
    )
  )
ggplot(loan_data, aes(x = nam, y = value, color = loan_type_clean)) +
  geom_line(size = 1.2) +
  geom_point(size = 2) +
  facet_wrap(~loan_type_clean, scales = "free_y", ncol = 1) +
  scale_x_continuous(breaks = seq(min(loan_data$nam), max(loan_data$nam), by = 1)) +
  labs(
    title = "So sánh các khoản vay qua các năm",
    x = "Năm",
    y = "Giá trị (tỷ đồng)",
    color = "Loại vay"
  ) +
  theme_minimal(base_size = 14) +
  theme(legend.position = "none")

Dòng 1–7 chuyển nam sang dạng số. Chọn các cột liên quan đến vay ngắn hạn và nợ dài hạn. Chuyển dữ liệu sang dạng dài với cột loan_type và value. Tạo cột loan_type_clean với nhãn tiếng Việt cho từng loại vay. Dòng 8–19 vẽ biểu đồ đường có phân tách theo loại vay gồm trục x là năm, trục y là giá trị khoản vay. Hiển thị xu hướng và điểm dữ liệu, tách riêng từng loại vay, trục y tự điều chỉnh, 1 cột. Hiển thị trục x đầy đủ các năm, thêm tiêu đề, nhãn trục, legend. Theme tối giản, cỡ chữ 14, ẩn legend.

1. Nợ dài hạn:

Giai đoạn 2015–2019: Nợ dài hạn tăng mạnh và liên tục. Giai đoạn 2020–2021: Nợ dài hạn giảm mạnh, từ gần 1.700 tỷ xuống khoảng 1.000 tỷ đồng. → Có thể do doanh nghiệp trả bớt nợ, cơ cấu lại nguồn vốn, hoặc hạn chế vay mới do ảnh hưởng của dịch COVID-19. Giai đoạn 2022–2024: Nợ dài hạn dao động nhẹ quanh 1.000–1.200 tỷ đồng, đến 2024 giảm nhẹ còn khoảng 950 tỷ.

2. Vay ngắn hạn:

Giai đoạn 2015–2019: Vay ngắn hạn tăng dần đều, từ khoảng 1.500 tỷ lên hơn 3.000 tỷ đồng. Năm 2020: Giảm mạnh xuống khoảng 2.000 tỷ đồng. Có thể liên quan đến việc giảm hoạt động sản xuất, ảnh hưởng dịch bệnh. Giai đoạn 2021–2024: Tăng trở lại rất mạnh, đặc biệt từ 2021 đến 2023, đạt gần 5.000 tỷ đồng và duy trì mức cao đến 2024.

14. Xu hướng các khoản phải trả người bán

Đây là một phần của nợ ngắn hạn, phản ánh các khoản doanh nghiệp còn nợ nhà cung cấp cho hàng hóa, dịch vụ đã nhận nhưng chưa thanh toán. Thuộc nhóm nợ phải trả trong bảng cân đối kế toán.

Ý nghĩa tài chính Đánh giá khả năng thanh toán ngắn hạn: Nếu khoản phải trả người bán tăng quá nhanh so với dòng tiền, có thể gây áp lực thanh khoản. Nếu giảm đều, doanh nghiệp quản lý thanh toán hiệu quả, không bị quá hạn.

trend_ap <- dataDBC %>%
  mutate(nam = as.numeric(as.character(nam))) %>%
  select(nam, phai_tra_nguoi_ban_ngan_han)

ggplot(trend_ap, aes(x = nam, y = phai_tra_nguoi_ban_ngan_han)) +
  geom_line(color = "#E67E22", size = 1.5) +
  geom_point(color = "#E67E22", size = 3) +
  geom_area(fill = "#E67E22", alpha = 0.2) +
  geom_smooth(method = "lm", se = FALSE, color = "red", linetype = "dashed") +
  scale_x_continuous(breaks = seq(min(trend_ap$nam), max(trend_ap$nam), by = 1)) +
  labs(
    title = "Xu hướng Phải trả người bán ngắn hạn",
    subtitle = "Đường đứt nét thể hiện xu hướng dài hạn",
    x = "Năm",
    y = "Giá trị (tỷ đồng)"
  ) +
  theme_minimal(base_size = 14)
## `geom_smooth()` using formula = 'y ~ x'

Dòng 1–3 chuyển nam sang dạng số. Chọn cột phai_tra_nguoi_ban_ngan_han để phân tích xu hướng. Dòng 4–13 vẽ biểu đồ xu hướng khoản phải trả người bán ngắn hạn: hiển thị đường nối và các điểm dữ liệu, màu cam, tô màu dưới đường cong với độ trong suốt 0.2. Thêm đường hồi quy tuyến tính đứt nét màu đỏ để thể hiện xu hướng dài hạn. Hiển thị đầy đủ các năm trên trục x. Thêm tiêu đề, subtitle, nhãn trục. Theme tối giản, cỡ chữ 14.

Phân tích xu hướng dài hạn (đường đứt đỏ) Dù có các biến động ngắn hạn, xu hướng dài hạn vẫn tăng dần theo thời gian. Điều này phản ánh quy mô hoạt động có xu hướng mở rộng hoặc doanh nghiệp duy trì chính sách mua chịu cao hơn so với giai đoạn đầu.

Vậy kết quả biểu đồ cho ta thấy: Giai đoạn 2015–2020: Ổn định, tăng trưởng chậm và bền vững. Giai đoạn 2021–2022: Bùng nổ bất thường – cần xem xét yếu tố nội bộ (đầu tư, hàng tồn kho, dòng tiền). Từ 2023 trở đi: Doanh nghiệp quay về mức ổn định, có thể đã tái cấu trúc hoặc giảm nợ ngắn hạn. Xu hướng tổng thể: Tăng nhẹ về dài hạn nhưng có biến động ngắn hạn mạnh. Năm 2022 là điểm đột biến đáng chú ý. Sau đó, doanh nghiệp có dấu hiệu kiểm soát tốt hơn công nợ và duy trì mức ổn định.

15. Phân tích đa chiều nguồn vốn

multi_chart_data <- dataDBC %>%
  mutate(
    nam = as.numeric(as.character(nam)),
    de_ratio = no_phai_tra / von_chu_so_huu,       
    size_group = cut(
      tong_cong_nguon_von,
      breaks = quantile(tong_cong_nguon_von, probs = c(0, 0.33, 0.66, 1), na.rm = TRUE),
      labels = c("Nhỏ", "Trung bình", "Lớn")
    )
  )
ggplot(multi_chart_data, aes(x = nam)) +
  geom_col(aes(y = no_phai_tra , fill = "Nợ phải trả"), alpha = 0.6) +
  geom_col(aes(y = von_chu_so_huu, fill = "Vốn chủ sở hữu"), alpha = 0.6) +
  geom_line(aes(y = de_ratio * 10000, color = "Tỷ lệ D/E (x10000)"), size = 1.5) +
  geom_point(aes(y = de_ratio * 10000, size = as.numeric(size_group)), color = "red") +
  scale_y_continuous(
    name = "Giá trị (tỷ đồng)",
    sec.axis = sec_axis(~ ./10000, name = "Tỷ lệ D/E")
  ) +
  scale_x_continuous(
    breaks = seq(min(multi_chart_data$nam), max(multi_chart_data$nam), by = 1)
  ) +
  scale_fill_manual(values = c("Nợ phải trả" = "#E74C3C", "Vốn chủ sở hữu" = "#2ECC71")) +
  scale_color_manual(values = c("Tỷ lệ D/E (x10000)" = "#F39C12")) +
  labs(
    title = "Phân tích đa chiều nguồn vốn",
    subtitle = "Kết hợp giá trị tuyệt đối và tỷ lệ tương đối",
    x = "Năm",
    fill = "Giá trị tuyệt đối",
    color = "Tỷ lệ",
    size = "Quy mô tổng nguồn vốn"
  ) +
  theme_minimal(base_size = 14) +
  theme(legend.position = "bottom")
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).

Dòng 1–10 chuyển nam sang số. Tạo biến de_ratio = nợ / vốn (D/E). Tạo nhóm size_group dựa trên tổng nguồn vốn, chia thành 3 mức: Nhỏ, Trung bình, Lớn theo phân vị 33% và 66%. Dòng 11–29 vẽ biểu đồ kết hợp đa chiều: vẽ cột nợ phải trả và vốn chủ sở hữu cùng trục y chính, alpha = 0.6. Vẽ đường tỷ lệ D/E nhân 10000 để hiển thị trên cùng biểu đồ. Thêm điểm màu đỏ, kích thước theo size_group. Tạo trục y phụ cho tỷ lệ D/E. Hiển thị đầy đủ các năm. Tùy chỉnh màu cho cột và đường. Thêm tiêu đề, subtitle, nhãn trục, legend và theme tối giản cỡ chữ 14, legend đặt dưới cùng.

Biểu đồ có tiêu đề “Phân tích đa chiều nguồn vốn”, thể hiện mối quan hệ giữa giá trị tuyệt đối của nguồn vốn (trục trái), tỷ lệ D/E (trục phải) và quy mô tổng nguồn vốn (kích thước điểm tròn đỏ) trong giai đoạn 2015–2024.

Nhận xét: Tỷ lệ D/E trung bình giai đoạn 2015–2024 dao động từ 1,0–2,1, cho thấy doanh nghiệp sử dụng đòn bẩy tài chính ở mức trung bình đến tương đối cao. Giai đoạn 2018–2019 là đỉnh điểm của rủi ro tài chính, do D/E vượt 2. Từ 2020 trở đi, xu hướng là giảm dần nợ vay, hướng tới cấu trúc tài chính an toàn hơn. Quy mô nguồn vốn tăng trưởng ổn định đến 2019, sau đó chững lại, phản ánh chu kỳ tăng trưởng – điều chỉnh – ổn định.

→ Xu hướng dài hạn: Doanh nghiệp duy trì tổng nguồn vốn ổn định, giảm dần phụ thuộc vào nợ vay, và hướng tới cấu trúc tài chính bền vững hơn.

16. Đánh giá khả năng thanh toán

Ở đây đánh giá khả năng thanh toán dựa trên các biến của nguồn vốn, là một ước lượng tỷ trọng nợ ngắn hạn trên tổng nguồn vốn, phản ánh phần nào “gánh nợ ngắn hạn” trong tổng vốn. Giá trị càng nhỏ thì doanh nghiệp ít phụ thuộc nợ ngắn hạn trong tổng vốn. Giá trị càng lớn thì rủi ro thanh khoản ngắn hạn cao hơn và thể hiện tỷ lệ vốn chủ sở hữu trên nợ, tức là khả năng dùng vốn chủ sở hữu để trang trải nợ.

liquidity_ratios <- dataDBC %>%
  mutate(
    nam = as.numeric(as.character(nam)),          
    current_ratio_approx = no_ngan_han / tong_cong_nguon_von,
    debt_coverage = von_chu_so_huu / no_phai_tra
  ) %>%
  select(nam, current_ratio_approx, debt_coverage)
print(round(liquidity_ratios, 3))
## # A tibble: 10 × 3
##      nam current_ratio_approx debt_coverage
##    <dbl>                <dbl>         <dbl>
##  1  2015                0.522         0.729
##  2  2016                0.476         0.733
##  3  2017                0.495         0.558
##  4  2018                0.488         0.49 
##  5  2019                0.502         0.461
##  6  2020                0.421         0.714
##  7  2021                0.476         0.759
##  8  2022                0.556         0.557
##  9  2023                0.549         0.559
## 10  2024                0.455         0.92

1. Tỷ lệ thanh toán ngắn hạn ước lượng \[ \text{Current Ratio Approx} = \frac{\text{Nợ ngắn hạn}}{\text{Tổng nguồn vốn}} \]

Nhận xét: Giá trị dao động từ 0.421 (2020) đến 0.556 (2022). Giá trị < 1 trong toàn bộ giai đoạn → nợ ngắn hạn chiếm ít hơn tổng nguồn vốn, doanh nghiệp không bị áp lực thanh toán ngắn hạn quá lớn. Có sự biến động nhẹ, năm 2020 là thấp nhất → nợ ngắn hạn chiếm tỷ trọng nhỏ nhất trong tổng vốn, có thể do doanh nghiệp tăng vốn chủ sở hữu hoặc giảm nợ ngắn hạn. Năm 2022 là cao nhất → nợ ngắn hạn tăng lên, 1 phần do ảnh hưởng của dịch. Kết luận: Doanh nghiệp duy trì tỷ lệ nợ ngắn hạn vừa phải, thanh khoản ngắn hạn ổn định.

2. Khả năng trang trải nợ \[ \text{Debt Coverage} = \frac{\text{Vốn chủ sở hữu}}{\text{Nợ phải trả}} \]

Nhận xét: Giá trị dao động từ 0.461 (2019) đến 0.920 (2024). Giá trị > 0.45 trong toàn bộ giai đoạn → vốn chủ sở hữu chiếm khoảng 45–92% so với nợ, doanh nghiệp có khả năng trang trải nợ tương đối tốt. Năm 2019 có giá trị thấp nhất → rủi ro nợ cao hơn, cần thận trọng. Năm 2024 tăng vọt lên 0.92 → vốn chủ sở hữu mạnh, doanh nghiệp rất chủ động trong quản lý nợ, khả năng thanh toán cao. Có sự biến động khá lớn qua các năm, phản ánh chiến lược quản lý nợ-vốn thay đổi theo từng năm.

Kết luận: Thanh khoản ngắn hạn: nợ ngắn hạn chiếm khoảng 42–56% tổng nguồn vốn, không quá áp lực, nhưng năm 2022–2023 có xu hướng tăng. Khả năng trang trải nợ: biến động khá lớn, năm 2019 là thấp nhất(do ảnh hưởng của dịch bệnh), năm 2024 là cao nhất: doanh nghiệp tăng vốn chủ sở hữu và quản lý nợ tốt hơn về cuối giai đoạn.

17. Phân tích tỉ lệ đòn bẩy tài chính

leverage_analysis <- dataDBC %>%
  mutate(
    nam = as.numeric(as.character(nam)),         
    financial_leverage = no_phai_tra / von_chu_so_huu,   
    operating_leverage = no_ngan_han / tong_cong_nguon_von, 
    total_leverage = financial_leverage * operating_leverage 
  ) %>%
  select(nam, financial_leverage, operating_leverage, total_leverage)
print(round(leverage_analysis, 3))
## # A tibble: 10 × 4
##      nam financial_leverage operating_leverage total_leverage
##    <dbl>              <dbl>              <dbl>          <dbl>
##  1  2015               1.37              0.522          0.716
##  2  2016               1.36              0.476          0.649
##  3  2017               1.79              0.495          0.888
##  4  2018               2.04              0.488          0.996
##  5  2019               2.17              0.502          1.09 
##  6  2020               1.40              0.421          0.59 
##  7  2021               1.32              0.476          0.628
##  8  2022               1.80              0.556          0.998
##  9  2023               1.79              0.549          0.982
## 10  2024               1.09              0.455          0.494

Dòng 1–8 chuyển nam sang dạng số. Tạo các chỉ số đòn bẩy: financial_leverage = nợ / vốn chủ sở hữu (đòn bẩy tài chính). operating_leverage = nợ ngắn hạn / tổng nguồn vốn (đòn bẩy hoạt động). total_leverage = tích của hai loại đòn bẩy trên, phản ánh tổng mức đòn bẩy.

Nhận xét:

Financial leverage (Nợ / Vốn chủ sở hữu): Tăng 2015–2019, giảm 2020–2021, tăng 2022–2023, giảm xuống 1.087 năm 2024. Công ty phụ thuộc nợ cao giai đoạn 2015–2019, rủi ro tài chính giảm dần đến 2024.

Operating leverage (Nợ ngắn hạn / Tổng nguồn vốn): Giảm 2015–2020, tăng 2022, giảm nhẹ 2024. Đòn bẩy hoạt động giảm, rủi ro vận hành thấp hơn.

Total leverage (Financial × Operating): Diễn biến tương tự, cao nhất năm 2019, thấp nhất năm 2024. Rủi ro tài chính tổng thể giảm, công ty ổn định hơn vào cuối giai đoạn.

18. Phân tích cơ cấu nợ theo kì hạn

Chỉ tiêu cơ cấu nợ theo kỳ hạn là rất quan trọng vì nó phản ánh phân bổ nợ giữa ngắn hạn và dài hạn, từ đó cho thấy: Thanh khoản của doanh nghiệp: Tỷ lệ nợ ngắn hạn cao → áp lực thanh toán trong vòng 12 tháng lớn → rủi ro thanh khoản cao. Tỷ lệ nợ dài hạn cao → doanh nghiệp có thời gian dài hơn để trả nợ → thanh khoản ít bị áp lực. Rủi ro tài chính: Nếu nợ ngắn hạn chiếm phần lớn tổng nợ, doanh nghiệp có thể gặp khó khăn khi dòng tiền biến động.

debt_maturity_analysis <- dataDBC %>%
  mutate(
    nam = as.numeric(as.character(nam)),             
    short_term_debt_ratio = no_ngan_han / no_phai_tra, 
    long_term_debt_ratio  = no_dai_han / no_phai_tra,  
    debt_maturity_gap     = no_ngan_han - no_dai_han   
  ) %>%
  select(nam, short_term_debt_ratio, long_term_debt_ratio, debt_maturity_gap)
print(round(debt_maturity_analysis, 3))
## # A tibble: 10 × 4
##      nam short_term_debt_ratio long_term_debt_ratio debt_maturity_gap
##    <dbl>                 <dbl>                <dbl>             <dbl>
##  1  2015                 0.903                0.097             2153.
##  2  2016                 0.824                0.176             2069.
##  3  2017                 0.772                0.228             2438.
##  4  2018                 0.727                0.273             2547.
##  5  2019                 0.734                0.266             3073.
##  6  2020                 0.722                0.278             2615.
##  7  2021                 0.837                0.163             4167.
##  8  2022                 0.866                0.134             6093.
##  9  2023                 0.856                0.144             5938.
## 10  2024                 0.873                0.127             5486.

Dòng 1 khởi tạo biến kết quả từ dữ liệu gốc. Dòng 2 mở hàm để tạo biến mới. Dòng 3 chuyển năm sang dạng số. Dòng 4 tính tỷ lệ nợ ngắn hạn trên tổng nợ. Dòng 5 tính tỷ lệ nợ dài hạn trên tổng nợ. Dòng 6 tính chênh lệch nợ ngắn hạn và dài hạn. Dòng 7 chọn các cột cần thiết cho phân tích.

Nhận xét về cơ cấu nợ và rủi ro thanh khoản:

Nợ ngắn hạn: Tỷ trọng tăng từ 2015–2018 giảm nhẹ, sau đó tăng mạnh 2020–2024, chiếm phần lớn tổng nợ (~87% năm 2024). Nợ dài hạn: Tỷ trọng thấp, tăng nhẹ đến 2020 rồi giảm mạnh 2021–2024, chiếm tỷ lệ nhỏ trong cơ cấu nợ. Khoảng cách kỳ hạn nợ (debt_maturity_gap): Tăng mạnh 2017–2022, giảm nhẹ 2023–2024; giai đoạn 2022–2024 rủi ro thanh khoản cao nhất do nợ ngắn hạn vượt nợ dài hạn nhiều. Công ty chủ yếu dựa vào nợ ngắn hạn, cơ cấu nợ mất cân đối, cần quản lý dòng tiền chặt để tránh rủi ro thanh toán nợ ngắn hạn.

19. Phân tích hiệu quả sử dụng vốn

capital_efficiency <- dataDBC %>%
  mutate(
    nam = as.numeric(as.character(nam)),
    equity_turnover    = loi_nhuan_sau_thue_chua_phan_phoi / von_chu_so_huu, 
    debt_utilization   = no_phai_tra / tong_cong_nguon_von,                   
    capital_productivity = tong_cong_nguon_von / no_phai_tra                  
  ) %>%
  select(nam, equity_turnover, debt_utilization, capital_productivity)
print(round(capital_efficiency, 3))
## # A tibble: 10 × 4
##      nam equity_turnover debt_utilization capital_productivity
##    <dbl>           <dbl>            <dbl>                <dbl>
##  1  2015           0.114            0.578                 1.73
##  2  2016           0.177            0.577                 1.73
##  3  2017           0.079            0.642                 1.56
##  4  2018           0.131            0.671                 1.49
##  5  2019           0.115            0.685                 1.46
##  6  2020           0.295            0.584                 1.71
##  7  2021           0.127            0.569                 1.76
##  8  2022           0.002            0.642                 1.56
##  9  2023           0.006            0.641                 1.56
## 10  2024           0.114            0.521                 1.92

Dòng 3 chuyển năm sang dạng số để thuận tiện phân tích. Dòng 4 tính vòng quay vốn chủ sở hữu = lợi nhuận chưa phân phối / vốn chủ sở hữu. Dòng 5 tính tỷ lệ sử dụng nợ = nợ phải trả / tổng nguồn vốn. Dòng 6 tính năng suất sử dụng vốn = tổng nguồn vốn / nợ phải trả. Dòng 8 chọn các cột liên quan để phân tích hiệu quả sử dụng vốn.

Nhận xét: Vậy từ kết quả cho thấy: Hiệu quả sử dụng vốn chủ sở hữu (equity_turnover) không ổn định → cần xem xét nguyên nhân lợi nhuận biến động. Tỷ lệ sử dụng nợ (debt_utilization) giảm dần nên công ty quản lý rủi ro nợ tốt hơn, cải thiện khả năng tài chính an toàn. Năng suất sử dụng vốn (capital_productivity) tăng nhẹ nên tổng vốn được sử dụng hợp lý, đặc biệt năm 2024 đạt mức cao. Năm 2020 và 2024 là năm biến động đáng chú ý về lợi nhuận và cơ cấu vốn.

20. Phân tích xu hướng dài hạn với hồi quy

trend_regression <- dataDBC %>%
  mutate(
    nam = as.numeric(as.character(nam)),
    time_trend = 1:n()
  )
debt_model <- lm(no_phai_tra ~ time_trend, data = trend_regression)
equity_model <- lm(von_chu_so_huu ~ time_trend, data = trend_regression)

Dòng 3 và 4 chuyển cột năm sang dạng số và tạo biến time_trend đánh số thứ tự các quan sát theo năm. Dòng 6 xây dựng mô hình hồi quy tuyến tính nợ phải trả theo xu hướng thời gian. Dòng 7 xây dựng mô hình hồi quy tuyến tính vốn chủ sở hữu theo xu hướng thời gian.

print(summary(debt_model))
## 
## Call:
## lm(formula = no_phai_tra ~ time_trend, data = trend_regression)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1194.14  -562.31   -74.26   576.32  1002.62 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  2577.07     538.13   4.789 0.001375 ** 
## time_trend    597.25      86.73   6.887 0.000126 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 787.7 on 8 degrees of freedom
## Multiple R-squared:  0.8557, Adjusted R-squared:  0.8376 
## F-statistic: 47.42 on 1 and 8 DF,  p-value: 0.0001262
print(summary(equity_model))
## 
## Call:
## lm(formula = von_chu_so_huu ~ time_trend, data = trend_regression)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -727.42 -298.09   70.92  229.31  903.59 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   1174.1      342.5   3.428  0.00898 ** 
## time_trend     468.8       55.2   8.493 2.83e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 501.4 on 8 degrees of freedom
## Multiple R-squared:  0.9002, Adjusted R-squared:  0.8877 
## F-statistic: 72.13 on 1 and 8 DF,  p-value: 2.832e-05

1. Mô hình Nợ phải trả Phương trình hồi quy: \[ \text{Nợ phải trả} = 2577.07 + 597.25 \cdot \text{time\_trend} \] p-value < 0.001: Hệ số có ý nghĩa thống kê → xu hướng tăng rõ ràng. R-squared = 0.8557: Mô hình giải thích khoảng 85,6% biến động nợ phải trả, cho thấy mô hình phù hợp. Residuals: Phân phối tương đối đều quanh 0, dao động từ -1194 đến 1002 tỷ, không quá lệch.

Nhận xét: Nợ phải trả tăng đều đặn qua các năm, phản ánh doanh nghiệp có xu hướng gia tăng nghĩa vụ tài chính. Đây là chỉ tiêu quan trọng để đánh giá áp lực nợ và thanh khoản ngắn hạn.

2. Mô hình Vốn chủ sở hữu Phương trình hồi quy: \[ \text{Vốn chủ sở hữu} = 1174.1 + 468.8 \cdot \text{time\_trend} \] Intercept (1174.1): Giá trị vốn chủ sở hữu ước tính năm 2015. Hệ số time_trend (468.8): Vốn chủ sở hữu tăng trung bình 468,8 tỷ đồng mỗi năm. p-value < 0.001: Hệ số có ý nghĩa thống kê → xu hướng tăng rõ rệt. R-squared = 0.9002: Mô hình giải thích 90% biến động vốn chủ sở hữu → mô hình rất phù hợp. Residuals: Dao động từ -727 đến 903 tỷ, phân bố đều quanh 0.

Nhận xét: Vốn chủ sở hữu tăng ổn định, phản ánh doanh nghiệp có khả năng duy trì hoặc mở rộng vốn tự có, cải thiện đòn bẩy tài chính và giảm rủi ro nợ.

21. Phân tích tương quan động

rolling_cor <- dataDBC %>%
  mutate(
    debt_equity_ratio = no_phai_tra / von_chu_so_huu,
    short_long_ratio = no_ngan_han / no_dai_han
  ) %>%
  select(nam, debt_equity_ratio, short_long_ratio, loi_nhuan_sau_thue_chua_phan_phoi) %>%
  mutate(across(-nam, ~ (.x - mean(.x, na.rm = TRUE)) / sd(.x, na.rm = TRUE))) %>%
  mutate(nam = as.numeric(as.character(nam)))

rolling_cor %>%
  pivot_longer(cols = -nam, names_to = "variable", values_to = "value") %>%
  ggplot(aes(x = nam, y = value, color = variable, group = 1)) +
  geom_line(size = 1) +
  geom_point(size = 1.5) +
  facet_wrap(~variable, ncol = 1, scales = "free_y") +
  labs(
    title = "PHÂN TÍCH TƯƠNG QUAN ĐỘNG CÁC CHỈ TIÊU",
    subtitle = "Dữ liệu đã được chuẩn hóa",
    x = "Năm", y = "Giá trị chuẩn hóa",
    color = "Chỉ tiêu"
  ) +
  theme_minimal(base_size = 14)+
  theme(
    axis.text.x = element_text(angle = 30, hjust = 1)
  )

Dòng 3 và 4 tạo các biến: debt_equity_ratio = nợ / vốn chủ sở hữu, short_long_ratio = nợ ngắn hạn / nợ dài hạn. Dòng 6 chọn các cột liên quan để phân tích cùng lợi nhuận chưa phân phối. Dòng 7 chuẩn hóa các biến (trừ năm) về giá trị z-score. Dòng 10 chuyển dữ liệu sang dạng dài để vẽ biểu đồ. Dòng 11 trở đi vẽ biểu đồ đường theo năm cho từng biến đã chuẩn hóa. Thêm điểm dữ liệu, phân tách từng biến theo facet_wrap. Thêm tiêu đề, subtitle, nhãn trục, legend, theme tối giản, cỡ chữ 14.

Nhận xét: Có sự tương phản giữa debt_equity_ratio (đạt đỉnh 2019) và loi_nhuan_sau_thue_chua_phan_phoi (đạt đỉnh 2020). Đặc biệt, sự suy giảm lợi nhuận mạnh (2021-2023) xảy ra cùng lúc với sự giảm mạnh tỷ lệ nợ/vốn (2020-2021), cho thấy các chính sách cơ cấu nợ/vốn có thể đã ảnh hưởng đến lợi nhuận.

22. Xu hướng chính sách nhận sự và phúc lợi

dataDBC <- dataDBC %>%
  mutate(
    ty_le_quy_phuc_loi = round(quy_khen_thuong_phuc_loi / phai_tra_nguoi_lao_dong * 100, 2)
  )
dataDBC$nam <- as.numeric(as.character(dataDBC$nam))
ggplot(dataDBC, aes(x = nam)) +
  geom_line(aes(y = phai_tra_nguoi_lao_dong, color = "Phải trả NLĐ"), linewidth = 1.2) +
  geom_line(aes(y = quy_khen_thuong_phuc_loi, color = "Quỹ KTPL"), linewidth = 1.2) +
  geom_line(aes(y = ty_le_quy_phuc_loi * 10, color = "Tỷ lệ QKTPL/PTNLĐ (x10)"), linewidth = 1.2) + 
  scale_y_continuous(
    name = "Giá trị (tỷ đồng)",
    sec.axis = sec_axis(~./10, name = "Tỷ lệ (%)")
  ) +
  labs(title = "XU HƯỚNG CHÍNH SÁCH NHÂN SỰ VÀ PHÚC LỢI",
       x = "Năm",
       color = "Chỉ tiêu") +
  scale_x_continuous(breaks = seq(min(dataDBC$nam), max(dataDBC$nam), 1)) +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", hjust = 0.5),
        legend.position = "bottom")

Dòng 3 tạo biến ty_le_quy_phuc_loi = tỷ lệ quỹ khen thưởng/phúc lợi trên phải trả NLĐ, làm tròn 2 chữ số. Dòng 6 trở đi vẽ biểu đồ đường theo năm: phai_tra_nguoi_lao_dong (nợ NLĐ) và quy_khen_thuong_phuc_loi (quỹ phúc lợi) với màu riêng. ty_le_quy_phuc_loi nhân 10 để hiển thị cùng biểu đồ, dùng trục y phụ. scale_y_continuous tạo trục y chính và trục y phụ cho tỷ lệ %. Thêm tiêu đề, nhãn trục, legend, hiển thị đầy đủ các năm trên trục x. Theme tối giản, tiêu đề in đậm, legend đặt dưới cùng.

Nhận xét: Chính sách phúc lợi tăng giảm theo từng năm, không ổn định, tỷ lệ QKTPL/Phải trả NLĐ biến động mạnh. Năm 2018 và 2022 có tỷ lệ rất cao (>80%), cho thấy quỹ KTPL chiếm phần lớn so với phải trả NLĐ, có thể do thưởng hoặc phúc lợi đặc biệt.