Trong suốt quá trình thực hiện bài tiểu luận môn Ngôn ngữ lập trình, em đã nhận được sự quan tâm, giúp đỡ và hướng dẫn tận tình từ quý Thầy Cô Trường Đại học Tài chính – Marketing.
Đặc biệt, em xin gửi lời cảm ơn chân thành đến Thầy Trần Mạnh Tường, người đã trực tiếp hướng dẫn, tận tâm chỉ bảo và giúp đỡ em trong quá trình nghiên cứu, xử lý dữ liệu cũng như hoàn thiện bài tiểu luận này.
Em cũng xin cảm ơn các anh chị, bạn bè đã hỗ trợ, chia sẻ tài liệu và góp ý quý báu trong suốt thời gian học tập và thực hiện bài báo cáo.
Em xin chân thành cảm ơn!

Gói readxl: Đọc dữ liệu từ các tệp Excel (.xls, .xlsx) vào R một cách nhanh chóng.
Gói dplyr: cú pháp rõ ràng, dễ đọc các thao tác xử lý dữ liệu như lọc, nhóm, sắp xếp, tạo biến mới và tổng hợp.
Gói tidyr: Hỗ trợ tái cấu trúc dữ liệu từ dạng rộng sang dạng dài và ngược lại, giúp dữ liệu “gọn gàng” hơn.
Gói ggplot2: Dùng để trực quan hóa dữ liệu, tạo các biểu đồ cột, đường, tròn,… theo nguyên tắc Grammar of Graphics.
Gói scales: Giúp định dạng trục và nhãn biểu đồ, hiển thị phần trăm, đơn vị tiền, hay chuẩn hóa tỉ lệ dễ đọc hơn.
Gói kableExtra: Dùng để tạo-định dạng bảng dữ liệu, hữu ích khi xuất báo cáo R Markdown sang HTML hoặc PDF.
Gói janitor: Làm sạch dữ liệu, ví dụ đổi tên biến về dạng chuẩn (clean_names()), loại bỏ cột trống.
Gói reshape2: Chuyển đổi cấu trúc dữ liệu bằng các hàm melt() và dcast(), tiện cho việc tổng hợp hoặc trực quan hóa.
Gói knitr: Là công cụ giúp biên dịch và tạo báo cáo động trong R Markdown (xuất ra HTML, PDF, Word,…).
Gói gridExtra: Cho phép ghép nhiều biểu đồ ggplot2 lên cùng một trang bằng hàm grid.arrange().

CHƯƠNG 1: PHÂN TÍCH BỘ DỮ LIỆU ANIME

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

1.1 Đọc dữ liệu gốc

dataset <- read_excel(file.choose())

Dùng read_excel() đọc file Excel, file.choose() mở hộp thoại chọn file

1.2 Xem cấu trúc dữ liệu

head(dataset)

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

dim(dataset)
## [1] 224383     13

Dim(dataset) được dùng để kiểm tra kích thước của một đối tượng dữ liệu
Kết quả: 224.383 quan sát và 13 biến

1.4 Xem tên các biến

names(dataset)
##  [1] "MalID"           "Username"        "Gender"         
##  [4] "DaysWatched"     "MeanScore"       "Watching"       
##  [7] "Completed"       "OnHold"          "Dropped"        
## [10] "PlantoWatch"     "TotalEntries"    "Rewatched"      
## [13] "EpisodesWatched"

names(dataset) được dùng để xem hoặc đặt tên các cột (columns) của data frame hoặc list.
Kết quả: 13 biến bao gồm MalID, Username, Gender, DaysMatched, MeanScore, Watching, Completed, OnHold, Dropped, PlantoWatch, TotalEntries, Rewatched, EpisodesMatched

1.5 Kiểm tra dòng trùng lặp

sum(duplicated(dataset))
## [1] 0
dataset <- dataset[!duplicated(dataset), ]

sum(duplicated(dataset)) sẽ đếm tổng số dòng trùng lặp
Kết quả: Không có dòng trùng lặp, không cần xử lý trùng lặp

1.6 Kiểm tra giá trị thiếu

colSums(is.na(dataset))
##           MalID        Username          Gender     DaysWatched 
##               0             203               0               8 
##       MeanScore        Watching       Completed          OnHold 
##               8               8               8               8 
##         Dropped     PlantoWatch    TotalEntries       Rewatched 
##               8               8               8               8 
## EpisodesWatched 
##               8
dataset <- na.omit(dataset)

colSums(is.na(dataset)) → đếm số giá trị NA cho từng cột
Username: 203 giá trị thiếu
Các biến khác: 8 giá trị thiếu
dataset <- na.omit(dataset) → loại bỏ tất cả các dòng có ít nhất một NA, dữ liệu còn lại sạch

1.7 Giải thích ý nghĩa biến

variable_meaning <- data.frame(
  Variable = names(dataset),
  Meaning = c("ID tài khoản", "Tên người dùng", "Giới tính", "Tổng ngày xem", 
              "Điểm trung bình", "Đang xem", "Đã hoàn thành", "Tạm dừng", 
              "Đã bỏ", "Dự định xem", "Tổng mục", "Xem lại", "Tập đã xem"),
  stringsAsFactors = FALSE
)
kable(variable_meaning, booktabs = TRUE)
Variable Meaning
MalID ID tài khoản
Username Tên người dùng
Gender Giới tính
DaysWatched Tổng ngày xem
MeanScore Điểm trung bình
Watching Đang xem
Completed Đã hoàn thành
OnHold Tạm dừng
Dropped Đã bỏ
PlantoWatch Dự định xem
TotalEntries Tổng mục
Rewatched Xem lại
EpisodesWatched Tập đã xem

1.8 Phân loại biến định lượng - định tính

cat("Số biến định lượng:", sum(sapply(dataset, is.numeric)), "\n")
## Số biến định lượng: 11
cat("Số biến định tính:", sum(sapply(dataset, is.character)), "\n")
## Số biến định tính: 2
cat("Biến định lượng:", names(dataset)[sapply(dataset, is.numeric)], "\n")
## Biến định lượng: MalID DaysWatched MeanScore Watching Completed OnHold Dropped PlantoWatch TotalEntries Rewatched EpisodesWatched
cat("Biến định tính:", names(dataset)[sapply(dataset, is.character)], "\n")
## Biến định tính: Username Gender

sapply(dataset, is.numeric) → kiểm tra cột nào là numeric (định lượng)
sapply(dataset, is.character) → kiểm tra cột nào là character (định tính)
sum(…) → đếm tổng số biến theo loại
names(dataset)[…] → lấy tên các biến theo loại
Kết quả: 11 biến định lượng, 2 biến định tính (Username, Gender)

1.9 Thống kê mô tả

summary(dataset)
##      MalID           Username            Gender         
##  Min.   :      1   Length:224172      Length:224172     
##  1st Qu.: 131416   Class :character   Class :character  
##  Median : 317844   Mode  :character   Mode  :character  
##  Mean   : 384603                                        
##  3rd Qu.: 481682                                        
##  Max.   :1291097                                        
##   DaysWatched          MeanScore         Watching      
##  Min.   :     0.00   Min.   : 0.000   Min.   :   0.00  
##  1st Qu.:     6.30   1st Qu.: 7.000   1st Qu.:   1.00  
##  Median :    29.20   Median : 7.800   Median :   4.00  
##  Mean   :    53.98   Mean   : 6.808   Mean   :  10.18  
##  3rd Qu.:    72.60   3rd Qu.: 8.470   3rd Qu.:  10.00  
##  Max.   :105338.60   Max.   :10.000   Max.   :2934.00  
##    Completed           OnHold           Dropped        
##  Min.   :    0.0   Min.   :   0.00   Min.   :    0.00  
##  1st Qu.:    9.0   1st Qu.:   0.00   1st Qu.:    0.00  
##  Median :   59.0   Median :   1.00   Median :    1.00  
##  Mean   :  151.8   Mean   :   7.98   Mean   :   10.39  
##  3rd Qu.:  183.0   3rd Qu.:   7.00   3rd Qu.:    8.00  
##  Max.   :13226.0   Max.   :5167.00   Max.   :14341.00  
##   PlantoWatch        TotalEntries       Rewatched       
##  Min.   :    0.00   Min.   :    0.0   Min.   :    0.00  
##  1st Qu.:    0.00   1st Qu.:   16.0   1st Qu.:    0.00  
##  Median :    7.00   Median :   94.0   Median :    0.00  
##  Mean   :   42.11   Mean   :  222.5   Mean   :   10.45  
##  3rd Qu.:   37.00   3rd Qu.:  279.0   3rd Qu.:    5.00  
##  Max.   :21804.00   Max.   :24817.0   Max.   :13215.00  
##  EpisodesWatched  
##  Min.   :      0  
##  1st Qu.:    377  
##  Median :   1748  
##  Mean   :   3440  
##  3rd Qu.:   4386  
##  Max.   :5433345

Ý nghĩa kỹ thuật:
summary() là hàm thống kê mô tả cơ bản cho từng cột trong dataset.
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 MeanScore
Min = 0 → một số người chưa đánh giá
Median = 7.8 → điểm trung vị đánh giá gần 8
Mean = 6.808 → trung bình thấp hơn median → có người đánh giá thấp kéo mean xuống
Max = 10 → đánh giá cao nhất là 10

1.10 Kiểm tra cấu trúc dữ liệu

str(dataset)
## tibble [224,172 × 13] (S3: tbl_df/tbl/data.frame)
##  $ MalID          : num [1:224172] 1 3 4 20 36 44 47 66 70 77 ...
##  $ Username       : chr [1:224172] "Xinil" "Aokaado" "Crystal" "vondur" ...
##  $ Gender         : chr [1:224172] "Male" "Male" "Female" "Male" ...
##  $ DaysWatched    : num [1:224172] 142.3 68.6 212.8 73.1 272.1 ...
##  $ MeanScore      : num [1:224172] 7.37 7.34 6.68 8.06 5.9 7.6 6.84 7.53 7.18 6.38 ...
##  $ Watching       : num [1:224172] 1 23 16 11 27 0 15 34 30 13 ...
##  $ Completed      : num [1:224172] 233 137 636 94 1144 ...
##  $ OnHold         : num [1:224172] 8 99 303 11 11 0 22 13 9 0 ...
##  $ Dropped        : num [1:224172] 93 44 0 2 55 0 3 6 8 0 ...
##  $ PlantoWatch    : num [1:224172] 64 40 45 20 338 0 19 10 22 2 ...
##  $ TotalEntries   : num [1:224172] 399 343 1000 138 1575 ...
##  $ Rewatched      : num [1:224172] 60 15 10 7 36 0 1 50 15 0 ...
##  $ EpisodesWatched: num [1:224172] 8458 4072 12781 4374 16309 ...
##  - attr(*, "na.action")= 'omit' Named int [1:211] 331 3840 8611 10498 12569 13020 16752 17187 18828 19263 ...
##   ..- attr(*, "names")= chr [1:211] "331" "3840" "8611" "10498" ...

Câu lệnh str() (structure) là hàm base R dùng để hiển thị cấu trúc của một đối tượng R
DaysWatched numeric: số ngày xem — có giá trị thực (decimal).
MeanScore numeric: điểm trung bình — thường từ 0–10

2. XỬ LÝ DỮ LIỆU THÔ - MÃ HÓA DỮ LIỆU

2.1 Chuyển kiểu dữ liệu Gender

dataset$Gender <- as.factor(dataset$Gender)

Lệnh chuyển cột Gender từ kiểu ký tự (character) sang kiểu nhân tố (factor) trong R.

2.2 Mã hóa Gender thành số

dataset <- dataset %>%
  mutate(Gender_Code = case_when(
    Gender == "Male" ~ 1,
    Gender == "Female" ~ 2,
    Gender == "Non-Binary" ~ 3,
    TRUE ~ NA_real_
  ))

Tạo thêm một biến mới tên là Gender_Code, trong đó mã hóa biến giới tính
Nam (“Male”) được gán giá trị 1,nữ là 2 và Non-Binary là 3

2.3 Chuẩn hóa DaysWatched

dataset$DaysWatched_Z <- scale(dataset$DaysWatched)

scale() là chuẩn hóa theo Z-score, sau khi chuẩn hóa, biến mới DaysWatched_Z sẽ phản ánh mức độ chênh lệch của từng giá trị so với trung bình, được tính bằng đơn vị độ lệch chuẩn.

2.4 Tạo biến Completion_Rate

dataset$Completion_Rate <- dataset$Completed / dataset$TotalEntries

Lệnh này tạo biến mới Completion_Rate, biểu thị tỷ lệ hoàn thành của mỗi người dùng hoặc mỗi đối tượng quan sát.
Ý nghĩa: Giúp đo lường mức độ tương tác hoặc cam kết của người dùng đối với nội dung họ theo dõi.

2.5 Xử lý ngoại lai DaysWatched

Q1 <- quantile(dataset$DaysWatched, 0.25)
Q3 <- quantile(dataset$DaysWatched, 0.75)
IQR <- Q3 - Q1
dataset <- dataset[dataset$DaysWatched >= (Q1 - 1.5*IQR) & 
                     dataset$DaysWatched <= (Q3 + 1.5*IQR), ]

quantile() tính phân vị (quartile) của biến DaysWatched:
Q1: phân vị thứ 25%
Q3: phân vị thứ 75%
IQR = Q3 - Q1 là khoảng tứ phân vị, thể hiện độ phân tán trung tâm.
Quy tắc 1.5*IQR được dùng để loại bỏ ngoại lai (outlier):
Giữ lại các giá trị trong khoảng [Q1 - 1.5IQR, Q3 + 1.5IQR].
Loại bỏ các điểm nằm quá xa trung tâm
Ý nghĩa: Giúp dữ liệu sạch hơn, tránh sai lệch thống kê do những cá nhân có giá trị quá cực đoan

2.6 Chuyển kiểu MalID

dataset$MalID <- as.character(dataset$MalID)

MalID là kiểu số (numeric), nhưng ID → không mang ý nghĩa tính toán.
as.character() chuyển cột này thành kiểu chuỗi (character).

2.7 Điền giá trị thiếu MeanScore

dataset$MeanScore[is.na(dataset$MeanScore)] <- mean(dataset$MeanScore, na.rm = TRUE)

is.na(dataset$MeanScore) → xác định các giá trị bị thiếu (NA).
mean(…, na.rm = TRUE) → tính trung bình của cột, bỏ qua các giá trị NA. Gán giá trị trung bình vào chỗ trống, giúp dữ liệu hoàn chỉnh hơn.

2.8 Tạo nhóm xem

dataset$Watch_Group <- cut(dataset$DaysWatched, breaks = 3, 
                           labels = c("Ít", "Trung bình", "Nhiều"))

cut chia biến liên tục (DaysWatched) thành 3 khoảng đều (breaks = 3).
labels = … gán tên cho từng khoảng.
Kết quả: biến phân loạicó 3 nhóm: “Ít”, “Trung bình”, “Nhiều”.

2.9 Sắp xếp dữ liệu

dataset <- dataset[order(dataset$DaysWatched, decreasing = TRUE), ]

order() sắp xếp các hàng theo giá trị của biến DaysWatched.
decreasing = TRUE → sắp xếp giảm dần (người xem nhiều nhất lên đầu).
Gán lại toàn bộ dataset theo thứ tự mới.

2.10 Tạo biến Productivity

dataset$Productivity <- dataset$EpisodesWatched / dataset$DaysWatched

Tạo biến mới Productivity = số tập xem được / số ngày xem.
Thể hiện hiệu suất xem trung bình mỗi ngày.
Ý nghĩa: Phản ánh tần suất xem, giúp nhận biết người xem ít hay nhiều.

2.11 Tạo biến Total_Watch_Time (giả định)

dataset$Total_Watch_Time <- dataset$DaysWatched * 24

Kết quả biểu thị tổng số giờ xem, giúp biểu diễn dữ liệu trên thang đo thời gian (hours)

2.12 Tạo biến Score_Group

dataset$Score_Group <- ifelse(dataset$MeanScore > 7, "Cao", "Thấp")

ifelse() tạo biến phân loại nhị phân dựa trên điều kiện:
Nếu MeanScore > 7 → nhóm “Cao”.
Ngược lại → nhóm “Thấp”.
Giúp phân loại người dùng hoặc sản phẩm theo mức đánh giá trung bình.

3. THỰC HIỆN CÁC THỐNG KÊ CƠ BẢN

3.1 Phân tổ dữ liệu

female_data <- dataset %>% filter(Gender == "Female")
head(female_data)

%>% — giúp viết code gọn, đọc theo thứ tự tự nhiên.
filter(Gender == “Female”): giữ lại chỉ những dòng có giá trị “Female” trong cột Gender.
head(female_data): hiển thị 6 dòng đầu tiên của dữ liệu nữ để kiểm tra.

male_data <- dataset %>% filter(Gender == "Male")
head(male_data)

Tương tự như trên, nhưng lọc ra những dòng có Gender == “Male”.
male_data bây giờ chỉ chứa người dùng nam.
head() giúp xem nhanh cấu trúc để xác nhận thao tác lọc chính xác.

3.2 Thống kê DaysWatched theo FEMALE

stats_days_female <- with(female_data, c(
  Min = min(DaysWatched), Max = max(DaysWatched), Mean = mean(DaysWatched),
  Median = median(DaysWatched), SD = sd(DaysWatched), Var = var(DaysWatched)
))
stats_days_female
##        Min        Max       Mean     Median         SD        Var 
##    0.00000  172.00000   31.15593   17.60000   36.64637 1342.95657

with(female_data, …): Giúp thực hiện các phép tính bên trong khung dữ liệu female_data mà không cần phải viết female_data$DaysWatched nhiều lần.
c(…): Gom tất cả các kết quả thống kê lại thành một vector có tên (tên các chỉ số như Min, Max, Mean…).
Các hàm thống kê cơ bản:
min() – giá trị nhỏ nhất
max() – giá trị lớn nhất
mean() – giá trị trung bình
median() – trung vị (giá trị giữa khi sắp xếp dữ liệu)
sd() – độ lệch chuẩn (mức độ phân tán dữ liệu quanh trung bình)
var() – phương sai (bình phương của SD)
Ý NGHĨA :Dữ liệu cho thấy số ngày xem của nhóm Female dao động mạnh từ 0 đến 172 ngày, với trung bình 31.16 ngày và trung vị 17.6 ngày.
Phân phối có xu hướng lệch phải, cho thấy phần lớn người dùng nữ có mức độ xem thấp, chỉ một nhóm nhỏ rất tích cực.
Độ lệch chuẩn cao (36.65) phản ánh sự chênh lệch đáng kể trong hành vi xem giữa các thành viên nữ.

3.3 Thống kê DaysWatched theo MALE

stats_days_male <- with(male_data, c(
  Min = min(DaysWatched), Max = max(DaysWatched), Mean = mean(DaysWatched),
  Median = median(DaysWatched), SD = sd(DaysWatched), Var = var(DaysWatched)
))
stats_days_male
##        Min        Max       Mean     Median         SD        Var 
##    0.00000  172.00000   46.36810   33.80000   44.11528 1946.15785

Min = 0: Có người dùng nam chưa xem ngày nào.
Max = 172: Người dùng tích cực nhất xem đủ 172 ngày
Mean = 46.37: Trung bình mỗi người nam xem khoảng 46 ngày.
Median = 33.8: Một nửa số người xem dưới ~34 ngày → phân phối có thể lệch phải (nhiều người xem ít, ít người xem nhiều).
SD = 44.1: Độ lệch chuẩn cao → mức độ xem phim giữa các nam giới rất khác nhau.
Var = 1946.16: Phương sai lớn củng cố rằng dữ liệu phân tán mạnh.
### 3.4 Thống kê MeanScore theo FEMALE

stats_score_female <- with(female_data, c(
  Min = min(MeanScore), Max = max(MeanScore), Mean = mean(MeanScore),
  Median = median(MeanScore), SD = sd(MeanScore)
))
stats_score_female
##       Min       Max      Mean    Median        SD 
##  0.000000 10.000000  6.689808  7.890000  3.240595

Mean = 6.69 và Median = 7.89 → trung vị cao hơn trung bình → phân phối lệch trái (đa số nữ chấm điểm cao, nhưng có vài người chấm rất thấp kéo trung bình xuống).
SD = 3.24 → độ lệch chuẩn khá lớn, thể hiện mức độ khác biệt trong cách đánh giá của nữ giới.
Min = 0 cho thấy có người không chấm điểm hoặc chấm cực thấp; Max = 10 là điểm cao nhất có thể.

3.5 Thống kê MeanScore theo MALE

stats_score_male <- with(male_data, c(
  Min = min(MeanScore), Max = max(MeanScore), Mean = mean(MeanScore),
  Median = median(MeanScore), SD = sd(MeanScore)
))
stats_score_male
##       Min       Max      Mean    Median        SD 
##  0.000000 10.000000  6.853234  7.790000  2.908539

Mean = 6.85 và Median = 7.79 → tương tự nữ, điểm trung vị cao hơn trung bình → phân phối hơi lệch trái.
SD = 2.91 thấp hơn nữ → nam chấm điểm ổn định hơn, ít dao động hơn.
So với nữ, nam có trung bình cao hơn một chút (6.85 vs 6.69) → nhìn chung, hai giới có cách đánh giá khá tương đồng.

3.6 Thống kê EpisodesWatched theo FEMALE

stats_episodes_female <- with(female_data, c(
  Min = min(EpisodesWatched), Max = max(EpisodesWatched), Mean = mean(EpisodesWatched),
  Median = median(EpisodesWatched), SD = sd(EpisodesWatched)
))
stats_episodes_female
##        Min        Max       Mean     Median         SD 
##      0.000 230425.000   1993.355   1058.000   3590.432

3.7 Thống kê EpisodesWatched theo FEMALE

