1 PHẦN 1. MARKETING CAMPAIGN PERFORMANCE DATASET

1.1 CÁC THÔNG TIN CƠ BẢN BỘ DỮ LIỆU

1.1.1 Tải thư viện cho bài

library(readxl)
library(tidyverse)
library(lubridate)
library(scales)
library(ggplot2)
library(dplyr)
library(stringr)
library(skimr)
library(kableExtra)
library(patchwork)
library(reshape2)
library(knitr)
library(janitor)
library(Hmisc)
library(psych)
library(forecast)
library(tseries)
library(GGally)
library(corrplot)
library(ggpubr)
library(moments) 
options(scipen = 999)
library(showtext)
font_add_google("Roboto", "Roboto")
showtext_auto()

1.1.2 Chuyển đổi các định dạng cần thiết

# Hàm định dạng số với dấu phân cách hàng nghìn
format_number <- function(x, digits = 0) {
  if(is.numeric(x)) {
    return(format(round(x, digits), big.mark = ",", scientific = FALSE, trim = TRUE))
  }
  return(x)
}

# Hàm định dạng tiền tệ (tỷ VND)
format_currency <- function(x, suffix = " tỷ VND", digits = 1) {
  if(is.numeric(x)) {
    value <- round(x/1e9, digits)
    return(paste0(format(value, big.mark = ",", scientific = FALSE), suffix))
  }
  return(x)
}

# Hàm áp dụng định dạng cho data frame
format_dataframe <- function(df, currency_cols = NULL, digit_list = NULL) {
  result <- df
  for(col in names(df)) {
    if(is.numeric(df[[col]])) {
      if(col %in% currency_cols) {
        result[[col]] <- format_currency(df[[col]])
      } else {
        digits <- if(!is.null(digit_list) && col %in% names(digit_list)) digit_list[[col]] else 0
        result[[col]] <- format_number(df[[col]], digits)
      }
    }
  }
  return(result)
}

Sử dụng hàm foramt_number(x) để chuẩn hóa dữ liệu số nhập từ file csv.

Tiếp theo sử dụng hàm format_currency(x) để tạo chuỗi tiền tệ

Và cuối cùng là hàm formar_dataframe(x) để làm sạch bồ dữ liệu.Giảm lỗi khi tính toán (vì “$1,200” không thể dùng trong phép tính nếu chưa chuyển đổi).

1.1.3 Đọc dữ liệu

dl <- read.csv("~/NNLT/Marketing-Campaign-Performance-Dataset.csv")

1.1.4 Kích thước dataset

dim_info <- data.frame(
  Thông_tin = c("Số quan sát", "Số biến"),
  Giá_trị = c(nrow(dl), ncol(dl))
)
dim_info
##     Thông_tin Giá_trị
## 1 Số quan sát  200000
## 2     Số biến      15

Kết quả cho thấy bộ dữ liệu có 200.000 quan sát và 15 biến.

1.1.5 Kiểm tra cấu trúc

glimpse(dl)
## Rows: 200,000
## Columns: 15
## $ Company          <chr> "Innovate Industries", "NexGen Systems", "Alpha Innov…
## $ Campaign_Type    <chr> "Email", "Email", "Influencer", "Display", "Email", "…
## $ Target_Audience  <chr> "Men 18-24", "Women 35-44", "Men 25-34", "All Ages", …
## $ Duration         <chr> "30 days", "60 days", "30 days", "60 days", "15 days"…
## $ Channel_Used     <chr> "Google Ads", "Google Ads", "YouTube", "YouTube", "Yo…
## $ Conversion_Rate  <dbl> 0.04, 0.12, 0.07, 0.11, 0.05, 0.07, 0.13, 0.08, 0.09,…
## $ Acquisition_Cost <chr> "$16,174.00", "$11,566.00", "$10,200.00", "$12,724.00…
## $ ROI              <dbl> 6.29, 5.61, 7.18, 5.55, 6.50, 4.36, 2.86, 5.55, 6.73,…
## $ Location         <chr> "Chicago", "New York", "Los Angeles", "Miami", "Los A…
## $ Language         <chr> "Spanish", "German", "French", "Mandarin", "Mandarin"…
## $ Clicks           <int> 506, 116, 584, 217, 379, 100, 817, 624, 861, 642, 321…
## $ Impressions      <int> 1922, 7523, 7698, 1820, 4201, 1643, 8749, 7854, 1754,…
## $ Engagement_Score <int> 6, 7, 1, 7, 3, 1, 10, 7, 6, 3, 10, 1, 10, 4, 1, 5, 3,…
## $ Customer_Segment <chr> "Health & Wellness", "Fashionistas", "Outdoor Adventu…
## $ Date             <chr> "01/01/2021", "02/01/2021", "03/01/2021", "04/01/2021…

1.1.6 Tên các biến

names_df <- data.frame(Biến = names(dl))
names_df
##                Biến
## 1           Company
## 2     Campaign_Type
## 3   Target_Audience
## 4          Duration
## 5      Channel_Used
## 6   Conversion_Rate
## 7  Acquisition_Cost
## 8               ROI
## 9          Location
## 10         Language
## 11           Clicks
## 12      Impressions
## 13 Engagement_Score
## 14 Customer_Segment
## 15             Date

Kết quả trả ra cho thấy bộ dữ liệu có tổng 15 biến.

1.1.7 Hiển thị 5 dòng đầu

head(dl, 5)
##               Company Campaign_Type Target_Audience Duration Channel_Used
## 1 Innovate Industries         Email       Men 18-24  30 days   Google Ads
## 2      NexGen Systems         Email     Women 35-44  60 days   Google Ads
## 3   Alpha Innovations    Influencer       Men 25-34  30 days      YouTube
## 4  DataTech Solutions       Display        All Ages  60 days      YouTube
## 5      NexGen Systems         Email       Men 25-34  15 days      YouTube
##   Conversion_Rate Acquisition_Cost  ROI    Location Language Clicks Impressions
## 1            0.04       $16,174.00 6.29     Chicago  Spanish    506        1922
## 2            0.12       $11,566.00 5.61    New York   German    116        7523
## 3            0.07       $10,200.00 7.18 Los Angeles   French    584        7698
## 4            0.11       $12,724.00 5.55       Miami Mandarin    217        1820
## 5            0.05       $16,452.00 6.50 Los Angeles Mandarin    379        4201
##   Engagement_Score    Customer_Segment       Date
## 1                6   Health & Wellness 01/01/2021
## 2                7        Fashionistas 02/01/2021
## 3                1 Outdoor Adventurers 03/01/2021
## 4                7   Health & Wellness 04/01/2021
## 5                3   Health & Wellness 05/01/2021

Đây là 5 dòng đầu tiên của bộ dữ liệu.

1.1.8 Phân loại biến

danh_sach_bien_so <- c("Duration", "Conversion_Rate", "Acquisition_Cost", 
                      "ROI", "Clicks", "Impressions", "Engagement_Score")

danh_sach_bien_chu <- c("Company", "Campaign_Type", "Channel_Used", 
                           "Location", "Customer_Segment")

biến_phân_loại <- data.frame(
  Loại = c("Biến số", "Biến phân loại"),
  Số_lượng = c(7, 5)
)

biến_phân_loại$Danh_sách <- list(
  danh_sach_bien_so,
  danh_sach_bien_chu)
print(biến_phân_loại$Danh_sách)
## [[1]]
## [1] "Duration"         "Conversion_Rate"  "Acquisition_Cost" "ROI"             
## [5] "Clicks"           "Impressions"      "Engagement_Score"
## 
## [[2]]
## [1] "Company"          "Campaign_Type"    "Channel_Used"     "Location"        
## [5] "Customer_Segment"
  • Dùng hàm data.frame() để tạo một bảng tên là biến_phân_loại. Tiếp theo sử dụng dàm c() để tạo 2 vector cho mỗi cột là danh_sach_bien_so và danh_sach_bien_chu. Kết quả trả ra ta được 1 bảng và trên đó thể hiện:

– 7 biến số: Duration, Conversion_Rate, Acquisition_Cost, ROI, Clicks, Impressions, Engagement_score.

– 5 biến phân loại: Company, Campaign_Type, Channel_Used, Location, Customer_Segment.

1.1.9 Thống kê mô tả

summary_stats <- summary(dl[c("Duration", "Conversion_Rate", "Acquisition_Cost", "ROI")])
summary_stats
##    Duration         Conversion_Rate   Acquisition_Cost        ROI       
##  Length:200000      Min.   :0.01000   Length:200000      Min.   :2.000  
##  Class :character   1st Qu.:0.05000   Class :character   1st Qu.:3.500  
##  Mode  :character   Median :0.08000   Mode  :character   Median :5.010  
##                     Mean   :0.08007                      Mean   :5.002  
##                     3rd Qu.:0.12000                      3rd Qu.:6.510  
##                     Max.   :0.15000                      Max.   :8.000

Đầu tiên, dùng hàm c()tạo 4 vector ký tự chứa 4 tên cột để phân tích (“Duration”, “Conversion_Rate”, “Acquisition_Cost”, “ROI”). Sau đó dùng hàm summary() là hàm kĩ thuật thống kê. Ta sẽ thống kê các chỉ số sau:

  • Min: Giá trị nhỏ nhất

  • 1st Qu.(Phân vị 25%): 25% dữ liệu nhỏ hơn giá trị này

  • Median(Trung vị): Giá trị ở giữa (50%)

  • Mean(Trung bình): Giá trị trung bình cộng

  • 3rd Qu.(Phân vị 75%): 75% dữ liệu nhỏ hơn giá trị này

  • Max: Giá trị lớn nhất

Ta được kết quả trả về như sau:

  • Conversion_Rate(Tỷ lệ chuyển đổi):

– Min.(Tối thiểu): 0.01000(1%)

– 1st Qu.(Phân vị 25%): 0.05000 (5%)

– Median(Trung vị): 0.08000 (8%)

– Mean(Trung bình): độ 0.08007

– 3rd Qu.(Phân vị 75%): 0.12000(12%)

– Max.(Tối đa): 0.15000 (15%)

Nhận xét: Dữ liệu khá tập trung, với 50% giá trị nằm trong khoảng từ 5% đến 12%.

  • ROI(Return on Investment - Tỷ suất hoàn vốn)

– Min.(Tối thiểu): 2.000

– 1st Qu.(Phân vị 25%): 3.500

– Median(Trung vị): 5.010

– Mean(Trung bình): 5.002

– 3rd Qu.(Phân vị 75%): 6.510

– Max.(Tối đa): 8.000

Nhận xét: Giá trị Trung vị (5.010) và Trung bình (5.002) rất gần nhau, cho thấy phân phối của ROI là khá đối xứng (symmetric).

1.1.10 Kiểm tra dữ liệu thiếu

missing_data <- data.frame(
  Tổng_giá_trị_thiếu = sum(is.na(dl)),
  Tỷ_lệ_thiếu = round(mean(is.na(dl)) * 100, 2)
)
missing_data
##   Tổng_giá_trị_thiếu Tỷ_lệ_thiếu
## 1                  0           0

Sử dụng tính năng Vector Hóa và quy tắc TRUE=1, FALSE=0 của R.

is.na(dl): Xác định tất cả các ô có giá trị thiếu (NA).

sum(…): Tính tổng số lượng ô bị thiếu (NA) trong toàn bộ data frame.

mean(…): Tính tỷ lệ phần trăm ô bị thiếu so với tổng số ô.

Và kết quả trả ra ta thấy được là bộ dữ liệu không có giá trị bị thiếu.

1.1.11 Kiểm tra trùng lặp

duplicate_info <- data.frame(
  Số_dòng_trùng_lặp = sum(duplicated(dl)),
  Tỷ_lệ_trùng_lặp = round(mean(duplicated(dl)) * 100, 2)
)
duplicate_info
##   Số_dòng_trùng_lặp Tỷ_lệ_trùng_lặp
## 1                 0               0

Dùng hàm duplicated() để tìm các dòng bị lặp lại.

duplicated(dl): Trả về TRUE cho mọi dòng mà nội dung toàn bộ dòng đó đã xuất hiện ở các dòng trước.

sum(…): Tính tổng số lượng dòng bị trùng lặp.

mean(…): Tính tỷ lệ phần trăm dòng bị trùng lặp so với tổng số dòng.

Kết quả là bộ dữ liệu không có giá trị trùng lặp.

1.1.12 Phạm vi thời gian

dl$Date <- as.Date(dl$Date, format = "%d/%m/%Y")
date_range <- data.frame(
  Ngày_bắt_đầu = min(dl$Date),
  Ngày_kết_thúc = max(dl$Date),
  Số_ngày = as.numeric(difftime(max(dl$Date), min(dl$Date), units = "days"))
)
date_range
##   Ngày_bắt_đầu Ngày_kết_thúc Số_ngày
## 1   2021-01-01    2021-12-31     364

Chuyển đổi cột Date từ dạng ký tự Character sang Ngày (Date) mà R có thể tính toán được.

Dùng as.Date() và chỉ định rõ định dạng gốc (%d/%m/%Y) để R không bị nhầm lẫn.

Tính toán phạm vi (Range Calculation): - Code: min(…), max(…), difftime(…)

  • min() & max(): Tìm ra ngày bắt đầu và ngày kết thúc của bộ dữ liệu.

  • difftime(…, units = “days”): Tính toán số ngày chính xác giữa hai mốc thời gian.

Kết quả bộ dữ liệu bắt đầu từ ngày 1-1-2021 đến 31-12-2021 đúng với bộ dữ liệu CSV.

1.2 XỬ LÍ DỮ LIỆU

1.2.1 Chuẩn hóa Acquisition_Cost

dl$Acquisition_Cost <- as.numeric(gsub("[\\$,]", "", dl$Acquisition_Cost))