stats_episodes_male <- with(male_data, c(
  Min = min(EpisodesWatched), Max = max(EpisodesWatched), Mean = mean(EpisodesWatched),
  Median = median(EpisodesWatched), SD = sd(EpisodesWatched)
))
stats_episodes_male
##        Min        Max       Mean     Median         SD 
##      0.000 715703.000   2943.234   2018.000   5547.167

Min = 0: có người chưa xem tập nào.
Max = 715,703 tập: một người xem cực nhiều (outlier).
Mean = 2,943 và Median = 2,018 → trung vị nhỏ hơn trung bình → phân phối lệch phải, nghĩa là phần lớn người xem ít, nhưng có một số ít người xem cực kỳ nhiều kéo trung bình lên cao.
SD = 5547 → độ lệch chuẩn rất lớn, chứng tỏ mức độ chênh lệch trong hành vi xem giữa người dùng rất cao.
Kết luận: Có sự phân hóa mạnh trong cường độ xem phim, một số người cực kỳ tích cực (xem hàng trăm nghìn tập), còn đa số xem ít hơn nhiều.

3.8 Thống kê Watching theo giới FEMALE

stats_watching_female <- with(female_data, c(
  Min = min(Watching), Max = max(Watching), Mean = mean(Watching),
  Median = median(Watching), SD = sd(Watching)
))
stats_watching_female
##         Min         Max        Mean      Median          SD 
##    0.000000 1187.000000    7.604905    3.000000   16.461041

Min = 0 → Có người không có anime đang xem.
Max = 1187 → Có người đang theo dõi tới hơn 1000 anime cùng lúc (outlier).
Mean = 7.6, Median = 3 → trung vị thấp hơn nhiều so với trung bình → phân phối lệch phải, hầu hết người dùng nữ chỉ đang xem vài bộ phim.
SD = 16.46 → chênh lệch lớn, phản ánh hành vi xem hiện tại rất khác nhau giữa các cá nhân.
Kết luận: Phần lớn nữ đang theo dõi số lượng nhỏ anime cùng lúc, nhưng có một số ít người “nghiện anime” xem cực nhiều

3.9 Thống kê Watching theo giới MALE

stats_watching_male <- with(male_data, c(
  Min = min(Watching), Max = max(Watching), Mean = mean(Watching),
  Median = median(Watching), SD = sd(Watching)
))
stats_watching_male
##         Min         Max        Mean      Median          SD 
##    0.000000 2579.000000    9.647564    4.000000   26.352849

Max = 2579 → người xem “đỉnh cao”, theo dõi hơn 2.500 anime cùng lúc (cực hiếm).
Mean = 9.65, Median = 4 → trung bình cao hơn nữ một chút → nam giới thường xem song song nhiều anime hơn nữ.
SD = 26.35 → độ lệch chuẩn cao hơn nữ → sự khác biệt giữa các nam giới càng lớn hơn nữa.
Kết luận :Nam giới có xu hướng xem nhiều anime cùng lúc hơn, và nhóm người cực kỳ hoạt động (super viewers) nhiều hơn nữ, cả hai giới đều có phân phối lệch phải, nhưng nam giới độ phân tán cao hơn rõ rệt.

3.10 Thống kê Completed theo FEMALE

stats_completed_female <- with(female_data, c(
  Min = min(Completed), Max = max(Completed), Mean = mean(Completed),
  Median = median(Completed), SD = sd(Completed)
))
stats_completed_female
##        Min        Max       Mean     Median         SD 
##    0.00000 4299.00000   80.87837   34.00000  118.82165

Min = 0 → có người chưa hoàn thành anime nào.
Max = 4299 → có người đã hoàn tất hơn 4000 anime (rất hiếm, outlier).
Mean = 80.9, Median = 34 → trung bình cao hơn trung vị → phân phối lệch phải, phần lớn người xem hoàn thành ít, nhưng có một nhóm nhỏ hoàn thành rất nhiều.
SD = 118.8 → chênh lệch lớn, thể hiện sự khác biệt rõ rệt về mức độ “xem hết” giữa người dùng nữ.
Kết luận: Người dùng nữ nhìn chung có mức độ hoàn thành thấp (chủ yếu chỉ hoàn thành vài chục anime), nhưng có một số ít “fan cứng” hoàn thành hàng nghìn bộ phim.

3.11 Thống kê Completed theo MALE

stats_completed_male <- with(male_data, c(
  Min = min(Completed), Max = max(Completed), Mean = mean(Completed),
  Median = median(Completed), SD = sd(Completed)
))
stats_completed_male
##       Min       Max      Mean    Median        SD 
##    0.0000 2821.0000  124.3644   69.0000  149.4438

Mean (124) và Median (69) đều cao hơn nữ → nam giới có xu hướng hoàn thành nhiều anime hơn.
SD = 149.4 cũng cao hơn → mức độ chênh lệch giữa người xem ít và người xem nhiều lớn hơn nữa.
Phân phối lệch phải tương tự nữ: phần lớn người chỉ hoàn thành ít phim, nhưng có một số hoàn thành cực nhiều.
Kết luận: Nam giới xem và hoàn thành nhiều hơn so với nữ, đồng thời có sự phân hóa mạnh trong hành vi xem.

3.12 Tương quan DaysWatched và EpisodesWatched

correlation <- cor(dataset$DaysWatched, dataset$EpisodesWatched)
correlation
## [1] 0.5397925

Hàm cor() tính hệ số tương quan Pearson (r) giữa hai biến liên tục:
DaysWatched: tổng số ngày người dùng đã dành ra để xem anime.
EpisodesWatched: tổng số tập đã xem.
Giá trị r nằm trong [-1, 1]:
r > 0 → tương quan thuận (biến này tăng → biến kia tăng).
r < 0 → tương quan nghịch.
|r| gần 1 → tương quan mạnh; |r| gần 0 → yếu.
r = 0.54 → tương quan thuận mức trung bình giữa hai biến
→ Người xem càng nhiều ngày thì thường cũng xem càng nhiều tập.
### 3.13 Kiểm định t-test MeanScore ### Lọc chỉ lấy 2 nhóm mong muốn

dataset_sub <- dataset %>% filter(Gender %in% c("Male", "Female"))

Chạy t-test trên dữ liệu đã lọc

t_test_result <- t.test(MeanScore ~ Gender, data = dataset_sub)
t_test_result
## 
##  Welch Two Sample t-test
## 
## data:  MeanScore by Gender
## t = -12.007, df = 189558, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group Female and group Male is not equal to 0
## 95 percent confidence interval:
##  -0.1901019 -0.1367491
## sample estimates:
## mean in group Female   mean in group Male 
##             6.689808             6.853234

Hàm t.test() được dùng để so sánh trung bình của hai nhóm độc lập (Independent Samples t-test).
Biến phụ thuộc: MeanScore (điểm trung bình người dùng chấm anime).
Biến độc lập: Gender (Male / Female).

3.14 Phân tích phương sai

anova_result <- aov(DaysWatched ~ Gender, data = dataset)
summary(anova_result)
##                 Df    Sum Sq Mean Sq F value Pr(>F)    
## Gender           2  12362797 6181399    3684 <2e-16 ***
## Residuals   210425 353109386    1678                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Giả thuyết kiểm định:
H₀: Không có sự khác biệt về MeanScore giữa nam và nữ.
H₁: Có sự khác biệt về MeanScore giữa nam và nữ.
p-value < 2.2e-16 → rất nhỏ hơn 0.05, bác bỏ giả thuyết H0.
Nghĩa là có sự khác biệt có ý nghĩa thống kê giữa điểm trung bình của hai giới.
So sánh trung bình: Nữ: 6.6898 Nam: 6.8532
→ Trung bình điểm của nam cao hơn nữ khoảng 0.16 điểm (khoảng tin cậy không chứa 0, củng cố kết luận có khác biệt).

3.15 Thống kê tổng số theo giới tính

total_stats <- dataset %>%
  group_by(Gender) %>%
  summarise(
    Total_Days = sum(DaysWatched), Total_Episodes = sum(EpisodesWatched),
    Total_Entries = sum(TotalEntries), Avg_Score = mean(MeanScore)
  )
total_stats

group_by(Gender): chia dữ liệu theo từng nhóm giới tính (Female, Male, Non-Binary).
summarise(): tính toán các thống kê tổng hợp cho từng nhóm:
Total_Days: tổng số ngày xem của từng nhóm giới tính.
Total_Episodes: tổng số tập phim đã xem.
Total_Entries: tổng số mục (entries) mà nhóm đó có.
Avg_Score: điểm trung bình (mean) mà nhóm đó đánh giá.
Nhận xét: Nam (Male) chiếm tỷ trọng hoạt động cao nhất: có tổng số ngày, số tập và số lượt xem cao hơn hẳn hai nhóm còn lại.
→ nam có xu hướng hoạt động tích cực hơn trong dữ liệu (xem nhiều hơn, đánh giá nhiều hơn).
Nữ (Female) xếp thứ hai, chiếm khoảng 35–40% tổng hoạt động.
Non-Binary tuy có quy mô mẫu nhỏ (rất thấp so với 2 nhóm còn lại), nhưng Avg_Score (7.23) lại cao nhất, nghĩa là họ đánh giá nội dung cao hơn trung bình so với các giới tính khác.

3.16 Phân bố phần trăm giới tính

gender_dist <- prop.table(table(dataset$Gender)) * 100
gender_dist
## 
##     Female       Male Non-Binary 
## 44.3738476 55.2355200  0.3906324

table(dataset$Gender): đếm số lượng người thuộc từng giới tính.
prop.table(…): chuyển đổi thành tỷ lệ phần trăm (%).
Nhân với 100 để hiển thị phần trăm.
Ý nghĩa: Dữ liệu cho thấy nam giới chiếm hơn nửa tổng mẫu (≈55%), trong khi nữ giới chiếm khoảng 44%.
Non-Binary chỉ chiếm 0.39%, tức là gần như không đáng kể về mặt số lượng thống kê.

3.17 Thống kê Rewatched theo FEMALE

stats_rewatch_female <- with(female_data, c(
  Min = min(Rewatched), Max = max(Rewatched), Mean = mean(Rewatched),
  Median = median(Rewatched), SD = sd(Rewatched)
))
stats_rewatch_female
##        Min        Max       Mean     Median         SD 
##   0.000000 555.000000   6.585114   0.000000  19.962080

3.18 Thống kê Rewatched theo MALE

stats_rewatch_male <- with(male_data, c(
  Min = min(Rewatched), Max = max(Rewatched), Mean = mean(Rewatched),
  Median = median(Rewatched), SD = sd(Rewatched)
))
stats_rewatch_male
##       Min       Max      Mean    Median        SD 
##   0.00000 625.00000   8.02132   0.00000  23.10559

Cả hai nhóm đều có Median = 0, nghĩa là phần lớn người dùng không xem lại (rewatch) phim.
Tuy nhiên, Mean của nhóm nam (≈8.02) cao hơn nữ (≈6.59) → nhóm nam có xu hướng xem lại nhiều hơn trung bình.
Độ lệch chuẩn (SD) của nam (23.11) cũng cao hơn → hành vi xem lại của nam phân tán hơn, tức là có những người xem lại rất nhiều lần, trong khi phần lớn ít hoặc không xem lại.

3.19 Ma trận tương quan

cor_matrix <- cor(dataset[, c("DaysWatched", "MeanScore", "EpisodesWatched", "Watching")])
cor_matrix
##                 DaysWatched MeanScore EpisodesWatched  Watching
## DaysWatched       1.0000000 0.2346507       0.5397925 0.2913603
## MeanScore         0.2346507 1.0000000       0.1387855 0.1096703
## EpisodesWatched   0.5397925 0.1387855       1.0000000 0.1532229
## Watching          0.2913603 0.1096703       0.1532229 1.0000000

Hàm cor() tính hệ số tương quan giữa các biến định lượng.
Kết quả là một ma trận vuông, trong đó:
Mỗi giá trị nằm giữa -1 và 1
Gần 1 → tương quan thuận mạnh
Gần -1 → tương quan nghịch mạnh
Gần 0 → không có mối liên hệ tuyến tính đáng kể.
Diễn giải: DaysWatched ↔︎ EpisodesWatched (r = 0.54)
→ Có tương quan thuận vừa phải, hợp lý: người xem nhiều ngày thì cũng xem nhiều tập phim.
DaysWatched ↔︎ MeanScore (r = 0.23)
→ Mối quan hệ yếu nhưng dương: người xem nhiều ngày có xu hướng đánh giá cao hơn.
MeanScore ↔︎ EpisodesWatched (r = 0.14)
→ Tương quan yếu, cho thấy việc xem nhiều chưa chắc dẫn đến điểm đánh giá cao.
Watching ↔︎ các biến khác (r ≈ 0.15–0.29)
→ Mối quan hệ yếu → biến “watching” có thể đại diện trạng thái hoặc thói quen, không hoàn toàn song hành với mức độ xem hoặc đánh giá.

3.20 Thống kê theo nhóm xem

watch_group_stats <- dataset %>%
  group_by(Watch_Group) %>%
  summarise(Count = n(), Avg_Days = mean(DaysWatched), Avg_Score = mean(MeanScore))
watch_group_stats

group_by(Watch_Group): chia dữ liệu thành 3 nhóm người xem:
“Ít”
“Trung bình”
“Nhiều”
summarise():
Count: số lượng người trong mỗi nhóm.
Avg_Days: số ngày xem trung bình của nhóm đó (được tính từ biến DaysWatched).
Avg_Score: điểm trung bình đánh giá của nhóm (biến MeanScore).
Ý nghĩa
Phân bố số lượng (Count):
Nhóm “Ít” chiếm đa số (~70% tổng mẫu, 153k người).
Nhóm “Trung bình” chiếm khoảng 20%,
Nhóm “Nhiều” chỉ khoảng 7–8%, tức là số người xem cực nhiều khá hiếm.
→ Phân bố này cho thấy hành vi xem có xu hướng nghiêng mạnh về nhóm ít xem (phân bố lệch phải).

4. TRỰC QUAN HÓA DỮ LIỆU (20 BIỂU ĐỒ - MỖI BIỂU ĐỒ 5+ LAYER)

đảm bảo các biến factor nếu cần

dataset <- dataset %>%
  mutate(
    Gender = as.factor(Gender),
    Watch_Group = as.factor(Watch_Group)
  )

mutate() dùng để tạo hoặc thay đổi biến trong bộ dữ liệu.
as.factor() chuyển biến từ dạng character hoặc numeric → factor

small helper để tránh lỗi với NA khi tính max/min/mean

safe_mean <- function(x) mean(x, na.rm = TRUE)
safe_max  <- function(x) max(x, na.rm = TRUE)
safe_min  <- function(x) min(x, na.rm = TRUE)

Hàm tự định nghĩa (custom functions) nhằm tránh lỗi khi trong dữ liệu có giá trị NA (missing value).

4.1 Biểu đồ cột - Phân bố giới tính (6 layer)

p1 <- ggplot(dataset, aes(x = Gender, fill = Gender)) +
  geom_bar(alpha = 0.85, width = 0.7) +
  geom_text(stat = 'count', aes(label = after_stat(count)), vjust = -0.5, size = 4) +
  geom_hline(yintercept = nrow(dataset) / 2, linetype = "dashed", color = "red", size = 0.6) +
  labs(title = "PHÂN BỐ GIỚI TÍNH", x = "Giới tính", y = "Số lượng") +
  theme_minimal()
print(p1)

Biểu đồ được tạo bằng ggplot2 với 6 lớp (layer):
geom_bar() vẽ cột thể hiện số lượng từng giới tính.
geom_text() hiển thị số liệu đếm trên mỗi cột.
geom_hline() thêm đường ngang đỏ dạng nét đứt ở vị trí nửa tổng mẫu để so sánh mức phân bố.
labs() đặt tiêu đề và nhãn trục.
theme_minimal() giúp biểu đồ rõ ràng, tối giản.
Ý nghĩa:
Nhóm “Male” chiếm tỷ lệ cao nhất (118,231 người).
Nhóm “Female” đứng thứ hai (93,375 người).
Nhóm “Non-Binary” rất ít (822 người), thể hiện rõ tính mất cân bằng giới tính trong mẫu khảo sát.
Đường đỏ đứt nét cho thấy không nhóm nào đạt đến mức một nửa tổng mẫu (≈106,214 người).

4.2 Biểu đô cột - Trung bình DaysWatched (6 layer)

p2 <- dataset %>%
  group_by(Gender) %>%
  summarise(Avg_Days = safe_mean(DaysWatched), n = n()) %>%
  ggplot(aes(x = Gender, y = Avg_Days, fill = Gender)) +
  geom_col(alpha = 0.85, width = 0.6) +
  geom_text(aes(label = round(Avg_Days, 1)), vjust = -0.6, size = 4, fontface = "bold") +
  geom_hline(yintercept = safe_mean(dataset$DaysWatched), linetype = "dashed", color = "red", size = 0.8) +
  geom_errorbar(aes(ymin = Avg_Days - sd(dataset$DaysWatched, na.rm = TRUE)/10,
                    ymax = Avg_Days + sd(dataset$DaysWatched, na.rm = TRUE)/10),
                width = 0.2, size = 0.6) +
  labs(title = "SỐ NGÀY XEM TRUNG BÌNH", y = "Số ngày") +
  theme_bw()
print(p2)

Biểu đồ được xây dựng bằng ggplot2 gồm nhiều lớp:
geom_col() vẽ các cột thể hiện số ngày xem trung bình (Avg_Days) theo giới tính.
geom_text() hiển thị nhãn số liệu trên mỗi cột.
geom_hline() thêm đường trung bình toàn bộ mẫu (màu đỏ, nét đứt) để dễ so sánh.
geom_errorbar() thể hiện độ lệch chuẩn (SD), giúp thấy mức dao động của dữ liệu trong từng nhóm.
labs() và theme_bw() định dạng tiêu đề, nhãn trục và bố cục trực quan.
Biểu đồ cho thấy: Non-Binary có số ngày xem trung bình cao nhất (≈ 61.2 ngày), vượt đáng kể mức trung bình chung, cho thấy nhóm này xem nội dung nhiều và thường xuyên hơn.
Nam giới (≈ 46.4 ngày) cũng cao hơn trung bình, phản ánh mức độ xem tích cực hơn nữ.
Nữ giới (≈ 31.2 ngày) thấp hơn trung bình, thể hiện thời gian xem ít hơn.
Thanh sai số (SD) cho thấy Non-Binary có mức phân tán lớn nhất, nghĩa là hành vi xem trong nhóm này đa dạng hơn giữa các cá nhân.

4.3 Biểu đồ đường - Xu hướng điểm số (6 layer)

p3 <- dataset %>%
  group_by(Watch_Group, Gender) %>%
  summarise(Avg_Score = safe_mean(MeanScore), .groups = "drop") %>%
  ggplot(aes(x = Watch_Group, y = Avg_Score, color = Gender, group = Gender)) +
  geom_line(size = 1.2, alpha = 0.9) +
  geom_point(size = 3, shape = 21, fill = "white", stroke = 1) +
  geom_text(aes(label = round(Avg_Score, 2)), vjust = -1, size = 3.2) +
  geom_ribbon(aes(ymin = Avg_Score - 0.1, ymax = Avg_Score + 0.1, fill = Gender), alpha = 0.08, color = NA) +
  labs(title = "XU HƯỚNG ĐIỂM SỐ THEO NHÓM XEM", x = "Nhóm xem", y = "Điểm TB") +
  theme_minimal()
print(p3)

Về mặt kỹ thuật:Biểu đồ đường (line chart) thể hiện mối quan hệ giữa mức độ xem (ít – trung bình – nhiều) và điểm trung bình (Avg_Score) cho từng giới tính.
Mỗi đường màu biểu diễn một giới, với vùng bóng mờ (ribbon) thể hiện khoảng dao động sai số ±0.1 điểm quanh trung bình – giúp minh họa độ ổn định của dữ liệu.
Về mặt thống kê:Xu hướng chung: Điểm trung bình tăng mạnh từ nhóm xem “ít” → “trung bình”, cho thấy tần suất xem cao hơn gắn với đánh giá tốt hơn.
Theo giới tính:Nữ (đỏ): Điểm tăng rõ nhất, từ 6.57 → 7.58, rồi ổn định ở 7.48 → cho thấy nhóm nữ phản ứng tích cực nhất khi tần suất xem tăng.
Nam (xanh lá): Cũng tăng tương tự nhưng thấp hơn nhẹ (6.59 → 7.48 → 7.38).
Non-binary (xanh dương): Điểm khá ổn định (khoảng 7.2–7.38), ít biến động → xu hướng đánh giá nhất quán hơn

4.4 Biểu đồ tròn - Phần trăm giới tính (6 layer)

p4 <- dataset %>%
  count(Gender) %>%
  mutate(Percentage = n / sum(n) * 100) %>%
  ggplot(aes(x = "", y = Percentage, fill = Gender)) +
  geom_col(width = 1, color = "white") +
  coord_polar("y", start = 0) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")),
            position = position_stack(vjust = 0.5), size = 4, color = "white", fontface = "bold") +
  labs(title = "PHÂN BỐ PHẦN TRĂM GIỚI TÍNH") +
  theme_void()
print(p4)

count(Gender) → Đếm số lượng mẫu theo từng giới tính.
mutate(Percentage = n / sum(n) * 100) → Tính phần trăm giới tính trong tổng mẫu.
geom_col() → Vẽ các cột biểu thị tỷ lệ; color=“white” tạo viền ngăn cách.
coord_polar(“y”) → Chuyển biểu đồ cột sang dạng tròn (pie chart).
geom_text() → Hiển thị nhãn phần trăm trên từng lát cắt, căn giữa và in đậm.
labs() → Đặt tiêu đề biểu đồ.
theme_void() → Loại bỏ trục, nhãn, lưới để biểu đồ nổi bật hơn.
Ý NGHĨA: Nam giới chiếm tỷ lệ cao nhất (55,2%).
Nữ giới chiếm 44,4%.
Non-Binary chỉ chiếm 0,4%, gần như không đáng kể.

4.5 Biểu đồ cột stacked - Trạng thái xem (6 layer)

if (!"OnHold" %in% names(dataset)) dataset$OnHold <- 0
p5 <- dataset %>%
  group_by(Gender) %>%
  summarise(Watching = sum(Watching, na.rm = TRUE),
            Completed = sum(Completed, na.rm = TRUE),
            OnHold = sum(OnHold, na.rm = TRUE),
            .groups = "drop") %>%
  pivot_longer(cols = c(Watching, Completed, OnHold), names_to = "Status", values_to = "Count") %>%
  ggplot(aes(x = Gender, y = Count, fill = Status)) +
  geom_col(position = "stack", alpha = 0.85, color = "black", size = 0.2) +
  geom_text(aes(label = Count), position = position_stack(vjust = 0.5), color = "white", size = 3) +
  geom_hline(yintercept = seq(0, safe_max(dataset$Watching + dataset$Completed), by = 50), 
             linetype = "dotted", alpha = 0.3) +
  labs(title = "TRẠNG THÁI XEM THEO GIỚI TÍNH", y = "Số lượng") +
  theme_minimal()
print(p5)

group_by(Gender) → Gom nhóm theo giới tính. summarise() → Tính tổng số lượng từng trạng thái xem (Watching, Completed, OnHold). pivot_longer() → Chuyển dữ liệu từ dạng rộng sang dài để vẽ cột chồng.
geom_col(position=“stack”) → Vẽ biểu đồ cột chồng thể hiện tổng số lượt xem theo trạng thái.
geom_text() → Hiển thị số lượng ngay trên cột.
geom_hline() → Thêm đường ngang chấm để định hướng tỷ lệ.
theme_minimal() → Tạo giao diện đơn giản, dễ đọc.
Ý nghĩa
Nam giới có số lượng xem cao nhất, đặc biệt ở trạng thái “Completed” (≈ 14,45 triệu lượt).
Nữ giới thấp hơn, với khoảng 7,55 triệu lượt Completed.
Non-Binary hầu như không đáng kể trong tổng thể dữ liệu.
Trạng thái “Watching” và “OnHold” chỉ chiếm phần nhỏ, cho thấy đa số người dùng có xu hướng xem trọn vẹn hơn là bỏ dở.

4.6 Biểu đồ cột grouped - So sánh chỉ số (7 layer)

p6 <- dataset %>%
  group_by(Gender) %>%
  summarise(Avg_Days = safe_mean(DaysWatched),
            Avg_Episodes = safe_mean(EpisodesWatched),
            Avg_Score = safe_mean(MeanScore),
            .groups = "drop") %>%
  pivot_longer(cols = c(Avg_Days, Avg_Episodes, Avg_Score), names_to = "Metric", values_to = "Value") %>%
  ggplot(aes(x = Metric, y = Value, fill = Gender)) +
  geom_col(position = position_dodge(width = 0.7), alpha = 0.85, width = 0.7) +
  geom_text(aes(label = round(Value, 1)), position = position_dodge(width = 0.7), vjust = -0.5, size = 3) +
  geom_errorbar(aes(ymin = Value - Value*0.05, ymax = Value + Value*0.05),
                position = position_dodge(width = 0.7), width = 0.2, size = 0.4) +
  labs(title = "SO SÁNH CHỈ SỐ THEO GIỚI TÍNH", y = "Giá trị trung bình") +
  theme_classic()
print(p6)

group_by() + summarise() → gom nhóm và tính trung bình.
pivot_longer() → biến các cột trung bình thành một cột “Metric” để dễ vẽ.
geom_col() → biểu đồ cột.
geom_errorbar() → thêm thanh sai số ±5% mô phỏng khoảng tin cậy.
geom_text() → ghi giá trị trung bình lên mỗi cột.
theme_classic() → hiển thị đồ thị đẹp, dễ đọc.
Ý NGHĨA
Biểu đồ cho thấy sự khác biệt rõ rệt giữa các giới tính ở ba chỉ số:
Avg_Days:
Nam (46.4 ngày) cao hơn Nữ (31.2 ngày), cho thấy nam giới có xu hướng duy trì hoạt động xem lâu hơn.
Non-Binary cao nhất (61.2 ngày), thể hiện mức độ gắn bó cao nhất.
Avg_Episodes:
Nữ xem trung bình 1.993 tập, thấp hơn nhiều so với Nam (2.973 tập) và Non-Binary (3.762 tập).
Điều này phản ánh khả năng “cày phim” cao hơn ở hai nhóm sau.
Avg_Score:
Các nhóm có mức điểm trung bình khá tương đồng (6.7–7.2), chứng tỏ đánh giá chất lượng không khác biệt lớn giữa các giới.
Thanh sai số (error bar) nhỏ → mức dao động thấp, các giá trị trung bình đáng tin cậy.

4.7 Biểu đồ cột có điều kiện - Trên trung bình (6 layer)

p7 <- dataset %>%
  mutate(Above_Avg = DaysWatched > safe_mean(DaysWatched)) %>%
  ggplot(aes(x = Gender, fill = Above_Avg)) +
  geom_bar(position = "fill", alpha = 0.85, width = 0.6, color = "black", size = 0.2) +
  geom_text(stat = 'count', aes(label = after_stat(count), group = Above_Avg),
            position = position_fill(vjust = 0.5), color = "white", size = 4) +
  geom_hline(yintercept = 0.5, linetype = "dashed", color = "yellow", size = 0.8) +
  labs(title = "TỶ LỆ NGƯỜI DÙNG CÓ SỐ NGÀY XEM TRÊN TRUNG BÌNH", y = "Tỷ lệ") +
  theme_bw()
print(p7)

Trục Y = tỷ lệ (%) đã được chuẩn hóa về tổng 1.0 (100%) cho từng giới tính thông qua position = “fill”.
Dòng kẻ ngang màu vàng tại 0.5 (50%) được thêm bằng geom_hline() để làm mức tham chiếu trung bình.
Các con số bên trong cột là số lượng người thực tế (geom_text()).
Màu đỏ = Không đạt trên mức trung bình (FALSE), màu xanh = Đạt trên mức trung bình (TRUE).
Biểu đồ đang so sánh tỷ lệ người dùng có số ngày xem video cao hơn trung bình giữa 3 giới: Female, Male, Non-Binary.
Giới Non-Binary có tỷ lệ người dùng xem nhiều ngày cao nhất (61%), vượt mức 50% → nhóm có mức độ tương tác tốt nhất.
Nam giới có tỷ lệ tương đối cân bằng (45%), nhưng vẫn thấp hơn mức trung bình.
Nữ giới có tỷ lệ thấp nhất (29%), cho thấy mức độ sử dụng kém hơn đáng kể so với hai nhóm còn lại.
Dòng ngang 50% giúp nhận biết nhanh nhóm nào vượt ngưỡng và nhóm nào dưới ngưỡng → hỗ trợ ra quyết định marketing phân khúc.

4.8 Biểu đồ Đường kết hợp điểm - Xu hướng theo phân vị (7 layer)

p8 <- dataset %>%
  mutate(Percentile = ntile(DaysWatched, 4)) %>%
  group_by(Percentile, Gender) %>%
  summarise(Avg_Score = safe_mean(MeanScore), .groups = "drop") %>%
  ggplot(aes(x = Percentile, y = Avg_Score, color = Gender)) +
  geom_line(size = 1.2, alpha = 0.9) +
  geom_point(size = 3) +
  geom_text(aes(label = round(Avg_Score, 2)), vjust = -0.9, size = 3) +
  geom_smooth(method = "lm", se = FALSE, linetype = "dashed", alpha = 0.5) +
  geom_ribbon(aes(ymin = Avg_Score - 0.05, ymax = Avg_Score + 0.05, fill = Gender), alpha = 0.08, color = NA) +
  labs(title = "XU HƯỚNG ĐIỂM SỐ THEO PHÂN VỊ", x = "Phân vị", y = "Điểm TB") +
  theme_minimal()
print(p8)

Phân vị (Percentile) được tạo bằng ntile(DaysWatched, 4) → chia người dùng thành 4 nhóm theo số ngày xem video (từ thấp → cao).
Dữ liệu được gom theo 2 biến: Percentile và Gender, sau đó tính Avg_Score = điểm trung bình xem video của từng nhóm bằng safe_mean.
Biểu đồ sử dụng line chart (đường nối) để thể hiện xu hướng điểm theo phân vị giữa các giới tính.
geom_text() được dùng để hiển thị giá trị điểm trung bình trên từng điểm dữ liệu.
geom_smooth(method = “lm”) thêm đường xu hướng hồi quy tuyến tính (dashed) → giúp nhận biết độ dốc tăng/giảm.
geom_ribbon() tạo lớp mờ xung quanh đường nhằm nhấn mạnh sự ổn định biến động (±0.05).
Trục X: Phân vị (1 = nhóm xem ít nhất, 4 = nhóm xem nhiều nhất).
Trục Y: Điểm trung bình (MeanScore).
Ý NGHĨA
Điểm trung bình tăng mạnh từ phân vị 1 → 2, sau đó có xu hướng giảm nhẹ ở các phân vị cao hơn (3 → 4).
Điều này cho thấy: những người xem rất ít video có điểm thấp, nhưng người xem nhiều nhất chưa chắc có điểm cao nhất → có dấu hiệu hiệu ứng “bão hòa”.

4.9 Biểu đồ cột với error bars (7 layer)

p9 <- dataset %>%
  group_by(Gender) %>%
  summarise(Mean_Days = safe_mean(DaysWatched), SE = sd(DaysWatched, na.rm = TRUE)/sqrt(n()), .groups = "drop") %>%
  ggplot(aes(x = Gender, y = Mean_Days, fill = Gender)) +
  geom_col(alpha = 0.75, width = 0.6) +
  geom_errorbar(aes(ymin = Mean_Days - SE, ymax = Mean_Days + SE), width = 0.2, color = "black", size = 0.6) +
  geom_text(aes(label = round(Mean_Days, 1)), vjust = -0.5, size = 4, fontface = "bold") +
  geom_hline(yintercept = safe_mean(dataset$DaysWatched), linetype = "dotted", color = "red", size = 0.8) +
  labs(title = "SỐ NGÀY XEM TRUNG BÌNH VỚI SAI SỐ", y = "Số ngày") +
  theme_light()
print(p9)

4.10 Biểu đồ tròn có điều kiện - Giới tính nhóm xem nhiều (6 layer)

p10 <- dataset %>%
  filter(Watch_Group == "Nhiều") %>%
  count(Gender) %>%
  mutate(Percentage = n / sum(n) * 100) %>%
  ggplot(aes(x = "", y = Percentage, fill = Gender)) +
  geom_col(width = 1, color = "white") +
  coord_polar("y", start = 0) +
  geom_text(aes(label = paste0(round(Percentage, 1), "%")), position = position_stack(vjust = 0.5), size = 4) +
  labs(title = "GIỚI TÍNH TRONG NHÓM XEM NHIỀU") +
  theme_void()
print(p10)

Biểu đồ được tạo sau khi lọc nhóm người dùng có mức xem cao (Watch_Group == “Nhiều”), tức nhóm top viewers.
Dữ liệu được đếm theo giới tính và quy đổi sang tỷ lệ phần trăm (n / sum(n) * 100).
Biểu đồ sử dụng geom_col + coord_polar() để chuyển cột thành biểu đồ tròn (pie chart).
Nữ giới chiếm 26.8%, tức chỉ bằng khoảng 1/3 số nam, cho thấy mức độ xem thấp hơn đáng kể.
Non-Binary chỉ chiếm 0.7%, gần như không đáng kể trong nhóm xem nhiều.
Kết luận: Nam là nhóm có xu hướng binge–watch cao nhất, đóng vai trò chính trong nhóm người xem nhiều tập.

4.11 Biểu đồ Histogram DaysWatched (6 layer)

p11 <- ggplot(dataset, aes(x = DaysWatched, fill = Gender)) +
  geom_histogram(bins = 15, alpha = 0.7, position = "identity", color = "black", size = 0.2) +
  geom_density(aes(y = after_stat(count)), color = "black", size = 0.7, alpha = 0.4) +
  geom_vline(xintercept = safe_mean(dataset$DaysWatched), linetype = "dashed", color = "red", size = 0.8) +
  facet_wrap(~Gender, ncol = 1) +
  labs(title = "PHÂN BỐ SỐ NGÀY XEM THEO GIỚI TÍNH", x = "Số ngày xem", y = "Tần số") +
  theme_classic()
print(p11)

(DaysWatched) theo từng giới tính, chia thành 15 bins.
Lớp density curve (đường đen) được thêm để mô tả hình dạng phân phối, giúp nhận diện độ lệch (skewness).
Biểu đồ được tách thành 3 panel bằng facet_wrap(), cho phép so sánh trực quan mà không bị chồng dữ liệu.
Đường gạch đỏ là giá trị trung bình toàn bộ mẫu (~45 ngày), dùng làm chuẩn so sánh giữa các nhóm.
Nhóm Female có phân bố lệch phải rõ rệt, đa số người xem dưới 30 ngày, rất ít người vượt 120 ngày.
Trung bình nhóm Female thấp hơn mức chung, khoảng 38 ngày, cho thấy mức độ xem không cao.
Kết luận: Nam xem nhiều ngày hơn và phân bố trải rộng nhất, nữ ở mức trung bình, non-binary thấp và ổn định hơn.

4.12 Biểu đồ Boxplot EpisodesWatched (7 layer)

p12 <- ggplot(dataset, aes(x = Gender, y = EpisodesWatched, fill = Gender)) +
  geom_boxplot(alpha = 0.75, outlier.color = "red", outlier.shape = 16) +
  geom_jitter(width = 0.2, alpha = 0.4, size = 1, color = "gray30") +
  stat_summary(fun = mean, geom = "point", shape = 18, size = 3, color = "red") +
  geom_hline(yintercept = safe_mean(dataset$EpisodesWatched), linetype = "dashed", color = "blue", size = 0.8) +
  labs(title = "PHÂN BỐ SỐ TẬP THEO GIỚI TÍNH", y = "Số tập") +
  theme_bw()
print(p12)

Điểm màu đỏ hình thoi là giá trị trung bình (mean) của mỗi nhóm giới, được thêm bằng stat_summary().
Đường gạch xanh là mức trung bình toàn bộ mẫu, giúp so sánh phương sai giữa các nhóm.
Nhóm Male có trung bình số tập cao nhất, khoảng ~45.000 tập, vượt mức trung bình chung (~28.000 tập).
Nhóm Female có trung bình thấp hơn, khoảng ~22.000 tập, nằm dưới mức chung.
Boxplot của Male rộng hơn ⇒ độ biến động lớn, cho thấy sự chênh lệch mạnh giữa người xem ít và người xem cực nhiều.
Có nhiều outliers (điểm đỏ) trong nhóm Male, đặc biệt có người xem hơn 600.000 tập, chứng tỏ hành vi binge-watching cực đoan.
Nhóm Female có ít outlier hơn và phân bố tập trung, thể hiện mức độ xem ổn định hơn.
Kết luận: Giới tính có ảnh hưởng rõ rệt đến mức độ xem, trong đó nam giới nhóm xem nhiều tập nhất và có độ phân tán lớn nhất.
### 4.13 Biểu đồ Scatter plot có điều kiện (7 layer)

top_thresh <- quantile(dataset$DaysWatched, 0.9, na.rm = TRUE)
p13 <- ggplot(dataset, aes(x = DaysWatched, y = EpisodesWatched, color = Gender, size = MeanScore)) +
  geom_point(alpha = 0.7) +
  geom_smooth(method = "lm", se = TRUE, alpha = 0.2, size = 0.8) +
  geom_rug(alpha = 0.5) +
  labs(title = "MỐI QUAN HỆ NGÀY XEM VÀ SỐ TẬP", x = "Số ngày xem", y = "Số tập") +
  theme_light()
if ("Username" %in% names(dataset)) {
  p13 <- p13 +
    geom_text(data = dataset %>% filter(DaysWatched > top_thresh),
              aes(label = Username), vjust = -0.5, size = 2.5, check_overlap = TRUE)
}
print(p13)

Biểu đồ sử dụng geom_point() để thể hiện mối quan hệ giữa DaysWatched (trục X) và EpisodesWatched (trục Y) dưới dạng scatter plot.
Mỗi điểm dữ liệu được tô màu theo Gender và kích thước điểm phản ánh MeanScore → điểm càng to nghĩa là đánh giá càng cao.
geom_smooth(method = “lm”) được thêm vào để fit đường hồi quy tuyến tính, giúp nhận diện xu hướng tổng quát giữa hai biến.
Kết quả đường hồi quy cho thấy xu hướng dương rõ rệt: người xem càng nhiều ngày thì số tập xem càng tăng theo.
Các giá trị tập trung dày ở khu vực 0–60 ngày xem và dưới 200.000 tập, thể hiện hành vi xem trung bình của đa số người dùng.
Điểm ngoại lệ (outlier) xuất hiện ở nhóm nam, có user xem >150 ngày và >600.000 tập, chứng tỏ nhóm này có mức độ binge-watching cao nhất.
Nhóm Female có phân bố thấp hơn, chủ yếu rơi vào vùng <100 ngày và <200k tập → tần suất xem thấp hơn nam.
Tổng quan: có mối quan hệ tuyến tính tích cực giữa số ngày xem và số tập, với nam giới là nhóm hoạt động cao nhất, đồng thời những người có điểm đánh giá cao (MeanScore lớn) thường thuộc nhóm xem nhiều tập.

4.14 Biểu đồ Density plot MeanScore (6 layer)

p14 <- ggplot(dataset, aes(x = MeanScore, fill = Gender)) +
  geom_density(alpha = 0.5, color = "black", size = 0.5) +
  geom_vline(xintercept = safe_mean(dataset$MeanScore), linetype = "dashed", color = "red", size = 0.8) +
  geom_rug(aes(color = Gender), sides = "b", alpha = 0.5) +
  facet_grid(Gender ~ .) +
  labs(title = "MẬT ĐỘ PHÂN PHỐI ĐIỂM SỐ", x = "Điểm trung bình") +
  theme_minimal()
print(p14)

Biểu đồ density thể hiện phân phối điểm trung bình (MeanScore) theo giới tính, được vẽ bằng geom_density().
Đường đỏ dọc đánh dấu điểm trung bình toàn bộ mẫu (~7.1) dùng làm mốc so sánh giữa các nhóm.
Biểu đồ được tách theo panel (facet_grid) giúp quan sát từng giới rõ ràng, không chồng dữ liệu.
Nhóm Male có đỉnh phân phối cao nhất (~7.6–7.8), phần lớn điểm nằm trên mức trung bình chung.
Điều này cho thấy nam đạt điểm tốt nhất trong ba nhóm cả về trung bình lẫn mật độ điểm cao.
Nhóm Female phân bố lệch phải, tập trung quanh 6.5–7.5 và xuất hiện nhiều trường hợp điểm < 6.
Kết quả cho thấy điểm nữ vừa thấp hơn nam vừa biến động lớn hơn (độ lệch chuẩn cao hơn).

4.15 Biểu đồ Bar plot tổng số (6 layer)

p15 <- dataset %>%
  group_by(Gender) %>%
  summarise(Total_Days = sum(DaysWatched, na.rm = TRUE),
            Total_Episodes = sum(EpisodesWatched, na.rm = TRUE),
            .groups = "drop") %>%
  pivot_longer(cols = c(Total_Days, Total_Episodes), names_to = "Type", values_to = "Total") %>%
  ggplot(aes(x = Gender, y = Total, fill = Type)) +
  geom_col(position = position_dodge(width = 0.7), alpha = 0.85, width = 0.7) +
  geom_text(aes(label = Total), position = position_dodge(width = 0.7), vjust = -0.5, size = 3.5) +
  labs(title = "TỔNG SỐ NGÀY VÀ TẬP THEO GIỚI TÍNH", y = "Tổng số") +
  theme_light()
print(p15)

group_by(Gender) → gom dữ liệu theo giới tính để tính tổng từng nhóm.
summarise(Total_Days = sum(DaysWatched), Total_Episodes = sum(EpisodesWatched))
→ tạo 2 biến mới chứa tổng số ngày xem và tập đã xem theo từng giới tính.
pivot_longer() → chuyển dữ liệu từ dạng rộng sang dài (phục vụ vẽ cột song song).
geom_col(position = position_dodge()) → vẽ biểu đồ cột so sánh song song giữa Total_Days và Total_Episodes.
geom_text(label = Total) → in số liệu trực tiếp lên cột để dễ đọc.
alpha = 0.85 + width = 0.7 → tăng độ trong suốt và kích thước cột để nhìn rõ.
Nam giới xem nhiều hơn rõ rệt:
Số tập xem của nam (342 triệu) gấp gần 1.8 lần so với nữ (186 triệu).Số ngày xem của nam (5.38 triệu) gần 2 lần nữ (2.9 triệu).
Nhóm Non-Binary rất nhỏ (chỉ chiếm <1% tổng lượng xem) → cỡ mẫu thấp, cần cẩn trọng khi suy luận thống kê.
Tỷ lệ giữa Total_Days và Total_Episodes cho thấy tần suất xem tập/ngày của nam cao hơn nữ, tức là nam xem dồn tập nhiều hơn.

4.16 Biểu đồ Line plot đa đường (7 layer)