gsub(“[\[\\(]", "", dl\)Acquisition_Cost): Đây là kỹ thuật xử lý chuỗi (string manipulation) sử dụng Biểu thức chính quy(Regex).

“[\[\$]”: Đây là mẫu Regex tìm kiếm ký tự [ và $ (cần phải escape bằng \ vì chúng là các ký tự đặc biệt trong Regex).

““: Thay thế các ký tự tìm thấy bằng chuỗi rỗng.

Kết quả là loại bỏ các ký tự không phải số khỏi cột.

as.numeric(…): Cuối cùng, chuyển đổi chuỗi đã được làm sạch thành kiểu số (numeric).

Ví dụ: Chuyển đổi từ định dạng tiền tệ $1,000 sang số 1000.

1.2.2 Chuẩn hóa Duration

dl$Duration <- as.numeric(gsub("days", "", dl$Duration))

gsub(“days”, ““, dl$Duration): Tương tự như trên, dùng gsub() để tìm và thay thế chuỗi ký tự”days” bằng chuỗi rỗng.

as.numeric(…): Chuyển đổi chuỗi kết quả thành kiểu số (numeric).

Ví dụ: Chuyển “30 days” thành số 30.

1.2.3 Tạo biến Revenue

dl$Revenue <- dl$ROI * dl$Acquisition_Cost

Tạo ra một biến mới (Revenue) dựa trên công thức kinh doanh: Doanh thu = ROI x Chi phí thu hút.

1.2.4 Tạo biến CTR

dl$CTR <- dl$Clicks / dl$Impressions

Tạo ra biến Tỷ lệ nhấp (Click-Through Rate - CTR), là một chỉ số quan trọng trong quảng cáo số.

Tính toán trên Vector. R thực hiện phép chia từng cặp phần tử tương ứng của hai cột.

1.2.5 Tạo biến thời gian

dl$Date <- as.Date(dl$Date, format = "%Y-%m-%d")  
dl$Month <- months(dl$Date)
dl$Quarter <- quarters(dl$Date)

as.Date(…, format = “%Y-%m-%d”): Bước này chuẩn hóa lại cột Date sau khi đã làm sạch. Việc sử dụng format %Y-%m-%d giả định rằng sau khi làm sạch các ký tự không phải số ở bước trước, định dạng ngày tháng là chuẩn ISO (Năm-Tháng-Ngày).

months(dl$Date): Hàm này trích xuất tên tháng (ví dụ: “Tháng Ba”, “March”) từ đối tượng ngày tháng.

quarters(dl$Date): Hàm này trích xuất quý (ví dụ: “Q1”, “Q2”) từ đối tượng ngày tháng.

Tạo biến tháng và quý cho phân tích theo thời gian

1.2.6 Mã hóa Gender

dl$Gender <- ifelse(grepl("Men", dl$Target_Audience), "Male",
                   ifelse(grepl("Women", dl$Target_Audience), "Female", "All"))

grepl(“Men”, dl$Target_Audience): Hàm này sử dụng Regex để kiểm tra xem chuỗi “Men” có xuất hiện ở bất cứ đâu trong cột Target_Audience. Nó trả về một vector TRUE/FALSE.

ifelse(Điều kiện, Giá trị nếu TRUE, Giá trị nếu FALSE): Điều kiện chéo.

Nếu tìm thấy “Men”, gán là “Male”.

Nếu không (FALSE ở điều kiện 1), nó tiếp tục kiểm tra điều kiện thứ hai: grepl(“Women”, dl$Target_Audience).

Nếu tìm thấy “Women”, gán là “Female”.

Nếu không tìm thấy cả “Men” lẫn “Women”, gán là “All”.

1.2.7 Mã hóa ROI Tier

dl$ROI_Tier <- cut(dl$ROI, breaks = c(0, 4, 6, 10), labels = c("Low", "Medium", "High"))
table(dl$ROI_Tier)
## 
##    Low Medium   High 
##  66822  66438  66740

breaks = c(0, 4, 6, 10): Tự định nghĩa các khoảng : (0-4], (4-6], (6-10].

labels = c(“Low”, “Medium”, “High”): Gán nhãn cho các khoảng này.

Từ kết quả trả về ta thấy: Có 66822 giá trị ở mức Low,66438 ở mức Medium và 66740 ở mức High.

1.2.8 Mã hóa Cost Tier

dl$Cost_Tier <- cut(dl$Acquisition_Cost, breaks = 3, labels = c("Low", "Medium", "High"))
table(dl$Cost_Tier)
## 
##    Low Medium   High 
##  66704  66495  66801

breaks = 3: Yêu cầu R tự động chia cột Acquisition_Cost thành 3 khoảng có kích thước bằng nhau.

labels = c(“Low”, “Medium”, “High”): Gán nhãn cho 3 khoảng đó.

Từ kết quả trả về ta thấy: Có 66704 giá trị ở mức Low,66495 ở mức Medium và 66801 ở mức High.

1.2.9 Chuẩn hóa kênh

dl$Channel_Used <- trimws(dl$Channel_Used)

Hàm trimws() loại bỏ khoảng trắng thừa ở đầu/cuối chuỗi.

Đảm bảo các tên kênh (Channel) giống nhau được nhận diện là một.

Ví dụ: ” Facebook ” → “Facebook”.

1.2.10 Mã hóa Performance

dl$Performance_Score <- scale(dl$ROI) + scale(dl$Conversion_Rate)

Sử dụng hàm scale() để chuẩn hóa hai biến (ROI và Conversion_Rate) về trung bình 0, độ lệch chuẩn 1 trước khi cộng lại.

Tạo điểm số tổng hợp để đánh giá hiệu suất.

1.2.11 Factor hóa biến phân loại

categorical_vars <- c("Company", "Campaign_Type", "Channel_Used", "Location",
                      "Customer_Segment", "Gender")
dl[categorical_vars] <- lapply(dl[categorical_vars], as.factor)

Dùng hàm lapply() để sử dụng hàm as.factor() lên tất cả các cột phân loại cùng một lúc.

Chuyển đổi các biến từ character sang kiểu Factor, bắt buộc cho mô hình thống kê.

Chuyển biến phân loại thành factor để phân tích thống kê.Tiết kiệm bộ nhớ, dễ dàng cho modeling.

1.2.12 Kiểm tra kết quả xử lý

processing_summary <- data.frame(
  Biến_đã_xử_lý = length(categorical_vars) + 7,
  Biến_mới_tạo = 6,
  Tổng_biến_hiện_có = ncol(dl)
)
processing_summary
##   Biến_đã_xử_lý Biến_mới_tạo Tổng_biến_hiện_có
## 1            13            6                23

Dùng hàm processing_summary() để tổng hợp các biến đã xử lí và các biến tạo mới.

Kết quả từ bảng ta thấy có 13 biến và tọa thêm 6 biến mới.

Tổng là 23 biến.

1.3 THỐNG KÊ CƠ BẢN

1.3.1 Thống kê tổng quan

stats_summary <- dl %>% 
  summarise(
    ROI_trung_bình = mean(ROI),
    Conversion_Rate_trung_bình = mean(Conversion_Rate),
    Chi_phí_trung_bình = mean(Acquisition_Cost),
    Tổng_doanh_thu = sum(Revenue),
    Tổng_lượt_nhấp = sum(Clicks)
  )
stats_summary
##   ROI_trung_bình Conversion_Rate_trung_bình Chi_phí_trung_bình Tổng_doanh_thu
## 1       5.002438                 0.08006965           12504.39    12517388674
##   Tổng_lượt_nhấp
## 1      109954406

Sử dụng cú pháp pipeline %>% để truyền data frame dl trực tiếp vào hàm summarise() để đi tính các chỉ số ta được kết quả:

  • ROI trung bình: 5.00 - Hiệu suất ở mức trung bình.

  • Tỷ lệ chuyển đổi: 8.01% - Khá tốt.

  • Tổng doanh thu: 12.52 tỷ - Quy mô lớn.

  • Tỷ lệ thành công: 50.03%(ROI > 5).

1.3.2 ROI theo Company

roi_company <- dl %>% 
  group_by(Company) %>% 
  summarise(ROI_trung_bình = mean(ROI)) %>%
  arrange(desc(ROI_trung_bình))
roi_company
## # A tibble: 5 × 2
##   Company             ROI_trung_bình
##   <fct>                        <dbl>
## 1 TechCorp                      5.01
## 2 Alpha Innovations             5.01
## 3 DataTech Solutions            5.01
## 4 Innovate Industries           5.00
## 5 NexGen Systems                4.99

group_by(Company): Phân chia bộ dữ liệu dl thành các nhóm riêng biệt dựa trên giá trị của cột Company.

summarise(ROI_trung_bình = mean(ROI)): Tính toán ROI trung bình cho từng nhóm Công ty đã được tạo.

arrange(desc(ROI_trung_bình)): Sắp xếp kết quả theo thứ tự giảm dần (desc) của ROI trung bình.

Ta được kết quả như sau:

  • TechCorp 5.007

  • Alpha Innovations 5.006

  • DataTech Solutions 5.006

  • Innovate Industries 5.002

  • NexGen Systems 4.99139913

Các công ty khác nên học hỏi chiến lược của TechCorp

1.3.3 ROI theo Campaign Type

roi_campaign <- dl %>% 
  group_by(Campaign_Type) %>% 
  summarise(ROI_trung_bình = mean(ROI))
roi_campaign
## # A tibble: 5 × 2
##   Campaign_Type ROI_trung_bình
##   <fct>                  <dbl>
## 1 Display                 5.01
## 2 Email                   4.99
## 3 Influencer              5.01
## 4 Search                  5.01
## 5 Social Media            4.99

Sử dụng pipeline (%>%) kết hợp với group_by() và summarise().

group_by(Campaign_Type): Chia data frame dl thành các nhóm nhỏ (ví dụ: nhóm “Influencer”, nhóm “Search”, v.v.).

summarise(ROI_trung_bình = mean(ROI)): Tính toán giá trị trung bình (mean) của cột ROI riêng biệt cho mỗi nhóm.

Xác định loại chiến dịch nào mang lại hiệu suất hoàn vốn cao nhất. Kết quả là:

Influencer & Search cho ROI cao nhất → mở rộng

Social Media & Email thấp hơn → tối ưu lại

1.3.4 ROI theo Channel

roi_channel <- dl %>% 
  group_by(Channel_Used) %>% 
  summarise(ROI_trung_bình = mean(ROI))
roi_channel
## # A tibble: 6 × 2
##   Channel_Used ROI_trung_bình
##   <fct>                 <dbl>
## 1 Email                  5.00
## 2 Facebook               5.02
## 3 Google Ads             5.00
## 4 Instagram              4.99
## 5 Website                5.01
## 6 YouTube                4.99

Tương tự như trên ta thu được kết quả như sau:

Facebook & Website hiệu quả nhất → tăng ngân sách

YouTube & Email kém hiệu quả → xem xét giảm đầu tư

1.3.5 Conversion Rate theo Gender

cr_gender <- dl %>% 
  group_by(Gender) %>% 
  summarise(Conversion_Rate_trung_bình = mean(Conversion_Rate))
cr_gender
## # A tibble: 3 × 2
##   Gender Conversion_Rate_trung_bình
##   <fct>                       <dbl>
## 1 All                        0.0800
## 2 Female                     0.0800
## 3 Male                       0.0802

Vẫn như trên để ta có được kết quả sau:

Tỷ lệ chuyển đổi gần như bằng nhau → chiến dịch không cần phân biệt giới tính.

1.3.6 Revenue theo Customer Segment

rev_segment <- dl %>% 
  group_by(Customer_Segment) %>% 
  summarise(Tổng_doanh_thu = sum(Revenue)) %>%
  arrange(desc(Tổng_doanh_thu))
rev_segment
## # A tibble: 5 × 2
##   Customer_Segment    Tổng_doanh_thu
##   <fct>                        <dbl>
## 1 Foodies                2523856973.
## 2 Tech Enthusiasts       2509875192.
## 3 Outdoor Adventurers    2501349290.
## 4 Health & Wellness      2497220342.
## 5 Fashionistas           2485086878.

Sử dụng cấu trúc group_by() và summarise() của dplyr để tính toán tổng hợp trên từng nhóm.

group_by(Customer_Segment): Chia dữ liệu thành các nhóm dựa trên từng Phân khúc Khách hàng (ví dụ: “Foodies”, “Tech Enthusiasts”).

summarise(Tổng_doanh_thu = sum(Revenue)): Tính Tổng cột Revenue cho từng Phân khúc.

arrange(desc(Tổng_doanh_thu)): Sắp xếp kết quả giảm dần để tìm ra Phân khúc mang lại doanh thu cao nhất.

Từ những phân tích trên ta được kết quả:

Tập trung vào Foodies - đang mang về doanh thu cao nhất

Tech Enthusiasts - vị trí thứ 2 rất ổn định

5 segment có doanh thu rất cân bằng (chênh lêch chỉ ~1.5%)

→ Chiến lược đa dạng hóa đang hiệu quả

→ Không nên bỏ segment nào

1.3.7 Phân tích theo tháng

monthly_stats <- dl %>% 
  group_by(Month) %>% 
  summarise(ROI_trung_bình = mean(ROI))
monthly_stats
## # A tibble: 12 × 2
##    Month     ROI_trung_bình
##    <chr>              <dbl>
##  1 April               4.99
##  2 August              5.00
##  3 December            5.00
##  4 February            5.01
##  5 January             5.01
##  6 July                4.98
##  7 June                4.99
##  8 March               4.98
##  9 May                 5.02
## 10 November            5.00
## 11 October             5.02
## 12 September           5.03

Vẫn sử dụng group_by() và summarise().

group_by(Month): Nhóm các quan sát dựa trên biến Month (biến đã được tạo ra từ trước).

summarise(ROI_trung_bình = mean(ROI)): Tính ROI trung bình cho từng tháng trong bộ dữ liệu.

1.3.8 Tương quan các biến

cor_matrix <- cor(dl[c("ROI", "Conversion_Rate", "Acquisition_Cost", "Clicks", "Impressions")])
round(cor_matrix, 3)
##                     ROI Conversion_Rate Acquisition_Cost Clicks Impressions
## ROI               1.000          -0.001            0.005 -0.002       0.002
## Conversion_Rate  -0.001           1.000            0.001  0.000      -0.003
## Acquisition_Cost  0.005           0.001            1.000  0.000       0.000
## Clicks           -0.002           0.000            0.000  1.000       0.000
## Impressions       0.002          -0.003            0.000  0.000       1.000

dl[c(…)]: Trích xuất một data frame con chỉ chứa 5 biến số (vì hàm cor() chỉ hoạt động trên dữ liệu số).

cor(…): Tính toán hệ số tương quan tuyến tính (thường là Pearson) giữa mọi cặp biến số trong data frame con đó, tạo ra một ma trận tương quan (Correlation Matrix).

round(…, 3): Làm tròn kết quả ma trận tương quan đến 3 chữ số thập phân để dễ đọc.

Ta đọc được kết quả: Các biến không tương quan mạnh → không có yếu tố nào quyết định duy nhất đến ROI.

1.3.9 Phân tích Duration

duration_stats <- dl %>% 
  group_by(Duration) %>% 
  summarise(ROI_trung_bình = mean(ROI))
duration_stats
## # A tibble: 4 × 2
##   Duration ROI_trung_bình
##      <dbl>          <dbl>
## 1       15           5.00
## 2       30           5.01
## 3       45           5.00
## 4       60           5.01

Sử dụng hàm list() để gán các vector (danh_sach_bien_so, danh_sach_bien_chu) vào một cột (Danh_sách) của data frame.

Kết quả: Cột Danh_sách trở thành một List-Column (cột danh sách). Thời gian giữa các chiến dịch không chênh lệch quá nhiều tuy nhiên vẫn nên ưu tiên các chiến dịch 30 ngày.

1.3.10 Phân tích Location

location_stats <- dl %>% 
  group_by(Location) %>% 
  summarise(ROI_trung_bình = mean(ROI))
location_stats
## # A tibble: 5 × 2
##   Location    ROI_trung_bình
##   <fct>                <dbl>
## 1 Chicago               5.00
## 2 Houston               5.01
## 3 Los Angeles           5.01
## 4 Miami                 5.01
## 5 New York              4.98

Sử dụng cấu trúc group_by() và summarise() của dplyr.

Mục đích: Tính ROI trung bình cho từng vị trí địa lý để chọn ra nơi tốt nhất.

Nên ưu tiên Miami, Los Angeles đây là 2 địa điểm trọng yếu.

1.3.11 Top 5 chiến dịch ROI cao nhất

top_roi <- dl %>% 
  arrange(desc(ROI)) %>% 
  head(5) %>% 
  select(Company, Campaign_Type, Channel_Used, ROI)
top_roi
##               Company Campaign_Type Channel_Used ROI
## 1      NexGen Systems       Display      Website   8
## 2 Innovate Industries    Influencer        Email   8
## 3      NexGen Systems        Search        Email   8
## 4   Alpha Innovations       Display    Instagram   8
## 5            TechCorp  Social Media        Email   8

Chuỗi ba hàm dplyr để trích xuất dữ liệu:

arrange(desc(ROI)): Sắp xếp toàn bộ data frame dl theo cột ROI theo thứ tự giảm dần (desc).

head(5): Lấy 5 dòng đầu tiên (tương đương 5 chiến dịch có ROI cao nhất).

select(…): Chỉ giữ lại các cột cần thiết (Company, Campaign_Type, v.v.) cho báo cáo.

Kết quả trả về cho thấy % chiến dịch có ROI cao nhất đếu bằng 8.

1.3.12 Phân tích Cost Tier

cost_tier_stats <- dl %>% 
  group_by(Cost_Tier) %>% 
  summarise(ROI_trung_bình = mean(ROI))
cost_tier_stats
## # A tibble: 3 × 2
##   Cost_Tier ROI_trung_bình
##   <fct>              <dbl>
## 1 Low                 4.99
## 2 Medium              5.00
## 3 High                5.01

Sử dụng group_by() và summarise() để đánh giá mối quan hệ giữa mức chi phí và ROI trung bình tương ứng.

Từ kết quả trả về ta thấy được sự chênh lệch giữa các loại là rất thấp.

1.3.13 Phân tích ROI Tier

roi_tier_stats <- dl %>% 
  group_by(ROI_Tier) %>% 
  summarise(Số_lượng = n(), Tỷ_lệ = n()/nrow(dl)*100)
roi_tier_stats
## # A tibble: 3 × 3
##   ROI_Tier Số_lượng Tỷ_lệ
##   <fct>       <int> <dbl>
## 1 Low         66822  33.4
## 2 Medium      66438  33.2
## 3 High        66740  33.4

n(): Đếm số lượng dòng trong mỗi nhóm (Số_lượng).

n()/nrow(dl)*100: Tính toán tỷ lệ phần trăm của mỗi nhóm so với tổng số dòng.

Phân phối ROI đồng đều: 33% mỗi mức (Low/Medium/High)

1.3.14 Engagement Score trung bình

engagement_stats <- dl %>% 
  group_by(Channel_Used) %>% 
  summarise(Engagement_trung_bình = mean(Engagement_Score))
engagement_stats
## # A tibble: 6 × 2
##   Channel_Used Engagement_trung_bình
##   <fct>                        <dbl>
## 1 Email                         5.49
## 2 Facebook                      5.50
## 3 Google Ads                    5.49
## 4 Instagram                     5.49
## 5 Website                       5.51
## 6 YouTube                       5.48

Đoạn code là phân tích hiệu suất theo kênh. Chia dữ liệu thành các nhóm dựa trên kênh (Channel_Used), sau đó tính giá trị trung bình (mean) của chỉ số hiệu suất (Engagement_Score hoặc CTR) cho từng kênh.

mean(Engagement_Score) / mean(CTR). Tính chỉ số hiệu suất Chính. Tính trung bình của điểm tương tác và tỷ lệ nhấp, cho phép bạn so sánh hiệu quả tương tác và thu hút click của các kênh.

Từ kết quả, ta thấy website là channel được khách yêu thích nhất.

1.3.15 CTR trung bình

ctr_stats <- dl %>% 
  group_by(Channel_Used) %>% 
  summarise(CTR_trung_bình = mean(CTR))
ctr_stats
## # A tibble: 6 × 2
##   Channel_Used CTR_trung_bình
##   <fct>                 <dbl>
## 1 Email                 0.141
## 2 Facebook              0.140
## 3 Google Ads            0.139
## 4 Instagram             0.140
## 5 Website               0.141
## 6 YouTube               0.141

Cũng như code ở trên thống kê từ các kênh như sau:

YouTube cao nhất (14.12%)

Website (14.10%)

Google Ads thấp nhất (13.92%)

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

variance_stats <- dl %>% 
  summarise(
    Phương_sai_ROI = var(ROI),
    Độ_lệch_chuẩn_ROI = sd(ROI)
  )
variance_stats
##   Phương_sai_ROI Độ_lệch_chuẩn_ROI
## 1        3.00845          1.734488

mean(Engagement_Score) / mean(CTR) Tính Chỉ số Hiệu suất Chính. Tính trung bình của Điểm tương tác và Tỷ lệ nhấp, cho phép bạn so sánh hiệu quả tương tác và thu hút click của các kênh.

1.3.17 Phân vị ROI

roi_quantiles <- data.frame(
  Phân_vị = c("Q1", "Q2 (Trung vị)", "Q3"),
  Giá_trị = quantile(dl$ROI, c(0.25, 0.5, 0.75))
)
roi_quantiles
##           Phân_vị Giá_trị
## 25%            Q1    3.50
## 50% Q2 (Trung vị)    5.01
## 75%            Q3    6.51

dl %>% summarise(…),Tính toán thống kê toàn bộ. Áp dụng trực tiếp lên cột ROI của toàn bộ data frame.

var(ROI),Tính Phương sai (Variance). Đo lường mức độ phân tán của các giá trị ROI so với giá trị trung bình của chúng.

sd(ROI),“Tính Độ lệch chuẩn (Standard Deviation). Đây là căn bậc hai của phương sai; nó cho biết trung bình một giá trị ROI lệch khỏi giá trị trung bình bao nhiêu, sử dụng cùng đơn vị với ROI.”

Độ lệch chuẩn thấp cho thấy ROI ổn định và dự đoán được, trong khi độ lệch chuẩn cao cho thấy rủi ro và sự biến động lớn.”

1.3.18 Tỷ lệ chiến dịch thành công

success_stats <- data.frame(
  Ngưỡng_ROI = "> 5",
  Số_chiến_dịch = sum(dl$ROI > 5),
  Tỷ_lệ = mean(dl$ROI > 5) * 100
)
success_stats
##   Ngưỡng_ROI Số_chiến_dịch  Tỷ_lệ
## 1        > 5        100056 50.028

dl$ROI > 5: Tạo ra một vector logic (TRUE/FALSE) cho toàn bộ cột ROI.sum(…): Đếm số lần TRUE (tổng số chiến dịch có ROI \(> 5\)).mean(…): Tính tỷ lệ số lần TRUE so với tổng số quan sát.Mục đích là định lượng tỷ lệ thành công dựa trên một tiêu chí kinh doanh cụ thể (ngưỡng ROI = 5).

Tỉ lệ thành công chỉ là trên 50% cho thấy các chiến dịch vẫn chưa hiệu quả

1.3.19 Phân tích Performance Score

performance_stats <- dl %>% 
  summarise(
    Điểm_trung_bình = mean(Performance_Score),
    Điểm_trung_vị = median(Performance_Score)
  )
performance_stats
##           Điểm_trung_bình Điểm_trung_vị
## 1 0.000000000000001052607    0.00286103

Performance_Score: Đây là biến tổng hợp (Feature Engineered) tạo ra bằng cách cộng các điểm Z-Score (scale(ROI) + scale(Conversion_Rate)).

mean(…) và median(…): Tính giá trị trung bình và trung vị của điểm tổng hợp này.

1.3.20 Tổng hợp insights

final_insights <- data.frame(
  Chỉ_số = c("ROI Trung bình", "Conversion Rate TB", "Tổng Doanh thu", "Tỷ lệ thành công"),
  Giá_trị = c(
    round(mean(dl$ROI), 2),
    round(mean(dl$Conversion_Rate), 4),
    paste0(round(sum(dl$Revenue)/1e6, 1), "M"),
    paste0(round(mean(dl$ROI > 5) * 100, 1), "%")
  )
)
final_insights
##               Chỉ_số  Giá_trị
## 1     ROI Trung bình        5
## 2 Conversion Rate TB   0.0801
## 3     Tổng Doanh thu 12517.4M
## 4   Tỷ lệ thành công      50%

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

1.4.1 Nhóm đồ thị theo hiệu suất tài chính

# 1. Phân phối ROI
p1 <- ggplot(dl, aes(x = ROI)) +
  geom_histogram(aes(y = after_stat(density)), fill = "lightblue", bins = 30, alpha = 0.7) +
  geom_density(color = "darkblue", linewidth = 1) +
  geom_vline(aes(xintercept = mean(ROI)), color = "red", linetype = "dashed", linewidth = 1) +
  labs(title = "PHÂN PHỐI ROI", x = "ROI", y = "Mật độ") +
  theme_minimal()

# 2. Phân phối Revenue
p2 <- ggplot(dl, aes(x = Revenue)) +
  geom_histogram(aes(y = after_stat(density)), fill = "lightgreen", bins = 30, alpha = 0.7) +
  geom_density(color = "darkgreen", linewidth = 1) +
  geom_vline(aes(xintercept = mean(Revenue)), color = "red", linetype = "dashed", linewidth = 1) +
  labs(title = "PHÂN PHỐI DOANH THU", x = "Revenue", y = "Mật độ") +
  theme_minimal()

# 3. Xu hướng ROI theo tháng
p3 <- dl %>%
  mutate(Month = paste0("T", month(Date))) %>%   # Tháng 1 → T1, Tháng 2 → T2, ...
  group_by(Month) %>%
  summarise(ROI_trung_bình = mean(ROI)) %>%
  ggplot(aes(x = factor(Month, levels = paste0("T", 1:12)), y = ROI_trung_bình, group = 1)) +
  geom_line(color = "darkgreen", linewidth = 1) +
  geom_point(color = "red", size = 2) +
  geom_hline(yintercept = mean(dl$ROI), linetype = "dashed", color = "blue") +
  labs(title = "XU HƯỚNG ROI THEO THÁNG", x = "Tháng", y = "ROI trung bình") +
  theme_minimal()


# 4. ROI theo Cost Tier
p4 <- ggplot(dl, aes(x = Cost_Tier, y = ROI, fill = Cost_Tier)) +
  geom_boxplot(alpha = 0.7) +
  stat_summary(fun = mean, geom = "point", shape = 18, size = 3, color = "black") +
  labs(title = "ROI THEO MỨC CHI PHÍ", x = "Mức chi phí", y = "ROI") +
  theme_minimal() +
  theme(legend.position = "none")

# Kết hợp 4 đồ thị
(p1 + p2) / (p3 + p4) +
  plot_annotation(title = "NHÓM ĐỒ THỊ HIỆU SUẤT TÀI CHÍNH",
                  theme = theme(plot.title = element_text(face = "bold", size = 16, hjust = 0.5)))

- Xử lí lại các vấn đề:

Bắt đầu bằng việc làm sạch dữ liệu bằng các kỹ thuật cần thiết như: loại bỏ ký tự không phải số ($, days) bằng gsub() và chuyển đổi sang kiểu numeric; chuẩn hóa ngày tháng bằng as.Date().

Tạo ra các biến mới quan trọng cho phân tích kinh doanh: Revenue và CTR (tỷ lệ nhấp).

Thực hiện Chuẩn hóa Z-Score (scale()) và cộng hai chỉ số hiệu suất để tạo ra Performance_Score; Phân loại biến số liên tục (ROI, Acquisition_Cost) thành các bậc rời rạc (Low, Medium, High) bằng hàm cut() (Binning).

Cuối cùng, sử dụng lapply() và as.factor() để chuyển đổi các biến phân loại sang kiểu Factor, tối ưu hóa cho mô hình hóa.

  • Phân Tích Thống Kê và Báo cáo (Statistical Analysis & Reporting):

Tận dụng tối đa cấu trúc pipeline (%>%), group_by() và summarise() của dplyr để thực hiện các phân tích phân khúc và tổng hợp:

Xác định Top Performers (Công ty, Kênh, Loại Chiến dịch) bằng cách tính ROI trung bình theo từng nhóm.

Sử dụng arrange(desc(…)) %>% head(5) để trích xuất các chiến dịch hoặc phân khúc có hiệu suất cao nhất.

Sử dụng các hàm thống kê cơ bản như cor() (tương quan), var() (phương sai), sd() (độ lệch chuẩn), và quantile() (phân vị) để hiểu rõ hơn về mối quan hệ và sự biến động của ROI.

Sử dụng logic sum(dl\(ROI > 5) và mean(dl\)ROI > 5) để định lượng tỷ lệ thành công dựa trên ngưỡng kinh doanh.

  • Trực Quan Hóa (Visualization):

Sử dụng thư viện ggplot2 để tạo ra các biểu đồ chuyên nghiệp, bao gồm:

Histogram và Density Plot (geom_histogram, geom_density) để phân tích hình dạng phân phối của ROI và Doanh thu.

Biểu đồ đường (geom_line) kết hợp với group_by() và mutate() để trực quan hóa Xu hướng ROI theo thời gian (tháng).

Box Plot (geom_boxplot) kết hợp với stat_summary() để so sánh phân phối ROI giữa các nhóm (ví dụ: Cost_Tier), làm nổi bật cả Trung vị và Trung bình của từng nhóm.

Sử dụng thư viện patchwork (/ và +) để sắp xếp và kết hợp các biểu đồ một cách khoa học.

  • Dựa trên biểu đồ phân tích hiệu suất tài chính, có thể rút ra những nhận định kinh tế quan trọng sau:

Phân phối ROI cho thấy một đặc điểm đáng chú ý của danh mục đầu tư marketing. ROI tập trung chủ yếu quanh mức trung bình 5.0 với phân phối gần như chuẩn, phản ánh tính ổn định và khả năng dự báo cao trong hiệu suất các chiến dịch. Sự phân bố này chỉ ra rằng doanh nghiệp đã xây dựng được một mô hình đầu tư marketing khá đồng đều và kiểm soát được rủi ro, với phần lớn các chiến dịch đều đạt hiệu suất ở mức trung bình khá, ít có các trường hợp ngoại lệ quá thấp hoặc quá cao.

Xu hướng ROI theo tháng càng khẳng định tính ổn định này khi biểu đồ cho thấy ROI trung bình hầu như không có biến động đáng kể qua các tháng, luôn duy trì quanh mức 5.0 với sai số rất nhỏ. Điều này cho thấy hiệu suất đầu tư marketing của doanh nghiệp ít chịu ảnh hưởng của yếu tố mùa vụ, đồng thời phản ánh năng lực quản lý và tối ưu chiến dịch xuyên suốt các tháng trong năm đều rất ổn định.

Tuy nhiên, insight kinh tế quan trọng nhất đến từ mối quan hệ giữa mức chi phí và hiệu suất ROI. Biểu đồ ROI theo mức chi phí thể hiện rõ quy luật “tiền nào của nấy” trong đầu tư marketing: các chiến dịch với mức chi phí cao đem lại ROI cao nhất, tiếp theo là mức trung bình và thấp nhất là những chiến dịch có ngân sách thấp. Điều này cho thấy việc đầu tư mạnh tay vào các chiến dịch chất lượng cao, có quy mô lớn thực sự mang lại hiệu quả vượt trội về mặt tài chính.

Nhìn tổng thể, dữ liệu này ủng hộ cho chiến lược đầu tư marketing tập trung và mạnh mẽ thay vì dàn trải ngân sách quá mỏng. Việc phân bổ ngân sách lớn hơn cho các chiến dịch chất lượng cao, được đầu tư bài bản sẽ mang lại hiệu quả kinh tế tốt hơn so với việc chia nhỏ ngân sách thành nhiều chiến dịch quy mô nhỏ. Đây là bài học kinh tế quan trọng cho việc hoạch định ngân sách marketing trong tương lai.

1.4.2 Nhóm đồ thị phân tích kênh Marketing

# Tổng hợp dữ liệu cần thiết cho biểu đồ cột (p6, p7, p8) ---
channel_stats <- dl %>% 
group_by(Channel_Used) %>% 
summarise(
Tổng_doanh_thu = sum(Revenue),
CTR_trung_bình = mean(CTR),
Engagement_trung_bình = mean(Engagement_Score)
)

# 5. ROI theo Channel 
p5 <- ggplot(dl, aes(x = ROI, y = Channel_Used, fill = Channel_Used)) + 
geom_boxplot(alpha = 0.7) +
labs(title = "ROI", x = "ROI", y = "") + 
theme_minimal() +
theme(legend.position = "none")
channel_stats <- dl %>% 
group_by(Channel_Used) %>% 
summarise(
Tổng_doanh_thu = sum(Revenue),
CTR_trung_bình = mean(CTR),
Engagement_trung_bình = mean(Engagement_Score))

# 6. Revenue theo Channel 
p6 <- channel_stats %>% # Dùng data frame đã tổng hợp
    ggplot(aes(x = reorder(Channel_Used, Tổng_doanh_thu), y = Tổng_doanh_thu, fill = Channel_Used)) +
    geom_col(alpha = 0.8) +
    scale_y_continuous(expand = expansion(mult = c(0, 0.40)), 
                       labels = scales::label_number(scale = 1e6, suffix = "M")) + 
    geom_text(aes(label = scales::dollar(Tổng_doanh_thu/1e6, suffix = "USD")), 
              vjust = -0.3, size = 2.5) + 
    coord_flip() +
    labs(title = "DOANH THU", x = "", y = "Tổng doanh thu (USD)") +
    theme_minimal() +
    theme(legend.position = "none") +
    theme(axis.text.x = element_blank())

# 7. CTR theo Channel 
p7 <- channel_stats %>% # Dùng data frame đã tổng hợp
ggplot(aes(x = reorder(Channel_Used, CTR_trung_bình), y = CTR_trung_bình, fill = Channel_Used)) +
geom_col(alpha = 0.8) +
scale_y_continuous(expand = expansion(mult = c(0, 0.35))) +
geom_text(aes(label = round(CTR_trung_bình * 100, 2)), 
            vjust = -0.3, size = 2.5) + 
coord_flip() +
labs(title = "CTR TRUNG BÌNH (%)", x = "", y = "CTR trung bình") +
theme_minimal() +
theme(legend.position = "none")

# 8. Engagement theo Channel 
p8 <- channel_stats %>% # Dùng data frame đã tổng hợp
ggplot(aes(x = reorder(Channel_Used, Engagement_trung_bình), 
           y = Engagement_trung_bình, fill = Channel_Used)) +
geom_col(alpha = 0.8) +

scale_y_continuous(expand = expansion(mult = c(0, 0.35))) +
geom_text(aes(label = round(Engagement_trung_bình, 2)), 
            vjust = -0.3, size = 2.5) + 
coord_flip() +
labs(title = "ENGAGEMENT", x = "", y = "Engagement trung bình") +
theme_minimal() +
theme(legend.position = "none")

# Kết hợp 4 đồ thị bằng patchwork 
(p5 + p6) / (p7 + p8) +
plot_annotation(title = "NHÓM ĐỒ THỊ PHÂN TÍCH KÊNH MARKETING",
theme = theme(plot.title = element_text(face = "bold", size = 16, hjust = 0.5)))

Tạo một Data Frame Trung gian (channel_stats) bằng cách sử dụng group_by() và summarise() để tính toán đồng thời ba chỉ số (Tổng_doanh_thu, CTR_trung_bình, Engagement_trung_bình) cho mỗi kênh.

Sử dụng kết hợp Violin Plot và Box Plot.

Violin Plot (geom_violin): Cho thấy mật độ phân phối (hình dạng) của ROI trong mỗi kênh, hữu ích hơn Box Plot khi muốn xem sự tập trung của dữ liệu.

Box Plot (geom_boxplot): Làm nổi bật Trung vị (Median), Tứ phân vị (Quartiles) và các giá trị ngoại lai (Outliers).

reorder(Channel_Used, …): Sắp xếp các kênh trên trục Y theo thứ tự giá trị tăng dần hoặc giảm dần của chỉ số, giúp việc so sánh Top/Low Performer dễ dàng hơn.

coord_flip()-Chuyển đổi trục: Biến biểu đồ cột dọc thành ngang. Điều này là bắt buộc khi các nhãn kênh (Email, Facebook,…) dài, giúp tránh bị chồng chéo.

geom_text(…, vjust = -0.3, size = 2.5)-Đặt nhãn giá trị: Đặt số liệu chính xác lên cột. Tham số vjust = -0.3 dịch chuyển nhãn ra khỏi đầu cột (sau khi coord_flip), giải quyết vấn đề chồng chéo nhãn cuối cùng.

scales::dollar(…) / scales::label_number(…)-Định dạng số: Chuyển đổi các số lớn (Tổng_doanh_thu) thành định dạng tiền tệ hoặc số có hậu tố (M), làm cho biểu đồ dễ đọc hơn.

Sử dụng thư viện patchwork để bố cục 4 biểu đồ thành một hình ảnh tổng hợp: p5 và p6 nằm trên hàng trên, p7 và p8 nằm trên hàng dưới.

Dựa trên biểu đồ phân tích hiệu suất các kênh marketing, có thể đưa ra nhận định toàn diện về hiệu quả hoạt động của từng kênh trong việc đóng góp vào mục tiêu kinh doanh. Phân tích được thực hiện dựa trên ba chỉ số quan trọng: ROI đo lường hiệu quả tài chính, CTR đánh giá khả năng thu hút tương tác, và doanh thu phản ánh khả năng tạo ra thu nhập thực tế.

Xét về góc độ hiệu quả tài chính (ROI), Facebook và Website thể hiện vị trí dẫn đầu rõ rệt, chứng tỏ đây là hai kênh mang lại giá trị đầu tư tốt nhất. Các kênh này không chỉ thu hút được sự quan tâm của khách hàng mà còn chuyển đổi thành hiệu quả kinh tế thực tế. Ở nhóm giữa, Google Ads duy trì được mức ROI tương đối ổn định, trong khi Email, Instagram và YouTube cho thấy hiệu suất tài chính thấp hơn đáng kể, điều này đặt ra câu hỏi về tính hiệu quả trong việc phân bổ ngân sách cho các kênh này.

Khi phân tích khả năng thu hút tương tác thông qua chỉ số CTR, một bức tranh khác xuất hiện khi YouTube vượt trội với CTR cao nhất, tiếp theo là Website và Email. Điều này cho thấy YouTube có sức hút lớn trong việc thu hút sự chú ý và tương tác của người dùng, tuy nhiên khả năng chuyển đổi những tương tác này thành giá trị kinh tế lại chưa tương xứng. Facebook và Instagram thể hiện mức CTR ở tầm trung, trong khi Google Ads có CTR thấp nhất trong tất cả các kênh.

Về khả năng tạo ra doanh thu, Email khẳng định vị thế là kênh bán hàng chủ lực khi dẫn đầu về doanh thu, minh chứng cho hiệu quả của việc tiếp cận khách hàng trực tiếp. Google Ads và Website theo sát ở vị trí thứ hai và ba, cho thấy đây là những kênh quan trọng trong việc tạo ra nguồn thu. Đáng chú ý, YouTube, Instagram và Facebook mặc dù có những ưu điểm nhất định về tương tác hoặc ROI nhưng lại cho doanh thu thấp hơn hẳn.

Tổng hợp cả ba chỉ số, Website nổi lên như kênh marketing toàn diện nhất khi có ROI cao, CTR tốt và doanh thu ổn định. Facebook cũng thể hiện sự vượt trội về ROI mặc dù doanh thu chưa thực sự nổi bật. YouTube cho thấy tiềm năng lớn về mặt thu hút tương tác nhưng cần tối ưu hóa để chuyển đổi thành hiệu quả tài chính. Email vẫn giữ vị trí quan trọng trong việc tạo doanh thu dù hiệu quả đầu tư không thực sự nổi bật. Instagram và Google Ads cần được xem xét lại về chiến lược triển khai để cải thiện hiệu quả tổng thể.

Dựa trên phân tích này, chiến lược tối ưu nên tập trung ngân sách mạnh vào Website và Facebook để tận dụng hiệu quả tài chính cao, đồng thời cần có giải pháp cải thiện khả năng chuyển đổi của YouTube để biến lợi thế về CTR thành giá trị kinh tế thực tế. Đối với Email, cần duy trì như kênh bán hàng chủ lực nhưng cần tối ưu chi phí để nâng cao ROI. Instagram và Google Ads cần được đánh giá lại toàn diện về chiến lược triển khai và hiệu quả sử dụng ngân sách.

1.4.3 Nhóm đồ thị phân tích chiến dịch

campaign_stats <- dl %>% 
group_by(Campaign_Type) %>% 
summarise(Tổng_doanh_thu = sum(Revenue))

duration_stats <- dl %>%
group_by(Duration) %>%
summarise(ROI_trung_bình = mean(ROI))


# 9. Revenue theo Campaign Type 
p9 <- campaign_stats %>% 
ggplot(aes(x = reorder(Campaign_Type, Tổng_doanh_thu), y = Tổng_doanh_thu, fill = Campaign_Type)) +
geom_col(alpha = 0.8) +
scale_y_continuous(expand = expansion(mult = c(0, 0.30)), 
                     labels = scales::label_number(scale = 1e6, suffix = "USD")) +
geom_text(aes(label = scales::dollar(Tổng_doanh_thu/1e6, suffix = "USD")), 
            vjust = -0.3, 
            size = 2.5) + 
coord_flip() +
labs(title = "DOANH THU", x = "", y = "Tổng doanh thu (USD)") +
theme_minimal() +
theme(legend.position = "none")+
theme(axis.text.x = element_blank())

# 10. ROI theo Campaign Type 
p10 <- ggplot(dl, aes(x = Campaign_Type, y = ROI, fill = Campaign_Type)) +
geom_boxplot(alpha = 0.7) +
stat_summary(fun = mean, geom = "point", shape = 18, size = 3, color = "black") +
labs(title = "ROI", x = "Loại chiến dịch", y = "ROI") +
theme_minimal() +
theme(legend.position = "none")

# 11. Phân bố Duration 
p11 <- ggplot(dl, aes(x = factor(Duration), fill = factor(Duration))) +
 geom_bar(alpha = 0.7) +
labs(title = "PHÂN BỐ", x = "Thời lượng (ngày)", y = "Số lượng") +
theme_minimal() +
theme(legend.position = "none")

# 12. ROI theo Duration 
p12 <- duration_stats %>%
ggplot(aes(x = factor(Duration), y = ROI_trung_bình, fill = factor(Duration))) +
geom_col(alpha = 0.8) +
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
geom_text(aes(label = round(ROI_trung_bình, 2)), vjust = -0.5, size = 3) +
labs(title = "ROI", x = "Thời lượng (ngày)", y = "ROI trung bình") +
theme_minimal() +
theme(legend.position = "none")

# Kết hợp 4 đồ thị
(p9 + p10) / (p11 + p12) +
plot_annotation(title = "NHÓM ĐỒ THỊ PHÂN TÍCH CHIẾN DỊCH",
theme = theme(plot.title = element_text(face = "bold", size = 16, hjust = 0.5)))

reorder(Channel_Used, …) (Sắp xếp Dữ liệu): Đây là một hàm tiện ích cơ bản nhưng cực kỳ quan trọng. Nó xác định thứ tự hiển thị của các nhóm (Channel_Used) trên trục phân loại (trục Y sau khi coord_flip).Giá trị: Thay vì để các kênh sắp xếp theo thứ tự bảng chữ cái (mặc định), việc sắp xếp theo giá trị của chỉ số (ví dụ: Tổng_doanh_thu) giúp người đọc dễ dàng so sánh Top Performers và Low Performers chỉ bằng một cái nhìn, tăng hiệu quả báo cáo

coord_flip() (Chuyển đổi Tọa độ): Hàm này hoán đổi trục X và trục Y. Nó chuyển biểu đồ cột dọc truyền thống thành biểu đồ cột ngang.Giá trị: Bắt buộc phải sử dụng khi các nhãn phân loại (như tên kênh Email, Facebook, Google Ads…) quá dài. Nếu để cột dọc, các nhãn này sẽ bị chồng chéo hoặc phải xoay, làm giảm khả năng đọc. Biểu đồ cột ngang là giải pháp lý tưởng cho việc hiển thị phân loại dữ liệu.

scale_y_continuous(expand = expansion(mult = c(0, 0.40))) (Tối ưu hóa Hiển thị Trục)Chức năng: Điều chỉnh giới hạn của trục liên tục (trục giá trị, là trục Y sau khi coord_flip).Giá trị: Đây là kỹ thuật khắc phục lỗi hiển thị. Tham số mult = c(0, 0.40) yêu cầu R mở rộng giới hạn trục thêm \(40\%\) không gian ở phía trên. Không gian bổ sung này là nơi để đặt nhãn giá trị (geom_text) mà không bị cắt hoặc chạm mép biểu đồ.

geom_text(…, vjust = -0.3, size = 2.5) (Đặt Nhãn Giá trị): Đặt các giá trị thống kê chính xác lên đỉnh của mỗi cột.Giá trị: Tham số vjust = -0.3 đóng vai trò quyết định sau khi coord_flip(). Nó dịch chuyển nhãn theo chiều dọc của cột nhưng ra xa khỏi thanh cột, kết hợp với expansion ở mục 3 để ngăn chặn hoàn toàn lỗi chồng chéo hoặc nhãn bị cắt.

scales::dollar(…) / scales::label_number(…) (Định dạng Số liệu)Chức năng: Các hàm từ thư viện scales được sử dụng để định dạng số liệu thô thành chuỗi dễ đọc (ví dụ: \(2,100,000,000\) thành $2.10B hoặc $2.10M).Giá trị: Cải thiện tính chuyên nghiệp và khả năng đọc của biểu đồ, đặc biệt với các số tiền hoặc số liệu lớn.

Dựa trên biểu đồ phân tích hiệu suất các loại chiến dịch marketing, có thể đưa ra đánh giá toàn diện về hiệu quả của từng loại hình chiến dịch dựa trên khả năng tạo ra doanh thu. Phân tích này cung cấp cái nhìn sâu sắc về việc phân bổ ngân sách marketing tối ưu cho các loại hình chiến dịch khác nhau.

Theo thứ tự hiệu quả về mặt doanh thu, chiến dịch Influencer (tiếp thị thông qua người có ảnh hưởng) dẫn đầu rõ rệt, chứng tỏ đây là loại hình chiến dịch mang lại hiệu quả kinh doanh cao nhất. Vị trí này phản ánh xu hướng marketing hiện đại khi người tiêu dùng ngày càng tin tưởng vào các đề xuất từ những người có ảnh hưởng hơn là các hình thức quảng cáo truyền thống. Sự thành công của chiến dịch Influencer cho thấy khả năng tiếp cận đúng đối tượng mục tiêu và tạo ra sự tin tưởng mạnh mẽ đối với khách hàng tiềm năng.

Ở vị trí thứ hai là chiến dịch Search (tìm kiếm), thể hiện hiệu quả bền vững của việc tiếp cận khách hàng thông qua các công cụ tìm kiếm. Điều này cho thấy nhu cầu tìm kiếm chủ động từ phía người dùng vẫn là kênh mang lại giá trị kinh doanh cao, khi khách hàng đã có sẵn nhu cầu và tìm kiếm giải pháp. Chiến dịch Search thường đi kèm với ý định mua hàng cao, dẫn đến tỷ lệ chuyển đổi tốt và doanh thu ổn định.

Chiến dịch Display (quảng cáo hiển thị) chiếm vị trí thứ ba, cho thấy hiệu quả của việc xây dựng nhận thức thương hiệu và tiếp cận khách hàng ở quy mô lớn. Mặc dù không mang lại doanh thu cao như hai loại hình trên, Display vẫn duy trì được vị trí quan trọng trong việc xây dựng sự hiện diện thương hiệu và hỗ trợ các kênh marketing khác.

Đáng chú ý, chiến dịch Email - từng là công cụ marketing chủ lực - nay chỉ xếp ở vị trí thứ tư. Điều này phản ánh sự thay đổi trong thói quen tiếp nhận thông tin của người tiêu dùng.

1.4.4 Nhóm đồ thị phân tích khách hàng

customer_stats <- dl %>% 
group_by(Customer_Segment) %>% 
summarise(
Tổng_doanh_thu = sum(Revenue),
Engagement_trung_bình = mean(Engagement_Score))
gender_stats <- dl %>%
group_by(Gender) %>%
summarise(Conversion_Rate_trung_bình = mean(Conversion_Rate))

# 13. ROI theo Customer Segment 
p13 <- ggplot(dl, aes(x = Customer_Segment, y = ROI, fill = Customer_Segment)) +
geom_boxplot(alpha = 0.7) +
coord_flip() +
labs(title = "ROI THEO KHÁCH HÀNG", x = "", y = "ROI") +
theme_minimal() +
theme(legend.position = "none")

# 14. Revenue theo Customer Segment 
p14 <- customer_stats %>%
ggplot(aes(x = reorder(Customer_Segment, Tổng_doanh_thu), y = Tổng_doanh_thu, fill = Customer_Segment)) +
geom_col(alpha = 0.8) +
scale_y_continuous(expand = expansion(mult = c(0, 0.30)), 
                     labels = scales::label_number(scale = 1e6, suffix = "USD")) +
geom_text(aes(label = scales::dollar(Tổng_doanh_thu/1e6, suffix = "USD")), 
            vjust = -0.3, size = 2.5) +
coord_flip() +
labs(title = "DOANH THU", x = "", y = "Tổng doanh thu (USD)") +
theme_minimal() +
theme(legend.position = "none")+
theme(axis.text.x = element_blank())

# 15. Conversion Rate theo Gender 
p15 <- gender_stats %>%
ggplot(aes(x = Gender, y = Conversion_Rate_trung_bình, fill = Gender)) +
geom_col(alpha = 0.8) +
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
geom_text(aes(label = round(Conversion_Rate_trung_bình, 4)), 
            vjust = -0.5, size = 3) +
labs(title = "CR THEO GIỚI TÍNH", x = "Giới tính", y = "Conversion Rate trung bình") +
theme_minimal() +
theme(legend.position = "none")

# 16. Engagement theo Customer Segment 
p16 <- customer_stats %>%
    ggplot(aes(x = reorder(Customer_Segment, Engagement_trung_bình), y = Engagement_trung_bình, fill = Customer_Segment)) +
    geom_col(alpha = 0.8) +
    coord_flip() +
    scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
    geom_text(aes(label = round(Engagement_trung_bình, 2)), 
              hjust = -0.5, # Dịch nhãn ra ngoài cột ngang
              size = 3) +
    labs(title = "ENGAGEMENT", x = "", y = "Engagement trung bình") +
    theme_minimal() +
    theme(legend.position = "none")+
theme(axis.text.x = element_blank())

# Kết hợp 4 đồ thị
(p13 + p14) / (p15 + p16) +
plot_annotation(title = "NHÓM ĐỒ THỊ PHÂN TÍCH KHÁCH HÀNG",
theme = theme(plot.title = element_text(face = "bold", size = 16, hjust = 0.5)))

- (ROI theo Customer Segment):

Sử dụng geom_boxplot kết hợp với coord_flip() (chuyển Box Plot thành ngang). Đây là cách tuyệt vời để so sánh phân phối ROI giữa các phân khúc một cách trực quan.

  • (Revenue theo Customer Segment):

Sử dụng group_by/summarise và geom_col kết hợp coord_flip() và reorder() để hiển thị tổng doanh thu theo thứ tự.

  • (Engagement theo Customer Segment):

Tương tự như p14, sử dụng cột dọc và reorder() để so sánh mức độ tương tác (Engagement) giữa các nhóm khách hàng.

  • (CR theo Gender):

Sử dụng geom_col để so sánh tỷ lệ chuyển đổi (Conversion_Rate) trung bình giữa các nhóm giới tính (All, Female, Male).

Phân tích ROI theo nhóm khách hàng cho thấy sự khác biệt đáng kể về hiệu quả đầu tư marketing giữa các phân khúc. Nhóm Tech Enthusiasts (những người đam mê công nghệ) thể hiện ROI cao nhất, điều này phản ánh khả năng sẵn sàng chi trả và độ trung thành của nhóm khách hàng này đối với các sản phẩm công nghệ. Tiếp theo là nhóm Outdoor Adventurers (những người yêu thích phiêu lưu ngoài trời) và Health & Wellness (sức khỏe và thể chất), cả hai đều cho thấy tiềm năng lớn trong việc mang lại lợi nhuận cho các chiến dịch marketing. Ngược lại, nhóm Foodies (người sành ăn) và Fashionistas (tín đồ thời trang) có ROI thấp hơn, cho thấy có thể các chiến dịch hướng đến nhóm này cần được tối ưu để cải thiện hiệu quả đầu tư.

Tuy nhiên, khi xem xét về tổng doanh thu, bức tranh lại hoàn toàn khác biệt. Nhóm Foodies dẫn đầu về doanh thu, chứng tỏ đây là phân khúc có quy mô thị trường lớn và khả năng chi tiêu mạnh mẽ. Tech Enthusiasts và Outdoor Adventurers theo sát ở vị trí thứ hai và ba, khẳng định tầm quan trọng của các nhóm khách hàng này trong cơ cấu doanh thu tổng thể. Health & Wellness và Fashionistas có doanh thu thấp hơn, nhưng vẫn đóng góp đáng kể vào tổng doanh thu.

Phân tích tỷ lệ chuyển đổi (Conversion Rate) theo giới tính cho thấy một kết quả thú vị: không có sự khác biệt đáng kể nào về tỷ lệ chuyển đổi giữa các nhóm giới tính. Cả ba nhóm “All” (tất cả), “Female” (nữ) và “Male” (nam) đều có tỷ lệ chuyển đổi tương đương nhau. Điều này cho thấy chiến lược marketing hiện tại đang tiếp cận hiệu quả với tất cả các nhóm giới tính, và không có nhóm nào thể hiện sự vượt trội rõ rệt về khả năng chuyển đổi. Tuy nhiên, điều này cũng gợi ý rằng có thể cần phân tích sâu hơn về giá trị đơn hàng trung bình hoặc tỷ lệ duy trì khách hàng theo giới tính để có cái nhìn toàn diện hơn.

Về chỉ số Engagement (mức độ tương tác), dữ liệu cho thấy sự phân bổ tương tác khá đồng đều trên thang điểm từ 1 đến 10, với xu hướng tập trung vào các mức điểm trung bình. Điều này cho thấy khách hàng có mức độ tương tác ổn định với thương hiệu, nhưng vẫn còn dư địa để cải thiện mức độ tương tác cao hơn. Các điểm engagement thấp có thể phản ánh những khách hàng mới hoặc những người ít tương tác, trong khi các điểm engagement cao thường đại diện cho những khách hàng trung thành hoặc những người đã có trải nghiệm tích cực với thương hiệu.

Tổng hợp các insights từ ba góc độ phân tích này, có thể thấy rằng mặc dù nhóm Foodies có ROI thấp hơn nhưng lại đóng góp doanh thu lớn nhất, điều này cho thấy đây là phân khúc cần được duy trì và tối ưu hóa để cải thiện hiệu quả đầu tư. Ngược lại, nhóm Tech Enthusiasts vừa có ROI cao vừa có doanh thu lớn, xứng đáng được ưu tiên đầu tư marketing. Việc không có sự khác biệt về tỷ lệ chuyển đổi theo giới tính cho phép doanh nghiệp tập trung vào các yếu tố khác trong segmentation thay vì tập trung quá nhiều vào giới tính. Cuối cùng, chỉ số engagement ổn định nhưng chưa cao cho thấy cơ hội trong việc phát triển các chiến lược tăng cường tương tác và xây dựng lòng trung thành khách hàng.

Dựa trên những phân tích này, chiến lược marketing nên ưu tiên phân bổ ngân sách cho nhóm Tech Enthusiasts và Foodies, đồng thời phát triển các chương trình tăng cường engagement cho tất cả các nhóm khách hàng. Việc cá nhân hóa trải nghiệm và cải thiện chất lượng dịch vụ có thể giúp nâng cao cả ROI và doanh thu từ tất cả các phân khúc khách hàng.

1.4.5 Nhóm đồ thị tương quan và tương tác

# 17. Tương quan ROI vs Conversion Rate
p17 <- ggplot(dl, aes(x = Conversion_Rate, y = ROI)) +
  geom_point(alpha = 0.3, color = "blue") +
  geom_smooth(method = "lm", color = "red", se = TRUE) +
  geom_hline(yintercept = mean(dl$ROI), linetype = "dashed", color = "gray") +
  geom_vline(xintercept = mean(dl$Conversion_Rate), linetype = "dashed", color = "gray") +
  labs(title = "ROI VS CONVERSION RATE", x = "Conversion Rate", y = "ROI") +
  theme_minimal()

# 18. Tương quan Clicks vs Impressions
p18 <- ggplot(dl, aes(x = Impressions, y = Clicks)) +
  geom_point(alpha = 0.3, color = "brown") +
  geom_smooth(method = "lm", color = "darkblue", se = TRUE) +
  labs(title = "CLICKS VS IMPRESSIONS", x = "Impressions", y = "Clicks") +
  theme_minimal()

# 19. Phân phối Engagement Score
p19 <- ggplot(dl, aes(x = Engagement_Score)) +
  geom_histogram(fill = "purple", bins = 15, alpha = 0.7) +
  geom_vline(aes(xintercept = mean(Engagement_Score)), color = "red", linetype = "dashed", linewidth = 1) +
  labs(title = "PHÂN PHỐI ĐIỂM TƯƠNG TÁC", x = "Engagement Score", y = "Tần số") +
  theme_minimal()

# 20. Phân bố ROI Tier
p20 <- ggplot(dl, aes(x = ROI_Tier, fill = ROI_Tier)) +
 geom_bar(alpha = 0.7) +
# TĂNG expansion trục Y lên 30% (từ 15%) để đảm bảo nhãn không bị cắt
scale_y_continuous(expand = expansion(mult = c(0, 0.30))) +
# Đặt nhãn số lượng
geom_text(stat = 'count', aes(label = after_stat(count)), vjust = -0.5, size = 3) +
labs(title = "PHÂN BỐ THEO MỨC ROI", x = "Mức ROI", y = "Số lượng") +
theme_minimal() +
theme(legend.position = "none")

# Kết hợp 4 đồ thị
(p17 + p18) / (p19 + p20) +
  plot_annotation(title = "NHÓM ĐỒ THỊ TƯƠNG QUAN VÀ TƯƠNG TÁC",
                  theme = theme(plot.title = element_text(face = "bold", size = 16, hjust = 0.5)))

- Phân tích Tương quan (p17, p18) geom_point(alpha = 0.3): Dùng Scatter Plot để hiển thị mối quan hệ giữa hai biến, sử dụng alpha để giảm độ đậm đặc của các điểm dữ liệu.

geom_smooth(method = “lm”, …): Thêm đường hồi quy tuyến tính (Linear Model - LM) để định lượng xu hướng. Vùng màu xám xung quanh đường thẳng (se = TRUE) là khoảng tin cậy (Confidence Interval), cho thấy mức độ chắc chắn của mối quan hệ.

geom_hline / geom_vline: Trong p17, thêm các đường tham chiếu ngang và dọc (yintercept và xintercept) tại giá trị trung bình, giúp dễ dàng xác định bốn góc phần tư của dữ liệu (Ví dụ: ROI cao, CR thấp).

  • Phân tích Phân phối (p19, p20) p19 (Phân phối Engagement Score):

Dùng geom_histogram để thể hiện tần suất.

Thêm geom_vline tại vị trí giá trị trung bình (mean), giúp người xem nhanh chóng xác định vị trí trung tâm của phân phối.

  • (Phân bố ROI Tier):

Dùng geom_bar(stat = ‘count’) để đếm số lượng các chiến dịch thuộc ba mức ROI (Low, Medium, High).

Dựa trên nhóm đồ thị phân tích tương quan và tương tác, có thể rút ra những insights quan trọng về mối quan hệ giữa các chỉ số hiệu suất marketing và phân phối của chúng.

Đồ thị tương quan giữa ROI và Conversion Rate cho thấy một phát hiện đáng chú ý: không có mối tương quan tuyến tính rõ rệt nào giữa hai chỉ số này. Các điểm dữ liệu phân tán rộng mà không hình thành một xu hướng cụ thể, chứng tỏ một Conversion Rate cao không đảm bảo ROI cao và ngược lại. Điều này cho thấy có những yếu tố khác ngoài tỷ lệ chuyển đổi ảnh hưởng đến hiệu quả tài chính của chiến dịch, như giá trị đơn hàng trung bình, chi phí acquisition, hay tỷ lệ giữ chân khách hàng. Các marketer cần nhìn nhận rằng việc tối ưu Conversion Rate chỉ là một phần của bài toán, và cần kết hợp với các chỉ số khác để đánh giá toàn diện hiệu quả.

Đồ thị tương quan giữa Clicks và Impressions thể hiện mối quan hệ tích cực và khá chặt chẽ giữa hai chỉ số này - khi số lượng impressions tăng thì clicks cũng có xu hướng tăng theo. Tuy nhiên, mật độ tập trung của các điểm dữ liệu cho thấy có một ngưỡng hiệu quả nhất định, vượt qua ngưỡng đó thì việc tăng thêm impressions không mang lại sự gia tăng tương xứng về clicks. Điều này gợi ý về quy luật giảm dần lợi ích trong việc mở rộng phạm vi tiếp cận, và nhấn mạnh tầm quan trọng của việc tối ưu hóa targeting thay vì chỉ tập trung vào việc gia tăng impressions.

Biểu đồ phân phối điểm Engagement Score tiết lộ một phân phối gần như chuẩn với đỉnh điểm quanh mức 5-6, cho thấy đa số khách hàng có mức độ tương tác trung bình. Phân phối này khá cân đối với cả hai phía của điểm trung bình, nhưng có sự sụt giảm đáng kể ở các mức engagement cao (8-10). Điều này chỉ ra rằng mặc dù doanh nghiệp đang duy trì được mức độ tương tục cơ bản với đa số khách hàng, nhưng vẫn còn dư địa lớn để chuyển đổi những khách hàng có engagement trung bình thành những người ủng hộ nhiệt thành.

Cuối cùng, biểu đồ phân bổ theo mức ROI cho thấy sự cân bằng tương đối giữa ba nhóm: Low, Medium và High. Sự phân bổ khá đồng đều này phản ánh một danh mục chiến dịch marketing đa dạng, trong đó có những chiến dịch hiệu quả cao, những chiến dịch trung bình và cả những chiến dịch cần cải thiện. Điều đáng chú ý là số lượng chiến dịch ở mức ROI High vẫn chiếm tỷ trọng đáng kể, chứng tỏ doanh nghiệp có khả năng tạo ra những chiến dịch chất lượng và nên tập trung học hỏi từ những thành công này để nhân rộng mô hình.

Tổng hợp lại, các đồ thị này cung cấp một cái nhìn toàn diện về hiệu suất marketing: Conversion Rate và ROI cần được phân tích độc lập, mối quan hệ giữa Clicks và Impressions tuân theo quy luật giảm dần, engagement của khách hàng tập trung ở mức trung bình, và danh mục chiến dịch có sự phân bổ ROI khá cân bằng. Những insights này gợi ý rằng chiến lược tối ưu nên tập trung vào việc nâng cao engagement từ mức trung bình lên cao, tối ưu targeting thay vì tăng impressions, và phân tích sâu các chiến dịch ROI cao để nhân rộng thành công.

2 PHẦN 2: BÁO CÁO TÀI CHÍNH CỦA CÔNG TY IMP

2.1 CÁC THÔNG TIN CƠ BẢN BỘ DỮ LIỆU

2.1.1 Đọc dữ liệu

ta <- read_excel("~/NNLT/bctc.xlsx")

Trong suốt giai đoạn 10 năm từ 2015 đến 2024, doanh nghiệp đã chứng kiến sự tăng trưởng vượt bậc về quy mô và lợi nhuận. Lợi nhuận sau thuế tăng trưởng liên tục và ấn tượng, từ mức 92.275 tỷ đồng năm 2015 lên đến 320.862 tỷ đồng năm 2024, gấp khoảng 3.5 lần, cho thấy khả năng mở rộng thị phần và hiệu quả kinh doanh ngày càng được cải thiện. Đặc biệt, các năm 2019-2020 và 2022-2023 là những giai đoạn tăng tốc mạnh mẽ, đưa lợi nhuận vượt mốc 200.000 tỷ và sau đó là 300.000 tỷ đồng.

Tuy nhiên, đằng sau thành công về lợi nhuận là những thách thức tài chính không nhỏ. Năm 2023 trở thành điểm đáng lo ngại khi lần đầu tiên sau nhiều năm, dòng tiền từ hoạt động kinh doanh (CFO) rơi vào trạng thái âm (~30.308 tỷ đồng). Nguyên nhân chính đến từ sự gia tăng mạnh của các khoản phải thu (~199.919 tỷ) và tồn kho (~260.749 tỷ), phản ánh áp lực thanh khoản và hiệu quả quản lý vốn lưu động chưa thực sự tốt. Bên cạnh đó, doanh nghiệp có xu hướng đầu tư mạnh qua nhiều năm, thể hiện ở dòng tiền đầu tư (CFI) âm liên tục, chủ yếu cho mua sắm tài sản cố định và gửi tiền tiết kiệm. Để duy trì hoạt động và mở rộng đầu tư, doanh nghiệp đã phải dựa nhiều vào vay nợ, với các khoản vay mới và trả nợ gốc luân phiên ở quy mô lớn.

Đến năm 2024, tín hiệu tích cực đã trở lại khi dòng tiền hoạt động phục hồi mạnh mẽ, đạt 216.267 tỷ đồng, đồng thời doanh nghiệp tiếp tục chú trọng trả nợ gốc, cho thấy nỗ lực cải thiện cơ cấu tài chính và giảm sự phụ thuộc vào đòn bẩy. Dù vậy, bài toán về quản lý vốn lưu động, kiểm soát công nợ và nâng cao hiệu suất sử dụng tài sản vẫn là những thách thức then chốt cần giải quyết để đảm bảo sự phát triển bền vững trong tương lai.

2.1.2 Xem dữ liệu

show(ta) %>% kable()
## # A tibble: 10 × 18
##     year LoiNhuanSauThue   Tien_DauKy  Tien_CuoiKy     CFO_Tong      KhauHao
##    <dbl>           <dbl>        <dbl>        <dbl>        <dbl>        <dbl>
##  1  2015     92275349999 178550050326  87841659460  81130888888  38402557093
##  2  2016    101159344647  87841659460 100127453686  84650650055  37320990534
##  3  2017    117360040786 100127453686 106457131642  97212899364  31379088060
##  4  2018    138683041628 106457131642 190436654283 132094454149  30515092412
##  5  2019    162386686793 190436654283  75035614726  66590387415  41208658249
##  6  2020    209696878289  75035614726  85268705365  73153422780  53360966033
##  7  2021    189094874963  85268705365 271272865376 234881036040  60412122442
##  8  2022    223540317602 271272865376 178845070328 378603401448  60385696030
##  9  2023    299556005542 178845070328 106200569241 -30308428665  82642281566
## 10  2024    320862393082 106200569241 161983318837 216267565018 105636226909
## # ℹ 12 more variables: BienDong_PhaiThu <dbl>, BienDong_TonKho <dbl>,
## #   BienDong_PhaiTra <dbl>, LaiVay_DaTra <dbl>, Thue_DaNop <dbl>,
## #   CFI_Tong <dbl>, Chi_MuaTSCD <dbl>, Chi_TienGui <dbl>, Thu_TienGui <dbl>,
## #   CFF_Tong <dbl>, VayMoi <dbl>, TraNoGoc <dbl>

Dùng hàm show() để tóm tắt bộ dữ liệu, kết hợp toán tử pipe(%>%)để kết quả trả ra là bảng.

2.1.3 Cấu trúc tổng thể

glimpse(ta)
## Rows: 10
## Columns: 18
## $ year             <dbl> 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023,…
## $ LoiNhuanSauThue  <dbl> 92275349999, 101159344647, 117360040786, 138683041628…
## $ Tien_DauKy       <dbl> 178550050326, 87841659460, 100127453686, 106457131642…
## $ Tien_CuoiKy      <dbl> 87841659460, 100127453686, 106457131642, 190436654283…
## $ CFO_Tong         <dbl> 81130888888, 84650650055, 97212899364, 132094454149, …
## $ KhauHao          <dbl> 38402557093, 37320990534, 31379088060, 30515092412, 4…
## $ BienDong_PhaiThu <dbl> -41333661601, -8928274802, -1437631837, 22334105781, …
## $ BienDong_TonKho  <dbl> 50382333195, 10749182912, -47523201453, -43797978420,…
## $ BienDong_PhaiTra <dbl> -35669331173, -25111605021, 23575925481, -13724008827…
## $ LaiVay_DaTra     <dbl> -605820692, -55154439, -618733502, -1275879713, -3707…
## $ Thue_DaNop       <dbl> -26094252845, -22380008319, -31711798648, -3208302429…
## $ CFI_Tong         <dbl> -204828797781, -14340785224, -443246932809, -48101241…
## $ Chi_MuaTSCD      <dbl> -116451196931, -103904028053, -274456614870, -2724400…
## $ Chi_TienGui      <dbl> -100000000000, -12000000000, -357729700000, -43817250…
## $ Thu_TienGui      <dbl> NA, 100000000000, 183075000000, 221737811648, 2629776…
## $ CFF_Tong         <dbl> 32990722640, -58008892000, 352371798300, NA, -6136326…
## $ VayMoi           <dbl> 95894850000, NA, 120000000000, 160076187844, 21888822…
## $ TraNoGoc         <dbl> -95894850000, NA, -120000000000, -160076187844, -1813…

Dùng hàm glimpse() thay thế hàm str() để cung cấp dữ liệu ngắn gọn, tổng thể.

2.1.4 Tóm tắt dữ liệu

summary(ta) 
##       year      LoiNhuanSauThue          Tien_DauKy          
##  Min.   :2015   Min.   : 92275349999   Min.   : 75035614726  
##  1st Qu.:2017   1st Qu.:122690790996   1st Qu.: 90913108016  
##  Median :2020   Median :175740780878   Median :106328850442  
##  Mean   :2020   Mean   :185461493333   Mean   :138003577443  
##  3rd Qu.:2022   3rd Qu.:220079457774   3rd Qu.:178771315328  
##  Max.   :2024   Max.   :320862393082   Max.   :271272865376  
##                                                              
##   Tien_CuoiKy              CFO_Tong               KhauHao            
##  Min.   : 75035614726   Min.   :-30308428665   Min.   : 30515092412  
##  1st Qu.: 90913108016   1st Qu.: 75147789307   1st Qu.: 37591382174  
##  Median :106328850442   Median : 90931774710   Median : 47284812141  
##  Mean   :136346904294   Mean   :133427627649   Mean   : 54126367933  
##  3rd Qu.:174629632455   3rd Qu.:195224287301   3rd Qu.: 60405515839  
##  Max.   :271272865376   Max.   :378603401448   Max.   :105636226909  
##                                                                      
##  BienDong_PhaiThu       BienDong_TonKho         BienDong_PhaiTra      
##  Min.   :-83306984898   Min.   :-260749238157   Min.   :-49525833086  
##  1st Qu.:-55960084902   1st Qu.: -61477533455   1st Qu.:-33029899635  
##  Median :-14460118668   Median : -34622213581   Median : -8277667477  
##  Mean   :-12166658588   Mean   : -41154397712   Mean   : -7535274795  
##  3rd Qu.: 14742465394   3rd Qu.:   6516640084   3rd Qu.: 16895829534  
##  Max.   :115759490658   Max.   :  52398387880   Max.   : 39579670960  
##                                                                       
##   LaiVay_DaTra           Thue_DaNop              CFI_Tong            
##  Min.   :-6699943903   Min.   :-83992016063   Min.   :-443246932809  
##  1st Qu.:-4413178073   1st Qu.:-56045224314   1st Qu.:-183596885752  
##  Median :-3598954722   Median :-41597605868   Median :-123911128404  
##  Mean   :-3046559562   Mean   :-45519649979   Mean   :-130736762123  
##  3rd Qu.: -783020055   3rd Qu.:-31804605059   3rd Qu.: -56861445622  
##  Max.   :  -55154439   Max.   :-22380008319   Max.   :  69894262492  
##                                                                      
##   Chi_MuaTSCD             Chi_TienGui             Thu_TienGui          
##  Min.   :-274456614870   Min.   :-451171580000   Min.   : 26297761332  
##  1st Qu.:-127456519988   1st Qu.:-335047275000   1st Qu.:100000000000  
##  Median :-101628608786   Median :-176494739041   Median :195897929613  
##  Mean   :-130057173899   Mean   :-198920800808   Mean   :204128349936  
##  3rd Qu.: -91456180145   3rd Qu.: -57862937500   3rd Qu.:221737811648  
##  Max.   : -52856687303   Max.   : -12000000000   Max.   :491300000000  
##                                                  NA's   :1             
##     CFF_Tong                 VayMoi                 TraNoGoc            
##  Min.   :-271718144243   Min.   :-315649453686   Min.   :-351293662887  
##  1st Qu.: -61363261179   1st Qu.:  95894850000   1st Qu.:-231513531376  
##  Median : -33304800015   Median : 160076187844   Median :-181308771504  
##  Mean   :  -4797122112   Mean   : 142392327092   Mean   :-183894915875  
##  3rd Qu.:  34495813019   3rd Qu.: 229739387189   3rd Qu.:-120000000000  
##  Max.   : 352371798300   Max.   : 387993511872   Max.   : -49387359000  
##  NA's   :1               NA's   :1               NA's   :1

Hàm đã được giải thích ở Phần 1

Năm: Biến thời gian của dữ liệu quan sát. Phân bố từ 2015 đến 2024. Đây là dữ liệu rời rạc, các chỉ số thống kê (Min, Q1, Median, Mean, Max) chỉ cho biết phạm vi thời gian của mẫu.

Lợi nhuận sau thuế: Doanh nghiệp thể hiện sự tăng trưởng lợi nhuận sau thuế ấn tượng trong giai đoạn 2015-2024, từ mức sàn 92.275 tỷ đồng lên đến mức trần 320.862 tỷ đồng. Với giá trị trung bình đạt 185.461 tỷ đồng và trung vị ở 175.741 tỷ đồng, có thể thấy hiệu quả kinh doanh được cải thiện đáng kể theo thời gian, mặc dù vẫn tồn tại sự chênh lệch khá lớn giữa các năm.

Về dòng tiền hoạt động (CFO): Sức khỏe dòng tiền từ hoạt động kinh doanh có dấu hiệu bất ổn. Giá trị âm sâu nhất lên tới -30.308 tỷ đồng, trong khi năm đỉnh điểm đạt 378.603 tỷ đồng, cho thấy khả năng tạo tiền không ổn định và có thể phụ thuộc nhiều vào yếu tố mùa vụ hoặc chu kỳ kinh doanh. Trung bình dòng tiền ở mức 133.428 tỷ đồng là tích cực, nhưng sự dao động mạnh là một điểm đáng lưu ý.

Tiền đầu kỳ (Cash at the beginning of the period): Số dư tiền và các khoản tương đương tiền tại thời điểm đầu kỳ. Phân bố tương đối ổn định với Median là 1,063 tỷ. Mức cao nhất là 2,712 tỷ, cho thấy có những thời điểm dự trữ tiền mặt rất cao.

Tiền cuối kỳ (Cash at the end of the period): Số dư tiền và các khoản tương đương tiền tại thời điểm cuối kỳ. Rất gần với Tien_DauKy, cho thấy dòng tiền ròng trong kỳ không thay đổi đáng kể, với Median là 1,063 tỷ và Max là 2,712 tỷ.

Dòng tiền thuần từ hoạt động tài chính (Net Cash Flow from Financing Activities): Tổng lượng tiền mặt thu được hoặc chi ra từ việc phát hành/mua lại cổ phiếu, vay/trả nợ, và chi trả cổ tức. Phạm vi rất rộng (Min: -2,717 tỷ, Max: 3,523 tỷ). Median là -333 tỷ (âm) và Mean là -479 tỷ (âm), cho thấy xu hướng chung là công ty chi tiền cho hoạt động tài chính (có thể là trả nợ, mua lại cổ phiếu hoặc chi cổ tức).

Dòng tiền thuần từ hoạt động đầu tư (Net Cash Flow from Investing Activities): Tổng lượng tiền mặt thu được hoặc chi ra từ việc mua/thanh lý tài sản cố định hoặc đầu tư tài chính dài hạn. Toàn bộ các chỉ số (Min, Median, Mean, Max) đều là số âm (Mean: -1,307 tỷ). Điều này mạnh mẽ cho thấy công ty thường xuyên chi tiền cho hoạt động đầu tư, tức là mua sắm tài sản cố định (nhà xưởng, máy móc) hoặc các khoản đầu tư dài hạn.

Biến động các khoản phải thu (Change in Receivables): Sự thay đổi trong khoản tiền khách hàng nợ công ty (Thường là Phải thu cuối kỳ - Phải thu đầu kỳ). Median là -144 tỷ (âm), cho thấy trung bình các khoản phải thu giảm (tức là công ty thu được tiền từ khách hàng nhanh hơn), đây là dấu hiệu tốt về quản lý vốn lưu động. Phạm vi rất rộng (Max: 1,157 tỷ).

Biến động tồn kho (Change in Inventory): Sự thay đổi trong giá trị hàng tồn kho. Median là -346 tỷ (âm), cho thấy trung bình hàng tồn kho giảm. Nếu không phải là do mùa vụ, sự giảm này có thể là tín hiệu tốt về khả năng tiêu thụ. Phạm vi lớn (Min: -2,607 tỷ, Max: 523 tỷ).

Biến động các khoản phải trả (Change in Payables): Sự thay đổi trong khoản tiền công ty nợ nhà cung cấp. Median là -753 tỷ (âm), cho thấy trung bình các khoản phải trả giảm (tức là công ty chi tiền trả cho nhà cung cấp nhanh hơn hoặc vay ít hơn).

Chi mua tài sản cố định (Cash Paid for Fixed Assets/PPE): Lượng tiền mặt chi ra để mua sắm tài sản cố định (Chi đầu tư). Toàn bộ đều âm (Median: -1,016 tỷ; Mean: -1,300 tỷ), khẳng định công ty thường xuyên đầu tư mua sắm tài sản cố định.

Chi tiền gửi (Increase in Cash Deposits/Investments): Lượng tiền mặt dùng để gửi vào ngân hàng hoặc đầu tư ngắn hạn. Toàn bộ đều âm (Median: -1,764 tỷ; Mean: -1,989 tỷ), cho thấy công ty thường xuyên sử dụng tiền mặt để gửi tiết kiệm hoặc đầu tư an toàn.

Thu tiền gửi (Decrease in Cash Deposits/Investments): Lượng tiền mặt thu về từ việc rút tiền gửi hoặc thanh lý các khoản đầu tư ngắn hạn. Toàn bộ đều dương (Median: 1,958 tỷ; Mean: 2,041 tỷ). Có 1 giá trị NA (Not Available), cho thấy dữ liệu này có sự thiếu hụt.

Vay mới (New Debt Raised): Tổng số tiền mới vay thêm trong kỳ. Phạm vi từ -315 tỷ đến 3,879 tỷ. Median là 160 tỷ (dương), cho thấy công ty có xu hướng vay thêm vốn, nhưng mức độ rất đa dạng. Có 1 giá trị NA.

Trả nợ gốc (Principal Repayment): Lượng tiền mặt dùng để trả nợ gốc (không bao gồm lãi). Toàn bộ đều âm (Median: -1,813 tỷ; Mean: -1,838 tỷ). Mức trả nợ gốc rất lớn và ổn định, cao hơn nhiều so với VayMoi, phản ánh chính sách giảm nợ của công ty trong mẫu. Có 1 giá trị NA.

Tổng quan rủi ro: Mặc dù có tăng trưởng lợi nhuận tốt và chiến lược đầu tư bài bản, sự dao động mạnh của các chỉ số tài chính cùng với sự hiện diện của một số giá trị thiếu (NA) trong dữ liệu là những rủi ro tiềm ẩn. Việc ổn định dòng tiền và nâng cao hiệu quả quản lý vốn lưu động là chìa khóa để đảm bảo sự phát triển bền vững trong tương lai.

2.1.5 Danh sách tên biến

names(ta)
##  [1] "year"             "LoiNhuanSauThue"  "Tien_DauKy"       "Tien_CuoiKy"     
##  [5] "CFO_Tong"         "KhauHao"          "BienDong_PhaiThu" "BienDong_TonKho" 
##  [9] "BienDong_PhaiTra" "LaiVay_DaTra"     "Thue_DaNop"       "CFI_Tong"        
## [13] "Chi_MuaTSCD"      "Chi_TienGui"      "Thu_TienGui"      "CFF_Tong"        
## [17] "VayMoi"           "TraNoGoc"

Dùng hàm name() để lấy ra danh sách tên các cột (biến).Kết quả hiển thị một danh sách 18 tên biến.

2.1.6 Kích thước dữ liệu

n_distinct(ta$year)
## [1] 10
dim(ta)
## [1] 10 18

Hàm n_distinct() đếm số lượng các giá trị duy nhất của biến year.

Hàm dim() trả về kích thước của đối tượng dữ liệu ta dưới dạng một vector số nguyên, với phần tử đầu tiên là số hàng và phần tử thứ hai là số cột.

Kết quả:

[1] 10 (Kết quả từ n_distinct(ta$year)):

Điều này có nghĩa là có 10 giá trị năm duy nhất trong dữ liệu (ví dụ: từ 2015 đến 2024, như đã thấy trong phân tích summary() trước đó).

[1] 10 18 (Kết quả từ dim(ta)):

10: Là số hàng (Row) hay số quan sát (Observation).

18: Là số cột (Column) hay số biến (Variable).

2.1.7 Kiểu dữ liệu từng biến

sapply(ta, class) %>% kable()
x
year numeric
LoiNhuanSauThue numeric
Tien_DauKy numeric
Tien_CuoiKy numeric
CFO_Tong numeric
KhauHao numeric
BienDong_PhaiThu numeric
BienDong_TonKho numeric
BienDong_PhaiTra numeric
LaiVay_DaTra numeric
Thue_DaNop numeric
CFI_Tong numeric
Chi_MuaTSCD numeric
Chi_TienGui numeric
Thu_TienGui numeric
CFF_Tong numeric
VayMoi numeric
TraNoGoc numeric

Dùng hàm sapply() để xác định kiểu dữ liệu từng biến và trong bộ dữ liệu này 18 biến đều có kiểu dữ liệu numeric.

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

sum(is.na(ta))
## [1] 4
colSums(is.na(ta)) %>% kable()
x
year 0
LoiNhuanSauThue 0
Tien_DauKy 0
Tien_CuoiKy 0
CFO_Tong 0
KhauHao 0
BienDong_PhaiThu 0
BienDong_TonKho 0
BienDong_PhaiTra 0
LaiVay_DaTra 0
Thue_DaNop 0
CFI_Tong 0
Chi_MuaTSCD 0
Chi_TienGui 0
Thu_TienGui 1
CFF_Tong 1
VayMoi 1
TraNoGoc 1

Kiểm tra có dữ liệu bị thiếu ở cột, ta thấy được có 14 cột không bị thiếu và 4 cột bị thiếu.

2.1.9 Kiểm tra số dòng bị trùng lặp

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

Kết quả trả ra cho thấy dữ liệu không bị trùng lặp.

2.1.10 Kiểm tra dữ liệu ngoại lai

ta %>%
  summarise(across(where(is.numeric), 
    function(x) {
      q1 <- quantile(x, 0.25, na.rm = TRUE)
      q3 <- quantile(x, 0.75, na.rm = TRUE)
      iqr <- IQR(x, na.rm = TRUE)
      lower_bound <- q1 - 1.5 * iqr
      upper_bound <- q3 + 1.5 * iqr
      sum(x < lower_bound | x > upper_bound, na.rm = TRUE)
    })) %>%
  print(n = Inf, width = Inf)
## # A tibble: 1 × 18
##    year LoiNhuanSauThue Tien_DauKy Tien_CuoiKy CFO_Tong KhauHao BienDong_PhaiThu
##   <int>           <int>      <int>       <int>    <int>   <int>            <int>
## 1     0               0          0           0        1       1                0
##   BienDong_TonKho BienDong_PhaiTra LaiVay_DaTra Thue_DaNop CFI_Tong Chi_MuaTSCD
##             <int>            <int>        <int>      <int>    <int>       <int>
## 1               1                0            0          0        1           2
##   Chi_TienGui Thu_TienGui CFF_Tong VayMoi TraNoGoc
##         <int>       <int>    <int>  <int>    <int>
## 1           0           1        2      1        0

ta %>% summarise(…): Bắt đầu bằng việc áp dụng các phép toán tóm tắt lên đối tượng dữ liệu ta.

across(where(is.numeric), function(x) {…}):across(): Áp dụng cùng một hàm cho nhiều cột.where(is.numeric): Chỉ áp dụng hàm cho tất cả các cột có kiểu dữ liệu là số (numeric).

Tính toán ranh giới ngoại lai:q1 <- quantile(x, 0.25, na.rm = TRUE): Tính Tứ phân vị thứ nhất (Q1).q3 <- quantile(x, 0.75, na.rm = TRUE): Tính Tứ phân vị thứ ba (Q3).iqr <- IQR(x, na.rm = TRUE): Tính Khoảng tứ phân vị (IQR): \(IQR = Q3 - Q1\).lower_bound <- q1 - 1.5 * iqr: Tính Ranh giới dưới.upper_bound <- q3 + 1.5 * iqr: Tính Ranh giới trên.sum(x < lower_bound | x > upper_bound, na.rm = TRUE):

Đây là bước đếm số lượng ngoại lai. Hàm này đếm tổng số các giá trị x (trong cột hiện tại) mà nhỏ hơn ranh giới dưới HOẶC lớn hơn ranh giới trên.

Tỷ lệ dữ liệu ngoại lai tương đối thấp, với chỉ 8/18 biến có giá trị ngoại lai và số lượng ngoại lai trên mỗi biến rất ít (chỉ 1-2 giá trị).

2.2 XỬ LÍ DỮ LIỆU

2.2.1 Mô tả các biến bằng Hmisc

describe_data <- Hmisc::describe(ta %>% select(where(is.numeric)))
print(describe_data)
## ta %>% select(where(is.numeric)) 
## 
##  18  Variables      10  Observations
## --------------------------------------------------------------------------------
## year 
##        n  missing distinct     Info     Mean  pMedian      Gmd      .05 
##       10        0       10        1     2020     2020    3.667     2015 
##      .10      .25      .50      .75      .90      .95 
##     2016     2017     2020     2022     2023     2024 
##                                                             
## Value      2015 2016 2017 2018 2019 2020 2021 2022 2023 2024
## Frequency     1    1    1    1    1    1    1    1    1    1
## Proportion  0.1  0.1  0.1  0.1  0.1  0.1  0.1  0.1  0.1  0.1
## --------------------------------------------------------------------------------
## LoiNhuanSauThue 
##            n      missing     distinct         Info         Mean      pMedian 
##           10            0           10            1 185461493333 181111679615 
##          Gmd          .05          .10          .25          .50          .75 
##  93704691028  96273147591 100270945182 122690790997 175740780878 220079457774 
##          .90          .95 
## 301686644296 311274518689 
##                                                                            
## Value       92275349999 101159344647 117360040786 138683041628 162386686793
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
##                                                                            
## Value      189094874963 209696878289 223540317602 299556005542 320862393082
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
## --------------------------------------------------------------------------------
## Tien_DauKy 
##            n      missing     distinct         Info         Mean      pMedian 
##           10            0           10            1 138003577443 133343364894 
##          Gmd          .05          .10          .25          .50          .75 
##  70952273443  79640505514  84245396301  90913108017 106328850442 178771315328 
##          .90          .95 
## 198520275392 234896570384 
##                                                                            
## Value       75035614726  85268705365  87841659460 100127453686 106200569241
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
##                                                                            
## Value      106457131642 178550050326 178845070328 190436654283 271272865376
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
## --------------------------------------------------------------------------------
## Tien_CuoiKy 
##            n      missing     distinct         Info         Mean      pMedian 
##           10            0           10            1 136346904294 132736134505 
##          Gmd          .05          .10          .25          .50          .75 
##  69847824677  79640505514  84245396301  90913108017 106328850442 174629632455 
##          .90          .95 
## 198520275392 234896570384 
##                                                                            
## Value       75035614726  85268705365  87841659460 100127453686 106200569241
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
##                                                                            
## Value      106457131642 161983318837 178845070328 190436654283 271272865376
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
## --------------------------------------------------------------------------------
## CFO_Tong 
##            n      missing     distinct         Info         Mean      pMedian 
##           10            0           10            1 133427627649 108372552102 
##          Gmd          .05          .10          .25          .50          .75 
## 127539214837  13296038571  56900505807  75147789307  90931774710 195224287301 
##          .90          .95 
## 249253272581 313928337014 
##                                                                            
## Value      -30308428665  66590387415  73153422780  81130888888  84650650055
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
##                                                                            
## Value       97212899364 132094454149 216267565018 234881036040 378603401448
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
## --------------------------------------------------------------------------------
## KhauHao 
##           n     missing    distinct        Info        Mean     pMedian 
##          10           0          10           1 54126367933 49407339768 
##         Gmd         .05         .10         .25         .50         .75 
## 27299776648 30903890454 31292688495 37591382174 47284812141 60405515839 
##         .90         .95 
## 84941676100 95288951505 
##                                                                            
## Value       30515092412  31379088060  37320990534  38402557093  41208658249
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
##                                                                            
## Value       53360966033  60385696030  60412122442  82642281566 105636226909
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
## --------------------------------------------------------------------------------
## BienDong_PhaiThu 
##            n      missing     distinct         Info         Mean      pMedian 
##           10            0           10            1 -12166658588 -19991962534 
##          Gmd          .05          .10          .25          .50          .75 
##  65155095978 -74646713996 -65986443094 -55960084902 -14460118668  14742465394 
##          .90          .95 
##  31676644269  73718067463 
##                                                                            
## Value      -83306984898 -64061938449 -60835559336 -41333661601 -19991962534
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
##                                                                            
## Value       -8928274802  -1437631837  20135831138  22334105781 115759490658
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
## --------------------------------------------------------------------------------
## BienDong_TonKho 
##             n       missing      distinct          Info          Mean 
##            10             0            10             1  -41154397712 
##       pMedian           Gmd           .05           .10           .25 
##  -27689897272   93877850593 -177273252799  -93797267441  -61477533455 
##           .50           .75           .90           .95 
##  -34622213581    6516640084   50583938664   51491163272 
## 
## -260749238157 (1, 0.1), -75247048473 (1, 0.1), -66128977456 (1, 0.1),
## -47523201453 (1, 0.1), -43797978420 (1, 0.1), -25446448742 (1, 0.1),
## -6180988401 (1, 0.1), 10749182912 (1, 0.1), 50382333195 (1, 0.1), 52398387880
## (1, 0.1)
## --------------------------------------------------------------------------------
## BienDong_PhaiTra 
##            n      missing     distinct         Info         Mean      pMedian 
##           10            0           10            1  -7535274795  -7695765269 
##          Gmd          .05          .10          .25          .50          .75 
##  36086924875 -44642488855 -39759144624 -33029899635  -8277667477  16895829534 
##          .90          .95 
##  25176300029  32377985494 
##                                                                            
## Value      -49525833086 -38673957017 -35669331173 -25111605021 -13724008827
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
##                                                                            
## Value       -2831326127   6749916226  20277800636  23575925481  39579670960
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
## --------------------------------------------------------------------------------
## LaiVay_DaTra 
##           n     missing    distinct        Info        Mean     pMedian 
##          10           0          10           1 -3046559562 -2957747374 
##         Gmd         .05         .10         .25         .50         .75 
##  2690738115 -6074322471 -5448701040 -4413178073 -3598954722  -783020055 
##         .90         .95 
##  -550754067  -302954253 
##                                                                       
## Value      -6699943903 -5309674055 -4475116208 -4227363668 -3707340260
## Frequency            1           1           1           1           1
## Proportion         0.1         0.1         0.1         0.1         0.1
##                                                                       
## Value      -3490569184 -1275879713  -618733502  -605820692   -55154439
## Frequency            1           1           1           1           1
## Proportion         0.1         0.1         0.1         0.1         0.1
## --------------------------------------------------------------------------------
## Thue_DaNop 
##            n      missing     distinct         Info         Mean      pMedian 
##           10            0           10            1 -45519649979 -43083226117 
##          Gmd          .05          .10          .25          .50          .75 
##  23293691764 -78058454868 -72124893673 -56045224314 -41597605868 -31804605059 
##          .90          .95 
## -25722828392 -24051418356 
##                                                                            
## Value      -83992016063 -70806324518 -59623516944 -45310346424 -42339105925
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
##                                                                            
## Value      -40856105810 -32083024291 -31711798648 -26094252845 -22380008319
## Frequency             1            1            1            1            1
## Proportion          0.1          0.1          0.1          0.1          0.1
## --------------------------------------------------------------------------------
## CFI_Tong 
##             n       missing      distinct          Info          Mean 
##            10             0            10             1 -130736762123 
##       pMedian           Gmd           .05           .10           .25 
## -123702553600  152761727925 -335958772046 -228670611284 -183596885752 
##           .50           .75           .90           .95 
## -123911128404  -56861445623   -5917280452   31988491020 
## 
## -443246932809 (1, 0.1), -204828797781 (1, 0.1), -199303865931 (1, 0.1),
## -136475945213 (1, 0.1), -127199192457 (1, 0.1), -120623064351 (1, 0.1),
## -83142058686 (1, 0.1), -48101241268 (1, 0.1), -14340785224 (1, 0.1),
## 69894262492 (1, 0.1)
## --------------------------------------------------------------------------------
## Chi_MuaTSCD 
##             n       missing      distinct          Info          Mean 
##            10             0            10             1 -130057173899 
##       pMedian           Gmd           .05           .10           .25 
## -107902193225   82834794453 -273549149043 -272641683216 -127456519988 
##           .50           .75           .90           .95 
## -101628608786  -91456180145  -62462345838  -57659516571 
## 
## -274456614870 (1, 0.1), -272440024143 (1, 0.1), -131124961007 (1, 0.1),
## -116451196931 (1, 0.1), -103904028053 (1, 0.1), -99353189519 (1, 0.1),
## -96770733614 (1, 0.1), -89684662322 (1, 0.1), -63529641231 (1, 0.1),
## -52856687303 (1, 0.1)
## --------------------------------------------------------------------------------
## Chi_TienGui 
##             n       missing      distinct          Info          Mean 
##            10             0            10             1 -198920800808 
##       pMedian           Gmd           .05           .10           .25 
## -197500000000  193215909957 -420494369000 -389817158000 -335047275000 
##           .50           .75           .90           .95 
## -176494739041  -57862937500  -20550000000  -16275000000 
## 
## -451171580000 (1, 0.1), -383000000000 (1, 0.1), -357729700000 (1, 0.1),
## -267000000000 (1, 0.1), -247049478082 (1, 0.1), -105940000000 (1, 0.1),
## -100000000000 (1, 0.1), -43817250000 (1, 0.1), -21500000000 (1, 0.1),
## -12000000000 (1, 0.1)
## --------------------------------------------------------------------------------
## Thu_TienGui 
##            n      missing     distinct         Info         Mean      pMedian 
##            9            1            9            1 204128349936 200423323415 
##          Gmd 
## 169716617638 
##                                                                            
## Value       26297761332  47675066830 100000000000 183075000000 195897929613
## Frequency             1            1            1            1            1
## Proportion        0.111        0.111        0.111        0.111        0.111
##                                                               
## Value      218000000000 221737811648 353171580000 491300000000
## Frequency             1            1            1            1
## Proportion        0.111        0.111        0.111        0.111
## --------------------------------------------------------------------------------
## CFF_Tong 
##            n      missing     distinct         Info         Mean      pMedian 
##            9            1            9            1  -4797122112 -13433724080 
##          Gmd 
## 185363554013 
## 
## -271718144243 (1, 0.111), -112229740937 (1, 0.111), -61363261179 (1, 0.111),
## -58008892000 (1, 0.111), -33304800015 (1, 0.111), 32990722640 (1, 0.111),
## 34495813019 (1, 0.111), 73592405403 (1, 0.111), 352371798300 (1, 0.111)
## --------------------------------------------------------------------------------
## VayMoi 
##            n      missing     distinct         Info         Mean      pMedian 
##            9            1            9            1 142392327092 162817118595 
##          Gmd 
## 220894300500 
## 
## -315649453686 (1, 0.111), 59802742133 (1, 0.111), 95894850000 (1, 0.111),
## 120000000000 (1, 0.111), 160076187844 (1, 0.111), 218888228325 (1, 0.111),
## 229739387189 (1, 0.111), 324785490153 (1, 0.111), 387993511872 (1, 0.111)
## --------------------------------------------------------------------------------
## TraNoGoc 
##             n       missing      distinct          Info          Mean 
##             9             1             9             1 -183894915875 
##       pMedian           Gmd 
## -181308771504  111059252054 
## 
## -351293662887 (1, 0.111), -275297558126 (1, 0.111), -231513531376 (1, 0.111),
## -190282322134 (1, 0.111), -181308771504 (1, 0.111), -160076187844 (1, 0.111),
## -120000000000 (1, 0.111), -95894850000 (1, 0.111), -49387359000 (1, 0.111)
## --------------------------------------------------------------------------------

Mô tả chi tiết các biến số tài chính dạng số, được tạo ra bằng hàm describe(), cung cấp thông tin thống kê chuyên sâu hơn, bao gồm:

  • số quan sát (n) .
  • số lượng giá trị bị thiếu (missing).
  • số lượng giá trị duy nhất (distinct).
  • độ tin cậy của ước tính (Info).
  • trung bình (Mean), độ lệch trung bình Gini (Gmd).
  • và các giá trị phân vị chi tiết (.05 đến .95).

Khả năng sinh lời Lợi nhuận sau thuế (LoiNhuanSauThue) cho thấy xu hướng tăng trưởng mạnh mẽ và liên tục. Giá trị trung bình đạt 185.461 tỷ đồng và trung vị là 181.112 tỷ đồng, cho thấy sự phân bố khá cân đối. Điều đáng chú ý là giá trị nhỏ nhất là 92.275 tỷ đồng (2015) và lớn nhất lên tới 320.862 tỷ đồng (2024), phản ánh quy mô lợi nhuận được mở rộng đáng kể sau 10 năm.

Dòng tiền hoạt động (CFO) & Chi phí Dòng tiền từ hoạt động kinh doanh (CFO_Tong) có trung bình tích cực (133.428 tỷ đồng) nhưng biến động rất lớn (Gmd = 127.539 tỷ đồng), từ mức âm sâu -30.308 tỷ đồng đến mức dương kỷ lục 378.603 tỷ đồng. Điều này cho thấy khả năng tạo tiền không ổn định. Chi phí khấu hao (KhauHao) có xu hướng tăng đều qua các năm, với giá trị trung bình n Đây là điểm nghẽn đáng quan tâm: - Biến động phải thu (BienDong_PhaiThu): Trung bình âm ở -12.167 tỷ đồng, dao động từ -83.307 tỷ đến +115.759 tỷ đồng, cho thấy có những năm doanh nghiệp bị chiếm dụng vốn rất lớn. - Biến động tồn kho (BienDong_TonKho): Trung bình âm sâu ở -41.154 tỷ đồng, với biên độ rất rộng (từ -260.749 tỷ đến +52.398 tỷ đồng), phản ánh sự bất ổn trong quản lý hàng tồn kho. - Biến động phải trả (BienDong_PhaiTra): Trung bình âm (-7.535 tỷ đồng), cho thấy áp lực thanh toán cho nhà cung cấp.

Hoạt động đầu tư (CFI) Dòng tiền đầu tư (CFI_Tong) chủ yếu là âm (trung bình -130.737 tỷ đồng), khẳng định chiến lược đầu tư mở rộng liên tục. Các khoản chi chính bao gồm: - Chi mua TSCD (Chi_MuaTSCD): Trung bình -130.057 tỷ đồng. - Chi tiền gửi (Chi_TienGui): Trung bình -198.921 tỷ đồng, một khoản đầu tư tài chính đáng kể. - Thu tiền gửi (Thu_TienGui): Có trung bình dương (204.128 tỷ đồng), cho thấy hoạt động thu hồi các khoản đầu tư này cũng diễn ra thường xuyên.

Hoạt động tài trợ (CFF) & Cơ cấu nợ - Dòng tiền tài trợ (CFF_Tong): Trung bình gần bằng 0 (-4.797 tỷ đồng) nhưng biến động cực lớn, từ -271.718 tỷ đến +352.372 tỷ đồng, phản ánh sự thay đổi thất thường trong cơ cấu vốn. - Vay mới (VayMoi): Trung bình 142.392 tỷ đồng, cho thấy nhu cầu vay liên tục để tài trợ. - Trả nợ gốc (TraNoGoc): Trung bình -183.895 tỷ đồng, lớn hơn cả vay mới, chứng tỏ doanh nghiệp có chính sách quản lý nợ chủ động, ưu tiên giảm đòn bẩy.

2.2.2 Phân loại biến theo tính chất

variable_types <- data.frame(
  Bien = names(ta),
  Kieu = sapply(ta, class),
  So_NA = colSums(is.na(ta)),
  So_Gia_Tri_Duy_Nhat = sapply(ta, function(x) length(unique(x)))
)
kable(variable_types, caption = "PHÂN LOẠI BIẾN TRONG BỘ DỮ LIỆU")
PHÂN LOẠI BIẾN TRONG BỘ DỮ LIỆU
Bien Kieu So_NA So_Gia_Tri_Duy_Nhat
year year numeric 0 10
LoiNhuanSauThue LoiNhuanSauThue numeric 0 10
Tien_DauKy Tien_DauKy numeric 0 10
Tien_CuoiKy Tien_CuoiKy numeric 0 10
CFO_Tong CFO_Tong numeric 0 10
KhauHao KhauHao numeric 0 10
BienDong_PhaiThu BienDong_PhaiThu numeric 0 10
BienDong_TonKho BienDong_TonKho numeric 0 10
BienDong_PhaiTra BienDong_PhaiTra numeric 0 10
LaiVay_DaTra LaiVay_DaTra numeric 0 10
Thue_DaNop Thue_DaNop numeric 0 10
CFI_Tong CFI_Tong numeric 0 10
Chi_MuaTSCD Chi_MuaTSCD numeric 0 10
Chi_TienGui Chi_TienGui numeric 0 10
Thu_TienGui Thu_TienGui numeric 1 10
CFF_Tong CFF_Tong numeric 1 10
VayMoi VayMoi numeric 1 10
TraNoGoc TraNoGoc numeric 1 10

names(): Lấy ra danh sách tên các cột (biến) trong tập dữ liệu ta.

sapply(…, class): Xác định kiểu dữ liệu (ví dụ: numeric, character) cho từng cột trong ta.

colSums(is.na(…)): Đếm số lượng giá trị bị thiếu (NA) trong từng cột.

sapply(…, unique): Đếm số lượng giá trị duy nhất (distinct) cho từng cột.

Về cấu trúc và độ bao phủ của dữ liệu: Bộ dữ liệu bao gồm 18 biến số (numeric), ghi nhận thông tin tài chính trong vòng 10 năm liên tục (từ 2015 đến 2024). Một điểm đáng chú ý là tất cả các biến đều có đúng 10 giá trị duy nhất, tương ứng với mỗi năm, cho thấy dữ liệu được thu thập một cách nhất quán, không có sự trùng lặp hay thiếu sót theo trục thời gian.

Về tính toàn vẹn và chất lượng: Chất lượng dữ liệu được đánh giá là rất tốt khi có tới 15/18 biến hoàn toàn không chứa giá trị thiếu (NA). Chỉ có 4 biến là Thu_TienGui, CFF_Tong, VayMoiTraNoGoc là có 1 giá trị thiếu. Tỷ lệ hoàn chỉnh cao này đảm bảo độ tin cậy cho hầu hết các phân tích, và việc xử lý số ít giá trị thiếu kia cũng sẽ không gây khó khăn đáng kể.

Về ý nghĩa và cách phân nhóm biến: Các biến được thiết kế một cách có hệ thống, phản ánh toàn diện bức tranh tài chính của doanh nghiệp. Có thể phân loại chúng thành các nhóm ý nghĩa kinh tế rõ rệt: nhóm chỉ tiêu kết quả kinh doanh (như lợi nhuận, khấu hao), nhóm dòng tiền (hoạt động, đầu tư, tài trợ), nhóm vốn lưu động (các khoản phải thu, phải trả, tồn kho), nhóm thuế và chi phí tài chính, và nhóm huy động vốn (vay mới, trả nợ gốc).

Về tiềm năng khai thác và phân tích: Với cấu trúc hoàn chỉnh và đa dạng chỉ tiêu như trên, bộ dữ liệu này mở ra nhiều hướng phân tích chuyên sâu. Nó rất phù hợp để phân tích xu hướng biến động của các chỉ số tài chính qua 10 năm, đánh giá mối quan hệ nhân quả giữa các hoạt động (như tác động của đầu tư đến lợi nhuận), kiểm tra hiệu quả quản lý vốn lưu động, hoặc thậm chí xây dựng các mô hình dự báo cho tương lai.

2.2.3 Tổng quan giá trị theo năm

year_summary <- ta %>%
  group_by(year) %>%
  summarise(
    So_Bien = n(),
    Tong_Loi_Nhuan = sum(LoiNhuanSauThue, na.rm = TRUE),
    Tong_CFO = sum(CFO_Tong, na.rm = TRUE)
  ) %>%
  mutate(Phan_Tram_Loi_Nhuan = Tong_Loi_Nhuan/sum(Tong_Loi_Nhuan)*100)
kable(year_summary, caption = "TỔNG QUAN GIÁ TRỊ THEO NĂM")
TỔNG QUAN GIÁ TRỊ THEO NĂM
year So_Bien Tong_Loi_Nhuan Tong_CFO Phan_Tram_Loi_Nhuan
2015 1 92275349999 81130888888 4.975445
2016 1 101159344647 84650650055 5.454466
2017 1 117360040786 97212899364 6.328000
2018 1 138683041628 132094454149 7.477727
2019 1 162386686793 66590387415 8.755817
2020 1 209696878289 73153422780 11.306761
2021 1 189094874963 234881036040 10.195910
2022 1 223540317602 378603401448 12.053193
2023 1 299556005542 -30308428665 16.151925
2024 1 320862393082 216267565018 17.300755

summarise()Tạo ra bảng tổng hợp với các cột mới

So_Bien = n()Đếm số lượng quan sát trong mỗi nhóm năm (luôn là 1, vì dữ liệu đã là hàng năm).

Tong_Loi_Nhuan = sum(LoiNhuanSauThue, na.rm = TRUE)Tính Tổng Lợi nhuận Sau Thuế cho mỗi năm.

Tong_CFO = sum(CFO_Tong, na.rm = TRUE)Tính Tổng Dòng tiền từ Hoạt động Kinh doanh (CFO) cho mỗi năm.

mutate(…)mutate()Tạo một cột mới: Phần trăm Lợi nhuận.

Phan_Tram_Loi_Nhuan = Tong_Loi_Nhuan / sum(Tong_Loi_Nhuan) x 100

Tính Tỷ trọng Lợi nhuận của năm đó so với Tổng Lợi nhuận của toàn bộ 10 năm của công ty (kết quả đã được chia cho tổng lợi nhuận của toàn bộ tập dữ liệu, sau đó nhân 100).

Về tổng lợi nhuận sau thuế: Doanh nghiệp thể hiện đà tăng trưởng lợi nhuận sau thuế liên tục và rất ấn tượng trong suốt 10 năm. Từ mức 92.275 tỷ đồng năm 2015, lợi nhuận đã tăng lên hơn 320.862 tỷ đồng vào năm 2024, tăng gấp khoảng 3.5 lần. Tốc độ tăng trưởng đặc biệt mạnh mẽ trong giai đoạn 2020-2024, giúp tỷ trọng lợi nhuận năm 2024 chiếm tới 17.3% tổng lợi nhuận cả giai đoạn.

Về dòng tiền hoạt động (CFO): Dòng tiền từ hoạt động kinh doanh có diễn biến phức tạp hơn. Giai đoạn 2015-2018 chứng kiến CFO tăng trưởng ổn định và đạt đỉnh 132.094 tỷ đồng năm 2018. Tuy nhiên, năm 2019 và 2020 ghi nhận sự sụt giảm đáng kể. Đặc biệt, năm 2023 là một dấu hiệu bất thường nghiêm trọng khi CFO rơi vào trạng thái âm (-30.308 tỷ đồng), phản ánh khủng hoảng trong khả năng tạo tiền từ hoạt động cốt lõi. May mắn thay, đến năm 2024, CFO đã phục hồi mạnh mẽ lên 216.267 tỷ đồng.

Về mối quan hệ giữa lợi nhuận và dòng tiền: Sự chênh lệch lớn giữa lợi nhuận và dòng tiền ở một số năm (như 2019, 2020, 2023) cho thấy chất lượng lợi nhuận có vấn đề. Lợi nhuận cao không đồng nghĩa với tiền mặt tốt, có thể do doanh nghiệp ghi nhận doanh thu nhưng chưa thu được tiền (phải thu tăng) hoặc hàng tồn kho tích trữ nhiều. Ngược lại, năm 2021 và 2022 là những năm dòng tiền hoạt động vượt trội hơn hẳn so với lợi nhuận, cho thấy khả năng quản lý vốn lư động hiệu quả trong các năm này.

2.2.4 Top 5 Lợi nhuận sau thuế cao nhất

ta %>% top_n(5, LoiNhuanSauThue) %>% select(year, LoiNhuanSauThue) %>% kable()
year LoiNhuanSauThue
2020 209696878289
2021 189094874963
2022 223540317602
2023 299556005542
2024 320862393082

Dùng hàm top_n() để lọc ra 5 năm có lợi nhuận sau thuế cao nhất.

2.2.5 Làm sạch tên biến

ta_clean <- ta %>% clean_names() 
names(ta_clean)
##  [1] "year"               "loi_nhuan_sau_thue" "tien_dau_ky"       
##  [4] "tien_cuoi_ky"       "cfo_tong"           "khau_hao"          
##  [7] "bien_dong_phai_thu" "bien_dong_ton_kho"  "bien_dong_phai_tra"
## [10] "lai_vay_da_tra"     "thue_da_nop"        "cfi_tong"          
## [13] "chi_mua_tscd"       "chi_tien_gui"       "thu_tien_gui"      
## [16] "cff_tong"           "vay_moi"            "tra_no_goc"

2.2.6 Xử lý dữ liệu bị thiếu

colSums(is.na(ta_clean)) %>% kable()
x
year 0
loi_nhuan_sau_thue 0
tien_dau_ky 0
tien_cuoi_ky 0
cfo_tong 0
khau_hao 0
bien_dong_phai_thu 0
bien_dong_ton_kho 0
bien_dong_phai_tra 0
lai_vay_da_tra 0
thue_da_nop 0
cfi_tong 0
chi_mua_tscd 0
chi_tien_gui 0
thu_tien_gui 1
cff_tong 1
vay_moi 1
tra_no_goc 1
ta_clean1 <- ta_clean %>%
  mutate(across(where(is.numeric), 
                ~ifelse(is.na(.), median(., na.rm = TRUE), .)))

colSums(is.na(ta_clean1)) %>% kable()
x
year 0
loi_nhuan_sau_thue 0
tien_dau_ky 0
tien_cuoi_ky 0
cfo_tong 0
khau_hao 0
bien_dong_phai_thu 0
bien_dong_ton_kho 0
bien_dong_phai_tra 0
lai_vay_da_tra 0
thue_da_nop 0
cfi_tong 0
chi_mua_tscd 0
chi_tien_gui 0
thu_tien_gui 0
cff_tong 0
vay_moi 0
tra_no_goc 0

Kiểm tra lại các giá trị bị thiếu và thay bằng trung vị.

2.2.7 Chuẩn hóa dữ liệu số

ta_clean1 <- ta_clean1 %>%
  mutate(across(where(is.numeric), 
                list(
                  standardized = ~scale(.),
                  log_transformed = ~log(abs(.) + 1)
                )))

%>% (Pipe): Tiếp tục xử lý trên tập dữ liệu đã được làm sạch trước đó (ta_clean1).

mutate(): Thêm các cột mới (biến đã được biến đổi) vào tập dữ liệu ta_clean1.

across(…, where(is.numeric)): Áp dụng các hàm biến đổi sau cho tất cả các cột có kiểu dữ liệu là số (is.numeric).

scale()Chuẩn hóa (Standardization): Biến đổi dữ liệu sao cho Mean (Trung bình) bằng 0 và Standard Deviation (Độ lệch chuẩn) bằng 1.

log(abs(.) + 1): Áp dụng phép toán logarit tự nhiên để giảm độ lệch (skewness) của phân phối. Việc sử dụng abs(.) + 1 là để: - Đảm bảo dữ liệu luôn dương (abs(.) vì dữ liệu tài chính có thể âm, ví dụ: Chi phí, Dòng tiền Đầu tư).

  • Tránh lỗi log(0) (vì \(\ln(1)=0\)).

2.2.8 Tạo biến mới - Kiểm tra cân đối Báo cáo lưu chuyển tiền tệ

ta_clean1 <- ta_clean1 %>%
  mutate(bien_dong_tien_rong = tien_cuoi_ky - tien_dau_ky,
         KiemTra_BaoCaoLuuChuyenTienTe = cff_tong + cfi_tong + cfo_tong)

ta_clean1 <- ta_clean1 %>%
  mutate(ChenhLech = if_else(bien_dong_tien_rong == KiemTra_BaoCaoLuuChuyenTienTe, 
                                     0, 
                                     bien_dong_tien_rong - KiemTra_BaoCaoLuuChuyenTienTe))
kable(ta_clean1 %>% select(year, bien_dong_tien_rong, KiemTra_BaoCaoLuuChuyenTienTe, ChenhLech))
year bien_dong_tien_rong KiemTra_BaoCaoLuuChuyenTienTe ChenhLech
2015 -90708390866 -90707186253 -1204613
2016 12285794226 12300972831 -15178605
2017 6329677956 6337764855 -8086899
2018 83979522641 50688412866 33291109775
2019 -115401039557 -115395938115 -5101442
2020 10233090639 10269882970 -36792331
2021 186004160011 186234790373 -230630362
2022 -92427795048 -92418608726 -9186322
2023 -72644501087 -72643907110 -593977
2024 55782749596 55763572546 19177050

Chênh lệch nhỏ (Hầu hết các năm):

Hầu hết các năm (ví dụ: 2015, 2023), giá trị ChênhLệch rất nhỏ (-1.2 triệu VNĐ hoặc -0.5 triệu VNĐ).

Ý nghĩa: Điều này xác nhận rằng dữ liệu tiền tệ được thu thập có tính nhất quán cao; sự khác biệt nhỏ này thường là do sai số làm tròn trong quá trình tính toán hoặc báo cáo.

Chênh lệch lớn (Năm 2018):

Năm 2018, giá trị ChênhLệch là 33.29 tỷ VNĐ.

Ý nghĩa: Đây là một sai số lớn trong bối cảnh dữ liệu này. Nó có nghĩa là Biến động Tiền Ròng theo Bảng Cân đối Kế toán (83.97 tỷ VNĐ) không khớp với Tổng Dòng tiền từ 3 hoạt động (50.68 tỷ VNĐ).

2.2.9 Tạo biến Dòng tiền tự do

ta_clean1 <- ta_clean1 %>%
  mutate(DongTienTuDo = cfo_tong + chi_mua_tscd)
kable(ta_clean1 %>% select(year, DongTienTuDo))
year DongTienTuDo
2015 -35320308043
2016 -19253377998
2017 -177243715506
2018 -140345569994
2019 -64534573592
2020 -16531239542
2021 182024348737
2022 279250211929
2023 -93838069896
2024 119496831404

Giai đoạn FCF Âm (2015 - 2020):

FCF chủ yếu âm sâu trong giai đoạn này (ví dụ: -353 tỷ VNĐ năm 2015).

Ý nghĩa: Công ty đang trong giai đoạn tăng trưởng và mở rộng mạnh mẽ. Mặc dù hoạt động kinh doanh tạo ra tiền (CFO dương), nhưng chi tiêu cho tài sản cố định (Chi_MuaTSCD) quá lớn (âm mạnh, Mean -1,300 tỷ VNĐ), vượt quá khả năng tạo ra tiền mặt của hoạt động kinh doanh. Điều này buộc công ty phải dùng tiền mặt dự trữ hoặc đi vay để tài trợ cho việc mở rộng này.

Giai đoạn FCF Dương (2021 - 2022 và 2024):

FCF chuyển sang dương lớn (ví dụ: 182 tỷ VNĐ năm 2021 và 119 tỷ VNĐ năm 2024).

Ý nghĩa: Công ty đã hoàn tất một phần lớn giai đoạn đầu tư ban đầu và tài sản mới bắt đầu tạo ra dòng tiền lớn hơn chi phí duy trì hoặc đầu tư thêm. FCF dương cho thấy công ty có tiền mặt sẵn sàng để trả cổ tức, mua lại cổ phiếu, hoặc giảm nợ (phù hợp với việc TraNoGoc âm mạnh).

FCF Âm trở lại (Năm 2023):

FCF chuyển sang âm -93.8 tỷ VNĐ trong năm 2023.

Ý nghĩa: Điều này có thể do một đợt chi tiêu vốn lớn khác trong năm đó, hoặc do CFO âm bất thường trong năm 2023 (như đã thấy trong phân tích CFO trước đó), làm giảm mạnh khả năng tài trợ vốn đầu tư bằng tiền mặt nội bộ.

2.2.10 Mã hóa dữ liệu - Xu hướng lợi nhuận

ta_clean1 <- ta_clean1 %>% 
  mutate(TangGiam_LoiNhuan = ifelse(loi_nhuan_sau_thue > lag(loi_nhuan_sau_thue), "Tang", "Giam"))
kable(ta_clean1 %>% select(year, loi_nhuan_sau_thue, TangGiam_LoiNhuan))
year loi_nhuan_sau_thue TangGiam_LoiNhuan
2015 92275349999 NA
2016 101159344647 Tang
2017 117360040786 Tang
2018 138683041628 Tang
2019 162386686793 Tang
2020 209696878289 Tang
2021 189094874963 Giam
2022 223540317602 Tang
2023 299556005542 Tang
2024 320862393082 Tang

Năm 2015: Kết quả là NA vì không có dữ liệu năm trước để so sánh (hàm lag() không có giá trị ở hàng đầu tiên).

Xu hướng chung: Lợi nhuận có xu hướng Tăng trưởng liên tục trong hầu hết các năm, đặc biệt là giai đoạn 2016-2020 và 2022-2024.

Sự sụt giảm: Có một sự sụt giảm lợi nhuận xảy ra vào năm 2021 (“Giam”), sau đó lợi nhuận lại tiếp tục tăng mạnh trở lại.

Ý nghĩa: Sự sụt giảm trong năm 2021 có thể phản ánh tác động của các yếu tố kinh tế vĩ mô (ví dụ: đại dịch COVID-19) hoặc chu kỳ kinh doanh, nhưng công ty đã nhanh chóng phục hồi và đạt mức lợi nhuận kỷ lục vào các năm tiếp theo (2023 và 2024).

Kết luận: Phân tích này khẳng định xu hướng tăng trưởng lợi nhuận bền vững trong dài hạn, chỉ bị gián đoạn nhẹ trong một năm.

2.2.11 Mã hóa chiến lược nợ

ta_clean1 <- ta_clean1 %>% 
  mutate(VayRong = vay_moi + tra_no_goc,
    ChinhSachNo = case_when(
      VayRong > 0 ~ "Vay Them",
      VayRong < 0 ~ "Tra No", 
      TRUE        ~ "Can Bang" ))
kable(ta_clean1 %>% select(year, vay_moi, tra_no_goc, VayRong, ChinhSachNo))
year vay_moi tra_no_goc VayRong ChinhSachNo
2015 95894850000 -95894850000 0 Can Bang
2016 160076187844 -181308771504 -21232583660 Tra No
2017 120000000000 -120000000000 0 Can Bang
2018 160076187844 -160076187844 0 Can Bang
2019 218888228325 -181308771504 37579456821 Vay Them
2020 -315649453686 -49387359000 -365036812686 Tra No
2021 324785490153 -190282322134 134503168019 Vay Them
2022 59802742133 -231513531376 -171710789243 Tra No
2023 229739387189 -275297558126 -45558170937 Tra No
2024 387993511872 -351293662887 36699848985 Vay Them

Giai đoạn “Cân Bằng” (2015, 2017, 2018):

Công ty duy trì mức nợ ổn định khi khoản Vay Mới và Trả Nợ Gốc gần như triệt tiêu nhau, dẫn đến VayRong bằng 0.

Giai đoạn “Trả Nợ” (2016, 2020, 2022, 2023):

Chiếm đa số các năm (4/10 năm), đặc biệt là năm 2020 và 2023, công ty chi trả nợ gốc nhiều hơn khoản vay mới. Điều này phù hợp với việc công ty có Dòng tiền Tự Do dương (hoặc sắp dương) trong giai đoạn sau 2020, ưu tiên giảm gánh nặng nợ.

Giai đoạn “Vay Thêm” (2019, 2021, 2024):

Có 3 năm công ty Vay Thêm (Vay Ròng dương).

Ý nghĩa: Việc vay thêm diễn ra trong các năm có nhu cầu chi tiêu vốn lớn (Chi mua TSCĐ) hoặc để tài trợ cho các dự án mở rộng, cho thấy công ty vẫn linh hoạt trong việc sử dụng đòn bẩy khi cần thiết.

Kết luận: Chiến lược nợ của công ty chủ yếu là thận trọng và linh hoạt. Công ty có xu hướng giảm nợ (Tra No) khi có dòng tiền mạnh, nhưng sẵn sàng vay thêm (Vay Them) để tài trợ cho các cơ hội đầu tư và mở rộng.

2.2.12 Mã hóa xu hướng tồn kho

ta_clean1 <- ta_clean1 %>% 
  mutate(XuHuong_TonKho = case_when(
    bien_dong_ton_kho > 0 ~ "Tang",
    bien_dong_ton_kho < 0 ~ "Giam",
    TRUE                   ~ "On Dinh"
  ))
kable(ta_clean1 %>% select(year, bien_dong_ton_kho, XuHuong_TonKho))
year bien_dong_ton_kho XuHuong_TonKho
2015 50382333195 Tang
2016 10749182912 Tang
2017 -47523201453 Giam
2018 -43797978420 Giam
2019 -25446448742 Giam
2020 -75247048473 Giam
2021 -66128977456 Giam
2022 52398387880 Tang
2023 -260749238157 Giam
2024 -6180988401 Giam

Xu hướng: Biến động Tồn kho chuyển sang “Giảm” liên tục trong giai đoạn 2017-2021 và 2023-2024, cho thấy công ty quản lý và tiêu thụ hàng tồn kho rất hiệu quả.

2.2.13 Mã hóa biến định tính mới

ta_clean1 <- ta_clean1 %>%
  mutate(
    Quy_Trong_Nam = case_when(
      year %% 4 == 0 ~ "Năm nhuận",
      TRUE ~ "Năm thường"
    ),
    Giai_Doan_Phat_Trien = case_when(
      year <= 2017 ~ "Giai đoạn ổn định",
      year <= 2020 ~ "Giai đoạn tăng trưởng", 
      year <= 2023 ~ "Giai đoạn biến động",
      TRUE ~ "Giai đoạn phục hồi"
    )
  )

Kiểm soát Yếu tố Thời gian: Biến Quy_Trong_Nam giúp kiểm soát ảnh hưởng của số ngày khác biệt trong năm (366 ngày so với 365 ngày) đối với các chỉ số doanh thu/lợi nhuận/dòng tiền.

Mô hình hóa Hành vi: Biến Giai_Doan_Phat_Trien cho phép các mô hình hồi quy hoặc phân tích thống kê kiểm tra xem hành vi tài chính (ví dụ: chi tiêu vốn, chiến lược nợ) có thay đổi đáng kể qua các giai đoạn phát triển kinh doanh đã được định nghĩa hay không.

2.2.14 Phân tổ dữ liệu - Lợi nhuận theo phân vị

ta_clean1 <- ta_clean1 %>%
  mutate(muc_loi_nhuan = cut2(loi_nhuan_sau_thue, g = 3, levels.only = FALSE)) %>% 
  mutate(muc_loi_nhuan = case_when(
    muc_loi_nhuan == levels(muc_loi_nhuan)[1] ~ "Thấp",
    muc_loi_nhuan == levels(muc_loi_nhuan)[2] ~ "Trung bình",
    muc_loi_nhuan == levels(muc_loi_nhuan)[3] ~ "Cao",
    TRUE ~ as.character(muc_loi_nhuan)
  ))
kable(ta_clean1 %>% select(year, loi_nhuan_sau_thue, muc_loi_nhuan))
year loi_nhuan_sau_thue muc_loi_nhuan
2015 92275349999 Thấp
2016 101159344647 Thấp
2017 117360040786 Thấp
2018 138683041628 Thấp
2019 162386686793 Trung bình
2020 209696878289 Trung bình
2021 189094874963 Trung bình
2022 223540317602 Cao
2023 299556005542 Cao
2024 320862393082 Cao

Giai đoạn Lợi nhuận “Thấp” (2015-2018): Đây là giai đoạn đầu của tập dữ liệu. Mặc dù công ty đã có lãi, mức lợi nhuận vẫn nằm trong nhóm thấp nhất so với chính công ty trong 10 năm.

Giai đoạn Lợi nhuận “Trung bình” (2019-2021): Lợi nhuận đã tăng lên và ổn định ở mức giữa.

Giai đoạn Lợi nhuận “Cao” (2022-2024): Công ty đã đạt được hiệu suất kinh doanh vượt trội, với lợi nhuận nằm trong nhóm cao nhất. Điều này khẳng định xu hướng tăng trưởng lợi nhuận mạnh mẽ và bền vững trong những năm gần đây.

Ý nghĩa: Phân tổ này giúp phân tích tác động của các yếu tố kinh tế (ví dụ: Chiến lược Nợ, FCF) lên các mức lợi nhuận khác nhau, thay vì chỉ dựa vào giá trị tuyệt đối.

2.2.15 Phân tổ hàng tồn kho theo trung bình

ta_clean1 <- ta_clean1 %>%
  mutate(muc_ton_kho = ifelse(bien_dong_ton_kho < mean(bien_dong_ton_kho), "Thap", "Cao"))
kable(ta_clean1 %>% select(year, bien_dong_ton_kho, muc_ton_kho))
year bien_dong_ton_kho muc_ton_kho
2015 50382333195 Cao
2016 10749182912 Cao
2017 -47523201453 Thap
2018 -43797978420 Thap
2019 -25446448742 Cao
2020 -75247048473 Thap
2021 -66128977456 Thap
2022 52398387880 Cao
2023 -260749238157 Thap
2024 -6180988401 Cao

Giai đoạn “Cao” (2015, 2016, 2022, 2024): Trong các năm này, tồn kho có xu hướng tăng nhẹ (dương) hoặc giảm không đáng kể so với mức giảm trung bình 10 năm. Ví dụ, năm 2015-2016, tồn kho tăng (dương), được xếp vào nhóm “Cao” vì lớn hơn Mean -41.15 tỷ VNĐ. Năm 2024 có giá trị -6,180,988,401 (khoảng -6.18 tỷ VNĐ), cũng lớn hơn Mean -41.15 tỷ VNĐ, cho thấy tồn kho giảm rất nhẹ.

Giai đoạn “Thấp” (2017-2021, 2023): Trong các năm này, tồn kho có xu hướng giảm rất mạnh (các giá trị đều âm sâu, nhỏ hơn Mean -41.15 tỷ VNĐ). Đặc biệt năm 2023 là -260.7 tỷ VNĐ, cho thấy hoạt động bán hàng hoặc thanh lý tồn kho diễn ra cực kỳ hiệu quả trong những năm này.

Phân tổ này giúp thấy rõ sự khác biệt trong quản lý tồn kho: Giai đoạn sau 2017 công ty có vẻ quản lý tồn kho chặt chẽ và bán hàng hiệu quả hơn, chỉ bị gián đoạn nhẹ bởi năm 2022.

2.3 CÁC THỐNG KÊ CƠ BẢN

2.3.1 Lợi nhuận sau thuế

ta_clean1 %>%
  summarise(
    Mean = mean(loi_nhuan_sau_thue) / 1000000,
    Median = median(loi_nhuan_sau_thue) / 1000000,
    SD = sd(loi_nhuan_sau_thue) / 1000000,
    Variance = var(loi_nhuan_sau_thue) / 1000000,
    Min = min(loi_nhuan_sau_thue) / 1000000,
    Max = max(loi_nhuan_sau_thue) / 1000000,
    Range = Max - Min
  ) %>% kable(caption = "THỐNG KÊ LỢI NHUẬN SAU THUẾ")
THỐNG KÊ LỢI NHUẬN SAU THUẾ
Mean Median SD Variance Min Max Range
185461.5 175740.8 79267.83 6283389026124500 92275.35 320862.4 228587

summarise(): Tính toán các chỉ số thống kê từ cột loi_nhuan_sau_thue của tập dữ liệu.

mean(): Tính giá trị trung bình (Mean) của lợi nhuận.

median(): Tính giá trị trung vị (Median) của lợi nhuận.

sd(): Tính độ lệch chuẩn (Standard Deviation – SD), đo lường độ phân tán của dữ liệu.

var(): Tính phương sai (Variance), bình phương của độ lệch chuẩn.

min(): Tìm giá trị nhỏ nhất (Minimum) của lợi nhuận.

max(): Tìm giá trị lớn nhất (Maximum) của lợi nhuận.

Phép trừ: Tính phạm vi (Range), khoảng cách giữa giá trị lớn nhất và nhỏ nhất.

Mean (Trung bình): Lợi nhuận trung bình trong 10 năm là khoảng 1,855 tỷ VNĐ.

Median (Trung vị): Giá trị nằm giữa là 1,757 tỷ VNĐ. Giá trị này gần Mean, cho thấy phân phối khá đối xứng và không bị ảnh hưởng mạnh bởi ngoại lai.

SD (Độ lệch chuẩn): Lợi nhuận có độ lệch chuẩn lớn (khoảng 793 tỷ VNĐ), phản ánh sự tăng trưởng mạnh qua các năm, không chỉ là sự ổn định ở một mức duy nhất.

Variance (Phương sai) = 628,338,902,612,449,951,764,000. Phương sai rất lớn, do giá trị lợi nhuận lớn và sự chênh lệch đáng kể giữa các năm.

Min (Nhỏ nhất): Lợi nhuận thấp nhất là 922 tỷ VNĐ (năm 2015).

Max (Lớn nhất): Lợi nhuận cao nhất là 3,209 tỷ VNĐ (năm 2024).

Range (Phạm vi): Phạm vi lợi nhuận là 2,286 tỷ VNĐ, chứng minh sự tăng trưởng mạnh mẽ: lợi nhuận cao nhất gấp 3.47 lần lợi nhuận thấp nhất.

2.3.2 Dòng tiền hoạt động

ta_clean1 %>%
summarise(
Mean = mean(cfo_tong) / 1000000,
Median = median(cfo_tong) / 1000000,
SD = sd(cfo_tong) / 1000000,
Variance = var(cfo_tong) / 1000000,
Min = min(cfo_tong) / 1000000,
Max = max(cfo_tong) / 1000000,
Range = Max - Min
) %>% 
  kable(
    caption = "THỐNG KÊ DÒNG TIỀN HOẠT ĐỘNG",
    digits = 2,  
    format.args = list(
      big.mark = ",", 
      scientific = FALSE 
    )
  )
THỐNG KÊ DÒNG TIỀN HOẠT ĐỘNG
Mean Median SD Variance Min Max Range
133,427.6 90,931.77 114,796.2 13,178,169,807,990,848 -30,308.43 378,603.4 408,911.8

mean(cfo_tong): Giá trị Trung bình, đo lường xu hướng trung tâm của cfo_tong.

median(cfo_tong): Giá trị Trung vị, là giá trị nằm chính giữa tập dữ liệu khi sắp xếp, ít bị ảnh hưởng bởi giá trị ngoại lai (outliers) hơn Mean.

sd(cfo_tong): Độ lệch chuẩn (Standard Deviation), đo lường mức độ phân tán/dao động của dữ liệu so với giá trị Mean.

var(cfo_tong): Phương sai, là bình phương của SD, cũng đo lường mức độ phân tán.

min(cfo_tong): Giá trị nhỏ nhất của cfo_tong.

max(cfo_tong): Giá trị lớn nhất của cfo_tong.

Mean Giá trị Trung bình, thể hiện xu hướng trung tâm của dữ liệu (trên 1.33 tỷ).

Median Giá trị Trung vị, là giá trị chính giữa, cao hơn Mean, cho thấy dữ liệu bị lệch (trên 4.99 tỷ).

SD Độ lệch chuẩn, đo lường độ phân tán của dữ liệu (rất lớn, trên 9 tỷ). Variance Phương sai, là bình phương của SD, xác nhận mức độ phân tán cực kỳ lớn.

Min Giá trị nhỏ nhất (âm), chỉ ra có ít nhất một quan sát có dòng tiền hoạt động âm (-3.03 tỷ).

Max Giá trị lớn nhất (rất lớn, trên 53.7 tỷ).

Range Phạm vi (Max - Min), thể hiện khoảng cách biến động rộng giữa giá trị cao nhất và thấp nhất (trên 40.8 tỷ).

2.3.3 Thống kê mô tả chi tiết

stats_detailed <- ta_clean1 %>%
  mutate(across(where(is.numeric) & !c(year), ~ . / 1000000000)) %>% 
  select(where(is.numeric)) %>%
  psych::describe() %>%
  rownames_to_column("Bien") %>%
  select(Bien, n, mean, sd, min, max, skew, kurtosis) %>%
  mutate(across(where(is.numeric), ~ round(., 2))) 
kable(stats_detailed,
  caption = "THỐNG KÊ MÔ TẢ CHI TIẾT TÀI CHÍNH (Đơn vị: Tỷ VND)",
  format = "pipe",
  digits = 2,
  format.args = list(big.mark = ",", scientific = FALSE)
)
THỐNG KÊ MÔ TẢ CHI TIẾT TÀI CHÍNH (Đơn vị: Tỷ VND)
Bien n mean sd min max skew kurtosis
year 10 2,019.50 3.03 2,015.00 2,024.00 0.00 -1.56
loi_nhuan_sau_thue 10 185.46 79.27 92.28 320.86 0.44 -1.33
tien_dau_ky 10 138.00 63.71 75.04 271.27 0.78 -0.80
tien_cuoi_ky 10 136.35 62.74 75.04 271.27 0.86 -0.59
cfo_tong 10 133.43 114.80 -30.31 378.60 0.74 -0.39
khau_hao 10 54.13 24.31 30.52 105.64 0.87 -0.58
bien_dong_phai_thu 10 -12.17 57.50 -83.31 115.76 0.80 -0.17
bien_dong_ton_kho 10 -41.15 89.04 -260.75 52.40 -1.26 0.95
bien_dong_phai_tra 10 -7.54 29.92 -49.53 39.58 0.10 -1.59
lai_vay_da_tra 10 -3.05 2.27 -6.70 -0.06 -0.04 -1.61
thue_da_nop 10 -45.52 20.10 -83.99 -22.38 -0.63 -1.08
cfi_tong 10 -130.74 137.80 -443.25 69.89 -0.80 0.17
chi_mua_tscd 10 -130.06 78.92 -274.46 -52.86 -1.02 -0.66
chi_tien_gui 10 -198.92 162.82 -451.17 -12.00 -0.21 -1.74
thu_tien_gui 10 203.31 138.52 26.30 491.30 0.63 -0.54
cff_tong 10 -7.65 158.83 -271.72 352.37 0.69 0.43
vay_moi 10 144.16 190.60 -315.65 387.99 -1.10 0.75
tra_no_goc 10 -183.64 87.68 -351.29 -49.39 -0.33 -0.86
year_standardized 10 0.00 0.00 0.00 0.00 0.00 -1.56
year_log_transformed 10 0.00 0.00 0.00 0.00 0.00 -1.56
loi_nhuan_sau_thue_standardized 10 0.00 0.00 0.00 0.00 0.44 -1.33
loi_nhuan_sau_thue_log_transformed 10 0.00 0.00 0.00 0.00 0.03 -1.55
tien_dau_ky_standardized 10 0.00 0.00 0.00 0.00 0.78 -0.80
tien_dau_ky_log_transformed 10 0.00 0.00 0.00 0.00 0.40 -1.49
tien_cuoi_ky_standardized 10 0.00 0.00 0.00 0.00 0.86 -0.59
tien_cuoi_ky_log_transformed 10 0.00 0.00 0.00 0.00 0.45 -1.37
cfo_tong_standardized 10 0.00 0.00 0.00 0.00 0.74 -0.39
cfo_tong_log_transformed 10 0.00 0.00 0.00 0.00 0.08 -1.02
khau_hao_standardized 10 0.00 0.00 0.00 0.00 0.87 -0.58
khau_hao_log_transformed 10 0.00 0.00 0.00 0.00 0.42 -1.29
bien_dong_phai_thu_standardized 10 0.00 0.00 0.00 0.00 0.80 -0.17
bien_dong_phai_thu_log_transformed 10 0.00 0.00 0.00 0.00 -0.94 -0.07
bien_dong_ton_kho_standardized 10 0.00 0.00 0.00 0.00 -1.26 0.95
bien_dong_ton_kho_log_transformed 10 0.00 0.00 0.00 0.00 -0.20 -0.62
bien_dong_phai_tra_standardized 10 0.00 0.00 0.00 0.00 0.10 -1.59
bien_dong_phai_tra_log_transformed 10 0.00 0.00 0.00 0.00 -0.94 -0.45
lai_vay_da_tra_standardized 10 0.00 0.00 0.00 0.00 -0.04 -1.61
lai_vay_da_tra_log_transformed 10 0.00 0.00 0.00 0.00 -1.11 0.03
thue_da_nop_standardized 10 0.00 0.00 0.00 0.00 -0.63 -1.08
thue_da_nop_log_transformed 10 0.00 0.00 0.00 0.00 0.17 -1.40
cfi_tong_standardized 10 0.00 0.00 0.00 0.00 -0.80 0.17
cfi_tong_log_transformed 10 0.00 0.00 0.00 0.00 -0.58 -0.28
chi_mua_tscd_standardized 10 0.00 0.00 0.00 0.00 -1.02 -0.66
chi_mua_tscd_log_transformed 10 0.00 0.00 0.00 0.00 0.47 -1.00
chi_tien_gui_standardized 10 0.00 0.00 0.00 0.00 -0.21 -1.74
chi_tien_gui_log_transformed 10 0.00 0.00 0.00 0.00 -0.53 -1.38
thu_tien_gui_standardized 10 0.00 0.00 0.00 0.00 0.63 -0.54
thu_tien_gui_log_transformed 10 0.00 0.00 0.00 0.00 -0.70 -0.77
cff_tong_standardized 10 0.00 0.00 0.00 0.00 0.69 0.43
cff_tong_log_transformed 10 0.00 0.00 0.00 0.00 0.71 -1.13
vay_moi_standardized 10 0.00 0.00 0.00 0.00 -1.10 0.75
vay_moi_log_transformed 10 0.00 0.00 0.00 0.00 -0.38 -1.19
tra_no_goc_standardized 10 0.00 0.00 0.00 0.00 -0.33 -0.86
tra_no_goc_log_transformed 10 0.00 0.00 0.00 0.00 -0.68 -0.44
bien_dong_tien_rong 10 -1.66 94.51 -115.40 186.00 0.49 -0.96
KiemTra_BaoCaoLuuChuyenTienTe 10 -4.96 91.76 -115.40 186.23 0.57 -0.68
ChenhLech 10 3.30 10.54 -0.23 33.29 2.28 3.57
DongTienTuDo 10 3.37 145.78 -177.24 279.25 0.58 -1.10
VayRong 10 -39.48 137.65 -365.04 134.50 -1.17 0.49

ta_clean1 %>%: Đặt tập dữ liệu ta_clean1 làm đầu vào cho chuỗi lệnh tiếp theo . select(where(is.numeric)): Chọn lọc ra tất cả các cột có kiểu dữ liệu là số (numeric). Các cột không phải số (ví dụ: văn bản, ngày tháng) sẽ bị loại bỏ khỏi tính toán.

psych::describe(): Sử dụng hàm describe từ gói psych để tính toán thống kê mô tả chi tiết cho các cột đã chọn. Hàm này tính các chỉ số như n, mean, sd, min, max, skew (độ xiên), và kurtosis (độ nhọn).

rownames_to_column(“Bien”): Chuyển tên các hàng (là tên các biến/cột dữ liệu sau khi chạy describe()) thành một cột mới có tên là Bien.

select(Bien, n, mean, sd, min, max, skew, kurtosis): Chọn lọc ra một tập hợp con các cột kết quả cụ thể để hiển thị, sắp xếp theo thứ tự mong muốn: Tên biến, số lượng quan sát, trung bình, độ lệch chuẩn, giá trị nhỏ nhất, lớn nhất, độ xiên, và độ nhọn.

mutate(across(where(is.numeric), ~ round(., 2))): Định dạng lại các cột số bằng cách áp dụng hàm round(., 2) (làm tròn đến 2 chữ số thập phân) cho tất cả các cột có kiểu số.

stats_detailed: Lưu trữ kết quả của toàn bộ chuỗi lệnh vào một đối tượng (biến) mới có tên là stats_detailed.

caption: “THỐNG KÊ MÔ TẢ CHI TIẾT TÀI CHÍNH” Đặt tiêu đề cho bảng.

format “pipe”: Đảm bảo định dạng đầu ra phù hợp (ví dụ: cho tài liệu Markdown).

digits: 2 Giới hạn số chữ số thập phân hiển thị là 2 (phù hợp với lệnh round đã làm trước đó).

format.args = list(…): Cung cấp các đối số để định dạng số lớn.

big.mark = “,”: Sử dụng dấu phẩy (,) làm ký hiệu phân tách hàng nghìn.

scientific = FALSE: Tắt định dạng số khoa học (scientific notation). Xu hướng Trung tâm:

Mean (Trung bình): Khoảng 133.42 tỷ. Đây là dòng tiền hoạt động trung bình của các quan sát.

Độ Phân tán:

SD (Độ lệch chuẩn): Khoảng 90.31 tỷ. SD rất lớn so với Mean, cho thấy sự biến động và khác biệt rất lớn về dòng tiền hoạt động giữa các công ty/quan sát.

Phạm vi (Min - Max): Dòng tiền hoạt động dao động từ khoảng 3.03 tỷ (giá trị nhỏ nhất - Min) đến 401.44 tỷ (giá trị lớn nhất - Max).

Kết quả:

Skew (Độ xiên): 0.44 (dương). Giá trị này nằm giữa 0 và 1, cho thấy phân phối hơi lệch sang phải. Điều này có thể do có một vài giá trị dòng tiền hoạt động rất cao (Max) kéo trung bình lên.

Kurtosis (Độ nhọn): -0.39 (âm). Cho thấy phân phối hơi bẹt hơn so với phân phối chuẩn (platykurtic).

Kết luận: Dữ liệu tài chính trong mẫu nhỏ này có mức độ phân tán cực kỳ cao và hơi bị lệch dương, cho thấy sự không đồng nhất lớn giữa các công ty/quan sát.

2.3.4 Phân tích biến động theo năm

yearly_stats <- ta_clean1 %>%
  mutate(
    across(c(loi_nhuan_sau_thue, cfo_tong, cfi_tong, cff_tong),
           ~ . / 1000000)
  ) %>%
  
  group_by(year) %>%
  summarise(
    across(c(loi_nhuan_sau_thue, cfo_tong, cfi_tong, cff_tong),
           list(
             mean = ~mean(., na.rm = TRUE),
             sd = ~sd(., na.rm = TRUE),
             cv = ~sd(., na.rm = TRUE)/mean(., na.rm = TRUE) 
           )
    )
  )
kable(yearly_stats, caption = "THỐNG KÊ BIẾN ĐỘNG THEO NĂM (TRIỆU VND)")
THỐNG KÊ BIẾN ĐỘNG THEO NĂM (TRIỆU VND)
year loi_nhuan_sau_thue_mean loi_nhuan_sau_thue_sd loi_nhuan_sau_thue_cv cfo_tong_mean cfo_tong_sd cfo_tong_cv cfi_tong_mean cfi_tong_sd cfi_tong_cv cff_tong_mean cff_tong_sd cff_tong_cv
2015 92275.35 NA NA 81130.89 NA NA -204828.80 NA NA 32990.72 NA NA
2016 101159.34 NA NA 84650.65 NA NA -14340.79 NA NA -58008.89 NA NA
2017 117360.04 NA NA 97212.90 NA NA -443246.93 NA NA 352371.80 NA NA
2018 138683.04 NA NA 132094.45 NA NA -48101.24 NA NA -33304.80 NA NA
2019 162386.69 NA NA 66590.39 NA NA -120623.06 NA NA -61363.26 NA NA
2020 209696.88 NA NA 73153.42 NA NA -136475.95 NA NA 73592.41 NA NA
2021 189094.87 NA NA 234881.04 NA NA -83142.06 NA NA 34495.81 NA NA
2022 223540.32 NA NA 378603.40 NA NA -199303.87 NA NA -271718.14 NA NA
2023 299556.01 NA NA -30308.43 NA NA 69894.26 NA NA -112229.74 NA NA
2024 320862.39 NA NA 216267.57 NA NA -127199.19 NA NA -33304.80 NA NA

Dữ liệu thô phân tán mạnh: Hầu hết các biến tiền tệ gốc (như loi_nhuan_sau_thue, cfo_tong, DongTienTuDo) có Độ lệch chuẩn (SD) rất lớn so với Mean, và Phạm vi (Min-Max) cực rộng. Điều này khẳng định sự không đồng nhất cao trong dữ liệu mẫu.

Dữ liệu bị lệch (Skewness): Nhiều biến gốc có Độ xiên dương (ví dụ: cfo_tong là 0.74, ChenhLech là 2.28), cho thấy phân phối bị kéo dài về phía các giá trị dương lớn (có thể là outliers).

Hiệu quả của Biến đổi:

Các biến đã được chuẩn hóa (_standardized) luôn có Mean = 0.00 và SD = 1.00 theo định nghĩa Z-score.

Các biến đã được logarit hóa (_log_transformed) thường có độ xiên và độ nhọn giảm đáng kể (ví dụ: loi_nhuan_sau_thue_log_transformed có Skew là 0.03 so với 0.44 của bản gốc), chứng minh phép biến đổi logarit đã giúp phân phối gần với phân phối chuẩn hơn.

2.3.5 Phân tích phân vị

quantile_analysis <- ta_clean1 %>%
  mutate(across(c(loi_nhuan_sau_thue, cfo_tong, cfi_tong),
                ~ . / 1000000)) %>% 
  summarise(
    across(c(loi_nhuan_sau_thue, cfo_tong, cfi_tong),
           list(
             Q0 = ~quantile(., 0, na.rm = TRUE),
             Q1 = ~quantile(., 0.25, na.rm = TRUE),
             Q2 = ~quantile(., 0.5, na.rm = TRUE),
             Q3 = ~quantile(., 0.75, na.rm = TRUE),
             Q4 = ~quantile(., 1, na.rm = TRUE)
           )))

kable(quantile_analysis, 
      caption = "PHÂN TÍCH PHÂN VỊ CÁC CHỈ TIÊU CHÍNH (TRIỆU VND)",
      digits = 2, 
      format.args = list(big.mark = ",", scientific = FALSE))
PHÂN TÍCH PHÂN VỊ CÁC CHỈ TIÊU CHÍNH (TRIỆU VND)
loi_nhuan_sau_thue_Q0 loi_nhuan_sau_thue_Q1 loi_nhuan_sau_thue_Q2 loi_nhuan_sau_thue_Q3 loi_nhuan_sau_thue_Q4 cfo_tong_Q0 cfo_tong_Q1 cfo_tong_Q2 cfo_tong_Q3 cfo_tong_Q4 cfi_tong_Q0 cfi_tong_Q1 cfi_tong_Q2 cfi_tong_Q3 cfi_tong_Q4
92,275.35 122,690.8 175,740.8 220,079.5 320,862.4 -30,308.43 75,147.79 90,931.77 195,224.3 378,603.4 -443,246.9 -183,596.9 -123,911.1 -56,861.45 69,894.26

mutate(…)Biến đổi các cột tài chính (loi_nhuan_sau_thue, cfo_tong, cfi_tong) bằng cách chia giá trị cho \(1,000,000\) để chuyển đơn vị sang Triệu VND.

summarise(…)Tạo ra bảng tóm tắt, thực hiện các phép tính phân vị trên toàn bộ tập dữ liệu (sau khi đã chuyển đơn vị).

across(…)Áp dụng các phép tính phân vị cho nhiều cột tài chính cùng một lúc.quantile(., 0, na.rm = TRUE)Tính Phân vị 0 (Q0), tương đương với Giá trị nhỏ nhất (Min) của dữ liệu.

quantile(., 0.25, na.rm = TRUE)Tính Phân vị 1 (Q1), hay Tứ phân vị thứ nhất. 25% dữ liệu nhỏ hơn hoặc bằng giá trị này.

quantile(., 0.5, na.rm = TRUE)Tính Phân vị 2 (Q2), hay Trung vị (Median). 50% dữ liệu nhỏ hơn hoặc bằng giá trị này.

quantile(., 0.75, na.rm = TRUE)Tính Phân vị 3 (Q3), hay Tứ phân vị thứ ba. 75% dữ liệu nhỏ hơn hoặc bằng giá trị này.

quantile(., 1, na.rm = TRUE)Tính Phân vị 4 (Q4), tương đương với Giá trị lớn nhất (Max) của dữ liệu.

kable(…)Định dạng bảng kết quả. Tham số digits và format.args giúp làm gọn số và hiển thị đơn vị Triệu VND rõ ràng trong chú thích.

Lợi nhuận sau thuế (loi_nhuan_sau_thue)

Phân vị 1 (Q1 = 122,690.81 Triệu): 25% các công ty/quan sát có lợi nhuận dưới 122.69 tỷ VND. Phân vị 2 (Median = 175,740.82 Triệu): Trung vị của lợi nhuận là 175.74 tỷ VND. Phân vị 3 (Q3 = 220,079.53 Triệu): 75% các công ty/quan sát có lợi nhuận dưới 220.07 tỷ VND. Kết luận: Phân phối tập trung khá đều giữa Q1 và Q3 (khoảng cách Q3-Q1 là 97.38 tỷ), cho thấy phần lớn lợi nhuận nằm trong khoảnG 122.69 tỷ đến 220.07 tỷ.2.

Dòng tiền hoạt động (cfo_tong) Q0 (Min = -30,308.43 Triệu): Tồn tại các công ty/quan sát có dòng tiền hoạt động âm (-30.3 tỷ VND), cho thấy không đủ tiền mặt từ hoạt động kinh doanh cốt lõi.

Q2 (Median = 90,931.77 Triệu): Trung vị là 90.93 tỷ VND (dương), cho thấy hơn một nửa số quan sát có dòng tiền hoạt động tốt.

Q4 (Max = 378,603.40 Triệu): Giá trị tối đa rất cao, 378.6 tỷ VND.Kết luận: Dữ liệu có sự chênh lệch lớn, từ âm đến dương rất cao.

Phạm vi giữa Q3 và Q1 (195.22 - 75.14 = 120.08 tỷ) cho thấy sự đa dạng lớn trong hiệu quả kinh doanh.

Dòng tiền đầu tư (cfi_tong):

Q0 đến Q3 đều là giá trị âm: Điều này rất phổ biến. Dòng tiền đầu tư chủ yếu là chi cho tài sản cố định, vì vậy Q0 (Min) đến Q3 (75%) đều là giá trị âm (ví dụ, 75% các công ty chi từ 56.86 tỷ VND trở lên cho hoạt động đầu tư).

Q4 (Max = 69,894.26 Triệu): Có một số quan sát có dòng tiền đầu tư dương, nghĩa là họ đã bán tài sản đầu tư để thu tiền mặt.

Kết luận: Hoạt động đầu tư chủ yếu là chi tiêu (âm). Khoảng cách giữa Q3 và Q1 rất lớn (Phạm vi Liên Tứ phân vịIQR = Q3 - Q1), xác nhận mức độ biến động cao trong chi tiêu đầu tư.

2.3.6 Kiểm tra phân phối chuẩn

normality_tests <- ta_clean1 %>%
  summarise(across(c(loi_nhuan_sau_thue, cfo_tong, cfi_tong),
                   list(
                     shapiro_p = ~shapiro.test(.)$p.value
                   ))) %>%
  # Chuyển đổi định dạng bảng
  pivot_longer(everything(), names_to = "Bien", values_to = "p_value") %>%
  mutate(
    Bien = gsub("_shapiro_p", "", Bien),
    p_value = round(p_value, 4),
    Ket_qua = ifelse(p_value > 0.05, "Phân phối chuẩn", "Không phân phối chuẩn")
  )

kable(normality_tests, 
      caption = "KIỂM ĐỊNH PHÂN PHỐI CHUẨN (Shapiro-Wilk)",
      col.names = c("Biến", "Giá trị p", "Kết quả"))
KIỂM ĐỊNH PHÂN PHỐI CHUẨN (Shapiro-Wilk)
Biến Giá trị p Kết quả
loi_nhuan_sau_thue 0.4191 Phân phối chuẩn
cfo_tong 0.2409 Phân phối chuẩn
cfi_tong 0.3481 Phân phối chuẩn

normality_tests <- …Lưu trữ kết quả kiểm định vào biến normality_tests.

across(…, list(shapiro_p = ~shapiro.test(.) p.value))Áp dụng hàm shapiro.test() cho ba cột (loi_nhuan_sau_thue, cfo_tong, cfi_tong) và chỉ trích xuất Giá trị p ($p.value) của bài kiểm định.

pivot_longer(everything(), …)Chuyển đổi cấu trúc dữ liệu từ định dạng rộng (wide) sang định dạng dài (long), giúp mỗi biến và giá trị p của nó nằm trên một hàng riêng biệt.

mutate(…)Thực hiện các biến đổi sau: Bien = gsub(…)Làm sạch tên biến, loại bỏ hậu tố _shapiro_p để tên cột Bien gọn gàng hơn p_value = round(p_value, 4)Làm tròn giá trị p về 4 chữ số thập phân.

Ket_qua = ifelse(p_value > 0.05, “Phân phối chuẩn”, …)Đưa ra kết luận kiểm định: Nếu p.value > 0.05 (Mức ý nghĩa ), chấp nhận giả thuyết H_0 (Phân phối chuẩn); ngược lại, bác bỏ giả thuyết H_0 (Không phân phối chuẩn).

kable(…, col.names = c(“Biến”, “Giá trị p”, “Kết quả”))Định dạng kết quả thành bảng với tiêu đề cột thân thiện.

Tất cả các biến tài chính chính (loi_nhuan_sau_thue, cfo_tong, cfi_tong) đều có Giá trị p lớn hơn 0.05. có thể kết luận rằng cả ba biến đều tuân theo phân phối chuẩn (hoặc ít nhất, phân phối của chúng không khác biệt đáng kể so với phân phối chuẩn). Điều này là một điều kiện thuận lợi, cho phép bạn sử dụng các phương pháp thống kê tham số (parametric tests) như kiểm định t-test hoặc phân tích hồi quy tuyến tính cổ điển, vốn yêu cầu giả định về tính chuẩn của dữ liệu.

2.3.7 Phân tích phương sai (ANOVA)

anova_data <- ta_clean1 %>%
  select(year, loi_nhuan_sau_thue, cfo_tong, cfi_tong) %>%
  pivot_longer(-year, names_to = "variable", values_to = "value")

anova_result <- aov(value ~ variable, data = anova_data)
summary(anova_result)
##             Df                   Sum Sq                  Mean Sq F value
## variable     2 574905615849926177086222 287452807924963088548666   22.43
## Residuals   27 346050169844670467680826  12816672957210017399444        
##                 Pr(>F)    
## variable    0.00000182 ***
## Residuals                 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

select(…) Chọn ba cột tài chính (loi_nhuan_sau_thue, cfo_tong, cfi_tong) và cột year từ tập dữ liệu.

pivot_longer(…) Chuyển đổi cấu trúc dữ liệu từ định dạng rộng (wide) sang định dạng dài (long). Điều này là cần thiết để chuẩn bị dữ liệu cho ANOVA: names_to = “variable” Tạo cột mới variable chứa tên của ba biến tài chính. values_to = “value” Tạo cột mới value chứa giá trị của ba biến tài chính.

anova_result <- aov(value ~ variable, data = anova_data) Thực hiện phân tích phương sai (ANOVA). Mô hình kiểm tra xem liệu giá trị trung bình của cột value có bị ảnh hưởng bởi nhóm (variable) hay không.

summary(anova_result) In ra bảng kết quả ANOVA chính thức.

Bảng ANOVA kiểm tra giả thuyết rằng giá trị trung bình của loi_nhuan_sau_thue, cfo_tong, và cfi_tong là bằng nhau. Giả thuyết \(H_0\): \(\mu_{\text{loi\_nhuan}} = \mu_{\text{cfo}} = \mu_{\text{cfi}}\) (Không có sự khác biệt giữa các trung bình). Giả thuyết \(H_a\): Ít nhất một cặp trung bình là khác nhau.

Kết quả: Giá trị p (Pr(>F)): Giá trị p là 0.00000182.So sánh với \(\alpha\): 0.00000182 rất nhỏ hơn 0.05 (mức ý nghĩa tiêu chuẩn). Kết luận: Bác bỏ giả thuyết \(H_0\).

2.3.8 Kiểm định T-test

group_comparison <- ta_clean1 %>%
  mutate(High_Profit = loi_nhuan_sau_thue > median(loi_nhuan_sau_thue)) %>%
  summarise(
    t_test_cfo = t.test(cfo_tong ~ High_Profit)$p.value,
    t_test_cfi = t.test(cfi_tong ~ High_Profit)$p.value,
    t_test_cff = t.test(cff_tong ~ High_Profit)$p.value
  )

kable(group_comparison, caption = "KIỂM ĐỊNH T-TEST THEO NHÓM LỢI NHUẬN")
KIỂM ĐỊNH T-TEST THEO NHÓM LỢI NHUẬN
t_test_cfo t_test_cfi t_test_cff
0.3105355 0.4531494 0.3092235

mutate(High_Profit = loi_nhuan_sau_thue > median(loi_nhuan_sau_thue))Tạo biến phân nhóm (High_Profit): Phân chia tập dữ liệu thành hai nhóm: Lợi nhuận Cao (những công ty có lợi nhuận sau thuế lớn hơn Trung vị) và Lợi nhuận Thấp (nhỏ hơn hoặc bằng Trung vị).

summarise(…)Tính toán các kết quả kiểm định t-test.

t_test_cfo = t.test(cfo_tong ~ High_Profit)$p.valueThực hiện Kiểm định t-test để so sánh Trung bình Dòng tiền HĐ (cfo_tong) giữa nhóm Lợi nhuận Cao và nhóm Lợi nhuận Thấp, và chỉ lấy Giá trị p (p-value).

t_test_cfi = t.test(cfi_tong ~ High_Profit)$p.valueThực hiện Kiểm định t-test để so sánh Trung bình Dòng tiền ĐT (cfi_tong) giữa hai nhóm Lợi nhuận.

t_test_cff = t.test(cff_tong ~ High_Profit)$p.valueThực hiện Kiểm định t-test để so sánh Trung bình Dòng tiền TC (cff_tong) giữa hai nhóm Lợi nhuận.

kable(…)Định dạng kết quả thành bảng với tiêu đề phù hợp.

Kiểm định T-test kiểm tra giả thuyết rằng trung bình của hai nhóm là bằng nhau. Giả thuyết \(H_0\): Trung bình dòng tiền của Nhóm Lợi nhuận Cao = Trung bình dòng tiền của Nhóm Lợi nhuận Thấp. Mức ý nghĩa (\(\alpha\)): Thường là \(0.05\).

Tất cả các giá trị p đều lớn hơn 0.05. Ý nghĩa:

Không có sự khác biệt có ý nghĩa thống kê về Dòng tiền hoạt động (cfo_tong) giữa nhóm công ty có lợi nhuận cao và nhóm công ty có lợi nhuận thấp.

Không có sự khác biệt có ý nghĩa thống kê về Dòng tiền đầu tư (cfi_tong) giữa hai nhóm lợi nhuận.

Không có sự khác biệt có ý nghĩa thống kê về Dòng tiền tài chính (cff_tong) giữa hai nhóm lợi nhuận.

2.3.9 Hồi quy tuyến tính đơn

lm_simple <- lm(loi_nhuan_sau_thue ~ cfo_tong, data = ta_clean1)
summary_lm_simple <- summary(lm_simple)

kable(broom::tidy(lm_simple), caption = "HỒI QUY TUYẾN TÍNH ĐƠN: LỢI NHUẬN ~ DÒNG TIỀN")
HỒI QUY TUYẾN TÍNH ĐƠN: LỢI NHUẬN ~ DÒNG TIỀN
term estimate std.error statistic p.value
(Intercept) 169896933550.1840820 41442569003.729836 4.0995753 0.0034398
cfo_tong 0.1166517 0.240623 0.4847904 0.6408202

lm_simple <- lm(loi_nhuan_sau_thue ~ cfo_tong, data = ta_clean1): tạo mô hình hồi quy tuyến tính đơn: Dùng hàm lm() để mô tả mối quan hệ giữa lợi nhuận sau thuế (biến phụ thuộc) và dòng tiền hoạt động (biến độc lập).

summary_lm_simple <- summary(lm_simple) Tính toán và lưu trữ các thống kê mô hình chi tiết (hệ số, sai số chuẩn, giá trị t, giá trị p).

kable(broom::tidy(lm_simple), …) Định dạng kết quả hồi quy thành bảng (tidy giúp trích xuất các hệ số chính).

Mô hình hồi quy có dạng:\[\text{Lợi nhuận} = \beta_0 + \beta_1 \times \text{Dòng tiền HĐ} + \varepsilon\]

Phân tích Hệ số Chặn (Intercept - \(\beta_0\)):

Giá trị Ước tính: \(\approx 169.9\) tỷ VND.

Giá trị p: 0.00344 (\(\mathbf{< 0.05}\) - Có ý nghĩa thống kê).

Ý nghĩa: Khi Dòng tiền hoạt động (cfo_tong) bằng 0, Lợi nhuận sau thuế ước tính là 169.9 tỷ VND. Giá trị này có ý nghĩa thống kê.

Phân tích Hệ số Hồi quy (cfo_tong - \(\beta_1\)):

Giá trị Ước tính: \(0.11665\).

Giá trị p: \(0.64082\) (\(\mathbf{> 0.05}\) - Không có ý nghĩa thống kê).

Ý nghĩa:Về mặt kinh tế, nếu Dòng tiền hoạt động tăng thêm 1 VND, Lợi nhuận sau thuế ước tính sẽ tăng \(0.11665\) VND.Tuy nhiên, do giá trị p rất lớn (\(0.64\)), ta không thể bác bỏ giả thuyết \(H_0\) (Giả thuyết \(\beta_1 = 0\)).

2.3.10 Hồi quy tuyến tính đa biến

lm_multiple <- lm(loi_nhuan_sau_thue ~ cfo_tong + cfi_tong + cff_tong, 
                 data = ta_clean1)
summary_lm_multiple <- summary(lm_multiple)

kable(broom::tidy(lm_multiple), caption = "HỒI QUY TUYẾN TÍNH ĐA BIẾN")
HỒI QUY TUYẾN TÍNH ĐA BIẾN
term estimate std.error statistic p.value
(Intercept) 191167827191.3656616 48221491979.8729858 3.9643698 0.0074146
cfo_tong 0.1566295 0.3633626 0.4310556 0.6814841
cfi_tong 0.2060250 0.3660027 0.5629057 0.5938929
cff_tong -0.0431501 0.3299348 -0.1307838 0.9002212

lm_multiple <- lm(loi_nhuan_sau_thue ~ cfo_tong + cfi_tong + cff_tong, data = ta_clean1)Tạo mô hình hồi quy tuyến tính đa biến: Dùng hàm lm() để mô tả mối quan hệ giữa Lợi nhuận sau thuế (biến phụ thuộc) và Dòng tiền hoạt động, Đầu tư, Tài chính (biến độc lập).

summary_lm_multiple <- summary(lm_multiple)Tính toán và lưu trữ các thống kê mô hình chi tiết (bao gồm các hệ số, giá trị t, giá trị p, và \(R^2\)).

kable(broom::tidy(lm_multiple), …)Định dạng kết quả hồi quy thành bảng, trích xuất các hệ số chính.

Mô hình hồi quy có dạng:\[\text{Lợi nhuận} = \beta_0 + \beta_1 \times \text{CFO} + \beta_2 \times \text{CFI} + \beta_3 \times \text{CFF} + \varepsilon\]

Phân tích Hệ số Chặn (Intercept - \(\beta_0\))

Giá trị p: \(0.00741\) (\(\mathbf{< 0.05}\) - Có ý nghĩa thống kê).

Ý nghĩa: Khi tất cả các dòng tiền (CFO, CFI, CFF) đều bằng 0, Lợi nhuận sau thuế ước tính là \(\approx 191.17\) tỷ VND. Giá trị này có ý nghĩa.

Phân tích Hệ số Hồi quy (Các biến dòng tiền)

cfo_tong \(0.6814\). Không có ý nghĩa thống kê (\(p > 0.05\)).

cfi_tong \(0.5938\). Không có ý nghĩa thống kê (\(p > 0.05\)).

cff_tong \(0.9002\). Không có ý nghĩa thống kê (\(p > 0.05\)).

Tính ý nghĩa của Mô hình: Tương tự như hồi quy đơn, trong mô hình đa biến này, không có bất kỳ thành phần dòng tiền nào (CFO, CFI, CFF) có tác động có ý nghĩa thống kê đến Lợi nhuận sau thuế.

Mối quan hệ:

CFO và CFI có mối quan hệ dương với Lợi nhuận (tăng dòng tiền dự kiến tăng lợi nhuận), nhưng không đáng tin cậy về mặt thống kê.

CFF có mối quan hệ âm (tăng dòng tiền tài chính dự kiến giảm lợi nhuận), nhưng cũng không đáng tin cậy về mặt thống kê.

Kết luận chung: Mặc dù mô hình hồi quy đa biến này có vẻ mạnh mẽ hơn hồi quy đơn, nhưng do cỡ mẫu nhỏ (chỉ 10 quan sát) và độ phân tán dữ liệu lớn (như đã thấy ở các bảng thống kê trước), không có biến dòng tiền nào được chứng minh là có ảnh hưởng trực tiếp, có ý nghĩa thống kê đến Lợi nhuận sau thuế.

2.3.11 Phân tích chuỗi thời gian

ts_analysis <- ta_clean1 %>%
  select(year, loi_nhuan_sau_thue) %>%
  mutate(
    LNST_lag1 = lag(loi_nhuan_sau_thue),
    LNST_lag2 = lag(loi_nhuan_sau_thue, 2),
    LNST_diff = c(NA, diff(loi_nhuan_sau_thue)),
    LNST_growth = (loi_nhuan_sau_thue / lag(loi_nhuan_sau_thue) - 1) * 100
  )

kable(ts_analysis, caption = "PHÂN TÍCH CHUỖI THỜI GIAN LỢI NHUẬN")
PHÂN TÍCH CHUỖI THỜI GIAN LỢI NHUẬN
year loi_nhuan_sau_thue LNST_lag1 LNST_lag2 LNST_diff LNST_growth
2015 92275349999 NA NA NA NA
2016 101159344647 92275349999 NA 8883994648 9.627701
2017 117360040786 101159344647 92275349999 16200696139 16.015027
2018 138683041628 117360040786 101159344647 21323000842 18.168876
2019 162386686793 138683041628 117360040786 23703645165 17.091956
2020 209696878289 162386686793 138683041628 47310191496 29.134280
2021 189094874963 209696878289 162386686793 -20602003326 -9.824659
2022 223540317602 189094874963 209696878289 34445442639 18.215958
2023 299556005542 223540317602 189094874963 76015687940 34.005359
2024 320862393082 299556005542 223540317602 21306387540 7.112656

select(year, loi_nhuan_sau_thue)Lấy ra hai cột chính là Năm và Lợi nhuận sau thuế để phân tích.

mutate(…)Tạo ra các biến chuỗi thời gian mới

LNST_lag1 = lag(loi_nhuan_sau_thue)Tính giá trị độ trễ 1 kỳ (Lag 1) của Lợi nhuận sau thuế. Đây là lợi nhuận của năm trước đó (t-1).

LNST_lag2 = lag(loi_nhuan_sau_thue, 2)Tính giá trị độ trễ 2 kỳ (Lag 2) của Lợi nhuận sau thuế. Đây là lợi nhuận của hai năm trước (t-2).

LNST_diff = c(NA, diff(loi_nhuan_sau_thue))Tính chênh lệch tuyệt đối (First Difference) của Lợi nhuận sau thuế so với năm trước.

LNST_growth = (loi_nhuan_sau_thue / lag(loi_nhuan_sau_thue) - 1) * 100Tính tốc độ tăng trưởng phần trăm của Lợi nhuận sau thuế so với năm trước.

kable(ts_analysis, …)Định dạng bảng kết quả.

Lợi nhuận sau thuế có tính chu kỳ và sự biến động rất lớn qua các năm, với các năm tăng trưởng mạnh (2023: 34%) và năm sụt giảm sâu (2021: -9.824%).

Việc tính toán các biến độ trễ (LNST_lag1, LNST_lag2) cho phép sử dụng các giá trị lợi nhuận quá khứ làm biến độc lập trong các mô hình kinh tế lượng (ví dụ: AR, ARMA, hoặc hồi quy đa biến) để dự báo lợi nhuận tương lai.

2.3.12 Phân tích độ biến động

volatility_analysis <- ta_clean1 %>%
  summarise(
    Volatility_LNST = sd(loi_nhuan_sau_thue, na.rm = TRUE) / mean(loi_nhuan_sau_thue, na.rm = TRUE),
    Volatility_CFO = sd(cfo_tong, na.rm = TRUE) / mean(cfo_tong, na.rm = TRUE),
    Volatility_CFI = sd(cfi_tong, na.rm = TRUE) / mean(cfi_tong, na.rm = TRUE),
    Volatility_CFF = sd(cff_tong, na.rm = TRUE) / mean(cff_tong, na.rm = TRUE)
  )

kable(volatility_analysis, caption = "PHÂN TÍCH ĐỘ BIẾN ĐỘNG CÁC CHỈ TIÊU")
PHÂN TÍCH ĐỘ BIẾN ĐỘNG CÁC CHỈ TIÊU
Volatility_LNST Volatility_CFO Volatility_CFI Volatility_CFF
0.4274086 0.8603631 -1.054016 -20.76817

summarise(…)Tính toán các tỷ lệ biến động trên toàn bộ tập dữ liệu.

sd(loi_nhuan_sau_thue) / mean(loi_nhuan_sau_thue)Volatility_LNSTHệ số Biến thiên của Lợi nhuận sau thuế: Đo lường độ biến động tương đối của lợi nhuận.

sd(cfo_tong) / mean(cfo_tong)Volatility_CFOHệ số Biến thiên của Dòng tiền HĐ.

sd(cfi_tong) / mean(cfi_tong)Volatility_CFIHệ số Biến thiên của Dòng tiền ĐT.

sd(cff_tong) / mean(cff_tong)Volatility_CFFHệ số Biến thiên của Dòng tiền TC.

kable(…)Định dạng bảng kết quả.

Độ biến động tương đối cao nhất thuộc về Dòng tiền Tài chính (CFF), với CV tuyệt đối lên tới \(20.77\). Điều này cho thấy sự không ổn định rất lớn trong hoạt động huy động và trả nợ của các công ty.

Độ biến động cao thứ hai là Dòng tiền Đầu tư (CFI), với CV tuyệt đối là \(1.05\). Điều này phản ánh sự thiếu ổn định trong chi tiêu và thu hồi đầu tư tài sản dài hạn.

Lợi nhuận sau thuế (LNST) có độ biến động tương đối thấp nhất (\(0.43\)) trong số các chỉ tiêu tiền tệ lớn, cho thấy Lợi nhuận ổn định hơn Dòng tiền từ các hoạt động khác.

2.3.13 Phân tích xu hướng

trend_analysis <- ta_clean1 %>%
  mutate(Trend = 1:n()) %>%
  summarise(
    Trend_LNST = lm(loi_nhuan_sau_thue ~ Trend)$coefficients[2],
    Trend_CFO = lm(cfo_tong ~ Trend)$coefficients[2],
    Trend_CFI = lm(cfi_tong ~ Trend)$coefficients[2],
    Trend_CFF = lm(cff_tong ~ Trend)$coefficients[2]
  )

kable(trend_analysis, caption = "PHÂN TÍCH XU HƯỚNG TUYẾN TÍNH")
PHÂN TÍCH XU HƯỚNG TUYẾN TÍNH
Trend_LNST Trend_CFO Trend_CFI Trend_CFF
25306103573 12929647428 14466980504 -22777562748

mutate(Trend = 1:n())Tạo biến thời gian (Trend): Gán một chuỗi số tự nhiên tăng dần (1, 2, 3,…) cho mỗi quan sát. Đây là biến độc lập đại diện cho thời gian.

summarise(…)Tính toán các kết quả cho các mô hình hồi quy.Trend_LNST = lm(loi_nhuan_sau_thue ~ Trend)$coefficients[2]Thực hiện hồi quy tuyến tính đơn giữa Lợi nhuận sau thuế và Trend. Sau đó, trích xuất hệ số hồi quy (Coefficient - \(\beta_1\)), thể hiện mức tăng/giảm trung bình của Lợi nhuận sau thuế qua mỗi kỳ thời gian.

Trend_CFO, Trend_CFI, Trend_CFFTương tự, tính toán hệ số xu hướng cho Dòng tiền hoạt động (CFO), Dòng tiền đầu tư (CFI), và Dòng tiền tài chính (CFF).

kable(trend_analysis, …)Định dạng bảng kết quả.

Lợi nhuận và Dòng tiền Hoạt động/Đầu tư có Xu hướng Tăng: Lợi nhuận sau thuế, Dòng tiền hoạt động (CFO), và Dòng tiền đầu tư (CFI) đều có xu hướng tăng dương theo thời gian. Điều này cho thấy hoạt động kinh doanh và đầu tư đang mở rộng.

Dòng tiền Tài chính có Xu hướng Giảm: Dòng tiền tài chính (CFF) có xu hướng giảm âm theo thời gian. Điều này có thể phản ánh việc công ty/các công ty đang:

Giảm vay nợ (trả gốc nhiều hơn vay mới).

Tăng chi trả cổ tức (dòng tiền chi ra).

Tự chủ tài chính hơn, ít phụ thuộc vào huy động vốn bên ngoài.

2.3.14 Tính toán các tỷ số tài chính

ta_clean1 <- ta_clean1 %>%
  mutate(
    TySo_ThanhKhoanHienHanh = (tien_cuoi_ky + bien_dong_phai_thu + bien_dong_ton_kho) / abs(bien_dong_phai_tra),
    ROA = loi_nhuan_sau_thue / (tien_cuoi_ky + abs(bien_dong_phai_thu) + abs(bien_dong_ton_kho)),
    ROS = loi_nhuan_sau_thue / (loi_nhuan_sau_thue + abs(cfo_tong)),
    TySo_No = abs(vay_moi + tra_no_goc) / (loi_nhuan_sau_thue + 1),
    VongQuay_PhaiThu = cfo_tong / abs(bien_dong_phai_thu),
    VongQuay_TonKho = cfo_tong / abs(bien_dong_ton_kho)
  )

kable(ta_clean1 %>% select(year, TySo_ThanhKhoanHienHanh, ROA, ROS, TySo_No), 
      caption = "CÁC TỶ SỐ TÀI CHÍNH CHỦ CHỐT")
CÁC TỶ SỐ TÀI CHÍNH CHỦ CHỐT
year TySo_ThanhKhoanHienHanh ROA ROS TySo_No
2015 2.716348 0.5139037 0.5321340 0.0000000
2016 4.059811 0.8443673 0.5444236 0.2098925
2017 2.438772 0.7551253 0.5469471 0.0000000
2018 12.312203 0.5405298 0.5121661 0.0000000
2019 -2.144141 0.9868891 0.7091832 0.2314196
2020 -1.026008 0.9473487 0.7413705 1.7407832
2021 113.340309 0.4172794 0.4460038 0.7112999
2022 6.351222 0.8892551 0.3712408 0.7681424
2023 -4.513131 0.7741630 0.9081185 0.1520857
2024 3.575109 1.2759404 0.5973645 0.1143788

mutate(…)Thêm các cột tỷ số tài chính mới vào tập dữ liệu.

(tien_cuoi_ky + bien_dong_phai_thu + bien_dong_ton_kho) / abs(bien_dong_phai_tra).Tỷ số Thanh khoản Hiện hành (Current Ratio): Đo lường khả năng thanh toán các khoản nợ ngắn hạn bằng tài sản ngắn hạn.

loi_nhuan_sau_thue / (tien_cuoi_ky + abs(bien_dong_phai_thu) + abs(bien_dong_ton_kho)).Tỷ suất sinh lời trên Tổng tài sản (Return on Assets): Đo lường hiệu quả sử dụng tài sản để tạo ra lợi nhuận.

loi_nhuan_sau_thue / (loi_nhuan_sau_thue + abs(cfo_tong)).Tỷ suất sinh lời trên Doanh thu (Return on Sales): Đo lường hiệu quả của doanh thu đối với lợi nhuận. (Lưu ý: Công thức này có vẻ đã thay thế Doanh thu bằng một tổ hợp Lợi nhuận và Dòng tiền HĐ).

abs(vay_moi + tra_no_goc) / abs(loi_nhuan_sau_thue + 1).Tỷ số Nợ (Debt Ratio): Đo lường mức độ sử dụng nợ. (Công thức này không theo định nghĩa chuẩn, có thể là một tỷ số đặc thù).

cfo_tong / abs(bien_dong_phai_thu)Vòng quay Phải thu: Đo lường tốc độ thu hồi nợ (từ Dòng tiền HĐ so với Biến động Phải thu).

cfo_tong / abs(bien_dong_ton_kho)Vòng quay Tồn kho: Đo lường tốc độ bán hàng (từ Dòng tiền HĐ so với Biến động Tồn kho).

kable(…)Định dạng bảng kết quả.

Thanh khoản Biến động mạnh: Tỷ số Thanh khoản Hiện hành (TySo_ThanhKhoanHienHanh) có sự biến động cực lớn: Âm (-2.14) vào năm 2019 và -4.51 vào năm 2023: Giá trị âm là rất bất thường và có thể chỉ ra lỗi trong việc sử dụng biến abs() (giá trị tuyệt đối) trong công thức hoặc dữ liệu đầu vào. Tỷ số thanh khoản không được phép âm trong thực tế.

Cực cao (113.34) vào năm 2021: Giá trị này cho thấy tài sản ngắn hạn lớn hơn nợ ngắn hạn đến hơn 113 lần, một sự dư thừa thanh khoản không hợp lý, có thể do một giá trị ngoại lai lớn hoặc lỗi dữ liệu.

ROA và ROS: Các tỷ suất sinh lời (ROA và ROS) nhìn chung ổn định và dương, dao động trong khoảng \(0.4\) đến \(0.9\). Điều này cho thấy các công ty vẫn tạo ra lợi nhuận tốt từ tài sản và hoạt động kinh doanh.

Tỷ số Nợ có xu hướng tăng dần từ 2019 đến 2023 (từ \(0.23\) lên \(0.76\)), cho thấy sự phụ thuộc vào nợ hoặc huy động vốn tăng lên trong giai đoạn này.

2.4 TRỰC QUAN DỮ LIỆU

Kỹ thuật vẽ các biểu đồ đã giải thích ở Phần1

2.4.1 Tổng quan Hiệu suất Sinh lời

ta_visual <- ta_clean1 %>%
  mutate(
    loi_nhuan_sau_thue = loi_nhuan_sau_thue / 1000000000,
    cfo_tong = cfo_tong / 1000000000,
    DongTienTuDo = DongTienTuDo / 1000000000 
  )
format_number_m <- function(x) {
  format(round(x, 0), big.mark = ".", scientific = FALSE)
}
# Đồ thị 1: Xu hướng Lợi nhuận sau thuế (LNST) 
p1 <- ggplot(ta_visual, aes(x = year, y = loi_nhuan_sau_thue)) +
  geom_line(color = "blue", linewidth = 1) +
  geom_point(color = "blue", size = 3) +
  geom_text(aes(label = format_number_m(loi_nhuan_sau_thue)), vjust = -1.2, size = 3.5) +
  labs(title = "Xu hướng Lợi nhuận sau thuế (LNST)",
       subtitle = "Tăng trưởng liên tục qua các năm",
       x = " ", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(breaks = NULL) +
  theme_minimal()

#  Đồ thị 2: Xu hướng Dòng tiền từ HĐKD (CFO) 
p2 <- ggplot(ta_visual, aes(x = year, y = cfo_tong)) +
  geom_line(color = "darkgreen", linewidth = 1) +
  geom_point(color = "darkgreen", size = 3) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
  geom_text(aes(label = format_number_m(cfo_tong)), vjust = -1.2, size = 3.5) +
  labs(title = "Xu hướng (CFO)",
       subtitle = "Biến động mạnh và âm nặng",
       x = " ", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(breaks = NULL) +
  theme_minimal()

# Đồ thị 3: Xu hướng Dòng tiền Tự do (FCF) 
p3 <- ggplot(ta_visual, aes(x = year, y = DongTienTuDo)) +
  geom_line(color = "purple", linewidth = 1) +
  geom_point(color = "purple", size = 3) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +
  geom_text(aes(label = format_number_m(DongTienTuDo)), vjust = -1.2, size = 3.5) +
  labs(title = "Xu hướng Dòng tiền Tự do (FCF)",
       subtitle = "FCF = CFO - Chi mua TSCD (CAPEX)",
       x = "Năm", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(breaks = ta_clean1$year) +
  theme_minimal()



# Kết hợp 3 đồ thị 

(p1 + p2) / p3 + plot_annotation(title = "TỔNG QUAN LỢI NHUẬN VÀ DÒNG TIỀN")

Xu hướng Lợi nhuận sau thuế (LNST): Đồ thị này thể hiện một bức tranh rất tích cực về mặt kế toán. Lợi nhuận của công ty tăng trưởng liên tục và mạnh mẽ suốt 10 năm, từ khoảng 92 nghìn tỷ lên đến 320 nghìn tỷ. Điều này cho thấy khả năng mở rộng thị phần và kiểm soát chi phí (trên sổ sách) rất tốt.

Xu hướng Dòng tiền từ HĐKD (CFO): Đồ thị này cho thấy một thực tế hoàn toàn trái ngược. Dòng tiền (tiền thật) từ hoạt động kinh doanh cốt lõi rất bất ổn. Đặc biệt, năm 2023, công ty rơi vào khủng hoảng thanh khoản nghiêm trọng khi CFO âm tới 30 nghìn tỷ, mặc dù lợi nhuận sổ sách (Đồ thị 1) vẫn báo lãi rất cao. Đây là dấu hiệu “lãi giả, lỗ thật” (lãi trên giấy nhưng không thu được tiền). Rất may mắn, CFO đã phục hồi mạnh mẽ vào năm 2024.

Xu hướng Dòng tiền Tự do (FCF): Dòng tiền tự do (FCF = CFO - Chi mua TSCD) là số tiền thật sự còn lại sau khi đã chi cho đầu tư tài sản. Đây là tiền để trả nợ, chia cổ tức. Đồ thị cho thấy FCF liên tục âm trong nhiều năm (đỉnh điểm là 2023), nghĩa là công ty không tạo đủ tiền từ kinh doanh để tài trợ cho việc mở rộng, mà phải dựa vào vốn vay hoặc vốn chủ sở hữu bên ngoài.

2.4.2 Phân tích chất lượng lợi nhuận

ta_visual_quality <- ta_clean1 %>%
  mutate(
    loi_nhuan_sau_thue = loi_nhuan_sau_thue / 1000000000,
    cfo_tong = cfo_tong / 1000000000
  )

df_gap <- ta_visual_quality %>%
  select(year, loi_nhuan_sau_thue, cfo_tong) %>%
  pivot_longer(c(loi_nhuan_sau_thue, cfo_tong), names_to = "ChiTieu", values_to = "GiaTri")

# Đồ thị 4: Chênh lệch LNST & CFO 
p4 <- ggplot(df_gap, aes(x = factor(year), y = GiaTri, color = ChiTieu, group = ChiTieu)) + # Đổi year sang factor
  geom_line(linewidth = 1.2) +
  geom_point(size = 3) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "black") + # Đổi màu đường 0
  
  # Đổi nhãn và màu sắc cho ChiTieu
  scale_color_manual(values = c("cfo_tong" = "darkgreen", "loi_nhuan_sau_thue" = "blue"),
                     labels = c("cfo_tong" = "Dòng tiền (CFO)", "loi_nhuan_sau_thue" = "Lợi nhuận (LNST)")) +
  
  labs(title = "Chênh lệch LNST & CFO",
       subtitle = "Khoảng cách lớn năm 2023",
       x = "Năm", y = "Tỷ đồng", color = "Chỉ tiêu") +
  
  # Định dạng trục Y và Theme
  scale_y_continuous(labels = scales::comma) + 
  theme_minimal() +
  theme(legend.position = "bottom",
        # Đảm bảo nhãn trục X (Năm) hiển thị rõ ràng
        axis.text.x = element_text(angle = 0, hjust = 0.5)) 

# Đồ thị 5: Phân phối LNST (Đường cong màu xanh dương trong cột) 
p5 <- ggplot(ta_visual_quality, aes(x = loi_nhuan_sau_thue)) +
  
  # Biểu đồ Histogram (Cột)
  geom_histogram(aes(y = after_stat(density)), bins = 5, 
                 fill = "lightblue", color = "black") + # Viền màu đen cho cột
  
  # Đường cong mật độ (Density)
  geom_density(color = "blue", fill = "blue", alpha = 0.2, linewidth = 1.2) + # Đổi màu đường cong thành xanh dương
  
  labs(title = "Phân phối LNST",
       subtitle = "Lệch phải, thấp & trung bình",
       x = "Lợi nhuận sau thuế (Tỷ đồng)", y = "Mật độ") +
  
  # Định dạng trục X (tạm thời sử dụng labels::comma)
  scale_x_continuous(labels = scales::comma) + 
  theme_minimal()

# Kết hợp 2 đồ thị 
p4 + p5 + plot_annotation(title = "PHÂN TÍCH CHẤT LƯỢNG LỢI NHUẬN")

Chênh lệch LNST & CFO: Đây là đồ thị quan trọng nhất để đánh giá chất lượng lợi nhuận. Khoảng cách giữa đường màu xanh (Lợi nhuận) và đường màu xanh lá (Dòng tiền) chính là các khoản “dồn tích” (accruals) - tức là lợi nhuận chưa thành tiền. Giai đoạn 2015-2018, hai đường này khá gần nhau (chất lượng lợi nhuận tốt). Tuy nhiên, năm 2019, 2020 và đặc biệt là 2023, khoảng cách này giãn ra cực lớn. Điều này khẳng định lợi nhuận năm 2023 chủ yếu đến từ các khoản phải thu hoặc hàng tồn kho (chưa bán được), không phải tiền mặt, rủi ro cực cao.

Phân phối LNST: Đồ thị bên phải cho thấy trong 10 năm qua, phần lớn số năm công ty đạt mức lợi nhuận ở khoảng thấp và trung bình (dưới 200 nghìn tỷ). Các năm lợi nhuận “siêu cao” (như 2023, 2024) là các giá trị ngoại lai, cho thấy sự tăng trưởng bứt phá trong thời gian gần đây.

2.4.3 Cấu trúc dòng tiền

# Đồ thị 6: Dòng tiền HĐKD (CFO)
p6 <- ggplot(ta_clean1, aes(x = year, y = cfo_tong)) +
  geom_col(aes(fill = cfo_tong > 0), show.legend = FALSE) +
  scale_fill_manual(values = c("TRUE" = "darkgreen", "FALSE" = "red")) +
  geom_hline(yintercept = 0) +
  labs(title = "Dòng tiền HĐ Kinh doanh (CFO)",
       subtitle = "Tạo tiền/Mất tiền từ hoạt động cốt lõi",
       x = "Năm", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(breaks = ta_clean1$year) +
  theme_minimal()

# Đồ thị 7: Dòng tiền Đầu tư (CFI)
p7 <- ggplot(ta_clean1, aes(x = year, y = cfi_tong)) +
  geom_col(aes(fill = cfi_tong > 0), show.legend = FALSE) +
  scale_fill_manual(values = c("TRUE" = "darkgreen", "FALSE" = "orange")) +
  geom_hline(yintercept = 0) +
  labs(title = "Dòng tiền Đầu tư (CFI)",
       subtitle = "Màu cam: Đang mở rộng đầu tư (Âm)",
       x = "Năm", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(breaks = ta_clean1$year) +
  theme_minimal()

# Đồ thị 8: Dòng tiền Tài trợ (CFF)
p8 <- ggplot(ta_clean1, aes(x = year, y = cff_tong)) +
  geom_col(aes(fill = cff_tong > 0), show.legend = FALSE) +
  scale_fill_manual(values = c("TRUE" = "blue", "FALSE" = "purple")) +
  geom_hline(yintercept = 0) +
  labs(title = "Dòng tiền Tài trợ (CFF)",
       subtitle = "Màu xanh: Huy động vốn (Dương) | Màu tím: Trả nợ/Cổ tức (Âm)",
       x = "Năm", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(breaks = ta_clean1$year) +
  theme_minimal()

# Kết hợp 3 đồ thị
p6 / p7 / p8 + plot_annotation(title = "PHÂN TÍCH CẤU TRÚC 3 DÒNG TIỀN (CFO, CFI, CFF)")

Dòng tiền HĐ Kinh doanh (CFO): Như đã thấy, dòng tiền kinh doanh (màu xanh lá) là nguồn sống. Việc nó chuyển sang màu đỏ (âm) năm 2023 là tín hiệu nguy hiểm nhất cho thấy hoạt động cốt lõi không tạo ra tiền.

Dòng tiền Đầu tư (CFI): Dòng tiền đầu tư liên tục âm (màu cam) trong suốt 10 năm. Đây là đặc điểm của một công ty đang trong giai đoạn tăng trưởng, mở rộng mạnh mẽ. Công ty liên tục chi tiền để mua tài sản, đầu tư…

Dòng tiền Tài trợ (CFF): Dòng tiền tài trợ cho thấy công ty dùng tiền từ đâu để bù đắp cho thâm hụt.

Những năm CFF dương (xanh) như 2017: Công ty đang huy động vốn mạnh (đi vay nợ hoặc phát hành cổ phiếu) để bù đắp cho việc CFO yếu và CFI âm.

Những năm CFF âm (tím) như 2021, 2022: Công ty dùng tiền (thường là từ CFO) để trả nợ gốc hoặc chia cổ tức.

Kết luận: Công ty đang trong mô hình “Tăng trưởng > Đầu tư > Huy động vốn”. Năm 2023 là năm điển hình: Kinh doanh cạn tiền (CFO âm), vẫn phải đầu tư (CFI âm), buộc phải đi vay thêm (CFF dương - dù nhỏ) để tồn tại.

2.4.4 Quản lí vốn lưu động

# Đồ thị 9: Biến động Khoản phải thu
p9 <- ggplot(ta_clean1, aes(x = year, y = bien_dong_phai_thu)) +
  geom_col(aes(fill = bien_dong_phai_thu > 0), show.legend = FALSE) +
  geom_hline(yintercept = 0) +
  scale_fill_manual(values = c("TRUE" = "darkgreen", "FALSE" = "red")) +
  labs(title = "Biến động Khoản phải thu",
       subtitle = "Màu đỏ (Âm): Tăng phải thu (Bán chịu, đọng vốn)",
       x = "Năm", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(breaks = ta_clean1$year) +
  theme_minimal()

# Đồ thị 10: Biến động Hàng tồn kho
p10 <- ggplot(ta_clean1, aes(x = year, y = bien_dong_ton_kho)) +
  geom_col(aes(fill = bien_dong_ton_kho > 0), show.legend = FALSE) +
  geom_hline(yintercept = 0) +
  scale_fill_manual(values = c("TRUE" = "darkgreen", "FALSE" = "red")) +
  labs(title = "Biến động Hàng tồn kho",
       subtitle = "Màu đỏ (Âm): Tăng tồn kho (Ôm hàng, đọng vốn)",
       x = "Năm", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(breaks = ta_clean1$year) +
  theme_minimal()

# Đồ thị 11: Biến động Khoản phải trả
p11 <- ggplot(ta_clean1, aes(x = year, y = bien_dong_phai_tra)) +
  geom_col(aes(fill = bien_dong_phai_tra > 0), show.legend = FALSE) +
  geom_hline(yintercept = 0) +
  scale_fill_manual(values = c("TRUE" = "darkgreen", "FALSE" = "red")) +
  labs(title = "Biến động Khoản phải trả",
       subtitle = "Màu xanh (Dương): Tăng phải trả (Chiếm dụng vốn N.C.C)",
       x = "Năm", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(breaks = ta_clean1$year) +
  theme_minimal()

# Kết hợp 3 đồ thị
p9 / p10 / p11 + plot_annotation(title = "PHÂN TÍCH VỐN LƯU ĐỘNG (NGUYÊN NHÂN BIẾN ĐỘNG CFO)")

Biến động Khoản phải thu: Màu đỏ (âm) nghĩa là công ty đang tăng cường bán chịu, bị khách hàng chiếm dụng vốn. Các năm 2019, 2020 và đặc biệt là 2024 (âm) cho thấy công ty bán được hàng nhưng không thu được tiền.

Biến động Hàng tồn kho: Màu đỏ (âm) nghĩa là công ty nhập hàng về kho hoặc sản xuất ra nhưng chưa bán được. Năm 2023 là đỉnh điểm (âm sâu), cho thấy tiền của công ty đã “biến” thành hàng tồn kho, nằm bất động. Đây là nguyên nhân chính gây ra CFO âm năm 2023.

Biến động Khoản phải trả: Màu xanh (dương) nghĩa là công ty chiếm dụng được vốn của nhà cung cấp (mua hàng nhưng chưa trả tiền). Đây là một nguồn tài trợ. Tuy nhiên, năm 2023, khoản này lại âm (màu đỏ), nghĩa là công ty phải trả tiền cho nhà cung cấp, càng làm cạn kiệt dòng tiền.

Khủng hoảng CFO năm 2023 được giải thích rõ ràng: Công ty dùng tiền để trả nhà cung cấp (Phải trả âm), trong khi tiền lại bị kẹt trong Tồn kho (Tồn kho âm sâu).

2.4.5 Chiến lược đầu từ và tái đầu tư

ta_visual <- ta_clean1 %>%
  mutate(
    year_factor = factor(year), 
    cfi_tong = cfi_tong / 1000000000,
    chi_mua_tscd = chi_mua_tscd / 1000000000,
    loi_nhuan_sau_thue = loi_nhuan_sau_thue / 1000000000,
    DongTienTuDo = DongTienTuDo / 1000000000
  )

# Đồ thị 12: Dòng tiền đầu tư (CFI) và Chi mua TSCD (CAPEX) 
p12 <- ggplot(ta_visual, aes(x = year_factor)) + # Dùng year_factor
  geom_line(aes(y = cfi_tong, group = 1, color = "Tổng CFI"), linewidth = 1.2) +
  geom_col(aes(y = chi_mua_tscd, fill = "Chi mua TSCD (CAPEX)"), alpha = 0.7) +
  labs(title = "Dòng tiền Đầu tư (CFI) và CAPEX",
       subtitle = "Chi mua TSCD là hạng mục chính gây âm CFI",
       x = "Năm", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_color_manual(name = "", values = c("Tổng CFI" = "orange")) +
  scale_fill_manual(name = "", values = c("Chi mua TSCD (CAPEX)" = "darkred")) +
  theme_minimal() + 
  theme(legend.position = "bottom",
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

# Đồ thị 13: Lợi nhuận và Dòng tiền tự do 
p13 <- ggplot(ta_visual, aes(x = year_factor)) + # Dùng year_factor
  geom_line(aes(y = loi_nhuan_sau_thue, group = 1, color = "Lợi nhuận (LNST)"),
            linewidth = 1.2) +
  geom_line(aes(y = DongTienTuDo, group = 1, color = "Dòng tiền Tự do (FCF)"),
            linewidth = 1.2, linetype = "dashed") +
  geom_hline(yintercept = 0, linetype = "dotted") +
  labs(title = "LN & Dòng tiền Tự do",
       subtitle = "Bất cân xứng",
       x = "Năm", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_color_manual(name = "Chỉ tiêu", 
                     values = c("Lợi nhuận (LNST)" = "blue", "Dòng tiền Tự do (FCF)" = "purple")) +
  theme_minimal() + 
  theme(legend.position = "bottom",
        axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

# Kết hợp 2 đồ thị
p12 + p13 + plot_annotation(title = "CHIẾN LƯỢC ĐẦU TƯ")

Dòng tiền Đầu tư (CFI) và CAPEX: Đồ thị bên trái xác nhận chi_mua_tscd (CAPEX, các cột màu xám) là nguyên nhân chính khiến Dòng tiền Đầu tư (CFI, đường màu cam) liên tục âm. Công ty đang theo đuổi chiến lược thâm dụng vốn (capital intensive), chi rất nhiều tiền cho nhà xưởng, máy móc để mở rộng.

LN & Dòng tiền Tự do (FCF): Đồ thị bên phải so sánh lợi nhuận (đường xám) với dòng tiền tự do (đường tím nét đứt). Mặc dù lợi nhuận tăng đều, FCF lại liên tục nằm dưới mức 0 (âm). Điều này có nghĩa là, toàn bộ lợi nhuận kiếm được (và thậm chí còn nhiều hơn) đều bị “đốt” vào việc tái đầu tư (CAPEX). Công ty không còn lại tiền mặt tự do để trả cho cổ đông hoặc chủ nợ.

2.4.6 Chiến lược Tài trợ và Quản lý Nợ

# Chuẩn bị dữ liệu
df_vay <- ta_clean1 %>%
  select(year, vay_moi, tra_no_goc) %>%
  mutate(tra_no_goc = abs(tra_no_goc)) %>% # Chuyển số âm thành dương để dễ vẽ
  pivot_longer(cols = c(vay_moi, tra_no_goc), names_to = "Loai", values_to = "GiaTri")

# Đồ thị 14: Vay mới vs Trả nợ gốc
p14 <- ggplot(df_vay, aes(x = year, y = GiaTri, fill = Loai)) +
  geom_col(position = "dodge") +
  scale_fill_manual(values = c("vay_moi" = "blue", "tra_no_goc" = "gray"),
                    labels = c("Trả nợ gốc", "Vay mới")) +
  labs(title = "Vay mới vs. Trả nợ gốc",
       subtitle = "Liên tục vay nợ quy mô lớn",
       x = "Năm", y = "Tỷ đồng", fill = "Hoạt động") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(breaks = ta_clean1$year) +
  theme_minimal() + theme(legend.position = "bottom")

# Đồ thị 15: Vay ròng (Vay mới - Trả nợ)
p15 <- ggplot(ta_clean1, aes(x = year, y = VayRong)) +
  geom_col(aes(fill = VayRong > 0), show.legend = FALSE) +
  geom_hline(yintercept = 10) +
  scale_fill_manual(values = c("TRUE" = "blue", "FALSE" = "purple")) +
  labs(title = "Vay ròng",
       subtitle = "Xanh: Vay thêm ròng | Tím: Trả nợ ròng",
       x = "Năm", y = "Tỷ đồng") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(breaks = ta_clean1$year) +
  theme_minimal()

# Đồ thị 16: Phân loại Chính sách Nợ
p16 <- ggplot(ta_clean1, aes(x = ChinhSachNo, fill = ChinhSachNo)) +
  geom_bar(show.legend = FALSE) +
  geom_text(stat='count', aes(label=after_stat(count)), vjust=1) +
  labs(title = "Số năm theo Chính sách Nợ",
       x = "Chính sách Nợ", y = "Số năm") +
  theme_minimal()

# Kết hợp 3 đồ thị
(p14 / p15) + p16 + plot_annotation(title = "PHÂN TÍCH HOẠT ĐỘNG TÀI TRỢ (NỢ)")

Vay mới vs. Trả nợ gốc: Đồ thị 14 cho thấy quy mô vay và trả nợ của công ty là rất lớn, lên đến hàng trăm nghìn tỷ. Công ty có vẻ đang thực hiện chiến lược “đảo nợ” (rollover debt) - vay khoản mới để trả khoản cũ, đồng thời vay thêm để mở rộng.

Vay ròng: Đồ thị 15 là kết quả thực.

Các năm màu tím (âm) như 2020, 2021: Công ty trả nợ ròng (trả nhiều hơn vay). Đây là những năm CFO tốt, công ty có tiền để giảm đòn bẩy.

Các năm màu xanh (dương) như 2024: Công ty vay ròng (vay nhiều hơn trả).

Chính sách Nợ: Đồ thị 16 tổng kết lại, công ty có 6 năm trả nợ ròng và 2 năm vay thêm ròng (và 2 năm cân bằng). Mặc dù có xu hướng trả nợ, nhưng khi cần vay thì công ty vay với quy mô rất lớn.

2.4.7 Phân tích Tỷ số Tài chính

ta_visual <- ta_clean1 %>%
  mutate(
    year_factor = factor(year) )

# Đồ thị 17: Tỷ số ROA (Lợi nhuận/Tài sản) 
p17 <- ggplot(ta_visual, aes(x = year_factor, y = ROA)) + 
  geom_line(aes(group = 1), color = "darkred", linewidth = 1) + 
  geom_point(color = "darkred", size = 2) +
  labs(title = "Tỷ số sinh lời trên ROA",
       x = "Năm", y = "ROA") +
  scale_y_continuous(labels = scales::percent) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)
  )

# Đồ thị 18: Tỷ số ROS (Lợi nhuận/Doanh thu - Giả định) 
p18 <- ggplot(ta_visual, aes(x = year_factor, y = ROS)) + # Dùng year_factor
  geom_line(aes(group = 1), color = "darkblue", linewidth = 1) +
  geom_point(color = "darkblue", size = 2) +
  labs(title = "Tỷ số sinh lời trên ROS",
       x = "Năm", y = "ROS") +
  scale_y_continuous(labels = scales::percent) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)
  )

# Đồ thị 19: Tỷ số Thanh khoản Hiện hành (Giả định)
p19 <- ggplot(ta_visual, aes(x = year_factor, y = TySo_ThanhKhoanHienHanh))+  
  geom_line(aes(group = 1), color = "darkgreen", linewidth = 1) +
  geom_point(color = "darkgreen", size = 2) +
  geom_hline(yintercept = 1, linetype = "dashed", color = "red") +
  labs(title = "Tỷ số thanh khoản",
       subtitle = "Dưới 1 (màu đỏ) là rủi ro thanh khoản",
       x = "Năm", y = "Tỷ số") +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)
  )
# Đồ thị 20: Tỷ số Nợ (Giả định) 
p20 <- ggplot(ta_visual, aes(x = year_factor, y = TySo_No)) + # Dùng year_factor
  geom_line(aes(group = 1), color = "purple", linewidth = 1) +
  geom_point(color = "purple", size = 2) +
  labs(title = "Tỷ số nợ",
       x = "Năm", y = "Tỷ số") +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)
  )

# Kết hợp 4 đồ thị 
(p17 + p18) / (p19 + p20) +
  plot_annotation(title = "BẢNG ĐIỂU KHIỂN KẾT QUẢ TÀI CHÍNH")

Tỷ số Sinh lời trên Tài sản (ROA): Cho thấy hiệu quả sử dụng tài sản. ROA biến động nhưng có xu hướng tăng mạnh về cuối (2023-2024), cho thấy dù công ty đầu tư nhiều tài sản (CFI âm), nhưng lợi nhuận (LNST) tăng còn nhanh hơn.

Tỷ số Sinh lời trên Doanh thu (ROS): Biên lợi nhuận ròng. Tỷ số này biến động mạnh, đặc biệt sụt giảm năm 2021 và 2023, cho thấy hiệu quả quản lý chi phí/giá bán không ổn định.

Tỷ số Thanh khoản: Đây là tỷ số cảnh báo. Khi nó rơi xuống dưới 1 (đường đỏ) vào các năm 2019, 2020 và đặc biệt là 2023 (gần như bằng 0), nó cho thấy tài sản ngắn hạn không đủ để trả các khoản nợ ngắn hạn. Điều này khớp hoàn hảo với khủng hoảng CFO âm năm 2023. Năm 2021 tỷ số này tăng vọt bất thường, cần xem xét lại dữ liệu năm đó.

Tỷ số Nợ: Cho thấy gánh nặng nợ. Tỷ số này tăng vọt vào năm 2020, cho thấy nợ tăng nhanh hơn lợi nhuận. Điều này cũng khớp với việc CFF dương (vay thêm ròng) trong những năm đó.