p16 <- dataset %>%
  group_by(Gender, Watch_Group) %>%
  summarise(Avg_Score = safe_mean(MeanScore), Avg_Episodes = safe_mean(EpisodesWatched), .groups = "drop") %>%
  pivot_longer(cols = c(Avg_Score, Avg_Episodes), names_to = "Metric", values_to = "Value") %>%
  ggplot(aes(x = Watch_Group, y = Value, color = Metric, group = Metric)) +
  geom_line(size = 1.1, alpha = 0.85) +
  geom_point(size = 3) +
  geom_ribbon(aes(ymin = Value - 0.5, ymax = Value + 0.5, fill = Metric), alpha = 0.08, color = NA) +
  facet_wrap(~Gender, nrow = 1) +
  labs(title = "SO SÁNH CHỈ SỐ THEO NHÓM XEM", x = "Nhóm xem", y = "Giá trị") +
  theme_minimal()
print(p16)

Số tập xem trung bình (Avg_Episodes) tăng rõ rệt từ nhóm “Ít” → “Nhiều” ở cả ba giới tính, chứng minh phân nhóm mức độ xem là hợp lý.
Điểm số trung bình (Avg_Score) hầu như không thay đổi giữa các nhóm, cho thấy tần suất xem không ảnh hưởng đến mức độ đánh giá phim.
Không có sự khác biệt lớn về Avg_Score giữa Male, Female và Non-Binary, tức hành vi chấm điểm là thống nhất giữa các giới tính.
Nhóm “Nhiều” có số tập xem cao gấp nhiều lần nhóm “Ít” (khoảng 5–7 lần), phản ánh mức độ tiêu thụ nội dung tăng tuyến tính theo thói quen xem.
Dữ liệu Non-Binary có xu hướng dao động hơn do số lượng mẫu nhỏ, nên cần thận trọng khi diễn giải kết luận cho nhóm này.

4.17 Biểu đồ Area chart (6 layer)

p17 <- dataset %>%
  mutate(Score_Range = cut(MeanScore, breaks = 4)) %>%
  group_by(Gender, Score_Range) %>%
  summarise(Count = n(), .groups = "drop") %>%
  ggplot(aes(x = Score_Range, y = Count, fill = Gender)) +
  geom_area(position = "identity", alpha = 0.5) +
  geom_line(aes(group = Gender), size = 0.9) +
  geom_point(size = 2) +
  geom_text(aes(label = Count), vjust = -0.5, size = 3) +
  labs(title = "PHÂN BỐ ĐIỂM SỐ THEO GIỚI TÍNH", x = "Khoảng điểm", y = "Số lượng") +
  theme_minimal()
print(p17)

Hàm cut() chia giá trị MeanScore thành 4 khoảng điểm (ví dụ: (-0.01,2.5], (2.5,5], (5,7.5], (7.5,10]).
Count = n() đếm số lượng cá nhân thuộc mỗi nhóm này.
geom_area(): Tạo vùng diện tích tô màu mờ (alpha = 0.5) cho từng giới tính.
geom_line(): Nối các điểm bằng đường để thấy xu hướng thay đổi số lượng giữa các khoảng điểm.
geom_point(): Đánh dấu từng giá trị.
geom_text(): Hiển thị số lượng cụ thể tại mỗi điểm.
Ý NGHĨA:
Phân phối lệch phải (right-skewed)
Nữ (Female) có xu hướng điểm cao hơn nam.
Nam (Male) có số lượng điểm thấp hơn ở nhóm 7.5–10.
Non-Binary chỉ có vài người (470), không đủ để kết luận thống kê mạnh.
Phân bố không đều giữa các nhóm điểm
→ Có thể xem xét chuẩn hóa hoặc dùng các thước đo khác (trung bình, độ lệch chuẩn, median) để phân tích sâu hơn.

4.18 Biểu đồ Violin plot (7 layer)

p18 <- ggplot(dataset, aes(x = Gender, y = DaysWatched, fill = Gender)) +
  geom_violin(alpha = 0.75, trim = FALSE) +
  geom_boxplot(width = 0.1, fill = "white", alpha = 0.9, outlier.shape = NA) +
  geom_jitter(width = 0.05, alpha = 0.3, size = 1, color = "gray30") +
  stat_summary(fun = mean, geom = "point", shape = 18, size = 3, color = "red") +
  geom_hline(yintercept = median(dataset$DaysWatched, na.rm = TRUE), linetype = "dashed", color = "blue", size = 0.7) +
  labs(title = "PHÂN BỐ SỐ NGÀY XEM - VIOLIN PLOT", y = "Số ngày xem") +
  theme_classic()
print(p18)

geom_violin(alpha = 0.75, trim = FALSE)
→ Vẽ biểu đồ violin thể hiện phân bố mật độ xác suất của biến DaysWatched cho từng nhóm Gender.
geom_boxplot(width = 0.1, fill = “white”, alpha = 0.9, outlier.shape = NA)
→ Lồng boxplot vào trong violin để thể hiện trung vị, tứ phân vị và độ phân tán của dữ liệu.
geom_jitter(width = 0.05, alpha = 0.3, size = 1, color = “gray30”)
→ Thêm các điểm dữ liệu riêng lẻ được rải ngẫu nhiên, giúp thấy rõ sự phân tán thực tế của người xem.
stat_summary(fun = mean, geom = “point”, shape = 18, size = 3, color = “red”)
→ Đánh dấu giá trị trung bình (mean) của mỗi giới tính bằng hình thoi đỏ.
geom_hline(yintercept = median(dataset$DaysWatched, na.rm = TRUE), linetype = “dashed”, color = “blue”, size = 0.7)
Vẽ đường ngang màu xanh nét đứt thể hiện trung vị (median) của toàn bộ dữ liệu, để so sánh các nhóm.
theme_classic() làm gọn nền, loại bỏ chi tiết thừa, giúp nổi bật phân bố và đường thống kê.
Ý NGHĨA THỐNG KÊ CỦA BIỂU ĐỒ
Phân bố lệch phải (Right-skewed)
→ Cả ba nhóm giới tính đều có phân bố nghiêng về bên phải, tức đa số người xem ít ngày, chỉ một số ít xem rất nhiều ngày.
→ Điều này phản ánh xu hướng xem tập trung ở mức thấp — có thể do phần lớn người chỉ tham gia ngắn hạn.
Trung bình và trung vị khác biệt
→ Các điểm đỏ (mean) nằm cao hơn trung vị (đường xanh) → dữ liệu bị kéo lệch bởi một số người xem cực nhiều.
→ Trung bình vì thế không đại diện tốt cho xu hướng trung tâm, median phản ánh chính xác hơn hành vi phổ biến.
So sánh giữa các giới tính
→ Female và Male có phân bố tương tự nhau: mật độ tập trung nhiều ở mức thấp (ít ngày xem).
→ Non-Binary có phạm vi trải rộng hơn, trung bình (điểm đỏ) cao hơn → xem nhiều hơn trung bình so với hai giới còn lại.

4.19 Biểu đồ Point plot với kích thước (7 layer)

p19 <- dataset %>%
  group_by(Gender, Watch_Group) %>%
  summarise(Avg_Score = safe_mean(MeanScore), Avg_Days = safe_mean(DaysWatched), Count = n(), .groups = "drop") %>%
  ggplot(aes(x = Avg_Days, y = Avg_Score, color = Gender, size = Count)) +
  geom_point(alpha = 0.8) +
  geom_text(aes(label = Watch_Group), vjust = -1, size = 3, fontface = "bold", check_overlap = TRUE) +
  geom_smooth(method = "lm", se = FALSE, linetype = "dashed", alpha = 0.5) +
  geom_hline(yintercept = safe_mean(dataset$MeanScore), linetype = "dotted", color = "gray50") +
  geom_vline(xintercept = safe_mean(dataset$DaysWatched), linetype = "dotted", color = "gray50") +
  labs(title = "MỐI QUAN HỆ TRUNG BÌNH NGÀY XEM VÀ ĐIỂM SỐ", x = "Số ngày trung bình", y = "Điểm trung bình") +
  theme_light()
print(p19)

Female và Male có xu hướng tăng điểm khi thời gian xem tăng, thể hiện rằng khi họ đầu tư nhiều thời gian hơn, sự hài lòng hoặc cảm nhận chất lượng phim cũng cao hơn.
Non-Binary có đường xu hướng gần như phẳng → điểm đánh giá ổn định, ít phụ thuộc vào thời gian xem, cho thấy nhóm này có cách đánh giá nhất quán hơn.
Các điểm “ít” nằm dưới trung bình chung (xem ít – chấm điểm thấp), trong khi nhóm “nhiều” nằm phía trên (xem nhiều – chấm điểm cao).
Kích thước điểm lớn nhất ở nhóm “trung bình”, chứng tỏ phần lớn người dùng hoạt động ở mức xem vừa phải, còn nhóm “xem nhiều” tuy ít hơn nhưng đánh giá cao hơn rõ rệt.

4.20 Biểu đồ Facet grid đa biến (6 layer)

p20 <- dataset %>%
  select(Gender, DaysWatched, EpisodesWatched, MeanScore, Watching) %>%
  pivot_longer(cols = -Gender, names_to = "Variable", values_to = "Value") %>%
  ggplot(aes(x = Gender, y = Value, fill = Gender)) +
  geom_boxplot(alpha = 0.75, outlier.color = "red", outlier.shape = 16) +
  geom_jitter(width = 0.15, alpha = 0.3, size = 0.6, color = "gray30") +
  stat_summary(fun = mean, geom = "point", shape = 18, size = 2, color = "red") +
  facet_wrap(~Variable, scales = "free_y", ncol = 2) +
  labs(title = "PHÂN TÍCH ĐA BIẾN THEO GIỚI TÍNH", y = "Giá trị") +
  theme_minimal()
print(p20)

Dữ liệu được chuyển sang dạng dài (pivot_longer) để biểu diễn nhiều biến cùng lúc.
geom_boxplot() hiển thị phân bố từng biến theo giới tính, giúp so sánh trung vị và độ phân tán.
geom_jitter() thêm các điểm dữ liệu thực, giúp quan sát mật độ và ngoại lệ (outliers).
stat_summary(fun = mean) đánh dấu giá trị trung bình (chấm đỏ) của từng nhóm.
facet_wrap() chia thành 4 ô: DaysWatched, EpisodesWatched, MeanScore, và Watching — mỗi ô có trục tung riêng.
DaysWatched & EpisodesWatched:
Phân bố lệch phải, cho thấy đa số người dùng xem ít nhưng có một số ít cá nhân xem rất nhiều (outliers).
Nhóm Non-Binary có trung vị cao hơn nhẹ → xu hướng xem đều hơn, ít ngoại lệ cực trị.
MeanScore:
Điểm trung bình của cả ba giới tương đối cao (≈7–8), chênh lệch nhỏ.
Male có độ phân tán lớn hơn → nhóm nam đa dạng hơn trong cách đánh giá anime.
Watching (đang xem):
Phần lớn người dùng đang theo dõi ít anime cùng lúc, chỉ một số rất nhỏ (outlier) xem hàng nghìn tập.
Nhóm Male có số lượng người đang xem cao nhất, thể hiện mức độ hoạt động mạnh hơn.

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

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

1.1 Đọc dữ liệu gốc

data_full <- read_excel(file.choose())

1.2 Hiện vài dòng đầu để kiểm tra

head(data_full)

1.3 Làm sạch tên cột

data_full <- janitor::clean_names(data_full)

Hàm clean_names() chuẩn hóa tên cột: chuyển về chữ thường, bỏ dấu, thay khoảng trắng bằng dấu gạch dưới.

1.4 Kiểm tra tên cột thực tế

head(names(data_full), 10)
##  [1] "x1"                                     
##  [2] "tong_tai_san"                           
##  [3] "tai_san_ngan_han"                       
##  [4] "tien_va_tuong_duong_tien"               
##  [5] "tien"                                   
##  [6] "cac_khoan_tuong_duong_tien"             
##  [7] "gia_tri_thuan_dau_tu_ngan_han"          
##  [8] "dau_tu_ngan_han"                        
##  [9] "du_phong_dau_tu_ngan_han"               
## [10] "chung_khoan_dau_tu_giu_den_ngay_dao_han"

Hàm names() liệt kê toàn bộ tên biến (cột) hiện có.

1.5 In kích thước dữ liệu

dim(data_full)
## [1]  10 189

Dim kiểm tra kích thước dữ liệu, có 10 hàng (quan sát) và 189 cột (biến).

1.6 Kiểm tra cấu trúc dữ liệu

str(data_full)
## tibble [10 × 189] (S3: tbl_df/tbl/data.frame)
##  $ x1                                                             : chr [1:10] "2015" "2016" "2017" "2018" ...
##  $ tong_tai_san                                                   : num [1:10] 5.09e+12 5.88e+12 6.08e+12 6.83e+12 8.20e+12 ...
##  $ tai_san_ngan_han                                               : num [1:10] 3.21e+12 4.18e+12 4.81e+12 5.63e+12 7.13e+12 ...
##  $ tien_va_tuong_duong_tien                                       : num [1:10] 6.45e+10 1.79e+11 2.03e+11 7.35e+11 5.94e+11 ...
##  $ tien                                                           : num [1:10] 4.36e+10 1.79e+11 1.24e+11 4.00e+11 4.75e+11 ...
##  $ cac_khoan_tuong_duong_tien                                     : num [1:10] 2.10e+10 5.00e+07 7.87e+10 3.35e+11 1.19e+11 ...
##  $ gia_tri_thuan_dau_tu_ngan_han                                  : num [1:10] 0.00 4.00e+10 4.07e+10 8.00e+08 2.25e+11 ...
##  $ dau_tu_ngan_han                                                : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ du_phong_dau_tu_ngan_han                                       : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ chung_khoan_dau_tu_giu_den_ngay_dao_han                        : num [1:10] 0.00 4.00e+10 4.07e+10 8.00e+08 2.25e+11 ...
##  $ cac_khoan_phai_thu                                             : num [1:10] 6.76e+11 1.05e+12 9.76e+11 1.70e+12 1.96e+12 ...
##  $ phai_thu_khach_hang                                            : num [1:10] 4.96e+11 7.14e+11 7.03e+11 1.02e+12 9.41e+11 ...
##  $ tra_truoc_nguoi_ban                                            : num [1:10] 7.14e+10 2.04e+11 4.86e+10 2.80e+11 2.46e+11 ...
##  $ phai_thu_noi_bo                                                : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ phai_thu_ve_xdcb                                               : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ phai_thu_ve_cho_vay_ngan_han                                   : num [1:10] 4.00e+09 3.07e+10 3.75e+10 1.00e+10 7.67e+10 ...
##  $ phai_thu_khac                                                  : num [1:10] 1.31e+11 1.28e+11 2.07e+11 4.10e+11 7.07e+11 ...
##  $ du_phong_no_kho_doi                                            : num [1:10] -2.63e+10 -2.92e+10 -2.00e+10 -2.28e+10 -1.51e+10 ...
##  $ tai_san_thieu_cho_xu_ly                                        : num [1:10] 30846447 34403830 53098990 59203748 10783893 ...
##  $ hang_ton_kho_rong                                              : num [1:10] 2.44e+12 2.86e+12 3.54e+12 3.13e+12 4.19e+12 ...
##  $ hang_ton_kho                                                   : num [1:10] 2.44e+12 2.86e+12 3.54e+12 3.15e+12 4.20e+12 ...
##  $ du_phong_giam_gia_htk                                          : num [1:10] -4.50e+08 -5.99e+08 0.00 -1.47e+10 -9.68e+09 ...
##  $ tai_san_luu_dong_khac_23                                       : num [1:10] 3.35e+10 5.76e+10 5.18e+10 6.65e+10 1.63e+11 ...
##  $ tra_truoc_ngan_han                                             : num [1:10] 8.75e+09 4.24e+10 4.73e+10 6.20e+10 1.42e+11 ...
##  $ thue_vat_phai_thu                                              : num [1:10] 1.82e+10 5.24e+09 1.32e+09 1.88e+09 3.49e+09 ...
##  $ phai_thu_thue_khac                                             : num [1:10] 6.61e+09 9.92e+09 3.16e+09 2.61e+09 1.76e+10 ...
##  $ giao_dich_mua_ban_lai_trai_phieu_chinh_phu_27                  : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ tai_san_luu_dong_khac_28                                       : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ tai_san_dai_han                                                : num [1:10] 1.88e+12 1.69e+12 1.27e+12 1.20e+12 1.07e+12 ...
##  $ phai_thu_dai_han                                               : num [1:10] 3.18e+11 2.98e+11 2.92e+11 9.90e+10 8.46e+10 ...
##  $ phai_thu_khach_hang_dai_han                                    : num [1:10] 1.67e+11 1.69e+11 1.69e+11 8.32e+09 8.32e+09 ...
##  $ tra_truoc_nguoi_ban_dai_han                                    : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ von_kinh_doanh_o_cac_don_vi_truc_thuoc                         : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ phai_thu_noi_bo_dai_han                                        : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ phai_thu_ve_cho_vay_dai_han                                    : num [1:10] 6.21e+10 4.07e+10 3.43e+10 3.54e+09 0.00 ...
##  $ phai_thu_dai_han_khac                                          : num [1:10] 8.87e+10 8.88e+10 8.89e+10 8.71e+10 8.46e+10 ...
##  $ du_phong_phai_thu_dai_han                                      : num [1:10] 0.00 0.00 0.00 0.00 -8.32e+09 ...
##  $ tai_san_co_dinh                                                : num [1:10] 2.46e+11 2.59e+11 2.32e+11 3.60e+11 3.34e+11 ...
##  $ gtcl_tscd_huu_hinh                                             : num [1:10] 2.35e+11 2.47e+11 2.14e+11 3.40e+11 3.14e+11 ...
##  $ nguyen_gia_tscd_huu_hinh                                       : num [1:10] 4.23e+11 4.83e+11 4.51e+11 6.86e+11 6.11e+11 ...
##  $ khau_hao_luy_ke_tscd_huu_hinh                                  : num [1:10] -1.88e+11 -2.36e+11 -2.37e+11 -3.46e+11 -2.97e+11 ...
##  $ gtcl_tai_san_thue_tai_chinh                                    : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ nguyen_gia_tai_san_thue_tai_chinh                              : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ khau_hao_luy_ke_tai_san_thue_tai_chinh                         : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ gtcl_tai_san_co_dinh_vo_hinh                                   : num [1:10] 1.07e+10 1.18e+10 1.73e+10 2.00e+10 1.97e+10 ...
##  $ nguyen_gia_tscd_vo_hinh                                        : num [1:10] 1.14e+10 1.26e+10 1.82e+10 2.11e+10 2.02e+10 ...
##  $ khau_hao_luy_ke_tscd_vo_hinh                                   : num [1:10] -7.44e+08 -8.01e+08 -8.57e+08 -1.11e+09 -5.40e+08 ...
##  $ bat_dong_san_dau_tu                                            : num [1:10] 1.24e+11 1.21e+11 1.18e+11 1.60e+11 1.56e+11 ...
##  $ nguyen_gia_tai_san_dau_tu                                      : num [1:10] 1.44e+11 1.44e+11 1.44e+11 1.90e+11 1.89e+11 ...
##  $ khau_hao_luy_ke_tai_san_dau_tu                                 : num [1:10] -2.05e+10 -2.34e+10 -2.62e+10 -2.96e+10 -3.34e+10 ...
##  $ tai_san_do_dang_dai_han                                        : num [1:10] 7.80e+10 6.88e+10 6.80e+10 9.09e+10 8.94e+10 ...
##  $ chi_phi_san_xuat_kinh_doanh_do_dang_dai_han                    : num [1:10] 0 0 0 0 0 ...
##  $ xay_dung_co_ban_do_dang                                        : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ dau_tu_dai_han                                                 : num [1:10] 1.07e+12 8.95e+11 5.34e+11 4.03e+11 3.19e+11 ...
##  $ dau_tu_vao_cac_cong_ty_con                                     : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ dau_tu_vao_cong_ty_lien_doanh                                  : num [1:10] 8.09e+11 7.51e+11 2.45e+11 1.72e+11 1.93e+11 ...
##  $ dau_tu_dai_han_khac                                            : num [1:10] 2.22e+11 1.51e+11 3.01e+11 2.48e+11 1.19e+11 ...
##  $ du_phong_giam_gia_dau_tu_dai_han                               : num [1:10] -7.85e+09 -7.00e+09 -2.84e+10 -2.88e+10 -2.03e+10 ...
##  $ dau_tu_nam_giu_den_ngay_dao_han                                : num [1:10] 4.20e+10 0.00 1.60e+10 1.22e+10 2.72e+10 ...
##  $ tai_san_dai_han_khac                                           : num [1:10] 4.70e+10 5.19e+10 3.00e+10 8.54e+10 8.37e+10 ...
##  $ tra_truoc_dai_han                                              : num [1:10] 2.54e+10 3.09e+10 2.55e+10 3.18e+10 2.39e+10 ...
##  $ thue_thu_nhap_hoan_lai_phai_thu                                : num [1:10] 2.16e+10 2.10e+10 4.45e+09 4.36e+09 1.55e+10 ...
##  $ thiet_bi_vat_tu_phu_tung_thay_the_dai_han                      : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ cac_tai_san_dai_han_khac                                       : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ loi_the_thuong_mai                                             : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ no_phai_tra                                                    : num [1:10] 2.43e+12 3.08e+12 3.19e+12 3.61e+12 4.19e+12 ...
##  $ no_ngan_han                                                    : num [1:10] 9.96e+11 1.30e+12 1.61e+12 3.00e+12 3.27e+12 ...
##  $ phai_tra_nguoi_ban                                             : num [1:10] 1.14e+11 1.60e+11 2.14e+11 2.70e+11 3.26e+11 ...
##  $ nguoi_mua_tra_tien_truoc                                       : num [1:10] 2.86e+11 5.14e+11 7.60e+11 1.02e+12 1.73e+12 ...
##  $ thue_va_cac_khoan_phai_tra_nha_nuoc                            : num [1:10] 9.62e+09 3.62e+10 4.20e+10 8.88e+10 2.14e+11 ...
##  $ phai_tra_nguoi_lao_dong                                        : num [1:10] 1.90e+10 2.12e+10 2.31e+10 2.64e+10 2.15e+10 ...
##  $ chi_phi_phai_tra                                               : num [1:10] 7.81e+10 9.57e+10 9.56e+10 8.19e+10 1.71e+10 ...
##  $ phai_tra_noi_bo                                                : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ phai_tra_ve_xay_dung_co_ban                                    : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ doanh_thu_chua_thuc_hien_ngan_han                              : num [1:10] 3.49e+09 5.46e+09 3.37e+09 3.54e+09 4.83e+10 ...
##  $ phai_tra_khac                                                  : num [1:10] 1.75e+11 1.63e+11 1.07e+11 3.11e+11 3.49e+11 ...
##  $ vay_ngan_han                                                   : num [1:10] 3.10e+11 3.07e+11 3.64e+11 1.19e+12 5.48e+11 ...
##  $ du_phong_cac_khoan_phai_tra_ngan_han                           : num [1:10] 2e+08 0e+00 0e+00 0e+00 0e+00 ...
##  $ quy_khen_thuong_phuc_loi                                       : num [1:10] 7.26e+06 -3.02e+09 -1.97e+09 3.26e+09 1.38e+10 ...
##  $ quy_binh_on_gia                                                : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ giao_dich_mua_ban_lai_trai_phieu_chinh_phu_81                  : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ no_dai_han                                                     : num [1:10] 1.44e+12 1.78e+12 1.58e+12 6.15e+11 9.18e+11 ...
##  $ phai_tra_nha_cung_cap_dai_han                                  : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ nguoi_mua_tra_tien_truoc_dai_han                               : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ chi_phi_phai_tra_dai_han                                       : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ phai_tra_noi_bo_ve_von_kinh_doanh                              : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ phai_tra_noi_bo_dai_han                                        : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ doanh_thu_chua_thuc_hien                                       : num [1:10] 3.13e+11 3.10e+11 1.57e+11 1.54e+11 1.50e+11 ...
##  $ phai_tra_dai_han_khac                                          : num [1:10] 2.16e+09 1.41e+09 1.09e+09 1.44e+09 2.04e+10 ...
##  $ vay_dai_han                                                    : num [1:10] 1.08e+12 1.43e+12 1.40e+12 4.24e+11 7.30e+11 ...
##  $ trai_phieu_chuyen_doi                                          : num [1:10] 0.00 0.00 0.00 0.00 0.00 9.75e+09 0.00 0.00 0.00 0.00
##  $ co_phieu_uu_dai_92                                             : logi [1:10] NA NA NA NA NA NA ...
##  $ thue_thu_nhap_hoan_lai_phai_tra                                : num [1:10] 4.21e+10 3.67e+10 2.97e+10 3.52e+10 1.74e+10 ...
##  $ du_phong_tro_cap_thoi_viec                                     : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ du_phong_cac_khoan_cong_no_dai_han                             : num [1:10] 5.67e+08 6.45e+08 1.75e+09 1.19e+09 6.32e+08 ...
##  $ quy_phat_trien_khoa_hoc_cong_nghe                              : num [1:10] 0 0 0 0 0 0 0 0 0 0
##  $ von_chu_so_huu                                                 : num [1:10] 2.66e+12 2.80e+12 2.89e+12 3.22e+12 4.01e+12 ...
##  $ von_va_cac_quy                                                 : num [1:10] 2.66e+12 2.80e+12 2.89e+12 3.22e+12 4.01e+12 ...
##  $ von_gop                                                        : num [1:10] 2.15e+12 2.38e+12 2.38e+12 2.52e+12 3.15e+12 ...
##   [list output truncated]

Hàm str() trong R có nghĩa là “structure” (cấu trúc), dùng để hiển thị cấu trúc tổng quát của một đối tượng dữ liệu (numeric, character, factor, date…)
### 1.7 Kiểm tra số dòng trùng lặp

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

Hàm duplicated() phát hiện các dòng trùng lặp hoàn toàn.
sum() đếm số dòng bị trùng.

1.8 Kiểm tra NA trên toàn bộ bảng

na_check <- colSums(is.na(data_full))

if (any(na_check > 0)) {
  cat("Các biến có giá trị NA:\n")
  print(na_check[na_check > 0])
} else {
  cat("✅ Dữ liệu không có giá trị NA.\n")
}
## Các biến có giá trị NA:
## co_phieu_uu_dai_92 
##                 10

is.na() kiểm tra từng ô có bị thiếu dữ liệu không.
colSums() cộng theo cột, cho biết số lượng NA của từng biến.

1.9 Kiểm tra tóm tắt nhanh

### 1.9 Kiểm tra tóm tắt nhanh cho một biến
summary(data_full$tien_thu_tu_viec_ban_cac_khoan_dau_tu_vao_cac_doanh_nghiep_khac)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
## 6.532e+09 2.324e+10 1.348e+11 4.242e+11 3.210e+11 2.932e+12

Hàm summary() trong R được dùng để tạo bản tóm tắt thống kê nhanh cho toàn bộ bộ dữ liệu.
Biến tien_thu_tu_viec_ban_cac_khoan_dau_tu_vao_cac_doanh_nghiep_khac
Min (6.532e+09): DIG thu thấp nhất 6,53 tỷ đồng, phản ánh giai đoạn ít thoái vốn.
1st Qu. (2.324e+10): 25% năm có thu ≤ 23,24 tỷ đồng, cho thấy hoạt động đầu tư tài chính kém sôi động.
Median (1.348e+11): Mức thu điển hình khoảng 134,8 tỷ đồng mỗi năm.
Mean (4.242e+11): Trung bình 424,2 tỷ đồng, cao hơn trung vị → có năm đột biến do bán vốn lớn.
3rd Qu. (3.210e+11): 75% năm thu dưới 321 tỷ, chỉ vài năm đạt mức rất cao.

1.10 Lưu bản sao gốc

write.csv(data_full, "data_full_raw.csv", row.names = FALSE)

2. XỬ LÝ DỮ LIỆU THÔ, MÃ HÓA DỮ LIỆU

2.1 Loại bỏ dòng trùng

data_full <- data_full %>% distinct()

2.2 Lọc 10 biến quan trọng

data_selected <- data_full %>%
  select(
    tai_san_ngan_han,
    tai_san_dai_han,
    hang_ton_kho,
    no_ngan_han,
    nguoi_mua_tra_tien_truoc,
    doanh_thu_chua_thuc_hien,
    thang_du_von_co_phan,
    doanh_so_thuan,
    von_chu_so_huu,
    tai_san_do_dang_dai_han
  )

2.3 Xem nhanh data_selected

head(data_selected)

2.4 Xuất file dữ liệu riêng

write.csv(data_selected, "data_taichinh_10bien.csv", row.names = FALSE)

2.5 Kích thước

dim(data_selected)
## [1] 10 10

2.6 Kiểm tra trùng lặp trong data_selected

sum(duplicated(data_selected))
## [1] 0
data_selected <- data_selected[!duplicated(data_selected), ]

Lệnh sum(duplicated(data_selected)) đếm số dòng trùng lặp, còn data_selected
data_selected[!duplicated(data_selected), ] loại bỏ các dòng trùng, giữ lại lần xuất hiện đầu tiên.

2.7 Kiểm tra NA, thay NA bằng median theo numeric

colSums(is.na(data_selected))
##         tai_san_ngan_han          tai_san_dai_han 
##                        0                        0 
##             hang_ton_kho              no_ngan_han 
##                        0                        0 
## nguoi_mua_tra_tien_truoc doanh_thu_chua_thuc_hien 
##                        0                        0 
##     thang_du_von_co_phan           doanh_so_thuan 
##                        0                        0 
##           von_chu_so_huu  tai_san_do_dang_dai_han 
##                        0                        0
data_selected <- data_selected %>%
  mutate(across(where(is.numeric), ~ ifelse(is.na(.), median(., na.rm = TRUE), .)))

Lệnh colSums(is.na(data_selected)) đếm tổng số giá trị bị thiếu (NA) trong từng cột; mutate(across(…)) thay thế các giá trị NA của biến số bằng trung vị (median) tương ứng.
Ý nghĩa thống kê: Việc thay NA bằng trung vị giúp dữ liệu đầy đủ hơn, tránh mất thông tin và giảm ảnh hưởng của các giá trị ngoại lai đến phân tích

2.8 Kiểm tra kiểu dữ liệu

str(data_selected)
## tibble [10 × 10] (S3: tbl_df/tbl/data.frame)
##  $ tai_san_ngan_han        : num [1:10] 3.21e+12 4.18e+12 4.81e+12 5.63e+12 7.13e+12 ...
##  $ tai_san_dai_han         : num [1:10] 1.88e+12 1.69e+12 1.27e+12 1.20e+12 1.07e+12 ...
##  $ hang_ton_kho            : num [1:10] 2.44e+12 2.86e+12 3.54e+12 3.15e+12 4.20e+12 ...
##  $ no_ngan_han             : num [1:10] 9.96e+11 1.30e+12 1.61e+12 3.00e+12 3.27e+12 ...
##  $ nguoi_mua_tra_tien_truoc: num [1:10] 2.86e+11 5.14e+11 7.60e+11 1.02e+12 1.73e+12 ...
##  $ doanh_thu_chua_thuc_hien: num [1:10] 3.13e+11 3.10e+11 1.57e+11 1.54e+11 1.50e+11 ...
##  $ thang_du_von_co_phan    : num [1:10] 2.38e+11 6.61e+10 6.61e+10 6.61e+10 2.08e+11 ...
##  $ doanh_so_thuan          : num [1:10] 6.55e+11 1.15e+12 1.59e+12 2.35e+12 2.12e+12 ...
##  $ von_chu_so_huu          : num [1:10] 2.66e+12 2.80e+12 2.89e+12 3.22e+12 4.01e+12 ...
##  $ tai_san_do_dang_dai_han : num [1:10] 7.80e+10 6.88e+10 6.80e+10 9.09e+10 8.94e+10 ...

2.9 Tạo một vài biến mã hóa

data_selected <- data_selected %>%
  mutate(
    tong_tai_san = tai_san_ngan_han + tai_san_dai_han,
    he_so_no = ifelse(von_chu_so_huu == 0, NA, no_ngan_han / von_chu_so_huu),
    ty_le_hang_ton = ifelse(tai_san_ngan_han == 0, NA, hang_ton_kho / tai_san_ngan_han),
    ty_le_von_ts = ifelse((tai_san_ngan_han+tai_san_dai_han)==0, NA, von_chu_so_huu/(tai_san_ngan_han+tai_san_dai_han)),
    ty_suat_doanh_thu = ifelse(tai_san_dai_han==0, NA, doanh_so_thuan / tai_san_dai_han)
  )

2.10 Mã hóa phân loại doanh thu

data_selected <- data_selected %>%
  mutate(
    nhom_doanh_thu = case_when(
      doanh_so_thuan >= quantile(doanh_so_thuan, 0.75, na.rm=TRUE) ~ "Cao",
      doanh_so_thuan >= quantile(doanh_so_thuan, 0.25, na.rm=TRUE) ~ "Trung bình",
      TRUE ~ "Thấp"
    )
  )

Hàm case_when() chia biến doanh_so_thuan (doanh thu thuần) thành 3 nhóm dựa trên phân vị (quantile):
Từ 0.75 trở lên → “Cao”
Từ 0.25 đến <0.75 → “Trung bình”
Nhỏ hơn 0.25 → “Thấp”

2.11 Mã hóa phân loại theo hệ số nợ

data_selected <- data_selected %>%
  mutate(
    nhom_he_so_no = case_when(
      he_so_no > 1 ~ "Nợ cao",
      he_so_no > 0.5 ~ "Nợ trung bình",
      TRUE ~ "Nợ thấp"
    )
  )

Về kỹ thuật:
Hàm mutate() tạo biến mới nhom_he_so_no trong bộ dữ liệu.
Hàm case_when() phân loại giá trị của biến he_so_no thành 3 nhóm:
he_so_no > 1 → gán nhãn “Nợ cao”
he_so_no > 0.5 → gán nhãn “Nợ trung bình”
Còn lại (TRUE) → “Nợ thấp”
Ý nghĩa kinh tế:
Hệ số nợ phản ánh mức độ phụ thuộc vào vốn vay.
Nợ cao → doanh nghiệp đang rủi ro tài chính, dễ chịu áp lực trả nợ.
Nợ trung bình → cơ cấu vốn cân đối giữa nợ và vốn chủ sở hữu.
Nợ thấp → doanh nghiệp an toàn, chủ yếu dùng vốn tự có.

2.12 Kiểm tra lại các biến mới

names(data_selected)
##  [1] "tai_san_ngan_han"         "tai_san_dai_han"         
##  [3] "hang_ton_kho"             "no_ngan_han"             
##  [5] "nguoi_mua_tra_tien_truoc" "doanh_thu_chua_thuc_hien"
##  [7] "thang_du_von_co_phan"     "doanh_so_thuan"          
##  [9] "von_chu_so_huu"           "tai_san_do_dang_dai_han" 
## [11] "tong_tai_san"             "he_so_no"                
## [13] "ty_le_hang_ton"           "ty_le_von_ts"            
## [15] "ty_suat_doanh_thu"        "nhom_doanh_thu"          
## [17] "nhom_he_so_no"
summary(data_selected)
##  tai_san_ngan_han    tai_san_dai_han      hang_ton_kho      
##  Min.   :3.211e+12   Min.   :1.066e+12   Min.   :2.437e+12  
##  1st Qu.:5.016e+12   1st Qu.:1.378e+12   1st Qu.:3.245e+12  
##  Median :7.215e+12   Median :2.216e+12   Median :4.026e+12  
##  Mean   :8.432e+12   Mean   :2.654e+12   Mean   :4.507e+12  
##  3rd Qu.:1.113e+13   3rd Qu.:3.615e+12   3rd Qu.:5.545e+12  
##  Max.   :1.599e+13   Max.   :5.632e+12   Max.   :8.157e+12  
##   no_ngan_han        nguoi_mua_tra_tien_truoc
##  Min.   :9.958e+11   Min.   :2.857e+11       
##  1st Qu.:1.955e+12   1st Qu.:8.248e+11       
##  Median :3.608e+12   Median :1.599e+12       
##  Mean   :4.054e+12   Mean   :1.371e+12       
##  3rd Qu.:5.658e+12   3rd Qu.:1.759e+12       
##  Max.   :7.962e+12   Max.   :2.426e+12       
##  doanh_thu_chua_thuc_hien thang_du_von_co_phan doanh_so_thuan     
##  Min.   :1.144e+11        Min.   :6.611e+10    Min.   :6.552e+11  
##  1st Qu.:1.220e+11        1st Qu.:1.016e+11    1st Qu.:1.189e+12  
##  Median :1.519e+11        Median :2.672e+11    Median :1.745e+12  
##  Mean   :1.743e+11        Mean   :5.201e+11    Mean   :1.714e+12  
##  3rd Qu.:1.753e+11        3rd Qu.:1.046e+12    3rd Qu.:2.288e+12  
##  Max.   :3.130e+11        Max.   :1.121e+12    Max.   :2.569e+12  
##  von_chu_so_huu      tai_san_do_dang_dai_han  tong_tai_san      
##  Min.   :2.656e+12   Min.   :6.800e+10       Min.   :5.089e+12  
##  1st Qu.:2.973e+12   1st Qu.:8.048e+10       1st Qu.:6.270e+12  
##  Median :4.400e+12   Median :9.019e+10       Median :1.001e+13  
##  Mean   :5.176e+12   Mean   :9.235e+10       Mean   :1.109e+13  
##  3rd Qu.:7.764e+12   3rd Qu.:1.006e+11       3rd Qu.:1.631e+13  
##  Max.   :8.041e+12   Max.   :1.267e+11       Max.   :1.854e+13  
##     he_so_no      ty_le_hang_ton    ty_le_von_ts    ty_suat_doanh_thu
##  Min.   :0.3749   Min.   :0.3431   Min.   :0.4050   Min.   :0.3488   
##  1st Qu.:0.5187   1st Qu.:0.5189   1st Qu.:0.4588   1st Qu.:0.4645   
##  Median :0.7121   Median :0.5741   Median :0.4732   Median :0.5294   
##  Mean   :0.7486   Mean   :0.5796   Mean   :0.4725   Mean   :0.8586   
##  3rd Qu.:0.9746   3rd Qu.:0.6635   3rd Qu.:0.4859   3rd Qu.:1.1087   
##  Max.   :1.2498   Max.   :0.7590   Max.   :0.5285   Max.   :1.9840   
##  nhom_doanh_thu     nhom_he_so_no     
##  Length:10          Length:10         
##  Class :character   Class :character  
##  Mode  :character   Mode  :character  
##                                       
##                                       
## 

2.13 Lưu bộ dữ liệu đã xử lý

write.csv(data_selected, "data_selected_clean.csv", row.names = FALSE)

2.14 Hiển thị vài dòng cuối để kiểm tra

tail(data_selected)

2.15 Kiểm tra nếu có giá trị âm bất thường

colSums(data_selected < 0, na.rm = TRUE)
##         tai_san_ngan_han          tai_san_dai_han 
##                        0                        0 
##             hang_ton_kho              no_ngan_han 
##                        0                        0 
## nguoi_mua_tra_tien_truoc doanh_thu_chua_thuc_hien 
##                        0                        0 
##     thang_du_von_co_phan           doanh_so_thuan 
##                        0                        0 
##           von_chu_so_huu  tai_san_do_dang_dai_han 
##                        0                        0 
##             tong_tai_san                 he_so_no 
##                        0                        0 
##           ty_le_hang_ton             ty_le_von_ts 
##                        0                        0 
##        ty_suat_doanh_thu           nhom_doanh_thu 
##                        0                        0 
##            nhom_he_so_no 
##                        0

2.16 Đảm bảo các cột numeric là numeric

data_selected <- data_selected %>% mutate(across(where(is.numeric), as.numeric))

mutate(across(where(is.numeric), as.numeric))
➤ Dòng lệnh này đảm bảo tất cả các cột dạng số trong data_selected đều có kiểu dữ liệu numeric.
→ Hàm across(where(is.numeric), as.numeric) quét qua toàn bộ các cột, và ép kiểu dữ liệu về dạng số nếu cần.

2.17 Kiểm tra correlation-ready

cor_cols <- data_selected %>%
  select(tai_san_ngan_han,
         tai_san_dai_han,
         hang_ton_kho,
         no_ngan_han,
         nguoi_mua_tra_tien_truoc,
         doanh_thu_chua_thuc_hien,
         thang_du_von_co_phan,
         doanh_so_thuan,
         von_chu_so_huu,
         tai_san_do_dang_dai_han)
round(cor(cor_cols, use = "pairwise.complete.obs"), 2)
##                          tai_san_ngan_han tai_san_dai_han
## tai_san_ngan_han                     1.00            0.47
## tai_san_dai_han                      0.47            1.00
## hang_ton_kho                         0.93            0.26
## no_ngan_han                          0.90            0.47
## nguoi_mua_tra_tien_truoc             0.83            0.49
## doanh_thu_chua_thuc_hien            -0.56           -0.45
## thang_du_von_co_phan                 0.90            0.67
## doanh_so_thuan                       0.04            0.44
## von_chu_so_huu                       0.95            0.66
## tai_san_do_dang_dai_han              0.69            0.67
##                          hang_ton_kho no_ngan_han
## tai_san_ngan_han                 0.93        0.90
## tai_san_dai_han                  0.26        0.47
## hang_ton_kho                     1.00        0.87
## no_ngan_han                      0.87        1.00
## nguoi_mua_tra_tien_truoc         0.80        0.90
## doanh_thu_chua_thuc_hien        -0.48       -0.60
## thang_du_von_co_phan             0.75        0.72
## doanh_so_thuan                  -0.10        0.12
## von_chu_so_huu                   0.83        0.82
## tai_san_do_dang_dai_han          0.53        0.53
##                          nguoi_mua_tra_tien_truoc
## tai_san_ngan_han                             0.83
## tai_san_dai_han                              0.49
## hang_ton_kho                                 0.80
## no_ngan_han                                  0.90
## nguoi_mua_tra_tien_truoc                     1.00
## doanh_thu_chua_thuc_hien                    -0.70
## thang_du_von_co_phan                         0.64
## doanh_so_thuan                               0.42
## von_chu_so_huu                               0.77
## tai_san_do_dang_dai_han                      0.57
##                          doanh_thu_chua_thuc_hien
## tai_san_ngan_han                            -0.56
## tai_san_dai_han                             -0.45
## hang_ton_kho                                -0.48
## no_ngan_han                                 -0.60
## nguoi_mua_tra_tien_truoc                    -0.70
## doanh_thu_chua_thuc_hien                     1.00
## thang_du_von_co_phan                        -0.48
## doanh_so_thuan                              -0.66
## von_chu_so_huu                              -0.60
## tai_san_do_dang_dai_han                     -0.64
##                          thang_du_von_co_phan doanh_so_thuan
## tai_san_ngan_han                         0.90           0.04
## tai_san_dai_han                          0.67           0.44
## hang_ton_kho                             0.75          -0.10
## no_ngan_han                              0.72           0.12
## nguoi_mua_tra_tien_truoc                 0.64           0.42
## doanh_thu_chua_thuc_hien                -0.48          -0.66
## thang_du_von_co_phan                     1.00           0.02
## doanh_so_thuan                           0.02           1.00
## von_chu_so_huu                           0.98           0.13
## tai_san_do_dang_dai_han                  0.84           0.38
##                          von_chu_so_huu tai_san_do_dang_dai_han
## tai_san_ngan_han                   0.95                    0.69
## tai_san_dai_han                    0.66                    0.67
## hang_ton_kho                       0.83                    0.53
## no_ngan_han                        0.82                    0.53
## nguoi_mua_tra_tien_truoc           0.77                    0.57
## doanh_thu_chua_thuc_hien          -0.60                   -0.64
## thang_du_von_co_phan               0.98                    0.84
## doanh_so_thuan                     0.13                    0.38
## von_chu_so_huu                     1.00                    0.84
## tai_san_do_dang_dai_han            0.84                    1.00

Ý nghĩa kỹ thuật
select(where(is.numeric)): chọn chỉ các cột dạng số trong data_selected để chuẩn bị phân tích tương quan.
cor(…, use=“pairwise.complete.obs”): tính ma trận hệ số tương quan Pearson giữa các biến số, bỏ qua các giá trị bị thiếu (NA) theo từng cặp biến.
round(…, 2): làm tròn kết quả tương quan đến 2 chữ số thập phân cho dễ đọc.
Ý nghĩa thống kê:Bảng tương quan giúp xác định mức độ và chiều hướng mối liên hệ tuyến tính giữa các biến định lượng (ví dụ: doanh thu và tài sản, hay nợ và vốn).
→ Giá trị tương quan gần 1 hoặc -1 thể hiện mối liên hệ mạnh, trong khi gần 0 là yếu hoặc không liên quan.

2.18 Ghi chú xử lý

cat("Hoàn tất bước II — dữ liệu đã được xử lý thô và mã hóa. data_selected sẵn sàng.\n")
## Hoàn tất bước II — dữ liệu đã được xử lý thô và mã hóa. data_selected sẵn sàng.

2.19 Tạo backup cho an toàn

write.csv(data_selected, "data_selected_backup.csv", row.names = FALSE)

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

3.1 Tổng quan tóm tắt

summary(data_selected) 
##  tai_san_ngan_han    tai_san_dai_han      hang_ton_kho      
##  Min.   :3.211e+12   Min.   :1.066e+12   Min.   :2.437e+12  
##  1st Qu.:5.016e+12   1st Qu.:1.378e+12   1st Qu.:3.245e+12  
##  Median :7.215e+12   Median :2.216e+12   Median :4.026e+12  
##  Mean   :8.432e+12   Mean   :2.654e+12   Mean   :4.507e+12  
##  3rd Qu.:1.113e+13   3rd Qu.:3.615e+12   3rd Qu.:5.545e+12  
##  Max.   :1.599e+13   Max.   :5.632e+12   Max.   :8.157e+12  
##   no_ngan_han        nguoi_mua_tra_tien_truoc
##  Min.   :9.958e+11   Min.   :2.857e+11       
##  1st Qu.:1.955e+12   1st Qu.:8.248e+11       
##  Median :3.608e+12   Median :1.599e+12       
##  Mean   :4.054e+12   Mean   :1.371e+12       
##  3rd Qu.:5.658e+12   3rd Qu.:1.759e+12       
##  Max.   :7.962e+12   Max.   :2.426e+12       
##  doanh_thu_chua_thuc_hien thang_du_von_co_phan doanh_so_thuan     
##  Min.   :1.144e+11        Min.   :6.611e+10    Min.   :6.552e+11  
##  1st Qu.:1.220e+11        1st Qu.:1.016e+11    1st Qu.:1.189e+12  
##  Median :1.519e+11        Median :2.672e+11    Median :1.745e+12  
##  Mean   :1.743e+11        Mean   :5.201e+11    Mean   :1.714e+12  
##  3rd Qu.:1.753e+11        3rd Qu.:1.046e+12    3rd Qu.:2.288e+12  
##  Max.   :3.130e+11        Max.   :1.121e+12    Max.   :2.569e+12  
##  von_chu_so_huu      tai_san_do_dang_dai_han  tong_tai_san      
##  Min.   :2.656e+12   Min.   :6.800e+10       Min.   :5.089e+12  
##  1st Qu.:2.973e+12   1st Qu.:8.048e+10       1st Qu.:6.270e+12  
##  Median :4.400e+12   Median :9.019e+10       Median :1.001e+13  
##  Mean   :5.176e+12   Mean   :9.235e+10       Mean   :1.109e+13  
##  3rd Qu.:7.764e+12   3rd Qu.:1.006e+11       3rd Qu.:1.631e+13  
##  Max.   :8.041e+12   Max.   :1.267e+11       Max.   :1.854e+13  
##     he_so_no      ty_le_hang_ton    ty_le_von_ts    ty_suat_doanh_thu
##  Min.   :0.3749   Min.   :0.3431   Min.   :0.4050   Min.   :0.3488   
##  1st Qu.:0.5187   1st Qu.:0.5189   1st Qu.:0.4588   1st Qu.:0.4645   
##  Median :0.7121   Median :0.5741   Median :0.4732   Median :0.5294   
##  Mean   :0.7486   Mean   :0.5796   Mean   :0.4725   Mean   :0.8586   
##  3rd Qu.:0.9746   3rd Qu.:0.6635   3rd Qu.:0.4859   3rd Qu.:1.1087   
##  Max.   :1.2498   Max.   :0.7590   Max.   :0.5285   Max.   :1.9840   
##  nhom_doanh_thu     nhom_he_so_no     
##  Length:10          Length:10         
##  Class :character   Class :character  
##  Mode  :character   Mode  :character  
##                                       
##                                       
## 

3.2 Kích thước dataset

dim(data_selected) 
## [1] 10 17

3.3 Tên các biến

names(data_selected) 
##  [1] "tai_san_ngan_han"         "tai_san_dai_han"         
##  [3] "hang_ton_kho"             "no_ngan_han"             
##  [5] "nguoi_mua_tra_tien_truoc" "doanh_thu_chua_thuc_hien"
##  [7] "thang_du_von_co_phan"     "doanh_so_thuan"          
##  [9] "von_chu_so_huu"           "tai_san_do_dang_dai_han" 
## [11] "tong_tai_san"             "he_so_no"                
## [13] "ty_le_hang_ton"           "ty_le_von_ts"            
## [15] "ty_suat_doanh_thu"        "nhom_doanh_thu"          
## [17] "nhom_he_so_no"

3.4 Số quan sát không NA cho từng biến

colSums(!is.na(data_selected)) # đánh giá dữ liệu đầy đủ
##         tai_san_ngan_han          tai_san_dai_han 
##                       10                       10 
##             hang_ton_kho              no_ngan_han 
##                       10                       10 
## nguoi_mua_tra_tien_truoc doanh_thu_chua_thuc_hien 
##                       10                       10 
##     thang_du_von_co_phan           doanh_so_thuan 
##                       10                       10 
##           von_chu_so_huu  tai_san_do_dang_dai_han 
##                       10                       10 
##             tong_tai_san                 he_so_no 
##                       10                       10 
##           ty_le_hang_ton             ty_le_von_ts 
##                       10                       10 
##        ty_suat_doanh_thu           nhom_doanh_thu 
##                       10                       10 
##            nhom_he_so_no 
##                       10

3.5 Trung bình từng biến numeric

round(colMeans(select(data_selected, where(is.numeric)), na.rm=TRUE),2) 
##         tai_san_ngan_han          tai_san_dai_han 
##             8.432207e+12             2.654341e+12 
##             hang_ton_kho              no_ngan_han 
##             4.507087e+12             4.054141e+12 
## nguoi_mua_tra_tien_truoc doanh_thu_chua_thuc_hien 
##             1.371313e+12             1.742761e+11 
##     thang_du_von_co_phan           doanh_so_thuan 
##             5.201069e+11             1.714091e+12 
##           von_chu_so_huu  tai_san_do_dang_dai_han 
##             5.176498e+12             9.235171e+10 
##             tong_tai_san                 he_so_no 
##             1.108655e+13             7.500000e-01 
##           ty_le_hang_ton             ty_le_von_ts 
##             5.800000e-01             4.700000e-01 
##        ty_suat_doanh_thu 
##             8.600000e-01

select(…, where(is.numeric)): chọn tất cả các cột dạng số trong bộ dữ liệu data_selected.
colMeans(…, na.rm=TRUE): tính trung bình cho từng biến số (bỏ qua giá trị NA).
round(…, 2): làm tròn kết quả đến 2 chữ số thập phân.
Kết quả cho ra giá trị trung bình của từng chỉ tiêu tài chính từ 2015–2024.
Ý NGHĨA:Tài sản ngắn hạn (8.43e+12) cao hơn tài sản dài hạn (2.65e+12) → cơ cấu tài sản nghiêng về ngắn hạn, phản ánh hoạt động đầu tư chủ yếu ngắn hạn.
Nợ ngắn hạn (4.05e+12) chiếm khoảng 37% tổng tài sản → mức đòn bẩy trung bình, không quá rủi ro.
Hệ số nợ ~0.75 → trung bình 75% tài sản được tài trợ bằng nợ, thể hiện doanh nghiệp tận dụng vốn vay nhiều.
Tỷ suất doanh thu ~0.86 → hiệu quả sinh lợi khá cao, doanh thu duy trì gần bằng quy mô tài sản hoạt động.

3.6 Độ lệch chuẩn từng biến

round(sapply(select(data_selected, where(is.numeric)), sd, na.rm=TRUE),2) 
##         tai_san_ngan_han          tai_san_dai_han 
##             4.356181e+12             1.562626e+12 
##             hang_ton_kho              no_ngan_han 
##             1.821154e+12             2.541916e+12 
## nguoi_mua_tra_tien_truoc doanh_thu_chua_thuc_hien 
##             6.958012e+11             7.525787e+10 
##     thang_du_von_co_phan           doanh_so_thuan 
##             4.757754e+11             6.680732e+11 
##           von_chu_so_huu  tai_san_do_dang_dai_han 
##             2.386188e+12             1.883167e+10 
##             tong_tai_san                 he_so_no 
##             5.272965e+12             2.900000e-01 
##           ty_le_hang_ton             ty_le_von_ts 
##             1.300000e-01             4.000000e-02 
##        ty_suat_doanh_thu 
##             6.400000e-01

select(…, where(is.numeric)) → chọn các biến dạng số trong data_selected.
sapply(…, sd, na.rm=TRUE) → tính độ lệch chuẩn (Standard Deviation) của từng biến, bỏ qua giá trị NA.
round(…, 2) → làm tròn đến 2 chữ số thập phân.
→ Kết quả biểu thị mức độ biến động (dao động quanh giá trị trung bình) của từng chỉ tiêu tài chính.
Về ý nghĩa thống kê – tài chính:
Tài sản ngắn hạn (4.36e+12) và tổng tài sản (5.27e+12) có độ lệch chuẩn lớn → biến động mạnh qua các năm, phản ánh giai đoạn đầu tư – mở rộng quy mô mạnh.
Tài sản dài hạn (1.56e+12), vốn chủ sở hữu (2.39e+12) → dao động trung bình, cho thấy nguồn vốn và đầu tư dài hạn ổn định hơn.
Hệ số nợ (0.29) và tỷ lệ vốn/tài sản (0.04) có độ lệch chuẩn thấp → cấu trúc tài chính ít biến động, duy trì chính sách tài trợ ổn định.

3.7 Min-Max từng biến

sapply(select(data_selected, where(is.numeric)), range, na.rm=TRUE) 
##      tai_san_ngan_han tai_san_dai_han hang_ton_kho  no_ngan_han
## [1,]     3.211019e+12    1.066410e+12 2.437144e+12 9.957855e+11
## [2,]     1.598576e+13    5.632288e+12 8.157039e+12 7.961859e+12
##      nguoi_mua_tra_tien_truoc doanh_thu_chua_thuc_hien
## [1,]             2.856693e+11             114442807380
## [2,]             2.426154e+12             312988984851
##      thang_du_von_co_phan doanh_so_thuan von_chu_so_huu
## [1,]         6.611126e+10   6.552252e+11   2.656336e+12
## [2,]         1.121120e+12   2.568689e+12   8.041311e+12
##      tai_san_do_dang_dai_han tong_tai_san  he_so_no ty_le_hang_ton
## [1,]             67997970133 5.089310e+12 0.3748717      0.3431422
## [2,]            126652346287 1.853932e+13 1.2497910      0.7589940
##      ty_le_von_ts ty_suat_doanh_thu
## [1,]    0.4050451         0.3488412
## [2,]    0.5285356         1.9839876

3.8 Median từng biến

sapply(select(data_selected, where(is.numeric)), median, na.rm=TRUE)
##         tai_san_ngan_han          tai_san_dai_han 
##             7.214985e+12             2.215929e+12 
##             hang_ton_kho              no_ngan_han 
##             4.025741e+12             3.607599e+12 
## nguoi_mua_tra_tien_truoc doanh_thu_chua_thuc_hien 
##             1.599121e+12             1.518893e+11 
##     thang_du_von_co_phan           doanh_so_thuan 
##             2.672225e+11             1.745200e+12 
##           von_chu_so_huu  tai_san_do_dang_dai_han 
##             4.399788e+12             9.019191e+10 
##             tong_tai_san                 he_so_no 
##             1.001170e+13             7.121210e-01 
##           ty_le_hang_ton             ty_le_von_ts 
##             5.740644e-01             4.731896e-01 
##        ty_suat_doanh_thu 
##             5.294454e-01

Về ý nghĩa thống kê – tài chính:
Tài sản ngắn hạn: dao động từ 3.2e+12 → 1.6e+13; trung vị khoảng 7.2e+12 → tăng mạnh, cho thấy xu hướng mở rộng quy mô lưu động.
Tổng tài sản: biên độ lớn (5.1e+12 → 1.85e+13) → phản ánh giai đoạn tăng trưởng tài sản rõ rệt.
Vốn chủ sở hữu: tăng dần, trung vị ~5.3e+12 → nền tảng vốn hóa ngày càng vững.
Hệ số nợ (0.37–1.25): có giai đoạn đòn bẩy cao nhưng trung vị ~0.75 → vẫn trong ngưỡng an toàn.
Tỷ suất doanh thu (~0.86 median): ổn định, cho thấy hiệu quả hoạt động duy trì tốt.

3.9 Var từng biến

sapply(select(data_selected, where(is.numeric)), var, na.rm=TRUE)
##         tai_san_ngan_han          tai_san_dai_han 
##             1.897632e+25             2.441798e+24 
##             hang_ton_kho              no_ngan_han 
##             3.316601e+24             6.461336e+24 
## nguoi_mua_tra_tien_truoc doanh_thu_chua_thuc_hien 
##             4.841392e+23             5.663746e+21 
##     thang_du_von_co_phan           doanh_so_thuan 
##             2.263623e+23             4.463218e+23 
##           von_chu_so_huu  tai_san_do_dang_dai_han 
##             5.693894e+24             3.546320e+20 
##             tong_tai_san                 he_so_no 
##             2.780416e+25             8.234323e-02 
##           ty_le_hang_ton             ty_le_von_ts 
##             1.584670e-02             1.360113e-03 
##        ty_suat_doanh_thu 
##             4.091456e-01

3.10 Tính tổng cho từng cột

colSums(select(data_selected, where(is.numeric)), na.rm=TRUE)
##         tai_san_ngan_han          tai_san_dai_han 
##             8.432207e+13             2.654341e+13 
##             hang_ton_kho              no_ngan_han 
##             4.507087e+13             4.054141e+13 
## nguoi_mua_tra_tien_truoc doanh_thu_chua_thuc_hien 
##             1.371313e+13             1.742761e+12 
##     thang_du_von_co_phan           doanh_so_thuan 
##             5.201069e+12             1.714091e+13 
##           von_chu_so_huu  tai_san_do_dang_dai_han 
##             5.176498e+13             9.235171e+11 
##             tong_tai_san                 he_so_no 
##             1.108655e+14             7.485683e+00 
##           ty_le_hang_ton             ty_le_von_ts 
##             5.796395e+00             4.725418e+00 
##        ty_suat_doanh_thu 
##             8.586068e+00

3.11 Phân tích biến: Tài sản ngắn hạn (TSNH)

c(
  Min = min(data_selected$tai_san_ngan_han, na.rm=TRUE),
  Max = max(data_selected$tai_san_ngan_han, na.rm=TRUE),
  Mean = mean(data_selected$tai_san_ngan_han, na.rm=TRUE),
  Median = median(data_selected$tai_san_ngan_han, na.rm=TRUE),
  SD = sd(data_selected$tai_san_ngan_han, na.rm=TRUE)
) 
##          Min          Max         Mean       Median           SD 
## 3.211019e+12 1.598576e+13 8.432207e+12 7.214985e+12 4.356181e+12

min(), max(): xác định phạm vi dao động (range) của giá trị tài sản ngắn hạn trong dữ liệu.
mean(): giá trị trung bình cộng của TSNH.
median(): giá trị trung vị — điểm giữa của phân bố, giúp giảm ảnh hưởng của các giá trị ngoại lai.
sd(): độ lệch chuẩn — đo mức độ biến động quanh giá trị trung bình.
Ý nghĩa thống kê:
TSNH trung bình ≈ 8.43×10¹², khá lớn, cho thấy các công ty trong mẫu có quy mô tài sản ngắn hạn cao.
Độ lệch chuẩn 4.36×10¹² phản ánh sự chênh lệch đáng kể giữa các doanh nghiệp — có doanh nghiệp giữ lượng TSNH rất cao so với trung bình.
Trung vị (7.21×10¹²) < Mean nên phân bố lệch phải (right-skewed) — có một số công ty có TSNH cực lớn kéo trung bình lên cao.

3.12 Phân tích Tài sản dài hạn (TSDH)

c(Min=min(data_selected$tai_san_dai_han,na.rm=TRUE), Max=max(data_selected$tai_san_dai_han,na.rm=TRUE),
  Mean=mean(data_selected$tai_san_dai_han,na.rm=TRUE), SD=sd(data_selected$tai_san_dai_han,na.rm=TRUE))
##          Min          Max         Mean           SD 
## 1.066410e+12 5.632288e+12 2.654341e+12 1.562626e+12

Ý nghĩa thống kê:
TSDH trung bình thấp hơn TSNH, cho thấy cấu trúc tài sản của doanh nghiệp thiên về tài sản ngắn hạn.
SD = 1.56×10¹², nhỏ hơn so với TSNH nên mức độ biến động thấp hơn, nghĩa là các doanh nghiệp có cấu trúc tài sản dài hạn tương đối ổn định hơn.

3.13 Phân tích Hàng tồn kho

c(Mean=mean(data_selected$hang_ton_kho,na.rm=TRUE), SD=sd(data_selected$hang_ton_kho,na.rm=TRUE))
##         Mean           SD 
## 4.507087e+12 1.821154e+12

Ý nghĩa thống kê:
Trung bình hàng tồn kho khoảng 4.5×10¹², chiếm tỷ trọng đáng kể trong TSNH.
Độ lệch chuẩn khá lớn (≈ 40% giá trị trung bình), cho thấy sự khác biệt đáng kể về quy mô tồn kho

3.14 Phân tích Nợ ngắn hạn

summary(data_selected$no_ngan_han)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
## 9.958e+11 1.955e+12 3.608e+12 4.054e+12 5.658e+12 7.962e+12

Sử dụng hàm summary() để tính giá trị nhỏ nhất, lớn nhất, trung bình, trung vị và các tứ phân vị (quartiles).
1st Qu. là giá trị mà 25% mẫu nhỏ hơn nó; 3rd Qu. là giá trị mà 75% mẫu nhỏ hơn nó.
Ý nghĩa thống kê:
Nợ ngắn hạn trung bình ≈ 4.05×10¹² — chiếm tỷ trọng đáng kể so với tổng tài sản ngắn hạn.
Độ phân tán cao: từ 9.96×10¹¹ đến 7.96×10¹² → cho thấy sự khác biệt lớn về quy mô vay nợ ngắn hạn giữa các công ty.
Median (3.61×10¹²) < Mean (4.05×10¹²) nên phân bố lệch phải (right-skewed) — có một số công ty có nợ ngắn hạn rất cao kéo trung bình lên.

3.15 Phân tích Người mua trả tiền trước

summary(data_selected$nguoi_mua_tra_tien_truoc)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
## 2.857e+11 8.248e+11 1.599e+12 1.371e+12 1.759e+12 2.426e+12

Ý nghĩa thống kê:
Giá trị trung bình (1.37×10¹²) và trung vị (1.60×10¹²) tương đối gần nhau nên phân bố gần đối xứng, ít bị ảnh hưởng bởi giá trị ngoại lai.
Biến này dao động không quá lớn (từ 2.86×10¹¹ → 2.43×10¹²), cho thấy sự ổn định trong chính sách nhận tiền trước của khách hàng giữa các doanh nghiệp.

3.16 Phân tích Doanh thu chưa thực hiện

summary(data_selected$doanh_thu_chua_thuc_hien)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
## 1.144e+11 1.220e+11 1.519e+11 1.743e+11 1.753e+11 3.130e+11

Đây là khoản doanh thu nhận trước nhưng chưa được ghi nhận, vì hàng hóa/dịch vụ chưa được cung cấp.
Ý nghĩa thống kê:
Giá trị trung bình và trung vị khá nhỏ so với các biến tài sản và nợ khác từ đó biến này chỉ chiếm tỷ trọng nhỏ trong tổng nguồn vốn.
Phạm vi dao động không quá lớn nên biến khá ổn định giữa các doanh nghiệp.
Mean > Median nên vẫn có một vài doanh nghiệp có doanh thu chưa thực hiện cao hơn mức chung.

3.17 Tương quan TSNH - NNH (kiểm tra thanh khoản)

cor_tsn_nnh <- cor(data_selected$tai_san_ngan_han, data_selected$no_ngan_han, use="complete.obs")
cat("Hệ số tương quan TSNH vs NNH:", round(cor_tsn_nnh,2), "\n")
## Hệ số tương quan TSNH vs NNH: 0.9

Dùng hàm cor() trong R để tính hệ số tương quan Pearson giữa hai biến định lượng.
use=“complete.obs” giúp loại bỏ các giá trị thiếu trước khi tính.
Ý nghĩa thống kê:
Hệ số r = 0.9 → tương quan dương rất mạnh giữa TSNH và NNH.
Nghĩa là khi TSNH tăng, NNH thường cũng tăng.
Giải thích: hệ số >0.7 có thể cho thấy nợ tăng cùng TSNH

3.18 Tương quan HTK - NM (Hàng tồn kho & Người mua trả tiền trước)

cor_htk_nm <- cor(data_selected$hang_ton_kho, data_selected$nguoi_mua_tra_tien_truoc, use="complete.obs")
cat("Hệ số tương quan HTK vs NM:", round(cor_htk_nm,2), "\n")
## Hệ số tương quan HTK vs NM: 0.8

Hàm cor() trong R được dùng để tính hệ số tương quan Pearson giữa hai biến định lượng.
use=“complete.obs” đảm bảo chỉ sử dụng các quan sát đầy đủ, không có giá trị thiếu.
Kết quả: r = 0.8
Về ý nghĩa thống kê:
r = 0.8 → mối tương quan dương mạnh giữa hàng tồn kho và người mua trả tiền trước.
Nghĩa là: khi hàng tồn kho tăng, số tiền khách hàng trả trước cũng tăng, phản ánh sự liên kết giữa quy mô sản xuất – dự trữ và khả năng bán hàng/đặt trước.

3.19 Hồi quy đơn giản: Doanh số ~ Vốn chủ sở hữu

lm1 <- lm(doanh_so_thuan ~ von_chu_so_huu, data = data_selected)
summary(lm1) 
## 
## Call:
## lm(formula = doanh_so_thuan ~ von_chu_so_huu, data = data_selected)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -9.686e+11 -5.060e+11  2.516e+10  6.366e+11  7.869e+11 
## 
## Coefficients:
##                 Estimate Std. Error t value Pr(>|t|)  
## (Intercept)    1.529e+12  5.547e+11   2.756   0.0248 *
## von_chu_so_huu 3.581e-02  9.817e-02   0.365   0.7247  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 7.028e+11 on 8 degrees of freedom
## Multiple R-squared:  0.01636,    Adjusted R-squared:  -0.1066 
## F-statistic: 0.1331 on 1 and 8 DF,  p-value: 0.7247

Kết quả chính:
Hệ số góc (β₁) = 0.0365 → tác động dương nhưng nhỏ
p-value = 0.7247 > 0.05 → không có ý nghĩa thống kê
R² = 0.016 → mô hình chỉ giải thích được 1.6% biến thiên doanh số
Về ý nghĩa thống kê:Không có bằng chứng cho thấy vốn chủ sở hữu ảnh hưởng đáng kể đến doanh số thuần trong mẫu quan sát.
Độ phù hợp mô hình thấp → doanh số phụ thuộc vào nhiều yếu tố khác (nợ, đầu tư, thị trường…).

3.20 Hồi quy kiểm tra: TSNH ~ HTK

lm2 <- lm(tai_san_ngan_han ~ hang_ton_kho, data = data_selected)
summary(lm2)
## 
## Call:
## lm(formula = tai_san_ngan_han ~ hang_ton_kho, data = data_selected)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -1.474e+12 -6.837e+11 -6.113e+11  2.740e+10  4.244e+12 
## 
## Coefficients:
##                Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  -1.563e+12  1.530e+12  -1.022 0.336668    
## hang_ton_kho  2.218e+00  3.169e-01   6.999 0.000113 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.731e+12 on 8 degrees of freedom
## Multiple R-squared:  0.8596, Adjusted R-squared:  0.8421 
## F-statistic: 48.98 on 1 and 8 DF,  p-value: 0.0001128

Hệ số góc β₁ = 2.218: khi hàng tồn kho tăng thêm 1 đơn vị, tài sản ngắn hạn tăng trung bình 2.218 đơn vị, nếu các yếu tố khác không đổi.
p-value < 0.001 → biến HTK có ý nghĩa thống kê mạnh trong việc giải thích biến thiên của TSNH.
R² = 0.8596 → mô hình giải thích khoảng 85.96% biến động tài sản ngắn hạn thông qua hàng tồn kho, cho thấy mối quan hệ rất chặt chẽ.
F-statistic = 48.98 với p-value < 0.001 → mô hình tổng thể phù hợp, đáng tin cậy.

4. TRỰC QUAN HÓA DỮ LIỆU — 20 BIỂU ĐỒ, MỖI BIỂU ĐỒ ≥5 LAYER

theme_finance <- theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face="bold", hjust=0.5, size=14),
    plot.caption = element_text(hjust=0.5, face="italic"),
    axis.text.x = element_text(angle=45, hjust=1)
  )

Tạo cột năm 2015–2024 tương ứng số dòng trong data_selected

data_selected$nam <- 2015:(2015 + nrow(data_selected) - 1)
head(data_selected)

Thêm cột năm cho dữ liệu — có 10 dòng nên năm 2015–2024.

4.1 Tài sản ngắn hạn

ggplot(data_selected, aes(x = nam, y = tai_san_ngan_han)) +
  geom_col(fill="skyblue", alpha=0.8) +  # layer 1: cột
  geom_line(color="darkblue", linewidth=1) +  # layer 2: đường xu hướng
  geom_point(color="blue", size=2) +  # layer 3: điểm dữ liệu
  geom_smooth(method="lm", se=FALSE, color="orange", linewidth=1) +  # layer 4: đường hồi quy
  geom_hline(yintercept = mean(data_selected$tai_san_ngan_han, na.rm=TRUE),
             linetype="dashed", color="red") +  # layer 5: đường trung bình
  labs(
    title="Tài sản ngắn hạn qua các năm",
    x="Năm",
    y="Giá trị (VNĐ)",
    caption="Nguồn: data_selected"
  ) +
  scale_x_continuous(breaks = 2015:2024) +
  theme_finance

Biểu đồ thể hiện xu hướng tăng của tài sản ngắn hạn qua các năm 2015–2024.
Cột màu xanh: giá trị tài sản từng năm → cho thấy quy mô tăng dần.
Đường xanh đậm + chấm tròn: diễn biến thực tế qua từng năm.
Đường cam: xu hướng hồi quy tuyến tính → phản ánh mức tăng ổn định theo thời gian.
Đường đỏ đứt đoạn: giá trị trung bình tài sản ngắn hạn → dùng để so sánh các năm cao/thấp hơn mức trung bình.
Ý nghĩa kinh tế: doanh nghiệp đang mở rộng quy mô tài sản lưu động, phản ánh khả năng thanh khoản và đầu tư ngắn hạn được cải thiện qua các năm.

4.2 Tài sản dài hạn

ggplot(data_selected, aes(x = nam, y = tai_san_dai_han)) +
  geom_col(fill="lightgreen", alpha=0.8) +
  geom_line(color="darkgreen", linewidth=1) +
  geom_point(color="darkgreen", size=2) +
  geom_smooth(method="lm", se=FALSE, color="orange", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$tai_san_dai_han, na.rm=TRUE),
             linetype="dashed", color="red") +
  labs(title="Tài sản dài hạn qua các năm", x="Năm", y="Giá trị (VNĐ)") +
  scale_x_continuous(breaks = 2015:2024) +
  theme_finance

geom_col() – cột màu xanh lá hiển thị giá trị tài sản dài hạn từng năm.
geom_line() – đường xanh biểu diễn xu hướng biến động qua thời gian.
geom_point() – các điểm dữ liệu cụ thể từng năm.
geom_smooth(method=“lm”) – đường hồi quy màu cam, cho thấy xu hướng chung tăng nhẹ.
geom_hline() – đường đỏ đứt đoạn biểu thị mức trung bình toàn kỳ.

Về ý nghĩa kinh tế:
Tài sản dài hạn tăng mạnh giai đoạn 2019–2021, đạt đỉnh năm 2021, sau đó giảm dần đến 2024.
Xu hướng hồi quy cho thấy doanh nghiệp vẫn duy trì đầu tư dài hạn ổn định, dù có dao động ngắn hạn.
Mức trung bình (đường đỏ) giúp so sánh năm nào vượt hoặc thấp hơn mức chuẩn, hỗ trợ đánh giá hiệu quả đầu tư tài sản cố định theo thời gian.

4.3 Hàng tồn kho

ggplot(data_selected, aes(x = nam, y = hang_ton_kho)) +
  geom_col(fill="pink", alpha=0.8) +
  geom_line(color="darkred", linewidth=1) +
  geom_point(color="darkred", size=2) +
  geom_smooth(method="lm", se=FALSE, color="black", linewidth=1) +
  geom_hline(yintercept = median(data_selected$hang_ton_kho, na.rm=TRUE),
             linetype="dotted", color="gray") +
  labs(title="Hàng tồn kho qua các năm", x="Năm", y="Giá trị (VNĐ)") +
  scale_x_continuous(breaks = 2015:2024) +
  theme_finance

geom_col() – cột hồng thể hiện giá trị hàng tồn kho từng năm.
geom_line() – đường đỏ xu hướng biến động.
geom_point() – điểm dữ liệu từng năm.
geom_smooth(method=“lm”) – đường hồi quy đen thể hiện xu hướng tăng.
geom_hline() – đường xám đứt biểu thị mức trung vị.
Về ý nghĩa kinh tế:
Hàng tồn kho tăng đều, nhất là từ 2022–2024, phản ánh mức dự trữ hàng hóa lớn hơn.
Xu hướng hồi quy cho thấy tồn kho tăng ổn định, có thể do mở rộng quy mô hoặc tiêu thụ chậm.
Mức trung vị giúp nhận biết năm tồn kho cao/thấp hơn trung bình, hỗ trợ đánh giá hiệu quả quản lý hàng hóa.

4.4 Nợ ngắn hạn

ggplot(data_selected, aes(x = nam, y = no_ngan_han)) +
  geom_col(fill="plum", alpha=0.8) +
  geom_line(color="purple", linewidth=1) +
  geom_point(color="purple", size=2) +
  geom_smooth(method="lm", se=FALSE, color="darkred", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$no_ngan_han, na.rm=TRUE),
             linetype="dashed", color="red") +
  labs(title="Nợ ngắn hạn qua các năm", x="Năm", y="Giá trị (VNĐ)") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – cột tím thể hiện giá trị nợ ngắn hạn từng năm.
geom_line() – đường tím biểu diễn xu hướng biến động theo thời gian.
geom_point() – điểm dữ liệu từng năm.
geom_smooth(method=“lm”) – đường hồi quy nâu, thể hiện xu hướng tăng rõ rệt.
geom_hline() – đường đỏ đứt đoạn biểu thị mức trung bình toàn kỳ.
Về ý nghĩa kinh tế: Nợ ngắn hạn tăng mạnh qua các năm, đặc biệt giai đoạn 2020–2024, cho thấy doanh nghiệp mở rộng vay ngắn hạn hoặc tăng nhu cầu vốn lưu động.
Đường hồi quy thể hiện xu hướng nợ tăng ổn định, phản ánh sự phụ thuộc lớn hơn vào nguồn tài trợ ngắn hạn.
So với đường trung bình, các năm gần đây vượt xa mức chuẩn, cho thấy rủi ro thanh toán ngắn hạn tăng lên.

4.5 Người mua trả tiền trước

ggplot(data_selected, aes(x = nam, y = nguoi_mua_tra_tien_truoc)) +
  geom_col(fill="khaki", alpha=0.8) +
  geom_line(color="saddlebrown", linewidth=1) +
  geom_point(color="saddlebrown", size=2) +
  geom_smooth(method="lm", se=FALSE, color="blue", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$nguoi_mua_tra_tien_truoc, na.rm=TRUE),
             linetype="dashed", color="red") +
  labs(title="Người mua trả tiền trước qua các năm", x="Năm", y="Giá trị (VNĐ)") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – cột vàng thể hiện giá trị tiền khách trả trước từng năm.
geom_line() – đường nâu biểu diễn xu hướng biến động theo thời gian.
geom_point() – các điểm dữ liệu cụ thể từng năm.
geom_smooth(method=“lm”) – đường hồi quy xanh dương cho thấy xu hướng tăng ổn định.
geom_hline() – đường đỏ đứt đoạn biểu thị mức trung bình toàn kỳ.
Về ý nghĩa kinh tế: Khoản người mua trả tiền trước tăng đều qua các năm, phản ánh niềm tin và nhu cầu của khách hàng đối với doanh nghiệp.
Giai đoạn 2019–2020 đạt đỉnh, sau đó điều chỉnh nhẹ rồi tăng trở lại năm 2024.
Xu hướng hồi quy cho thấy doanh nghiệp có khả năng thu tiền trước tốt hơn theo thời gian, giúp cải thiện dòng tiền ngắn hạn và giảm áp lực vay vốn lưu động.

4.6 Doanh thu chưa thực hiện

ggplot(data_selected, aes(x = nam, y = doanh_thu_chua_thuc_hien)) +
  geom_col(fill="gold", alpha=0.8) +
  geom_line(color="darkgoldenrod", linewidth=1) +
  geom_point(color="darkgoldenrod", size=2) +
  geom_smooth(method="lm", se=FALSE, color="darkorange", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$doanh_thu_chua_thuc_hien, na.rm=TRUE),
             linetype="dashed", color="red") +
  labs(title="Doanh thu chưa thực hiện qua các năm", x="Năm", y="Giá trị (VNĐ)") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – cột vàng thể hiện doanh thu chưa thực hiện từng năm.
geom_line() – đường nâu biểu diễn xu hướng biến động doanh thu theo thời gian.
geom_point() – các điểm dữ liệu cụ thể từng năm.
geom_smooth(method=“lm”) – đường hồi quy màu cam cho thấy xu hướng giảm dần.
geom_hline() – đường đỏ đứt đoạn biểu thị mức trung bình toàn kỳ. Doanh thu chưa thực hiện giảm dần rõ rệt từ 2016 đến 2023, phản ánh doanh nghiệp đang ghi nhận doanh thu nhanh hơn hoặc ít hợp đồng dài hạn hơn.
Đến 2024 có dấu hiệu phục hồi nhẹ, cho thấy khả năng gia tăng hợp đồng trả trước hoặc dịch vụ dài hạn.

4.7 Thặng dư vốn cổ phần

ggplot(data_selected, aes(x = nam, y = thang_du_von_co_phan)) +
  geom_col(fill="lightsteelblue", alpha=0.8) +
  geom_line(color="steelblue4", linewidth=1) +
  geom_point(color="steelblue4", size=2) +
  geom_smooth(method="lm", se=FALSE, color="darkblue", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$thang_du_von_co_phan, na.rm=TRUE),
             linetype="dashed", color="red") +
  labs(title="Thặng dư vốn cổ phần qua các năm", x="Năm", y="Giá trị (VNĐ)") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – cột xanh nhạt thể hiện thặng dư vốn cổ phần từng năm.
geom_line() – đường xanh đậm biểu diễn sự thay đổi theo thời gian.
geom_point() – đánh dấu các giá trị cụ thể từng năm.
geom_smooth(method=“lm”) – đường xu hướng hồi quy tuyến tính màu xanh dương.
geom_hline() – đường đỏ đứt đoạn thể hiện mức trung bình toàn giai đoạn.
Về ý nghĩa kinh tế: Giai đoạn 2015–2019: thặng dư vốn thấp, dao động nhỏ → doanh nghiệp chưa có nhiều hoạt động phát hành thêm cổ phần hoặc thặng dư vốn tích lũy ít.
Từ 2020–2021: tăng mạnh, đạt đỉnh → cho thấy doanh nghiệp huy động thêm vốn cổ phần hoặc phát hành cổ phiếu với giá cao hơn mệnh giá.
2022–2024: duy trì ở mức cao, ổn định → phản ánh cơ cấu vốn cổ phần ổn định và niềm tin nhà đầu tư vững vàng.

4.8 Doanh số thuần

ggplot(data_selected, aes(x = nam, y = doanh_so_thuan)) +
  geom_col(fill="lightsalmon", alpha=0.8) +
  geom_line(color="tomato4", linewidth=1) +
  geom_point(color="tomato4", size=2) +
  geom_smooth(method="lm", se=FALSE, color="firebrick", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$doanh_so_thuan, na.rm=TRUE),
             linetype="dashed", color="red") +
  labs(title="Doanh số thuần qua các năm", x="Năm", y="Giá trị (VNĐ)") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – cột cam hiển thị doanh số thuần từng năm.
geom_line() – đường nâu biểu diễn xu hướng biến động doanh thu theo thời gian.
geom_point() – điểm dữ liệu cụ thể của từng năm.
geom_smooth(method=“lm”) – đường xu hướng hồi quy màu nâu đậm, thể hiện xu thế tăng nhẹ tổng thể.
geom_hline() – đường đỏ đứt đoạn thể hiện mức trung bình toàn kỳ.
Về ý nghĩa kinh tế:
2015–2018: doanh số thuần tăng nhanh, cho thấy hoạt động kinh doanh mở rộng mạnh.
2019–2021: đạt đỉnh cao, phản ánh giai đoạn tăng trưởng mạnh nhất.
2022–2023: doanh số giảm sâu, có thể do biến động thị trường hoặc chi phí gia tăng.
2024: doanh số phục hồi nhẹ, cho thấy dấu hiệu ổn định trở lại.

4.9 Vốn chủ sở hữu

ggplot(data_selected, aes(x = nam, y = von_chu_so_huu)) +
  geom_col(fill="lightblue", alpha=0.8) +
  geom_line(color="navy", linewidth=1) +
  geom_point(color="navy", size=2) +
  geom_smooth(method="lm", se=FALSE, color="steelblue", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$von_chu_so_huu, na.rm=TRUE),
             linetype="dashed", color="red") +
  labs(title="Vốn chủ sở hữu qua các năm", x="Năm", y="Giá trị (VNĐ)") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – các cột xanh nhạt biểu diễn vốn chủ sở hữu từng năm, giúp dễ quan sát quy mô theo thời gian.
geom_line() – đường màu xanh đậm thể hiện xu hướng biến động vốn qua các năm.
geom_point() – các điểm tròn đánh dấu giá trị cụ thể từng năm.
geom_smooth(method = “lm”) – đường xu hướng hồi quy tuyến tính màu xanh nhạt, cho thấy xu thế tăng trưởng dài hạn.
geom_hline() – đường đỏ đứt đoạn biểu diễn mức vốn chủ sở hữu trung bình toàn kỳ.
Về ý nghĩa kinh tế:
2015–2019: Vốn chủ sở hữu tăng đều và ổn định, phản ánh doanh nghiệp tích lũy vốn nội tại tốt, hoạt động kinh doanh hiệu quả.
2020: Có bước nhảy rõ rệt, cho thấy tăng vốn hoặc lợi nhuận giữ lại đột biến – có thể nhờ mở rộng hoạt động hoặc điều chỉnh cơ cấu vốn.
2021–2023: Duy trì ở mức cao ổn định, chứng tỏ doanh nghiệp giữ được năng lực tài chính vững mạnh, không bị suy giảm đáng kể.
2024: Tăng nhẹ, củng cố xu thế ổn định – tăng trưởng bền vững của nguồn vốn chủ sở hữu trong dài hạn.

4.10 Tài sản dở dang dài hạn

ggplot(data_selected, aes(x = nam, y = tai_san_do_dang_dai_han)) +
  geom_col(fill="lightpink", alpha=0.8) +
  geom_line(color="deeppink4", linewidth=1) +
  geom_point(color="deeppink4", size=2) +
  geom_smooth(method="lm", se=FALSE, color="brown", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$tai_san_do_dang_dai_han, na.rm=TRUE),
             linetype="dashed", color="red") +
  labs(title="Tài sản dở dang dài hạn qua các năm", x="Năm", y="Giá trị (VNĐ)") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – các cột màu hồng nhạt biểu diễn quy mô tài sản dở dang dài hạn từng năm.
geom_line() – đường màu tím đậm thể hiện xu hướng biến động giá trị tài sản qua thời gian.
geom_point() – các điểm tròn đánh dấu giá trị cụ thể của từng năm.
geom_smooth(method = “lm”) – đường nâu hồi quy tuyến tính, phản ánh xu hướng tăng trưởng dài hạn của chỉ tiêu.
geom_hline() – đường đỏ đứt đoạn thể hiện mức tài sản dở dang dài hạn trung bình toàn giai đoạn.
Về ý nghĩa kinh tế:
2015–2017: Giá trị tài sản dở dang duy trì ở mức thấp và ổn định – phản ánh quy mô đầu tư xây dựng chưa mở rộng.
2018–2020: Bắt đầu tăng dần, cho thấy doanh nghiệp mở rộng hoạt động đầu tư và các dự án dài hạn.
2021–2022: Đạt đỉnh cao, chứng tỏ nhiều dự án lớn được triển khai mạnh mẽ, có thể là giai đoạn tăng tốc đầu tư.
2023–2024: Có dấu hiệu giảm nhẹ nhưng vẫn cao hơn mức trung bình, cho thấy doanh nghiệp bước vào giai đoạn hoàn thiện dự án, giảm dần đầu tư mới.
Tóm lại: Tài sản dở dang dài hạn của DIG có xu hướng tăng ổn định trong dài hạn, phản ánh chiến lược đầu tư mở rộng quy mô hoạt động của doanh nghiệp.

4.11 Tỷ lệ hàng tồn kho / TSNH

ggplot(data_selected, aes(x = nam, y = ty_le_hang_ton)) +
  geom_col(fill="lightcyan", alpha=0.8) +
  geom_line(color="darkcyan", linewidth=1) +
  geom_point(color="darkcyan", size=2) +
  geom_smooth(method="loess", se=FALSE, color="darkblue", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$ty_le_hang_ton, na.rm=TRUE), linetype="dashed", color="red") +
  labs(title="Tỷ lệ hàng tồn kho / TSNH qua các năm", x="Năm", y="Tỷ lệ") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – các cột xanh nhạt biểu diễn tỷ lệ hàng tồn kho / TSNH theo từng năm.
geom_line() – đường màu xanh đậm-xu hướng biến động tỷ lệ tồn kho qua thời gian.
geom_point() – điểm xanh lam thể hiện giá trị cụ thể từng năm, giúp người xem dễ so sánh.
geom_smooth(method = “lm”) – đường hồi quy tuyến tính màu xanh dương nhạt, mô tả xu hướng giảm nhẹ tổng thể.
geom_hline() – đường đỏ đứt đoạn biểu diễn mức trung bình toàn kỳ của tỷ lệ hàng tồn kho trên TSNH.
Về ý nghĩa kinh tế: 2015–2017: Tỷ lệ hàng tồn kho / TSNH ở mức cao, dao động quanh 0,7–0,8, cho thấy doanh nghiệp tích trữ hàng hóa nhiều, có thể để đáp ứng nhu cầu tăng mạnh hoặc phòng ngừa rủi ro cung ứng.
2018–2020: Tỷ lệ giảm dần, phản ánh chính sách quản trị hàng tồn kho được cải thiện, doanh nghiệp tối ưu hóa vòng quay hàng hóa.
2021: Giảm mạnh xuống mức thấp nhất, có thể do doanh thu tăng nhanh hơn lượng hàng dự trữ, hoặc doanh nghiệp giảm quy mô lưu kho để tiết kiệm chi phí.
2022–2024: Tỷ lệ nhích lên nhẹ, nhưng vẫn dưới mức trung bình, cho thấy doanh nghiệp duy trì chiến lược kiểm soát hàng tồn kho thận trọng và hiệu quả hơn.
→ Tổng thể, đường hồi quy đi xuống nhẹ, thể hiện xu hướng giảm dần tỷ trọng hàng tồn kho trong tài sản ngắn hạn, hàm ý hiệu quả quản lý vốn lưu động được cải thiện.

4.12 Hệ số nợ (Nợ ngắn hạn / Vốn chủ sở hữu)

ggplot(data_selected, aes(x = nam, y = he_so_no)) +
  geom_col(fill="gray80", alpha=0.8) +
  geom_line(color="black", linewidth=1) +
  geom_point(color="black", size=2) +
  geom_smooth(method="loess", se=FALSE, color="red", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$he_so_no, na.rm=TRUE), linetype="dashed", color="red") +
  labs(title="Hệ số nợ qua các năm", x="Năm", y="Tỷ lệ") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – các cột xám nhạt biểu diễn hệ số nợ của doanh nghiệp theo từng năm.
geom_line() – đường đen mô tả biến động thực tế của hệ số nợ qua thời gian.
geom_point() – các điểm đen thể hiện giá trị cụ thể của từng năm.
geom_smooth(method = “loess”) – đường cong hồi quy màu đỏ, cho thấy xu hướng tổng thể biến động theo chu kỳ, không hoàn toàn tuyến tính.
geom_hline() – đường đỏ đứt đoạn biểu diễn mức trung bình toàn kỳ của hệ số nợ.
Về ý nghĩa kinh tế:
2015–2017: Hệ số nợ tăng dần từ mức thấp (~0,4) lên khoảng 0,6–0,7, thể hiện doanh nghiệp gia tăng sử dụng đòn bẩy tài chính để tài trợ cho mở rộng hoạt động.
2018–2020: Tiếp tục tăng mạnh, đạt đỉnh trên 1,2 lần vào năm 2020, cho thấy doanh nghiệp phụ thuộc đáng kể vào nguồn vốn vay, có thể nhằm tận dụng lãi suất thấp hoặc mở rộng đầu tư.
2021–2022: Giảm sâu, xuống mức thấp nhất khoảng 0,5, phản ánh xu hướng giảm nợ hoặc tái cơ cấu tài chính, giúp giảm rủi ro đòn bẩy.
2023–2024: Hệ số nợ phục hồi trở lại, tiến gần mức trung bình dài hạn (~0,8), doanh nghiệp đã cân bằng lại cấu trúc vốn duy trì mức vay hợp lý cho tăng trưởng.
→ Nhìn chung, đường xu hướng cong đỏ (loess) cho thấy chu kỳ tài chính rõ nét: giai đoạn tăng mạnh – điều chỉnh – ổn định trở lại, phản ánh quá trình quản trị nợ linh hoạt theo biến động của môi trường kinh doanh.

4.13 Tỷ lệ vốn chủ sở hữu / Tổng tài sản

ggplot(data_selected, aes(x = nam, y = ty_le_von_ts)) +
  geom_col(fill="palegreen", alpha=0.8) +
  geom_line(color="darkgreen", linewidth=1) +
  geom_point(color="darkgreen", size=2) +
  geom_smooth(method="loess", se=FALSE, color="darkblue", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$ty_le_von_ts, na.rm=TRUE), linetype="dashed", color="red") +
  labs(title="Tỷ lệ VCSH / Tổng tài sản qua các năm", x="Năm", y="Tỷ lệ") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

Về kỹ thuật:
Biểu đồ gồm 5 lớp chính:
geom_col() – cột màu xanh nhạt biểu diễn tỷ lệ VCSH/Tổng tài sản từng năm.
geom_line() – đường xanh đậm thể hiện xu hướng biến động của tỷ lệ này.
geom_point() – các điểm tròn xanh đánh dấu giá trị cụ thể qua từng năm.
geom_smooth(method=“loess”) – đường cong trơn màu xanh dương, mô tả xu thế tổng quát của dữ liệu.
geom_hline() – đường đỏ đứt đoạn thể hiện mức trung bình của tỷ lệ trong toàn giai đoạn.
Về ý nghĩa kinh tế:
2015–2017: Tỷ lệ VCSH/Tổng tài sản ở mức cao và ổn định → doanh nghiệp chủ yếu dùng vốn tự có, ít phụ thuộc nợ.
2018–2020: Tỷ lệ giảm mạnh, đặc biệt năm 2020 → mức độ sử dụng đòn bẩy tài chính tăng, doanh nghiệp huy động thêm nợ hoặc tăng đầu tư.
2021–2022: Tỷ lệ phục hồi mạnh, vượt mức trung bình → cho thấy doanh nghiệp tái cân đối nguồn vốn, củng cố năng lực tài chính.
2023–2024: Giảm nhẹ nhưng vẫn gần mức trung bình → cơ cấu vốn duy trì ổn định, phản ánh sự cân bằng hợp lý giữa vốn chủ và nợ.
Kết luận: Tỷ lệ VCSH/Tổng tài sản của DIG dao động quanh mức 45–55%, thể hiện cấu trúc tài chính tương đối an toàn và ổn định trong dài hạn.

4.14 Tỷ suất doanh thu / TSDH

ggplot(data_selected, aes(x = nam, y = ty_suat_doanh_thu)) +
  geom_col(fill="plum", alpha=0.8) +
  geom_line(color="purple4", linewidth=1) +
  geom_point(color="purple4", size=2) +
  geom_smooth(method="loess", se=FALSE, color="black", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$ty_suat_doanh_thu, na.rm=TRUE), linetype="dashed", color="red") +
  labs(title="Tỷ suất doanh thu / TSDH qua các năm", x="Năm", y="Tỷ lệ") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – cột tím nhạt biểu diễn tỷ suất doanh thu/Tài sản dài hạn (TSDH) từng năm.
geom_line() – đường tím đậm thể hiện xu hướng biến động của tỷ suất theo thời gian.
geom_point() – các điểm tròn tím đánh dấu giá trị cụ thể mỗi năm.
geom_smooth(method=“loess”) – đường đen mô tả xu hướng tổng thể, làm mượt biến động.
geom_hline() – đường đỏ đứt đoạn biểu diễn mức trung bình toàn kỳ.
Về ý nghĩa kinh tế: 2015–2018: Tỷ suất tăng nhanh, đạt đỉnh giai đoạn 2018–2019 (~2 lần) → cho thấy hiệu quả sử dụng TSDH cao, doanh nghiệp tận dụng tốt tài sản đầu tư cho hoạt động tạo doanh thu.
2020–2022: Giảm mạnh dưới mức trung bình → phản ánh hiệu quả khai thác tài sản giảm, có thể do đầu tư dở dang hoặc thị trường suy yếu.
2023–2024: Tỷ suất nhích tăng nhẹ → hiệu quả bắt đầu phục hồi, cho thấy khả năng sử dụng TSDH đang được cải thiện.
Kết luận: Hiệu quả sử dụng tài sản dài hạn của DIG đạt đỉnh năm 2018–2019, sau đó giảm nhưng có dấu hiệu phục hồi cuối kỳ, phản ánh quá trình tái đầu tư và điều chỉnh hoạt động sản xuất – kinh doanh.

4.15 So sánh TSNH & Nợ ngắn hạn

df_15 <- data_selected %>% select(nam, tai_san_ngan_han, no_ngan_han) %>% pivot_longer(-nam, names_to="Loai", values_to="GiaTri")
ggplot(df_15, aes(x=nam, y=GiaTri, fill=Loai)) +
  geom_col(position="dodge", alpha=0.8) +
  geom_line(aes(group=Loai, color=Loai), linewidth=1) +
  geom_point(aes(color=Loai), size=2) +
  geom_hline(yintercept = mean(data_selected$tai_san_ngan_han, na.rm=TRUE), linetype="dashed", color="red") +
  labs(title="So sánh TSNH & Nợ ngắn hạn", x="Năm", y="Giá trị (VNĐ)", fill="Loại", color="Loại") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – các cột song song màu đỏ và xanh ngọc, thể hiện giá trị nợ ngắn hạn và tài sản ngắn hạn (TSNH) theo từng năm.
genm_line() – đường nối cùng màu biểu diễn xu hướng biến động của từng chỉ tiêu.
geom_point() – các điểm tròn đánh dấu giá trị cụ thể mỗi năm.
geom_hline() – đường đỏ đứt đoạn biểu diễn mức TSNH trung bình toàn kỳ.
scale_x_continuous() – hiển thị rõ mốc thời gian 2015–2024.
Về ý nghĩa tài chính: 2015–2019: TSNH và nợ ngắn hạn cùng tăng, nhưng TSNH luôn cao hơn, phản ánh khả năng thanh toán ngắn hạn tốt, doanh nghiệp giữ được dự trữ tài sản lưu động ổn định.
2020–2021: Khoảng cách giữa TSNH và nợ ngắn hạn thu hẹp, cho thấy áp lực thanh khoản tăng – có thể do dòng tiền bị ứ đọng hoặc đầu tư dở dang.
2022–2024: TSNH tăng mạnh vượt xa nợ ngắn hạn, thể hiện khả năng tự chủ tài chính ngắn hạn cải thiện đáng kể.
Kết luận: DIG duy trì cơ cấu vốn lưu động lành mạnh, với tài sản ngắn hạn đủ bù đắp nợ ngắn hạn, đặc biệt giai đoạn 2022–2024 cho thấy sức mạnh tài chính ngắn hạn tăng rõ rệt và rủi ro thanh khoản giảm.

4.16 So sánh TSDH & Vốn chủ sở hữu

df_16 <- data_selected %>% select(nam, tai_san_dai_han, von_chu_so_huu) %>% pivot_longer(-nam, names_to="Loai", values_to="GiaTri")
ggplot(df_16, aes(x=nam, y=GiaTri, fill=Loai)) +
  geom_col(position="dodge", alpha=0.8) +
  geom_line(aes(group=Loai, color=Loai), linewidth=1) +
  geom_point(aes(color=Loai), size=2) +
  geom_hline(yintercept = mean(data_selected$tai_san_dai_han, na.rm=TRUE), linetype="dashed", color="red") +
  labs(title="So sánh TSDH & Vốn chủ sở hữu", x="Năm", y="Giá trị (VNĐ)", fill="Loại", color="Loại") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – các cột song song màu đỏ và xanh ngọc, thể hiện giá trị tài sản dài hạn (TSDH) và vốn chủ sở hữu (VCSH) theo từng năm.
geom_line() – đường nối cùng màu thể hiện xu hướng biến động của từng chỉ tiêu.
geom_point() – điểm tròn đánh dấu giá trị cụ thể mỗi năm.
geom_hline() – đường đỏ đứt đoạn biểu diễn mức TSDH trung bình toàn kỳ.
scale_x_continuous() – hiển thị rõ mốc thời gian 2015–2024.
Về ý nghĩa tài chính: 2015–2019: VCSH tăng đều, trong khi TSDH ổn định ở mức thấp → công ty duy trì đầu tư dài hạn thận trọng.
2020–2021: Cả hai cùng tăng mạnh, đặc biệt TSDH tăng vọt → giai đoạn DIG mở rộng quy mô đầu tư, phát triển dự án mới.
2022–2024: VCSH tiếp tục tăng, vượt xa TSDH → cơ cấu vốn an toàn, doanh nghiệp chủ động tài trợ tài sản dài hạn bằng vốn tự có.
Kết luận: DIG đang có cơ cấu tài chính vững chắc, với vốn chủ sở hữu tăng mạnh và bao phủ hoàn toàn tài sản dài hạn, cho thấy khả năng tự chủ tài chính cao, ít phụ thuộc nợ vay dài hạn và nền tảng tài chính ổn định để phát triển bền vững.

4.17 So sánh Tài sản dở dang & Người mua trả tiền trước

df_17 <- data_selected %>% select(nam, tai_san_do_dang_dai_han, nguoi_mua_tra_tien_truoc) %>% pivot_longer(-nam, names_to="Loai", values_to="GiaTri")
ggplot(df_17, aes(x=nam, y=GiaTri, fill=Loai)) +
  geom_col(position="dodge", alpha=0.8) +
  geom_line(aes(group=Loai, color=Loai), linewidth=1) +
  geom_point(aes(color=Loai), size=2) +
  geom_hline(yintercept = mean(data_selected$tai_san_do_dang_dai_han, na.rm=TRUE), linetype="dashed", color="red") +
  labs(title="So sánh TSDD dài hạn & Người mua trả tiền trước", x="Năm", y="Giá trị (VNĐ)", fill="Loại", color="Loại") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col() – các cột song song màu đỏ và xanh ngọc, thể hiện giá trị người mua trả tiền trước và tài sản dở dang dài hạn theo từng năm.
geom_line() – các đường cùng màu thể hiện xu hướng biến động của từng chỉ tiêu.
geom_point() – điểm tròn đánh dấu giá trị cụ thể mỗi năm.
geom_hline() – đường đỏ đứt biểu diễn mức tài sản dở dang dài hạn trung bình toàn kỳ.
scale_x_continuous() – hiển thị rõ mốc thời gian 2015–2024.
Về ý nghĩa tài chính: 2015–2019: Cả hai chỉ tiêu tăng, song người mua trả tiền trước tăng nhanh hơn nhiều → dự án mở rộng, khách hàng đặt tiền sớm.
2020–2021: Đạt đỉnh, thể hiện giai đoạn cao điểm triển khai dự án bất động sản.
2022–2024: Giảm nhẹ rồi tăng lại mạnh năm 2024 → dòng tiền khách hàng quay trở lại, dự án tái khởi động.
Tài sản dở dang dài hạn duy trì mức ổn định thấp, cho thấy tiến độ đầu tư kiểm soát tốt.

4.18 Scatter: Hàng tồn kho vs Người mua trả tiền trước

ggplot(data_selected, aes(x = hang_ton_kho, y = nguoi_mua_tra_tien_truoc)) +
  geom_point(color="darkred", size=2) +
  geom_smooth(method="lm", se=FALSE, color="blue", linewidth=1) +
  geom_vline(xintercept = mean(data_selected$hang_ton_kho, na.rm=TRUE), linetype="dotted") +
  geom_hline(yintercept = mean(data_selected$nguoi_mua_tra_tien_truoc, na.rm=TRUE), linetype="dotted") +
  geom_rug(sides="bl", alpha=0.3) +
  labs(title="Hàng tồn kho vs Người mua trả tiền trước", x="Hàng tồn kho", y="Người mua trả tiền trước") +
  theme_finance

geom_point() – các điểm tròn đỏ sẫm biểu diễn mối quan hệ giữa hàng tồn kho và người mua trả tiền trước theo từng năm.
geom_smooth(method = “lm”) – đường hồi quy tuyến tính màu xanh, cho thấy xu hướng tổng thể giữa hai biến.
geom_vline() và geom_hline() – hai đường chấm đen biểu diễn giá trị trung bình của mỗi biến, chia đồ thị thành bốn vùng để dễ nhận biết vị trí dữ liệu.
geom_rug() – các vạch nhỏ ở cạnh dưới và trái, giúp thể hiện phân bố dữ liệu.
Về ý nghĩa tài chính: Đường hồi quy có hệ số dương rõ rệt, chứng tỏ mối quan hệ tuyến tính thuận giữa hàng tồn kho và người mua trả tiền trước.
Khi hàng tồn kho tăng, người mua trả tiền trước cũng tăng → phản ánh doanh nghiệp ghi nhận doanh thu dở dang lớn hơn, nhiều hợp đồng bán hàng chưa bàn giao tài sản.
Điều này cho thấy DIG đang mở rộng hoạt động đầu tư và kinh doanh bất động sản, với lượng hàng tồn kho cao được hỗ trợ bởi dòng tiền ứng trước của khách hàng, giảm áp lực vốn lưu động.

4.19 Scatter: Doanh số thuần vs Vốn chủ sở hữu

ggplot(data_selected, aes(x = von_chu_so_huu, y = doanh_so_thuan)) +
  geom_point(color="darkblue", size=2) +
  geom_smooth(method="lm", se=FALSE, color="red", linewidth=1) +
  geom_vline(xintercept = mean(data_selected$von_chu_so_huu, na.rm=TRUE), linetype="dotted") +
  geom_hline(yintercept = mean(data_selected$doanh_so_thuan, na.rm=TRUE), linetype="dotted") +
  geom_rug(sides="bl", alpha=0.3) +
  labs(title="Doanh số thuần vs Vốn chủ sở hữu", x="Vốn chủ sở hữu", y="Doanh số thuần") +
  theme_finance

ggplot(data_selected, aes(…))
→ Khởi tạo biểu đồ dữ liệu data_selected, trục X vốn chủ sở hữu, trục Y là doanh số thuần.
geom_point(color=“darkblue”, size=2)
→ Vẽ các điểm dữ liệu (mỗi năm là 1 điểm màu xanh đậm).
geom_smooth(method=“lm”, se=FALSE, color=“red”, linewidth=1)
→ Thêm đường hồi quy tuyến tính (linear model) màu đỏ, không hiển thị vùng sai số.
geom_vline(…) và geom_hline(…)
→ Thêm đường trung bình của X và Y (đường chấm dọc và ngang) so sánh vị trí tương đối.
geom_rug(sides=“bl”, alpha=0.3) labs(…)
Biểu đồ thể hiện mối quan hệ giữa Doanh số thuần và Vốn chủ sở hữu.
Đường hồi quy màu đỏ có độ dốc rất nhỏ, cho thấy tương quan dương yếu giữa hai biến.
Nghĩa là: khi VCSH tăng, doanh thu thuần chỉ tăng nhẹ, chưa phản ánh hiệu quả sử dụng vốn.
Các điểm dữ liệu phân tán khá rộng → có thể bị ảnh hưởng bởi yếu tố thị trường, chu kỳ dự án hoặc doanh thu ghi nhận không đều theo từng năm.
Kết luận: Doanh nghiệp chưa tối ưu hóa hiệu quả sử dụng vốn chủ sở hữu, doanh thu tăng chậm hơn so với tốc độ tăng vốn.

4.20 Tổng tài sản (TSNH + TSDH)

if(!"tong_tai_san" %in% names(data_selected)) {
  data_selected <- data_selected %>% mutate(tong_tai_san = tai_san_ngan_han + tai_san_dai_han)
}
ggplot(data_selected, aes(x = nam, y = tong_tai_san)) +
  geom_col(fill="gold", alpha=0.8) +
  geom_line(color="darkorange", linewidth=1) +
  geom_point(color="orange", size=2) +
  geom_smooth(method="lm", se=FALSE, color="red", linewidth=1) +
  geom_hline(yintercept = mean(data_selected$tong_tai_san, na.rm=TRUE), linetype="dashed", color="red") +
  labs(title="Tổng tài sản qua các năm", x="Năm", y="Tổng giá trị (VNĐ)") +
  scale_x_continuous(breaks = 2015:2024) + theme_finance

geom_col()-cột vàng thể hiện tổng tài sản từng năm, giúp quan sát quy mô theo thời gian.
geom_line()-đường cam nối các điểm, biểu diễn xu hướng biến động tài sản.
geom_point()-các điểm tròn màu cam đánh dấu giá trị cụ thể mỗi năm.
geom_smooth(method = “lm”) – đường hồi quy màu đỏ, cho thấy xu hướng tăng dài hạn.
geom_hline()-đường đỏ đứt thể hiện mức tổng tài sản trung bình giai đoạn 2015–2024.
Về ý nghĩa tài chính:
2015–2019: Tổng tài sản tăng đều, cho thấy doanh nghiệp mở rộng quy mô và đầu tư tích cực.
2020–2021: Tăng mạnh đột biến, giai đoạn mở rộng tài sản lớn (đầu tư, dự án mới).
2022–2024: Tiếp tục duy trì mức cao, năng lực tài chính và tích lũy tài sản ổn định.
Kết luận: Tổng tài sản của DIG có xu hướng tăng mạnh và ổn định, phản ánh quy mô hoạt động ngày càng mở rộng và năng lực tài chính được củng cố trong dài hạn.