LỜI CẢM ƠN

Trong suốt quá trình thực hiện bài tiểu luận môn Ngôn ngữ lập trình, em đã nhận được rất nhiều sự hướng dẫn và giúp đỡ từ thầy. Em xin gửi lời cảm ơn chân thành đến Thầy giảng viên hướng dẫn, đã tận tình chỉ bảo, định hướng và hỗ trợ em trong suốt quá trình nghiên cứu và hoàn thiện bài làm. Mặc dù đã rất cố gắng, nhưng bài tiểu luận khó tránh khỏi những thiếu sót. Em rất mong nhận được ý kiến đóng góp từ quý thầy cô để bài làm được hoàn thiện hơn.

LỜI CAM ĐOAN

Nhóm xin cam đoan rằng toàn bộ nội dung trong bài tiểu luận là kết quả nghiên cứu, phân tích và trình bày của riêng nhóm, không sao chép hay vi phạm bản quyền. Các số liệu và kết quả được sử dụng trong bài đều trung thực, có nguồn gốc rõ ràng và được xử lý cẩn thận. Nhóm hoàn toàn chịu trách nhiệm về tính chính xác và trung thực của toàn bộ nội dung bài làm.

Sinh viên thực hiện: Phạm Thị Kiều Oanh & Tăng Mạch Thanh Xuân

PHẦN 1: BỘ DỮ LIỆU NEW REATAIL DATA

CHƯƠNG 1: GIỚI THIỆU BỘ DỮ LIỆU

1.1 Đọc dữ liệu

1. retail <- read_csv("C:/Users/ASUS/Downloads/archive (7)/new_retail_data.csv")
1. head(retail)
## # A tibble: 6 × 30
##   Transaction_ID Customer_ID Name       Email  Phone Address City  State Zipcode
##            <dbl>       <dbl> <chr>      <chr>  <dbl> <chr>   <chr> <chr>   <dbl>
## 1        8691788       37249 Michelle … Ebon… 1.41e9 3959 A… Dort… Berl…   77985
## 2        2174773       69749 Kelsey Hi… Mark… 6.85e9 82072 … Nott… Engl…   99071
## 3        6679610       30192 Scott Jen… Shan… 8.36e9 4133 Y… Geel… New …   75929
## 4        7232460       62101 Joseph Mi… Mary… 2.78e9 8148 T… Edmo… Onta…   88420
## 5        4983775       27901 Debra Col… Char… 9.10e9 5813 L… Bris… Engl…   48704
## 6        6095326       41289 Ryan John… Hale… 3.29e9 532 As… Bris… New …   74430
## # ℹ 21 more variables: Country <chr>, Age <dbl>, Gender <chr>, Income <chr>,
## #   Customer_Segment <chr>, Date <chr>, Year <dbl>, Month <chr>, Time <time>,
## #   Total_Purchases <dbl>, Amount <dbl>, Total_Amount <dbl>,
## #   Product_Category <chr>, Product_Brand <chr>, Product_Type <chr>,
## #   Feedback <chr>, Shipping_Method <chr>, Payment_Method <chr>,
## #   Order_Status <chr>, Ratings <dbl>, products <chr>

Giải thích kỹ thuật: Để đọc bộ dữ liệu đầu tiên chúng ta nạp thu viện readr để sử dụng các hàm đọc dữ liệu CSV. File CSV “new_retail_data.csv” trong thư mục được đọc vào R bằng read_csv() và được lưu vào object retail. Cuối cùng, head(retail) được sử dụng để hiển thị 6 dòng đầu tiên, giúp kiểm tra nhanh dữ liệu và chắc chắn rằng việc đọc file đã thành công.

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

Xem 10 dòng đầu tiên của bộ dữ liệu

1. head(retail,10)
## # A tibble: 10 × 30
##    Transaction_ID Customer_ID Name      Email  Phone Address City  State Zipcode
##             <dbl>       <dbl> <chr>     <chr>  <dbl> <chr>   <chr> <chr>   <dbl>
##  1        8691788       37249 Michelle… Ebon… 1.41e9 3959 A… Dort… Berl…   77985
##  2        2174773       69749 Kelsey H… Mark… 6.85e9 82072 … Nott… Engl…   99071
##  3        6679610       30192 Scott Je… Shan… 8.36e9 4133 Y… Geel… New …   75929
##  4        7232460       62101 Joseph M… Mary… 2.78e9 8148 T… Edmo… Onta…   88420
##  5        4983775       27901 Debra Co… Char… 9.10e9 5813 L… Bris… Engl…   48704
##  6        6095326       41289 Ryan Joh… Hale… 3.29e9 532 As… Bris… New …   74430
##  7        5434096       97285 Erin Lew… Arth… 1.58e9 600 Br… Kitc… Onta…   47545
##  8        2344675       26603 Angela F… Tany… 3.67e9 237 Yo… Muni… Berl…   86862
##  9        4155845       80175 Diane Cl… Mart… 6.22e9 8823 M… Woll… New …   39820
## 10        4926148       31878 Lori Bell Jess… 6.00e9 6225 W… Colo… Berl…   64317
## # ℹ 21 more variables: Country <chr>, Age <dbl>, Gender <chr>, Income <chr>,
## #   Customer_Segment <chr>, Date <chr>, Year <dbl>, Month <chr>, Time <time>,
## #   Total_Purchases <dbl>, Amount <dbl>, Total_Amount <dbl>,
## #   Product_Category <chr>, Product_Brand <chr>, Product_Type <chr>,
## #   Feedback <chr>, Shipping_Method <chr>, Payment_Method <chr>,
## #   Order_Status <chr>, Ratings <dbl>, products <chr>

Xem 10 dòng cuối cùng của bộ dữ liệu

1. tail(retail,10)
## # A tibble: 10 × 30
##    Transaction_ID Customer_ID Name      Email  Phone Address City  State Zipcode
##             <dbl>       <dbl> <chr>     <chr>  <dbl> <chr>   <chr> <chr>   <dbl>
##  1        9862022       99656 Amber Fi… Dona… 6.47e9 50022 … Plym… Engl…   92925
##  2        5561211       35974 Jordan H… Holl… 2.06e9 806 Al… Ball… New …   99633
##  3        8961631       79479 Jason We… Jaso… 6.28e9 764 Ga… Hami… Onta…   61218
##  4        2844206       18799 Angel Ho… Jose… 2.83e9 7593 J… Cair… New …   39837
##  5        4833982       94117 Kara Hart Tamm… 7.11e9 872 Ro… Char… Miss…   65301
##  6        4246475       12104 Meagan E… Cour… 7.47e9 389 To… Town… New …    4567
##  7        1197603       69772 Mathew B… Jenn… 5.75e9 52809 … Hano… Berl…   16852
##  8        7743242       28449 Daniel L… Chri… 9.38e9 407 Aa… Brig… Engl…   88038
##  9        9301950       45477 Patrick … Rebe… 9.37e9 3204 B… Hali… Onta…   67608
## 10        2882826       53626 Dustin M… Will… 9.52e9 143 Am… Tucs… West…   25242
## # ℹ 21 more variables: Country <chr>, Age <dbl>, Gender <chr>, Income <chr>,
## #   Customer_Segment <chr>, Date <chr>, Year <dbl>, Month <chr>, Time <time>,
## #   Total_Purchases <dbl>, Amount <dbl>, Total_Amount <dbl>,
## #   Product_Category <chr>, Product_Brand <chr>, Product_Type <chr>,
## #   Feedback <chr>, Shipping_Method <chr>, Payment_Method <chr>,
## #   Order_Status <chr>, Ratings <dbl>, products <chr>

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

1. dim(retail)
## [1] 302010     30

Nhận xét: Theo kết quả chạy lệnh dim(retail) cho ta thấy bộ dữ liệu có 302010 dòng và 30 cột. Điều này có nghĩa là dataset chưa 302010 quan sát với 30 biến khác nhau. Thông tin giúp ta nắm được quy mô dữ liệu.

1.3 Danh sách tên các biếnn của dữ liệu

1. names(retail)
##  [1] "Transaction_ID"   "Customer_ID"      "Name"             "Email"           
##  [5] "Phone"            "Address"          "City"             "State"           
##  [9] "Zipcode"          "Country"          "Age"              "Gender"          
## [13] "Income"           "Customer_Segment" "Date"             "Year"            
## [17] "Month"            "Time"             "Total_Purchases"  "Amount"          
## [21] "Total_Amount"     "Product_Category" "Product_Brand"    "Product_Type"    
## [25] "Feedback"         "Shipping_Method"  "Payment_Method"   "Order_Status"    
## [29] "Ratings"          "products"

1.4 Cấu trúc dữ liệu

1. str (retail)
## spc_tbl_ [302,010 × 30] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ Transaction_ID  : num [1:302010] 8691788 2174773 6679610 7232460 4983775 ...
##  $ Customer_ID     : num [1:302010] 37249 69749 30192 62101 27901 ...
##  $ Name            : chr [1:302010] "Michelle Harrington" "Kelsey Hill" "Scott Jensen" "Joseph Miller" ...
##  $ Email           : chr [1:302010] "Ebony39@gmail.com" "Mark36@gmail.com" "Shane85@gmail.com" "Mary34@gmail.com" ...
##  $ Phone           : num [1:302010] 1.41e+09 6.85e+09 8.36e+09 2.78e+09 9.10e+09 ...
##  $ Address         : chr [1:302010] "3959 Amanda Burgs" "82072 Dawn Centers" "4133 Young Canyon" "8148 Thomas Creek Suite 100" ...
##  $ City            : chr [1:302010] "Dortmund" "Nottingham" "Geelong" "Edmonton" ...
##  $ State           : chr [1:302010] "Berlin" "England" "New South Wales" "Ontario" ...
##  $ Zipcode         : num [1:302010] 77985 99071 75929 88420 48704 ...
##  $ Country         : chr [1:302010] "Germany" "UK" "Australia" "Canada" ...
##  $ Age             : num [1:302010] 21 19 48 56 22 58 29 29 46 25 ...
##  $ Gender          : chr [1:302010] "Male" "Female" "Male" "Male" ...
##  $ Income          : chr [1:302010] "Low" "Low" "Low" "High" ...
##  $ Customer_Segment: chr [1:302010] "Regular" "Premium" "Regular" "Premium" ...
##  $ Date            : chr [1:302010] "9/18/2023" "12/31/2023" "4/26/2023" "5/8/2023" ...
##  $ Year            : num [1:302010] 2023 2023 2023 2023 2024 ...
##  $ Month           : chr [1:302010] "September" "December" "April" "May" ...
##  $ Time            : 'hms' num [1:302010] 22:03:55 08:42:04 04:06:29 14:55:17 ...
##   ..- attr(*, "units")= chr "secs"
##  $ Total_Purchases : num [1:302010] 3 2 3 7 2 4 2 1 8 10 ...
##  $ Amount          : num [1:302010] 108 403 354 352 124 ...
##  $ Total_Amount    : num [1:302010] 324 807 1063 2467 249 ...
##  $ Product_Category: chr [1:302010] "Clothing" "Electronics" "Books" "Home Decor" ...
##  $ Product_Brand   : chr [1:302010] "Nike" "Samsung" "Penguin Books" "Home Depot" ...
##  $ Product_Type    : chr [1:302010] "Shorts" "Tablet" "Children's" "Tools" ...
##  $ Feedback        : chr [1:302010] "Excellent" "Excellent" "Average" "Excellent" ...
##  $ Shipping_Method : chr [1:302010] "Same-Day" "Standard" "Same-Day" "Standard" ...
##  $ Payment_Method  : chr [1:302010] "Debit Card" "Credit Card" "Credit Card" "PayPal" ...
##  $ Order_Status    : chr [1:302010] "Shipped" "Processing" "Processing" "Processing" ...
##  $ Ratings         : num [1:302010] 5 4 2 4 1 4 1 1 1 4 ...
##  $ products        : chr [1:302010] "Cycling shorts" "Lenovo Tab" "Sports equipment" "Utility knife" ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   Transaction_ID = col_double(),
##   ..   Customer_ID = col_double(),
##   ..   Name = col_character(),
##   ..   Email = col_character(),
##   ..   Phone = col_double(),
##   ..   Address = col_character(),
##   ..   City = col_character(),
##   ..   State = col_character(),
##   ..   Zipcode = col_double(),
##   ..   Country = col_character(),
##   ..   Age = col_double(),
##   ..   Gender = col_character(),
##   ..   Income = col_character(),
##   ..   Customer_Segment = col_character(),
##   ..   Date = col_character(),
##   ..   Year = col_double(),
##   ..   Month = col_character(),
##   ..   Time = col_time(format = ""),
##   ..   Total_Purchases = col_double(),
##   ..   Amount = col_double(),
##   ..   Total_Amount = col_double(),
##   ..   Product_Category = col_character(),
##   ..   Product_Brand = col_character(),
##   ..   Product_Type = col_character(),
##   ..   Feedback = col_character(),
##   ..   Shipping_Method = col_character(),
##   ..   Payment_Method = col_character(),
##   ..   Order_Status = col_character(),
##   ..   Ratings = col_double(),
##   ..   products = col_character()
##   .. )
##  - attr(*, "problems")=<externalptr>

Nhận xét: Bộ dữ liệu có 302010 quan sát với 30 biến. Mỗi dòng là một giao dịch mua hàng, chưa thông tin về khách hàng, sản phẩm, giá tiền, phương thức thanh toán,..

Có 10 biến thuộc kiểu dữ liệu numeric: Transaction_ID, Customer_ID, Phone, Zipcode, Age, Year, Total_Purchases, Amout, Total_Amount, Rating.

Có 19 biến thuộc kiểu dữ liệu character: Name, Email, Address, City, State, Country, Gender, Income, Customer_Segment, Date,Product_Category, Product_Brand, Product_Type, Feedback, Shipping_Method, Payment_Method, Order_Status, products.

Có 1 biến kiểu dữ liệu hms: Time.

1.5 Kiểu dữ liệu từng cột

1. sapply(retail,class)
## $Transaction_ID
## [1] "numeric"
## 
## $Customer_ID
## [1] "numeric"
## 
## $Name
## [1] "character"
## 
## $Email
## [1] "character"
## 
## $Phone
## [1] "numeric"
## 
## $Address
## [1] "character"
## 
## $City
## [1] "character"
## 
## $State
## [1] "character"
## 
## $Zipcode
## [1] "numeric"
## 
## $Country
## [1] "character"
## 
## $Age
## [1] "numeric"
## 
## $Gender
## [1] "character"
## 
## $Income
## [1] "character"
## 
## $Customer_Segment
## [1] "character"
## 
## $Date
## [1] "character"
## 
## $Year
## [1] "numeric"
## 
## $Month
## [1] "character"
## 
## $Time
## [1] "hms"      "difftime"
## 
## $Total_Purchases
## [1] "numeric"
## 
## $Amount
## [1] "numeric"
## 
## $Total_Amount
## [1] "numeric"
## 
## $Product_Category
## [1] "character"
## 
## $Product_Brand
## [1] "character"
## 
## $Product_Type
## [1] "character"
## 
## $Feedback
## [1] "character"
## 
## $Shipping_Method
## [1] "character"
## 
## $Payment_Method
## [1] "character"
## 
## $Order_Status
## [1] "character"
## 
## $Ratings
## [1] "numeric"
## 
## $products
## [1] "character"

1.6 Mô tả các biến trong bộ dữ liệu

1. unique_info <- data.frame(
2.   Bien = names(retail),
3.   So_luong_gia_tri = sapply(retail, function(x) length(unique(x))),
4.   Gia_tri_cu_the = sapply(retail, function(x) {
5.     vals <- as.character(unique(x))
6.     if (length(vals) > 10) {
7.       paste(c(vals[1:10], "..."), collapse = ", ")
8.     } else {
9.       paste(vals, collapse = ", ")
10.     }
11.   }),
12.   stringsAsFactors = FALSE)
13. kable(unique_info, caption = "Bảng: Giá trị duy nhất của từng biến trong bộ dữ liệu")
Bảng: Giá trị duy nhất của từng biến trong bộ dữ liệu
Bien So_luong_gia_tri Gia_tri_cu_the
Transaction_ID Transaction_ID 294462 8691788, 2174773, 6679610, 7232460, 4983775, 6095326, 5434096, 2344675, 4155845, 4926148, …
Customer_ID Customer_ID 86767 37249, 69749, 30192, 62101, 27901, 41289, 97285, 26603, 80175, 31878, …
Name Name 159391 Michelle Harrington, Kelsey Hill, Scott Jensen, Joseph Miller, Debra Coleman, Ryan Johnson, Erin Lewis, Angela Fields, Diane Clark, Lori Bell, …
Email Email 52898 , , , , , , , , , , …
Phone Phone 299296 1414786801, 6852899987, 8362160449, 2776751724, 9098267635, 3292677006, 1578355423, 3668096144, 6219779557, 6004895059, …
Address Address 299330 3959 Amanda Burgs, 82072 Dawn Centers, 4133 Young Canyon, 8148 Thomas Creek Suite 100, 5813 Lori Ports Suite 269, 532 Ashley Crest Suite 014, 600 Brian Prairie Suite 497, 237 Young Curve, 8823 Mariah Heights Apt. 263, 6225 William Lodge, …
City City 131 Dortmund, Nottingham, Geelong, Edmonton, Bristol, Brisbane, Kitchener, Munich, Wollongong, Cologne, …
State State 55 Berlin, England, New South Wales, Ontario, Virginia, Nevada, Colorado, Arkansas, Texas, Oklahoma, …
Zipcode Zipcode 93979 77985, 99071, 75929, 88420, 48704, 74430, 47545, 86862, 39820, 64317, …
Country Country 6 Germany, UK, Australia, Canada, USA, NA
Age Age 54 21, 19, 48, 56, 22, 58, 29, 46, 25, 64, …
Gender Gender 3 Male, Female, NA
Income Income 4 Low, High, Medium, NA
Customer_Segment Customer_Segment 4 Regular, Premium, New, NA
Date Date 367 9/18/2023, 12/31/2023, 4/26/2023, 5/8/2023, 1/10/2024, 9/21/2023, 6/26/2023, 3/24/2023, 1/6/2024, 10/4/2023, …
Year Year 3 2023, 2024, NA
Month Month 13 September, December, April, May, January, June, March, October, July, November, …
Time Time 83678 22:03:55, 08:42:04, 04:06:29, 14:55:17, 16:54:07, 23:24:27, 13:35:51, 10:12:56, 14:38:26, 22:27:40, …
Total_Purchases Total_Purchases 11 3, 2, 7, 4, 1, 8, 10, 9, 6, 5, …
Amount Amount 299298 108.0287567, 403.3539073, 354.4775997, 352.4077173, 124.2765245, 296.2918059, 315.0576476, 46.58807038, 328.8393017, 397.6112295, …
Total_Amount Total_Amount 299306 324.08627, 806.7078147, 1063.432799, 2466.854021, 248.5530491, 1185.167224, 630.1152951, 46.58807038, 2630.714413, 3976.112295, …
Product_Category Product_Category 6 Clothing, Electronics, Books, Home Decor, Grocery, NA
Product_Brand Product_Brand 19 Nike, Samsung, Penguin Books, Home Depot, Nestle, Apple, Zara, Random House, Coca-Cola, Adidas, …
Product_Type Product_Type 33 Shorts, Tablet, Children’s, Tools, Chocolate, Television, Shirt, Decorations, Non-Fiction, Water, …
Feedback Feedback 5 Excellent, Average, Bad, Good, NA
Shipping_Method Shipping_Method 4 Same-Day, Standard, Express, NA
Payment_Method Payment_Method 5 Debit Card, Credit Card, PayPal, Cash, NA
Order_Status Order_Status 5 Shipped, Processing, Pending, Delivered, NA
Ratings Ratings 6 5, 4, 2, 1, 3, NA
products products 318 Cycling shorts, Lenovo Tab, Sports equipment, Utility knife, Chocolate cookies, QLED TV, Dress shirt, Dark chocolate, Candles, Screwdriver set, …

Giải thích ý nghĩa kỹ thuật: Có chức năng tóm tắt thông tin cơ bản về các biến trong một bộ dữ liệu. Cụ thể, đầu tiên nó dùng names(retail) để liệt kê tên tất cả các biến, sau đó sapplyretaila, function(x) length(unique(x))) đếm số lượng giá trị duy nhất của mỗi biến, giúp nhận biết biến nào là phân loại hay liên tục. Tiếp theo, sapply(retail, function(x){…}) tạo một cột liệt kê các giá trị cụ thể của từng biến; nếu số lượng giá trị lớn hơn 20, chỉ hiển thị 10 giá trị đầu và thêm dấu “…” để tránh bảng quá dài. Tất cả kết quả được gom vào một data.frame với stringsAsFactors = FALSE để giữ dữ liệu dạng chuỗi, cuối cùng kable() từ thư viện knitr in ra bảng đẹp kèm chú thích.

CHƯƠNG 2: XỬ LÝ VÀ MÃ HÓA DỮ LIỆU

2.1 Kiểm tra và làm sạch dữ liệu

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

1. sum(duplicated(retail))
## [1] 4
1. retail[duplicated(retail), ]
## # A tibble: 4 × 30
##   Transaction_ID Customer_ID Name       Email  Phone Address City  State Zipcode
##            <dbl>       <dbl> <chr>      <chr>  <dbl> <chr>   <chr> <chr>   <dbl>
## 1        4476510       20103 Christine… Jame… 2.38e9 8176 R… Kitc… Onta…    7099
## 2        5340129       29920 Collin Da… Cour… 4.09e9 371 Cy… Woll… New …   47758
## 3        4942326       25416 Pamela Ma… Chri… 6.66e9 9851 M… Leic… Engl…   57655
## 4        3200766       49598 Mikayla M… Kenn… 6.98e9 716 Jo… Brem… Berl…   64747
## # ℹ 21 more variables: Country <chr>, Age <dbl>, Gender <chr>, Income <chr>,
## #   Customer_Segment <chr>, Date <chr>, Year <dbl>, Month <chr>, Time <time>,
## #   Total_Purchases <dbl>, Amount <dbl>, Total_Amount <dbl>,
## #   Product_Category <chr>, Product_Brand <chr>, Product_Type <chr>,
## #   Feedback <chr>, Shipping_Method <chr>, Payment_Method <chr>,
## #   Order_Status <chr>, Ratings <dbl>, products <chr>

Nhận xét: Kết quả là 4 cho thấy có 4 quan sát bị trùng lặp trong bộ dữ liệu. Mặc dù con số nay rất nhỏ so với 302010 dòng nhưng các dòng trùng lặp vẫn có thể ảnh hưởng đến kết quả thống kê. Vì vậy trước khi tiến hành phân tích sẽ thực hiện loại bỏ các dòng trùng lặp để đảm bảo dữ liệu sạch và kết quả chính xác.

1. retail <- retail[!duplicated(retail), ]
2. nrow(retail)
## [1] 302006

Nhận xét: Dữ liệu sau khi loại bỏ các quan sát trùng lặp thì số quan sát còn lại là 302006.

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

Tổng số quan sát giá trị bị thiếu trong toàn bộ dữ liệu

1. sum(is.na(retail))
## [1] 8382

Nhận xét: Trong bộ dữ liệu có 8382 ô bị thiếu

Số lượng giá trị bị thiếu theo từng cột

1. sapply(retail,function(retail) sum(is.na(retail)))
##   Transaction_ID      Customer_ID             Name            Email 
##              333              308              382              347 
##            Phone          Address             City            State 
##              362              315              248              281 
##          Zipcode          Country              Age           Gender 
##              340              271              173              317 
##           Income Customer_Segment             Date             Year 
##              290              215              359              350 
##            Month             Time  Total_Purchases           Amount 
##              273              350              361              356 
##     Total_Amount Product_Category    Product_Brand     Product_Type 
##              350              283              281                0 
##         Feedback  Shipping_Method   Payment_Method     Order_Status 
##              184              337              297              235 
##          Ratings         products 
##              184                0

Nhận xét: Kết quả cho thấy tất cả các cột trong dữ liệu đều chứa giá trị bị thiếu (NA) trừ Product_type và products. Bên cạnh đó, các cột có dữ liệu NA rất cao như Name, Phone, Date, Total_Purchases, Amount đều có kết quả lớn hơn 350 giá trị thiếu.Ngoài ra các cột còn lại cũng có số lượng giá trị thiếu đáng kể trong khoảng 200 đếm 300.Điều này cho thấy dữ liệu chưa được làm sạch hoàn toàn, cần phải xử lý trước khi tiến hành phân tích sâu hơn tránh ảnh hưởng đến sai sót khi phân tích hành vi khách hàng

Sau khi kiểm tra số quan sát bị thiếu, tiến hành xử lí các quan sát bị thiếu
Đối với kiểu dữ liệu là numeric bằng cách thay NA bằng giá trị trung bình của cột đó

Đối với kiểu dữ liệu là character tôi tiến hành thay thế các dữ liệu bị thiếu đó bằng “Nothing”.

Xử lí dữ liệu bị thiếu của biến time

1. retail <- retail %>% mutate( across( .cols = where(is.numeric), .fns = ~ ifelse(is.na(.), mean(., na.rm = TRUE), .)))
2. retail <- retail %>% mutate( across( .cols = where(is.character), ~ ifelse(is.na(.), "Nothing", .)))
3. sapply(retail,function(retail) sum(is.na(retail)))
##   Transaction_ID      Customer_ID             Name            Email 
##                0                0                0                0 
##            Phone          Address             City            State 
##                0                0                0                0 
##          Zipcode          Country              Age           Gender 
##                0                0                0                0 
##           Income Customer_Segment             Date             Year 
##                0                0                0                0 
##            Month             Time  Total_Purchases           Amount 
##                0              350                0                0 
##     Total_Amount Product_Category    Product_Brand     Product_Type 
##                0                0                0                0 
##         Feedback  Shipping_Method   Payment_Method     Order_Status 
##                0                0                0                0 
##          Ratings         products 
##                0                0

Nhận xét: Sau khi xử lý dữ liệu bị thiếu, toàn bộ giá trị NA trong các biến numeric đã được thay bằng giá trị trung bình của từng cột, giữ nguyên phân bố dữ liệu và đảm bảo các thống kê tổng hợp như tổng doanh thu (Total_Amout) hay số lần mua (Total_Purchases) không bị lệch. Các biến character được thay NA bằng “Nothing”, giữ nguyên cấu trúc dữ liệu để thuận tiện cho phân loại thống kê tần suất. Biến Time được chuẩn hóa, thay NA “00:00:00”, đảm bảo tính nhất quán khi phân tích theo ngày hoặc khung giờ.

2.2 Mã hóa biến

2.2.1 Chuyển các cột character thành factor

1. retail <- retail %>%
2.   mutate(
3.     Gender = as.factor(Gender),
4.     Income = factor(Income, levels = c("Nothing", "Low", "Medium", "High"), ordered = TRUE),
5.     Customer_Segment = as.factor(Customer_Segment),
6.     Product_Category = as.factor(Product_Category),
7.     Product_Brand = as.factor(Product_Brand),
8.     Product_Type = as.factor(Product_Type),
9.     Payment_Method = as.factor(Payment_Method),
10.     Shipping_Method = as.factor(Shipping_Method),
11.     Feedback = as.factor(Feedback),
12.     Order_Status = as.factor(Order_Status)
13.   )

Giải thích kỹ thuật: Lệnh mutate() trong dplyr được sử dụng để chuyển các biến dạng character sang factor, giúp R nhận biết các biến là biến phân loại. Biến Income được chuyển thành ordered factor với thứ tự “Nothing” < “Low” < “Medium” < “High”, cho phép thực hiện các phép so sánh theo thứ tự và các phân tích thống kê phù hợp. Việc này đảm bảo rằng các hàm thống kê và trực quan hóa như summary(), table() hay các biểu đồ barplot sẽ nhận diện đúng loại biến, tránh nhầm lẫn với biến character hay numeric.

Nhận xét: Việc mã hóa các biến như Gender, Income, Customer_Segment, Product_Category hay Payment_Method giúp ta dễ dàng phân tích hành vi khách hàng theo nhóm, xác định mức chi tiêu trung bình của từng nhóm thu nhập, đánh giá khách hàng VIP và lập chiến lược marketing theo phân khúc. Đồng thời, việc mã hóa các biến sản phẩm, phương thức thanh toán và trạng thái đơn hàng cũng hỗ trợ phân tích doanh thu theo loại sản phẩm, phương thức giao dịch và mức độ hài lòng của khách hàng một cách chính xác hơn.

2.2.2 Chuyển các cột character thành factor

1. retail <- retail %>%
2.   mutate(
3.     FeedbackScore = case_when(
4.       Feedback == "Excellent" ~ 5,
5.       Feedback == "Good"      ~ 4,
6.       Feedback == "Average"   ~ 3,
7.       Feedback == "Bad"       ~ 2,
8.       TRUE                    ~ NA_real_  ))
1. retail <- retail %>%
2.   mutate(Income_Code = case_when(
3.     Income == "Low" ~ 1,
4.     Income == "Medium" ~ 2,
5.     Income == "High" ~ 3,
6.     TRUE ~ NA_real_))

2.3 Thống kê tần suất các biến phân loại

1. freq_table <- function(x) {
2.   tab <- table(x, useNA = "ifany")   
3.   freq <- as.data.frame(tab)
4.   colnames(freq) <- c("Muc_do", "Tan_suat")
5.   freq <- freq %>%
6.     mutate(Ty_le = round(100 * Tan_suat / sum(Tan_suat), 2))
7.   return(freq)
8. }
9. freq_gender <- freq_table(retail$Gender)
10. freq_income <- freq_table(retail$Income)
11. freq_segment <- freq_table(retail$Customer_Segment)
12. freq_category <- freq_table(retail$Product_Category)
13. freq_brand <- freq_table(retail$Product_Brand)
14. freq_type <- freq_table(retail$Product_Type)
15. freq_payment <- freq_table(retail$Payment_Method)
16. freq_shipping <- freq_table(retail$Shipping_Method)
17. freq_feedback <- freq_table(retail$Feedback)
18. freq_status <- freq_table(retail$Order_Status)
19. list(
20.   "Giới tính" = freq_gender,
21.   "Thu nhập" = freq_income,
22.   "Phân khúc khách hàng" = freq_segment,
23.   "Danh mục sản phẩm" = freq_category,
24.   "Thương hiệu" = freq_brand,
25.   "Loại sản phẩm" = freq_type,
26.   "Thanh toán" = freq_payment,
27.   "Giao hàng" = freq_shipping,
28.   "Phản hồi" = freq_feedback,
29.   "Trạng thái đơn hàng" = freq_status
30. )
## $`Giới tính`
##    Muc_do Tan_suat Ty_le
## 1  Female   114093 37.78
## 2    Male   187596 62.12
## 3 Nothing      317  0.10
## 
## $`Thu nhập`
##    Muc_do Tan_suat Ty_le
## 1 Nothing      290  0.10
## 2     Low    96257 31.87
## 3  Medium   130230 43.12
## 4    High    75229 24.91
## 
## $`Phân khúc khách hàng`
##    Muc_do Tan_suat Ty_le
## 1     New    91185 30.19
## 2 Nothing      215  0.07
## 3 Premium    64387 21.32
## 4 Regular   146219 48.42
## 
## $`Danh mục sản phẩm`
##        Muc_do Tan_suat Ty_le
## 1       Books    54622 18.09
## 2    Clothing    54739 18.13
## 3 Electronics    71196 23.57
## 4     Grocery    66784 22.11
## 5  Home Decor    54382 18.01
## 6     Nothing      283  0.09
## 
## $`Thương hiệu`
##               Muc_do Tan_suat Ty_le
## 1             Adidas    18236  6.04
## 2              Apple    18073  5.98
## 3  Bed Bath & Beyond    18244  6.04
## 4           BlueStar     2256  0.75
## 5          Coca-Cola    18392  6.09
## 6      HarperCollins    18353  6.08
## 7         Home Depot    18145  6.01
## 8               IKEA    17994  5.96
## 9         Mitsubhisi     6724  2.23
## 10            Nestle    18109  6.00
## 11              Nike    18139  6.01
## 12           Nothing      281  0.09
## 13     Penguin Books    18138  6.01
## 14             Pepsi    30290 10.03
## 15      Random House    18122  6.00
## 16           Samsung    18376  6.08
## 17              Sony    18319  6.07
## 18         Whirepool     7445  2.47
## 19              Zara    18370  6.08
## 
## $`Loại sản phẩm`
##                                Muc_do Tan_suat Ty_le
## 1                            Bathroom     6026  2.00
## 2                             Bedding     6011  1.99
## 3                         BlueStar AC     2256  0.75
## 4                          Children's     6147  2.04
## 5                           Chocolate     6051  2.00
## 6                              Coffee     6178  2.05
## 7                         Decorations    12178  4.03
## 8                               Dress     6123  2.03
## 9                             Fiction    18045  5.98
## 10                             Fridge     7445  2.47
## 11                          Furniture    11969  3.96
## 12                         Headphones     6080  2.01
## 13                             Jacket     6003  1.99
## 14                              Jeans     6134  2.03
## 15                              Juice    12230  4.05
## 16                            Kitchen     6228  2.06
## 17                             Laptop     5981  1.98
## 18                           Lighting     6075  2.01
## 19                         Literature     6051  2.00
## 20 Mitsubishi 1.5 Ton 3 Star Split AC     6724  2.23
## 21                        Non-Fiction    18172  6.02
## 22                              Shirt     6132  2.03
## 23                              Shoes    12140  4.02
## 24                             Shorts     6087  2.02
## 25                         Smartphone    18468  6.12
## 26                             Snacks     5901  1.95
## 27                         Soft Drink    12034  3.98
## 28                            T-shirt    12180  4.03
## 29                             Tablet    12091  4.00
## 30                         Television    12197  4.04
## 31                           Thriller     6262  2.07
## 32                              Tools     5948  1.97
## 33                              Water    24459  8.10
## 
## $`Thanh toán`
##        Muc_do Tan_suat Ty_le
## 1        Cash    73807 24.44
## 2 Credit Card    90115 29.84
## 3  Debit Card    76790 25.43
## 4     Nothing      297  0.10
## 5      PayPal    60997 20.20
## 
## $`Giao hàng`
##     Muc_do Tan_suat Ty_le
## 1  Express   102354 33.89
## 2  Nothing      337  0.11
## 3 Same-Day   104155 34.49
## 4 Standard    95160 31.51
## 
## $`Phản hồi`
##      Muc_do Tan_suat Ty_le
## 1   Average    62673 20.75
## 2       Bad    43297 14.34
## 3 Excellent   100754 33.36
## 4      Good    95098 31.49
## 5   Nothing      184  0.06
## 
## $`Trạng thái đơn hàng`
##       Muc_do Tan_suat Ty_le
## 1  Delivered   130448 43.19
## 2    Nothing      235  0.08
## 3    Pending    49101 16.26
## 4 Processing    57198 18.94
## 5    Shipped    65024 21.53

Giải thích kỹ thuật: Để thống kê bảng tần suất các biến phân loại sử dụng hàm table() kết hợp dplyr::mutate() để tạo bảng tần suất và tỷ lệ phần trăm cho các biến phân loại. Mỗi biến phân loại như: Gender, Income, Customer_Segment, Product_Category, Product_Brand, Product_Type, Payment_Method, Shipping_Method, Feedback và Order_Status được tính số lượng quan sát trong từng mức và tỷ lệ phần trăm so với tổng số quan sát, bao gồm cả các giá trị bị thiếu. Giúp thống kê sơ bộ các biến categorical, phát hiện mức độ phổ biến, hiếm gặp đồng thời chuẩn bị dữ liệu cho trực quan hóa hoặc phân tích theo nhóm.

Nhận xét: Đối với biến Gender theo kết quả chạy được ta thấy tỷ lệ của Female là 114.093 (37,78%), Male là 187.596 (62,12%) còn lại là nothing 317 (0,10%). Dữ liệu cho thấy khách hàng nam chiếm tỷ lệ lớn hơn khách hàng nữ, điều này có thể phản ánh cơ cấu thị trường hoặc thói quen mua sắm của nhóm khách hàng chính. Doanh nghiệp có thể thiết kế các chương trình khuyến mãi, quảng cáo và chăm sóc khách hàng tập trung vào nhóm nam, nhưng vẫn chú ý cân bằng với nhóm nữ để không bỏ sót thị trường tiềm năng

Đối với biến Income chiếm tỷ lệ nhiều nhất là nhóm Medium 43,12% cho thấy phần lớn khách hàng có mức thu nhập trung bình. Nhóm Low chiếm 31,87% vẫn chiếm tỷ lệ khá lớn phản ảnh một lượng khách hàng chi tiêu hạn chế nhưng số lượng đông.Nhóm High chiếm 24,91% tuy ít về số lượng nhưng có thể đóng góp doanh thu lớn. Việc biết được cơ cấu thu nhập giúp doanh nghiệp xác định được nhóm khách hàng mục tiêu, thiết kế chiến lược bán hàng và marketing phù hợp với từng nhóm thu nhập của khách hàng. Đối với những khách hàng có mức thu nhập Medium cần duy trì tương tác để ổn định doanh thu. Nhóm High nhóm chi tiêu cao, có thể áp dụng các chương trình ưu đãi đặc biệt,khách hàng VIP. Còn lại khách hàng thuộc nhóm thu nhập Low tập trung vào các sản phẩm giá vừa phải khuyến mãi để tăng số lượng giao dịch.

2.4 Xử lý và khai thác biến thời gian

2.4.1 Chuyển định dạng Date

1. retail <- retail %>%
2.   mutate(Date = as.Date(Date, format = "%m/%d/%Y"))
3. str(retail$Date)
##  Date[1:302006], format: "2023-09-18" "2023-12-31" "2023-04-26" "2023-05-08" "2024-01-10" ...

CHƯƠNG 3: THỐNG KÊ CƠ BẢN

3.1 Phân tích AOV

3.1.1 Theo thành phố

AOV hay còn được gọi là giá trị đơn hàng trung bình. Đây là một trong những chỉ số hiệu suất quan trọng nhất của ngành bán lẻ và điện tử (2 sản phẩm chính của bộ dữ liệu) nên việc đánh giá AOV là cần thiết.

1. aov_region <- retail %>%
2.   group_by(City) %>% 
3.   summarise(
4.     Mean_AOV = mean(Total_Amount, na.rm = TRUE),
5.     SD_AOV   = sd(Total_Amount, na.rm = TRUE),
6.     CoV_AOV  = (SD_AOV / Mean_AOV) * 100,
7.     IQR_AOV  = IQR(Total_Amount, na.rm = TRUE))
8. aov_region
## # A tibble: 131 × 5
##    City           Mean_AOV SD_AOV CoV_AOV IQR_AOV
##    <chr>             <dbl>  <dbl>   <dbl>   <dbl>
##  1 Adelaide          1365.  1134.    83.1   1595.
##  2 Albuquerque       1389.  1151.    82.8   1613.
##  3 Albury-Wodonga    1367.  1130.    82.7   1608.
##  4 Arlington         1389.  1176.    84.6   1655.
##  5 Atlanta           1414.  1162.    82.2   1715.
##  6 Austin            1302.  1140.    87.6   1466.
##  7 Ballarat          1383.  1138.    82.2   1594.
##  8 Baltimore         1378.  1128.    81.9   1695.
##  9 Barrie            1361.  1114.    81.8   1631.
## 10 Belfast           1382.  1155.    83.6   1665.
## # ℹ 121 more rows

Giải thích kỹ thuật: group_by (city) nhóm dữ liệu theo từng thành phố, sau đó dùng hàm smmarise để sử dụng các hàm sau để tính: mean để tính giá trị trung bình, sd để tính độ lệch chuẩn, IQR tính khoảng tứ phân vị, tất cả đều bỏ qua giá trị NA.

Nhận xét: 5 thành phố Dallas, San Jose, San Diego, Memphis, Phoenix (Mean_AOV > 1.400) là những thành phố có mức chi tiêu trung bình cho từng đơn hàng cao nhất, là thị trường trọng điểm có tiềm năng sinh lời cao, doanh nghiệp nên đầu tư marketing hoặc phát triển thêm những sản phẩm cao cấp hoặc phát triển cửa hàng, tập trung phân phối ở tại những khu vực này. Ngược lại những thành phố Munich, Austin, Virginia Beach, Colorado Springs, Kansas City là nơi có chỉ số Mean_AOV thấp hơn 1.320, đánh giá sức mua trung bình cho mỗi sản phẩm thấp, thể hiện khách hàng mua ít sản phẩm hoặc chỉ mua những sản phẩm giá rẻ. Do đó tại những khu vực này doanh nghiệp nên triển khai những chương trình khuyến mãi, giảm giá, hoặc phân phối những dòng sản phẩm rẻ hơn.

Kết quả thống kê cho thấy chỉ số SD_AOV (độ lệch chuẩn của giá trị đơn hàng) dao động trong khoảng từ 1.062.241 (Virginia Beach) đến 1.206.037 (Tulsa), mức chênh lệch xấp xỉ 0.88%. Điều này cho thấy mức độ khác biệt trong độ biến động chi tiêu của khách hàng giữa các thành phố là khá đồng đều. Tuy nhiên chỉ số SD_AOV trung bình ở mỗi thành phố khá cao thể hiện hành vi chi tiêu của khách hàng trong từng thành phố rất đa dạng, tồn tại cả nhóm khách hàng chi tiêu cao và thấp. Qua đó, doanh nghiệp có thể áp dụng một chiến lược giá và marketing thống nhất trên toàn hệ thống đồng thời điều chỉnh linh hoạt về chính sách khuyến mãi hoặc danh mục sản phẩm cho những khu vực có sức mua trung bình thấp.

Chỉ số CoV_AOV cũng đã thể hiện điều tương tự về phân khúc khách hàng rõ rệt trong từng khu vực khi chỉ số CoV_AOV của mỗi thành phố đều cao hơn 70%. Còn lại chỉ số IQR_AOV cũng thể hiện kết quả tương tự tuy nhiên mức chênh lệch giữa các phân khúc khách hàng tương đối ổn định, không quá lớn nhưng vẫn đòi hỏi doanh nghiệp đa dạng hóa sản phẩm để phù hợp với từng nhóm khách hàng

1. aov_top10 <- aov_region %>%
2.   arrange(desc(Mean_AOV)) %>%
3.   slice_head(n = 10) %>%
4.   mutate(
5.     y_mean_label = Mean_AOV + SD_AOV * 0.6,   
6.     y_cov_label  = Mean_AOV + SD_AOV * 1.25,  
7.     y_iqr_top    = Mean_AOV + (IQR_AOV / 2),
8.     y_iqr_bot    = Mean_AOV - (IQR_AOV / 2))
9. p1 <- ggplot(aov_top10, aes(x = reorder(City, Mean_AOV), y = Mean_AOV, fill = City)) +
10.   geom_col(width = 0.6, alpha = 0.85, show.legend = FALSE) +
11.   geom_errorbar(aes(ymin = Mean_AOV - SD_AOV, ymax = Mean_AOV + SD_AOV),
12.                 width = 0.18, color = "black", linewidth = 0.9) +
13.   geom_point(aes(y = y_iqr_top), color = "red", size = 3) +
14.   geom_point(aes(y = y_iqr_bot), color = "red", size = 3) +
15.   geom_text_repel(aes(y = y_mean_label, label = round(Mean_AOV, 1)),nudge_x = 0, nudge_y = 0,direction = "y",segment.size = 0.25,size = 3.8, fontface = "bold",max.overlaps = 30) +
16.   geom_text_repel(aes(y = y_cov_label, label = paste0("CoV: ", round(CoV_AOV, 1), "%")),nudge_x = 0, nudge_y = 0,direction = "y",segment.size = 0.25,size = 3.2, color = "blue4",max.overlaps = 30) +
17.   geom_hline(yintercept = mean(aov_region$Mean_AOV), color = "darkgreen", linetype = "dotdash", linewidth = 0.7) +
18.   labs(
19.     title = "Biểu đồ so sánh AOV và các chỉ số khác theo thành phố",
20.     subtitle = "Thành phố có AOV cao nhất",
21.     x = "Thành phố",
22.     y = "Giá trị trung bình đơn hàng (Mean_AOV)",
23.     caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
24.   theme_minimal(base_size = 13) +
25.   theme(
26.     plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
27.     plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
28.     axis.text = element_text(color = "black"),
29.     axis.title = element_text(face = "bold"),
30.     panel.grid.minor = element_blank(),
31.     axis.text.x = element_text(angle = 30, hjust = 1, vjust = 1)) +
32.   scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.35))) 
33. p2 <- p1 + coord_flip() +
34.   theme(axis.text.x = element_text(angle = 0)) +
35.   labs(x = "Thành phố (theo AOV giảm dần)", y = "Mean_AOV")
36. p2

Giải thích kỹ thuật: Từ dòng 1 đến 7, tạo 1 dataframe (aov_top10), dùng arrange() để xếp giảm dần theo AOV trung bình, lấy 10 thành phố cao nhất, dùng mutate () để tạo 4 biến mới gồm: y_mean_label, y_cov_label, y_iqr_top, y_iqr_bot. Từ dòng, vẽ biểu đồ với trục X là thành phố, trục Y là AOV trung bình. Ở dòng vẽ thanh sai số để đánh giá độ ổn định của AOV. Dòng là 2 điểm thể hiện IQR (Q1 và Q3) dùng để đánh giá độ phân tán dữ liệu. Vẽ đường trung bình toàn quốc để so sánh với từng thành phố ở dòng. Cuối cùng ở dòng, dùng coord_flip() để xoay ngang biểu đồ.

Nhận xét: Biểu đồ cho thấy sự khác biệt tương đối nhỏ về hành vi chi tiêu giữa các thành phố. Dallas dẫn đầu với AOV trung bình 1.447,6, theo sau là San Jose với 1.437,2 và San Diego với 1.425,6, cho thấy sức mua cao và ổn định tại 3 thành phố này. Các thành phố như Memphis, Phoenix và Atlanta có AOV thấp hơn đôi chút nhưng vẫn duy trì mức biến động (CoV ≈ 80%) tương tự nhóm dẫn đầu. Có thể thấy không có sự chênh lệch AOV giữa các thành phố qua đó thị trường bán lẻ phân bố khá đồng đều về sức mua nhưng các thành phố lớn như Dallas và San Jose có tiềm năng doanh thu cao hơn, phù hợp để ưu tiên triển khai chiến lược mở rộng hoặc chiến dịch tiếp thị tập trung.

3.1.2 Theo phân khúc thu nhập

1. aov_income <- retail %>%
2.   group_by(Income) %>% 
3.   summarise(
4.     Mean_AOV = mean(Total_Amount, na.rm = TRUE),
5.     SD_AOV   = sd(Total_Amount, na.rm = TRUE),
6.     CoV_AOV  = (SD_AOV / Mean_AOV) * 100,
7.     IQR_AOV  = IQR(Total_Amount, na.rm = TRUE))
8. aov_income
## # A tibble: 4 × 5
##   Income  Mean_AOV SD_AOV CoV_AOV IQR_AOV
##   <ord>      <dbl>  <dbl>   <dbl>   <dbl>
## 1 Nothing    1370.  1143.    83.5   1548.
## 2 Low        1371.  1127.    82.2   1590.
## 3 Medium     1369.  1133.    82.7   1595.
## 4 High       1361.  1123.    82.5   1577.

Giải thích kỹ thuật: group_by (Income) nhóm dữ liệu theo từng chi tiêu, sau đó dùng mean để tính giá trị trung bình, sd để tính độ lệch chuẩn, IQR tính khoảng tứ phân vị, tất cả đều bỏ qua giá trị NA.

Nhận xét: Kết quả thống kê mô tả cho thấy thu nhập không ảnh hưởng đáng kể đến giá trị đơn hàng trung bình (AOV). Mean_AOV giữa các nhóm thu nhập không có sự khác biệt đáng kể, dao động trong khoảng từ 1.361.081 đến 1.370.922, cho thấy chi tiêu trung bình giữa các nhóm thu nhập gần như tương đương. SD_AOV và IQR_AOV biến động rất nhỏ (< 2%), phản ánh mức độ dao động chi tiêu tương tự nhau giữa các nhóm. CoV_AOV khoảng 82 – 83%, cho thấy hành vi chi tiêu không đồng nhất trong từng nhóm. Nhóm “Nothing” có CoV cao nhất, thể hiện sự phân tán lớn hơn do đặc điểm thu nhập không rõ ràng.

1. aov_income <- retail %>%
2.   group_by(Income) %>%
3.   summarise(
4.     Mean_AOV = mean(Total_Amount, na.rm = TRUE),
5.     SD_AOV   = sd(Total_Amount, na.rm = TRUE),
6.     CoV_AOV  = (SD_AOV / Mean_AOV) * 100,
7.     IQR_AOV  = IQR(Total_Amount, na.rm = TRUE)) %>%
8.   mutate(
9.     Mean_lbl = round(Mean_AOV, 0),
10.     CoV_lbl  = paste0(round(CoV_AOV, 1), "%"),
11.     IQR_top = Mean_AOV + (IQR_AOV / 2),
12.     IQR_bot = Mean_AOV - (IQR_AOV / 2))
13. ggplot(aov_income, aes(x = reorder(Income, -Mean_AOV), y = Mean_AOV, fill = Income)) +
14.   geom_col(width = 0.6, alpha = 0.9, show.legend = FALSE) +
15.   geom_errorbar(aes(ymin = pmax(0, Mean_AOV - SD_AOV), ymax = Mean_AOV + SD_AOV), width = 0.18, color = "black", size = 0.9) +
16.   geom_point(aes(y = IQR_top), color = "red", size = 3, shape = 18) +
17.   geom_point(aes(y = IQR_bot), color = "red", size = 3, shape = 18) +
18.   geom_segment(aes(x = as.numeric(factor(Income)) - 0.15, xend = as.numeric(factor(Income)) + 0.15,y = IQR_top, yend = IQR_top), color = "red", size = 0.6) +
19.   geom_segment(aes(x = as.numeric(factor(Income)) - 0.15,xend = as.numeric(factor(Income)) + 0.15,y = IQR_bot, yend = IQR_bot),color = "red", size = 0.6) +
20.   geom_segment(aes(x = as.numeric(factor(Income)), xend = as.numeric(factor(Income)), y = IQR_bot, yend = IQR_top),color = "red", size = 0.4, linetype = "dashed") +
21.   geom_text(aes(label = Mean_lbl), vjust = -0.8, size = 3.8, fontface = "bold") +
22.   geom_text(aes(label = CoV_lbl, y = Mean_AOV + SD_AOV + (0.06 * max(Mean_AOV))),vjust = 0, size = 3, color = "navy") +
23.   geom_hline(yintercept = mean(aov_income$Mean_AOV, na.rm = TRUE),color = "darkgreen", linetype = "dotdash", size = 0.6) +
24.    labs(
25.     title = "AOV (Mean_AOV) theo phân khúc thu nhập (Income)",
26.     subtitle = "Cột: Mean_AOV | Thanh lỗi: SD | Điểm đỏ & đoạn nối: IQR | Nhãn trên cột: Mean | Nhãn trên cao: CoV%",x = "Phân khúc thu nhập",y = "Giá trị trung bình đơn hàng (Mean_AOV)",caption = "Nguồn: retail") +
27.   theme_minimal(base_size = 13) +
28.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),axis.title =    element_text(face = "bold"),axis.text.x = element_text(angle = 0, vjust = 0.5),legend.position = "none") +
29.   
30.   scale_y_continuous(labels = scales::comma) 

Giải thích kỹ thuật: Từ dòng 1 đến 12, tạo 1 data.frame (aov_income), dùng group_by() để chia dữ liệu theo từng phân khúc thu nhập, dùng summarise để tính các chỉ số thống kê của AOV và dùng mutate để tạo các cột phụ. Từ dòng vẽ biêu đồ cột với trục X là phân khúc thu nhập, trục Y là AOV trung bình. ở dòng tạo thanh độ lệch chuẩn để đánh giá hành vi mua của từng khách. từ dòng tới, biểu diễn IQR để đánh giá sự phân tán của . Vẽ đường trung bình của toàn bộ nhóm thu nhập, để so sánh có nhóm thu nhập với mặt bằng chung.

Nhận xét: Biểu đồ thể hiện giá trị trung bình đơn hàng (Mean_AOV) theo các phân khúc thu nhập (Low, Nothing, Medium, High) cho thấy sự khác biệt là không đáng kể. Giá trị AOV dao động rất sát nhau, từ 1361 đến 1371, và hệ số biến động (CoV%) đều trên 82%, phản ánh mức độ dao động cao và khá đồng đều giữa các nhóm thu nhập. Điều này cho thấy thu nhập không phải là yếu tố chính ảnh hưởng đến AOV.

Kết luận: AOV có xu hướng không phụ thuộc đáng kể vào mức thu nhập của người tiêu dùng, ngụ ý rằng hành vi chi tiêu trung bình trên mỗi đơn hàng có thể bị chi phối bởi các yếu tố khác như danh mục sản phẩm, chiến lược định giá hoặc chương trình khuyến mãi. Doanh nghiệp nên tập trung vào các chiến lược tiếp cận hành vi tiêu dùng và nhu cầu thực tế, thay vì chỉ phân loại khách hàng theo thu nhập để tối ưu hóa doanh thu.

3.1.3 Kiểm định T-test (AOV: Nam vs Nữ)

1. gender_data <- retail %>%
2.   filter(Gender %in% c("Male", "Female"))
3. t_test_gender <- t.test(Total_Amount ~ Gender, data = gender_data)
4. t_test_gender
## 
##  Welch Two Sample t-test
## 
## data:  Total_Amount by Gender
## t = 0.32912, df = 240862, p-value = 0.7421
## alternative hypothesis: true difference in means between group Female and group Male is not equal to 0
## 95 percent confidence interval:
##  -6.908821  9.697320
## sample estimates:
## mean in group Female   mean in group Male 
##             1368.496             1367.102

Giải thích kỹ thuật: Dùng Filter để lọc dữ liệu, chỉ giữ lại các dòng có giới tính xác định rõ là “Male” hoặc “Female”. Thực hiện t-test kiểm tra xem giá trị trung bình của biến Total_Amount giữa hai nhóm giới tính có khác biệt có ý nghĩa thống kê hay không với giả thuyết H0: Không có sự khác biệt về chi tiêu trung bình giữa Nam và Nữ.

Nhận xét: Giá trị p-value = 0.7421 > 0.05: không đủ cơ sở để bác bỏ H₀. Cho thấy giới tính không ảnh hưởng đáng kể đến hành vi chi tiêu, cả nam và nữ đều có hành vi mua sắm tương tự nhau, doanh nghiệp không cần thiết lập chiến lược giá hoặc khuyến mãi riêng biệt chỉ dựa trên giới tính. Thay vào đó, doanh nghiệp nên tập trung phân khúc theo các yếu tố khác chẳng hạn như độ tuổi, thu nhập hoặc khu vực.

Kết quả này cũng cho thấy chiến lược marketing hiện tại đang cân bằng giữa hai giới, không thiên lệch về nhóm nào, đây là tín hiệu tích cực trong việc tiếp cận khách hàng.

3.1.4 Kiểm định T-test của Income

1. income_data <- retail %>%
2.   filter(Income %in% c("Low", "Medium", "High"))
3. anova_income <- aov(Total_Amount ~ Income, data = income_data)
4. summary(anova_income)
##                 Df    Sum Sq Mean Sq F value Pr(>F)
## Income           2 4.519e+06 2259507   1.775   0.17
## Residuals   301713 3.841e+11 1273136

Giải thích kỹ thuật: dùng filter để giữ lại các quan sát thuộc 3 nhóm thu nhập. Sau đấy dùng aov(Total_Amount ~ Income, data = income_data) để xây dựng mô hình ANOVA so sánh giá trị trung bình của Total_Amount giữa các nhóm thu nhập với giả thuyết H0: Mức chi tiêu trung bình của các nhóm thu nhập là như nhau.

Nhận xét: Kết quả cho thấy thu nhập không ảnh hưởng rõ ràng đến hành vi chi tiêu của khách hàng (p-value = 0.17 > 0.05). Khách hàng thuộc nhóm Low, Medium hay High thì mức chi tiêu trung bình không khác biệt đáng kể. Cho thấy các sản phẩm, dịch vụ doanh nghiệp cung cấp mang tính phổ thông, phù hợp cho nhiều nhóm thu nhập.

Tuy nhiên, để tối ưu doanh thu, doanh nghiệp nên phân tích sâu hơn theo danh mục sản phẩm hoặc độ tuổi (ví dụ: sản phẩm cao cấp, công nghệ, hoặc thời trang).

3.2 Top 10 thương hiệu có doanh thu cao nhất

1. top_brands <- retail %>%
2.   group_by(Product_Brand) %>%
3.   summarise(Revenue = sum(Total_Amount, na.rm = TRUE)) %>%
4.   arrange(desc(Revenue)) %>%
5.   slice_head(n = 10)
6. top_brands
## # A tibble: 10 × 2
##    Product_Brand       Revenue
##    <fct>                 <dbl>
##  1 Pepsi             41408759.
##  2 Samsung           25400245.
##  3 Sony              25117061.
##  4 Coca-Cola         25039102.
##  5 Nike              25030857.
##  6 Zara              25017044.
##  7 Bed Bath & Beyond 25008364.
##  8 HarperCollins     24939001.
##  9 Penguin Books     24895740.
## 10 Adidas            24854304.

Giải thích kỹ thuật: Đoạn code sử dụng các hàm trong dplyr để lọc và sắp xếp dữ liệu doanh thu theo thương hiệu, dùng group_by(Product_Brand) nhóm dữ liệu theo từng thương hiệu và dùng summarise tính tổng doanh thu của mỗi thương hiệu. Cuối cùng, arrange sắp xếp kết quả theo doanh thu giảm dần.

Nhận xét: Dữ liệu cho thấy Pepsi là thương hiệu dẫn đầu về doanh thu, vượt xa các thương hiệu còn lại với mức 41.4 triệu, cao gần gấp đôi so với nhóm kế tiếp như Samsung, Sony hay Coca-Cola (khoảng 25 triệu). Sự chênh lệch giữa các thương hiệu từ vị trí thứ 2 đến thứ 10 không lớn, cho thấy doanh thu của nhóm này tương đối đồng đều. Điều này gợi ý rằng Pepsi đang có lợi thế cạnh tranh mạnh mẽ hơn trong danh mục sản phẩm, trong khi các thương hiệu khác duy trì mức doanh thu ổn định.

3.3 Quốc gia có độ lệch doanh thu lớn nhất

1. retail %>%
2.   group_by(Country) %>%
3.   summarise(SD = sd(Total_Amount, na.rm = TRUE),
4.             Mean = mean(Total_Amount, na.rm = TRUE),
5.             CV = SD / Mean) %>%
6.   arrange(desc(CV))
## # A tibble: 6 × 4
##   Country      SD  Mean    CV
##   <chr>     <dbl> <dbl> <dbl>
## 1 Canada    1127. 1363. 0.827
## 2 USA       1126. 1364. 0.825
## 3 Germany   1128. 1367. 0.825
## 4 UK        1134. 1376. 0.825
## 5 Australia 1128. 1370. 0.823
## 6 Nothing   1046. 1287. 0.813

Giải thích kỹ thuật: Đoạn code thực hiện thống kê mô tả cho biến doanh thu (Total_Amount) theo từng quốc gia (Country), với ba chỉ số chính: SD để tính độ lệch chuẩn, thể hiện mức độ dao động doanh thu so với trung bình; Mean để tính giá trị trung bình doanh thu (Mean) cho mỗi quốc gia; CV để tính hệ số biến thiên, giúp so sánh sự ổn định doanh thu giữa các quốc gia (CV càng cao thì biến động càng lớn).

Nhận xét: Canada, Mỹ và Đức là các thị trường có độ biến động doanh thu cao, hành vi chi tiêu của khách hàng thiếu ổn định có thể đến từ sự khác biệt thu nhập, mùa vụ, hoặc tần suất mua hàng không đều. Doanh nghiệp nên tăng cường các chương trình để giữ chân nhóm chi tiêu cao, phân tích thêm theo mùa hoặc danh mục sản phẩm để hiểu rõ nguyên nhân biến động.

Bên cạnh đó Anh và Úc thể hiện thị trường ổn định hơn, thích hợp để duy trì chiến lược giá và quảng bá ổn định.

3.4 Phân tích độ tập trung doanh thu

1. top_customers <- retail %>%
2.   group_by(Customer_ID) %>%
3.   summarise(Revenue = sum(Total_Amount, na.rm = TRUE)) %>%
4.   arrange(desc(Revenue)) %>%
5.   mutate(CumPercent = cumsum(Revenue) / sum(Revenue))
6. pareto_80 <- top_customers %>% filter(CumPercent <= 0.8)
7. nrow(pareto_80) / nrow(top_customers) 
## [1] 0.5429253

Giải thích kỹ thuật: Đoạn code thực hiện phân nguyên lý Pareto (80/20) trên dữ liệu khách hàng, tìm tỷ lệ khách hàng chiếm khoảng 80% tổng doanh thu. Dùng Group_by để nhóm dữ liệu theo Customer_ID và summarise để tính tổng doanh thu của mỗi khách hàng. Sau đó thêm cột CumPercent bằng cách lấy tổng doanh thu cộng dồn của từng khách hàng chia cho tổng doanh thu toàn bộ. Phần lọc filter(CumPercent <= 0.8) chọn ra nhóm khách hàng đóng góp 80% tổng doanh thu của doanh nghiệp, còn câu lệnh cuối cùng nrow(pareto_80) / nrow(top_customers) là tính tỷ lệ số lượng khách hàng VIP này so với toàn bộ tập khách hàng.

Nhận xét: Kết quả là 54.3% thể hiện để đạt 80% tổng doanh thu, doanh nghiệp cần đến 54.4% số lượng khách hàng hàng đầu. Doanh nghiệp không phụ thuộc vào một nhóm nhỏ khách hàng VIP mà doanh thu được trải đều, có tính ổn định và ít biến động.

3.5 Tốc độ tăng trưởng khách hàng mỗi tháng

1. retail %>%
2.   mutate(
3.     Month = tolower(Month),
4.     Month = tools::toTitleCase(Month),
5.     YearMonth = paste0(Year, "-", match(Month, month.name))) %>%
6.   mutate(
7.     YearMonth = format(as.Date(paste0(YearMonth, "-01")), "%Y-%m")) %>%
8.   group_by(YearMonth) %>%
9.   summarise(unique_customers = n_distinct(Customer_ID)) %>%
10.   arrange(YearMonth)
## # A tibble: 23 × 2
##    YearMonth unique_customers
##    <chr>                <int>
##  1 2023-01              14158
##  2 2023-02                276
##  3 2023-03              17021
##  4 2023-04              30600
##  5 2023-06              16429
##  6 2023-07              24541
##  7 2023-08              25801
##  8 2023-09              16551
##  9 2023-10              17005
## 10 2023-11              16410
## # ℹ 13 more rows

Giải thích kỹ thuật: Trước khi xét tốc độ tăng trưởng, đoạn code ghép hai cột Year và Month, đầu tiên dùng mutate(Month = tolower(Month); Month = tools::toTitleCase(Month) chuẩn hoá tên tháng (chuyển về chữ thường rồi viết hoa chữ đầu) để tránh khác biệt do chữ hoa, nhỏ. Sau đấy chuẩn hóa tên tháng từ chữ sang dạng số và ghép thành chuỗi năm-tháng. Sau khi có cột YearMonth, dùng group_by gom theo mỗi mốc tháng-năm, dùng summarise đếm số khách hàng khác nhau trong mỗi tháng, và cuối cùng arrange(YearMonth) sắp xếp kết quả theo thứ tự thời gian

Nhận xét: Kết quả thống kê cho thấy số lượng khách hàng duy nhất biến động mạnh theo thời gian, phản ánh rõ tính mùa vụ trong hành vi tiêu dùng của khách hàng. Năm 2023, lượng khách hàng tăng mạnh vào tháng 3–4, đạt đỉnh ở tháng 4/2023 (30.600 khách), sau đó duy trì ổn định trong mùa hè rồi giảm nhẹ về cuối năm. Năm 2024, khách hàng giảm sức mua từ tháng 3 đến tháng 11, cho thấy dấu hiệu suy giảm hoạt động hoặc dữ liệu không được ghi nhận đầy đủ.

Dữ liệu cho thấy sức mua của khách hàng có tính chu kỳ và tập trung vào các giai đoạn khuyến mãi, đặc biệt là tháng 4 và tháng 12. Doanh nghiệp nên tăng cường chiến dịch marketing, quảng bá và ưu đãi trong các tháng cao điểm, đồng thời phát triển chương trình giữ chân khách hàng trong mùa thấp điểm để duy trì tăng trưởng ổn định.

3.6 Hệ số tương quan

3.6.1 Mối quan hệ giữa Total_Amount và Total_Purchase

1. cor(retail$Total_Purchases, retail$Total_Amount, use = "complete.obs")
## [1] 0.6483009

Giải thích kỹ thuật: dùng hàm cor để tính hệ số tương quan giữa 2 biến, mặc định là tương quan Pearson (giá trị nằm trong khoảng -1 tới 1), use = “complete.obs” dùng để bỏ qua các giá trị NA khi tính.

Nhận xét: hệ số tương quan giữa tổng giá trị mua hàng và tổng số lượng mua có mối quan hệ khá chặt chẽ (> 0.6), cho thấy doanh thu tăng một phần do số lượng của sản phẩm được mua, từ đó doanh nghiệp có thể tăng doanh thu nhờ vào các phương pháp upsell, combo hoặc những chương trình mua 2 tặng 1 sẽ mang lại hiệu quả kinh doanh.

3.6.2 Mối quan hệ giữa Total_Amount và Age

1. cor(retail$Age, retail$Total_Amount, use = "complete.obs")
## [1] 0.02251137

Giải thích kỹ thuật: dùng hàm cor để tính hệ số tương quan giữa 2 biến, mặc định là tương quan Pearson (giá trị nằm trong khoảng -1 tới 1), use = “complete.obs” dùng để bỏ qua các giá trị NA khi tính.

Nhận xét: chỉ số 0.2 cho thấy không có mối quan hệ tuyến tính giữa tuổi và tổng doanh thu. Điều đó nghĩa là mức chi tiêu của khách hàng không phụ thuộc rõ ràng vào độ tuổi, doanh nghiệp không nên dựa vào tuổi làm biến phân khúc

3.7 Mối quan hệ giữa Total_Amount và Age

1. retail %>%
2.   group_by(Customer_ID) %>%
3.   summarise(Customer_Revenue = sum(Total_Amount)) %>%
4.   summarise(Mean_CLV_Proxy = mean(Customer_Revenue))
## # A tibble: 1 × 1
##   Mean_CLV_Proxy
##            <dbl>
## 1          4760.

Giải thích kỹ thuật: Dùng group_by để gom nhóm dữ liệu theo ID khách hàng. Sau đó dùng summarise () để tính tổng doanh thu của từng khách, tiếp tục dùng tổng doanh thu của từng khách để tính giá trị trung bình của tổng chi tiêu mà 1 khách hàng mang lại cho doanh nghiệp.

Nhận xét: Với CLV trung bình đạt 4,760.30, doanh nghiệp đang sở hữu một lượng khách hàng có giá trị đáng kể. Điều này phản ánh khả năng tạo doanh thu ổn định từ khách hàng hiện có, đồng thời mở ra cơ hội tăng trưởng thông qua chiến lược giữ chân khách hàng trung thành và gia tăng giá trị đơn hàng trung bình.

3.8 Tần suất mua hàng trung bình

1. customer_frequency <- retail %>%
2.   group_by(Customer_ID) %>% 
3.   summarise(Total_Transactions = n())
4. summary(customer_frequency$Total_Transactions)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.000   2.000   3.000   3.481   5.000 308.000

Giải thích kỹ thuật: Dùng group_by để gom nhóm dữ liệu theo ID khach hàng, dùng summarise để tạo bảo tóm tắt cho mỗi khách hàng, dùng n() để đếm số lần khách hàng mua hàng của doanh nghiệp. Cuối cùng hàm summary() để tóm tắt thống kê của cột Total_Transaction.

Nhận xét: Giá trị nhỏ nhất (Min = 1): Có những khách hàng chỉ phát sinh 1 giao dịch duy nhất. Trung vị (Median = 3): Một khách hàng thực hiện khoảng 3 giao dịch trong giai đoạn nghiên cứu. Nghĩa là hơn một nửa khách hàng có tần suất mua hàng ≤ 3 lần.

Giá trị trung bình (Mean = 3.481): Mỗi khách hàng trung bình thực hiện khoảng 3–4 đơn hàng, phản ánh mức độ quay lại ở mức trung bình khá. Việc Mean cao hơn Median một chút cho thấy một số khách hàng có tần suất mua hàng rất cao (outliers) đã kéo trung bình tăng lên.

Giá trị lớn nhất (Max = 308): Có ít nhất một khách hàng thực hiện tới 308 giao dịch, cho thấy là nhóm khách hàng giá trị nhất (VIP customers) mà doanh nghiệp nên ưu tiên chăm sóc, có những dịch vụ ưu đãi hơn.

Doanh nghiệp nên tập trung tăng tỷ lệ mua lại thông qua những chính sách giữ chân khách hàng thay vì chỉ đầu tư vào việc thu hút khách hàng mới. Vì kết quả cho thấy chỉ cần mỗi khách hàng trung bình mua thêm 1 lần nữa, doanh thu tổng có thể tăng 25–30% mà không cần tăng chi phí marketing.

3.9 Tỷ lệ khách hàng mua 1 lần

1. customer_frequency %>%
2.   filter(Total_Transactions == 1) %>%
3.   summarise(One_Time_Customers = n() / nrow(customer_frequency) * 100)
## # A tibble: 1 × 1
##   One_Time_Customers
##                <dbl>
## 1               12.4

Giải thích kỹ thuật: Đoạn code trên để tính tỷ lệ khách hàng mua chỉ 1 lần. Đầu tiên dùng filter giữ lại những hàng (mỗi hàng tương ứng một khách) có số giao dịch đúng bằng 1, dùng summarise() tổng hợp kết quả chứa cột One_Time_Customers

Nhận xét: Tỷ lệ khách hàng chỉ mua hàng một lần chiếm 12,37% tổng số khách hàng. Tỷ lệ này thể hiện rằng doanh nghiệp đã xây dựng được mức độ hài lòng và lòng tin nhất định từ phía khách hàng, phản ánh rằng doanh nghiệp đã xây dựng được mối quan hệ lâu dài với khách hàng và tạo ra giá trị bền vững trong vòng đời tiêu dùng (Customer Lifetime Value – CLV).

3.10 Tỷ lệ đơn hàng chưa hoàn tất

1. product_status <- retail %>%
2.   group_by(Product_Category) %>%
3.   summarise(
4.     Total_Orders = n(),
5.     Uncompleted_Orders = sum(Order_Status %in% c("Pending", "Processing"), na.rm = TRUE),
6.     Uncompleted_Rate = (Uncompleted_Orders / Total_Orders) * 100) %>%
7.   arrange(desc(Uncompleted_Rate))
8. product_status
## # A tibble: 6 × 4
##   Product_Category Total_Orders Uncompleted_Orders Uncompleted_Rate
##   <fct>                   <int>              <int>            <dbl>
## 1 Nothing                   283                115             40.6
## 2 Books                   54622              20397             37.3
## 3 Clothing                54739              20393             37.3
## 4 Grocery                 66784              24700             37.0
## 5 Home Decor              54382              20062             36.9
## 6 Electronics             71196              20632             29.0

Giải thích kỹ thuật: Đoạn code trên tổng hợp tình trạng đơn hàng theo từng nhóm sản phẩm. Đầu tiên dùng group_by gom dữ liệu theo loại sản phẩm và summarise() tính ba chỉ tiêu quan trọng: Total_Orders, Uncompleted_Orders, Uncompleted_Rate. Cuối cùng, dùng arrange để sắp xếp các nhóm sản phẩm theo tỷ lệ đơn chưa hoàn thành giảm dần.

Nhận xét: Kết quả cho thấy nhóm sản phẩm “Nothing” có tỷ lệ đơn hàng chưa hoàn thành cao nhất, lên tới 40.6%, tuy nhiên số lượng đơn chỉ là 283 nên mức độ ảnh hưởng tổng thể không đáng kể. Ngược lại, các nhóm sản phẩm chính như Books, Clothing, Grocery, Home Decor đều có tỷ lệ đơn chưa hoàn thành dao động quanh 36–37%, phản ánh tình trạng tồn đọng hoặc chậm xử lý đơn hàng khá phổ biến trong hoạt động bán lẻ. Đáng chú ý, Electronics là nhóm có tỷ lệ thấp nhất (khoảng 29%) cho thấy khả năng kiểm soát quy trình tốt hơn.

3.11 Tính thời gian trung bình giữa 2 lần mua của mỗi khách hàng

1. purchase_interval <- retail %>%
2.   arrange(Customer_ID, as.Date(Date)) %>%
3.   group_by(Customer_ID) %>%
4.   mutate(Purchase_Interval = as.numeric(difftime(Date, lag(Date), units = "days"))) %>%
5.   summarise(Avg_Interval = mean(Purchase_Interval, na.rm = TRUE)) %>%
6.   filter(!is.infinite(Avg_Interval))
7. summary(purchase_interval$Avg_Interval)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
##    0.00   48.00   69.50   83.42  103.00  362.00   10782

Giải thích kỹ thuật: Đoạn code trên được dùng để tính thời gian trung bình giữa hai lần mua hàng của từng khách hàng, theo các bước: arrange sắp xếp dữ liệu theo khách hàng và ngày mua hàng tăng dần. Group_by() gom nhóm từng khách hàng để tính toán riêng cho từng người. Mutate(Purchase_Interval = as.numeric(difftime(Date, lag(Date), units = “days”))) sử dụng hàm lag() để lấy ngày mua trước đó của cùng khách hàng. Sau đó dùng difftime() tính khoảng cách thời gian giữa hai lần mua (đơn vị ngày), và dùng as.numeric() chuyển kết quả sang số. Cuối cùng dùng summarise tính trung bình số ngày giữa các lần mua hàng cho từng khách và summary () để xuất thống kê mô tả.

Nhận xét: Kết quả cho thấy thời gian trung bình giữa hai lần mua hàng của khách hàng là khoảng 83 ngày, khoảng thời gian dao động từ 0 đến 362 ngày. Điều này cho thấy hành vi mua sắm của khách hàng không đồng đều, một số khách quay lại mua hàng rất nhanh (trong vài ngày), trong khi nhiều khách khác có chu kỳ mua lại dài hơn ba tháng.

Tuy nhiên, phần lớn khách hàng có xu hướng quay lại trong khoảng 1 tháng rưỡi đến 2 tháng, chứng tỏ doanh nghiệp vẫn có tỷ lệ khách hàng quay lại tương đối ổn định. Chu kỳ mua hàng trung bình gần 3 tháng cho thấy doanh nghiệp chưa tạo được thói quen mua hàng thường xuyên ở phần lớn khách hàng. Do đó, cần đẩy mạnh các chương trình kích cầu sau 45 – 60 ngày kể từ lần mua trước.

3.12 So sánh mức độ đánh giá thấp giữa các sản phẩm

1. retail %>%
2.   filter(!is.na(Ratings)) %>%
3.   mutate(Low_Rated = Ratings <= 2) %>%
4.   group_by(Product_Category) %>%
5.   summarise(Low_Rated_Share = mean(Low_Rated, na.rm = TRUE)) %>%
6.   arrange(desc(Low_Rated_Share))
## # A tibble: 6 × 2
##   Product_Category Low_Rated_Share
##   <fct>                      <dbl>
## 1 Clothing                   0.389
## 2 Nothing                    0.389
## 3 Home Decor                 0.387
## 4 Books                      0.387
## 5 Grocery                    0.317
## 6 Electronics                0.298

Giải thích kỹ thuật: Dòng 3 dùng mutate để tạo biến mới dạng logic để đánh giá sản phẩm đó có bị đánh giá thấp không, bé hơn hoặc bằng 2 sẽ bị xem là đánh giá thấp. Sau đó gom nhóm dữ liệu theo loại sản phẩm bằng group_by. Dùng summarise () để tính tỷ lệ phần trăm sản phẩm bị đánh giá thấp. Cuối cùng dùng arrange để sắp xếp kết quả theo tỷ lệ đánh giá thấp giảm dần

Nhận xét: Nhóm có tỷ lệ đánh giá thấp cao nhất là Clothing (38.88%), Home Decor (38.72%) và Books (38.71%). Điều này cho thấy mức độ không hài lòng của khách hàng cao, có thể do chất lượng sản phẩm không ổn định, không đúng mô tả, hoặc vấn đề về kích cỡ, hình ảnh (đặc biệt trong nhóm quần áo và đồ trang trí).

Nhóm có tỷ lệ thấp nhất là Electronics (29.77%) và Grocery (31.70%), các nhóm này nhìn chung đạt mức độ hài lòng cao hơn, có thể vì chất lượng ổn định và tiêu chuẩn rõ ràng.

Qua đó doanh nghiệp cần tập trung cải thiện quy trình sản phẩm và trải nghiệm mua sắm trong các nhóm có tỷ lệ đánh giá thấp cao.

3.13 Phân tổ dữ liệu

3.13.1 Phân tổ khách hàng theo giới tính và thu nhập

1. customer_income_gender <- retail %>%
2.   group_by(Gender, Income) %>%
3.   summarise(Count = n(),Total_Revenue = sum(Total_Amount, na.rm = TRUE)) %>%
4.   arrange(desc(Count))
5. customer_income_gender
## # A tibble: 11 × 4
## # Groups:   Gender [3]
##    Gender  Income  Count Total_Revenue
##    <fct>   <ord>   <int>         <dbl>
##  1 Male    Medium  79677    108912187.
##  2 Male    Low     59436     81372373.
##  3 Female  Medium  50412     69179147.
##  4 Male    High    48304     65923407.
##  5 Female  Low     36719     50449285.
##  6 Female  High    26851     36365150.
##  7 Male    Nothing   179       254906.
##  8 Nothing Medium    141       195100.
##  9 Female  Nothing   111       142264.
## 10 Nothing Low       102       139207.
## 11 Nothing High       74       104169.

Giải thích kỹ thuật: Dòng 2 dùng để gom nhóm theo 2 biến: Gender và Income. Dòng 3 dùng để đếm số khách hàng và tính tổng doanh thu từ nhóm đó. Dòng 4 sắp xếp theo số lượng khách hàng giảm dần.

Nhận xét: xét theo giới tính, nhóm khách hàng nam giới mang lại tổng doanh thu cao nhất, đạt khoảng 256 triệu đô, chiếm hơn 60% tổng doanh thu toàn doanh nghiệp. Điều này cho thấy nam giới có xu hướng chi tiêu cao hơn hoặc mua hàng thường xuyên hơn so với nữ giới. Trong khi đó, nhóm khách hàng nữ tạo ra khoảng 156 triệu đô doanh thu, thấp hơn nam giới 40%.

Xét theo mức thu nhập, nhóm thu nhập trung bình (medium) đóng góp doanh thu lớn nhất với khoảng 178 triệu đô, chiếm gần một nửa tổng doanh thu. Đây là nhóm khách hàng chính, vừa có số lượng đông đảo, vừa duy trì mức chi tiêu ổn định. Nhóm thu nhập thấp (low) xếp thứ hai với 132 triệu đô, chiếm hơn 1/3 tổng doanh thu. Dù khả năng chi trả thấp, nhưng có lượng khách hàng lớn, nên vẫn góp phần quan trọng vào tổng doanh thu. Trong khi đó, nhóm thu nhập cao (high) chỉ chiếm khoảng 102 triệu đô. Tuy nhiên, mỗi khách hàng trong nhóm này có mức chi tiêu trung bình cao, cho thấy tiềm năng tăng trưởng nếu doanh nghiệp phát triển các sản phẩm hoặc dịch vụ cao cấp hơn.

Kết luận doanh thu của doanh nghiệp hiện đang phụ thuộc mạnh vào nhóm khách hàng nam có thu nhập trung bình và thấp. Bên cạnh đó sự mất cân đối giữa các nhóm giới tính và thu nhập cũng chỉ ra rằng doanh nghiệp cần đa dạng hóa chiến lược để thu hút thêm khách hàng nữ cũng như khai thác hiệu quả hơn nhóm khách hàng thu nhập cao.

3.13.2 Phân tổ theo hiệu quả kinh doanh của doanh nghiệp

1. bussiness_efficiency <- retail %>%
2.   group_by(Customer_Segment, Product_Category) %>%
3.   summarise(
4.     Total_Revenue = sum(Total_Amount, na.rm = TRUE),
5.     Avg_Rating = mean(Ratings, na.rm = TRUE)) %>%
6.   arrange(desc(Total_Revenue))
7. bussiness_efficiency
## # A tibble: 23 × 4
## # Groups:   Customer_Segment [4]
##    Customer_Segment Product_Category Total_Revenue Avg_Rating
##    <fct>            <fct>                    <dbl>      <dbl>
##  1 Regular          Electronics          48884199.       3.16
##  2 Regular          Grocery              41935155.       3.06
##  3 Regular          Home Decor           36512437.       2.99
##  4 Regular          Books                36406687.       2.98
##  5 Regular          Clothing             36275729.       2.98
##  6 New              Grocery              28171047.       3.22
##  7 New              Electronics          27675840.       3.29
##  8 New              Clothing             23135079.       3.14
##  9 New              Books                22957435.       3.17
## 10 New              Home Decor           22663776.       3.15
## # ℹ 13 more rows

Giải thích kỹ thuật: Dòng 2 dùng để gom nhóm theo 2 biến. Dòng 3 để tính tổng doanh thu và tính trung bình của điểm đánh giá. Dòng 4 sắp xếp theo thứ tự giảm dần.

Nhận xét: Phân khúc Regular là nguồn doanh thu lớn nhất, đứng đầu ở 5 danh mục, trong đó Regular_Electronics dẫn đầu với tổng doanh thu khoảng 48 triệu đô, cho thấy doanh thu của doanh nghiệp phần lớn phụ thuộc vào tệp khách hàng này. Theo sau đó, là phân khúc New cũng có khoảng doanh thu ấn tượng từ 22 triệu đô đến 28 triệu đô, thể hiện tiềm năng tăng trưởng tốt của doanh nghiệp.Ngoài ra 2 danh mục sản phẩm là Electronics và Grocery có đóng góp đáng kể ở cả 3 phân khúc Regular, New và Premium.

Tuy nhiên cần chú ý về mức độ hài lòng của khách hàng ở phân khúc Regular khi đây là phân khúc mang lại doanh thu lớn nhất nhưng lại có điểm đánh giá trung bình thấp nhất (2.9 - 3.1). Ngược lại phân khúc Premium có điểm đánh giá cao nhất (3.3 đến 3.5), cho thấy chất lượng dịch vụ, sản phẩm cao đã được đáp ứng cho nhóm khách hàng giá trị này.

3.13.3 Phân tổ theo hành vi mua hàng

1. buying_behavior <- retail %>%
2.   group_by(Shipping_Method, Payment_Method, Customer_Segment, Product_Category) %>%
3.   summarise(Orders = n(),Avg_Amount = mean(Amount, na.rm = TRUE),Avg_Rating = mean(Ratings, na.rm = TRUE)) %>%
4.   arrange(desc(Orders))
5. buying_behavior
## # A tibble: 377 × 7
## # Groups:   Shipping_Method, Payment_Method, Customer_Segment [71]
##    Shipping_Method Payment_Method Customer_Segment Product_Category Orders
##    <fct>           <fct>          <fct>            <fct>             <int>
##  1 Same-Day        Credit Card    Regular          Electronics        4534
##  2 Express         Cash           Regular          Electronics        3409
##  3 Express         Credit Card    Regular          Electronics        3378
##  4 Same-Day        Credit Card    New              Electronics        3343
##  5 Same-Day        Cash           Regular          Electronics        2966
##  6 Express         Credit Card    Regular          Grocery            2943
##  7 Standard        Credit Card    Regular          Electronics        2915
##  8 Express         Debit Card     Regular          Electronics        2890
##  9 Same-Day        Credit Card    Premium          Electronics        2851
## 10 Same-Day        Debit Card     Regular          Electronics        2823
## # ℹ 367 more rows
## # ℹ 2 more variables: Avg_Amount <dbl>, Avg_Rating <dbl>

Giải thích kỹ thuật: Dòng 2 gom nhóm theo 4 biến. Dòng 3 để đếm số lượng đơn hàng, tính giá trị đơn hàng trung bình, sắp xếp theo thứ tự giảm dần.

Nhận xét: Kết quả cho thấy nhóm phân khúc có số lượng đơn hàng lớn nhất Regular có xu hướng sử dụng 2 phương thức vận chuyển nhanh là Same-day và Express, kết luận nhu cầu về tốc độ giao hàng của nhóm khách hàng này rất cao. Bên cạnh đó mức độ hài lòng của nhóm khách hàng ghi nhận ở mức trung bình. Phương thức thanh toán được sử dụng nhiều nhất là Credit Card và Cash, phương thức thanh toán khác như PayPal thường đi với các đơn hàng có giá trị cao khoảng 400 đô đến 490 đô.

3.13.4 Phân tổ độ tuổi theo phân khúc khách hàng và thu nhập

Trước khi phân tích, em chia nhóm tuổi ra thành 4 nhóm và đánh giá 4 nhóm tuổi theo phân khúc khách hàng và thu nhập.

1. age_customer <- retail %>%
2.   mutate(Age_Group = cut(Age,breaks = c(18, 25, 40, 60, Inf),labels = c("18-25", "26-40", "41-60", "60+"),right = TRUE, include.lowest = TRUE))
3. Age_Group_customer <- age_customer %>%
4.   group_by(Customer_Segment, Income, Age_Group) %>%
5.   summarise(Count = n() ) %>%
6.   arrange(desc(Count))
7. Age_Group_customer
## # A tibble: 61 × 4
## # Groups:   Customer_Segment, Income [16]
##    Customer_Segment Income Age_Group Count
##    <fct>            <ord>  <fct>     <int>
##  1 Regular          Medium 18-25     33556
##  2 Regular          High   18-25     22340
##  3 New              Medium 18-25     18041
##  4 Regular          High   26-40     15574
##  5 Regular          Medium 41-60     13067
##  6 Regular          Medium 26-40     11814
##  7 Regular          Low    41-60     11778
##  8 New              Medium 41-60     11209
##  9 Regular          Low    18-25     11173
## 10 New              Low    18-25     11071
## # ℹ 51 more rows

Giải thích kỹ thuật: Dòng 2,3 dùng để phân loại độ tuổi, chia độ tuổi thành 4 nhóm. Từ dòng 5, gom nhóm dữ liệu theo 3 biến, đếm số khách hàng trong mỗi nhóm và sắp xếp theo số lượng khách hàng giảm dần.

Nhận xét: Phân khúc khách hàng tập trung của doanh nghiệp là nhóm thường xuyên có thu nhập Medium, High và độ tuổi từ 18 - 25 tuổi. Điều này chỉ ra rằng công ty đang rất thành công trong việc thu hút thế hệ thanh niên và trung niên trẻ tuổi có khả năng chi tiêu, ngoài ra nhóm khách hàng mới cũng nằm trong độ tuổi này, thể hiện rằng xu hướng này vẫn đang tiếp diễn. Kết quả còn cho thấy phân khúc regular, new thường là những người trẻ tuổi còn phân khúc premium lại có xu hướng lớn tuổi hơn.

1. age_summary <- retail %>%
2.   group_by(Customer_Segment, Income) %>%
3.   summarise(Mean_Age = mean(Age, na.rm = TRUE),Median_Age = median(Age, na.rm = TRUE),Min_Age = min(Age, na.rm = TRUE),Max_Age = max(Age, na.rm = TRUE), Count = n()) %>%
4.   arrange(desc(Count))
5. age_summary
## # A tibble: 16 × 7
## # Groups:   Customer_Segment [4]
##    Customer_Segment Income  Mean_Age Median_Age Min_Age Max_Age Count
##    <fct>            <ord>      <dbl>      <dbl>   <dbl>   <dbl> <int>
##  1 Regular          Medium      31.9       24        18      70 62721
##  2 Regular          High        29.5       26        18      70 45785
##  3 New              Medium      34.7       31        18      70 41450
##  4 Regular          Low         37.3       34        18      70 37599
##  5 New              Low         36.9       34        18      70 33023
##  6 Premium          Medium      41.6       43        18      70 25977
##  7 Premium          Low         41.6       44        18      70 25539
##  8 New              High        36.4       34        18      70 16620
##  9 Premium          High        41.8       44        18      70 12788
## 10 Regular          Nothing     36.7       34        19      68   114
## 11 Nothing          Low         41.5       38.5      18      70    96
## 12 New              Nothing     38.5       38.5      19      70    92
## 13 Premium          Nothing     42.2       46        18      69    83
## 14 Nothing          Medium      43.4       46        18      70    82
## 15 Nothing          High        39.7       34.5      19      70    36
## 16 Nothing          Nothing     46         46        46      46     1

Giải thích kỹ thuật: Dòng 2 để gom nhóm theo 2 biến. Sau đấy tính các chỉ số thống kê cơ bản của độ tuổi.

Nhận xét: Nhóm phân khúc khách hàng Regular thường tập trung ở độ tuổi trung bình 30 đến 32 tuổi và là nhóm có thu nhập từ trung bình (Medium) trở lên. Nhóm phân khúc khách hàng Premium là nhóm có độ tuổi trung nhiên trong khoảng 41 đến 42 tuổi, là nhóm có thu nhập ổn định (Medium, High) phù hợp với những phân khúc sản phẩm cao cấp. Nhóm phân khúc khách hàng New cũng có xu hướng là những người trẻ tuổi, độ tuổi trung bình khoảng 35 đến 37 tuổi.

CHƯƠNG 4: TRỰC QUAN HÓA DỮ LIỆU

4.1 Doanh thu trung bình theo thứ

1. retail %>%
2. mutate(Weekday = wday(Date, label = TRUE, abbr = FALSE, week_start = 1)) %>%
3. group_by(Weekday) %>%
4. summarise(Avg_Sales = mean(Total_Amount, na.rm = TRUE)) %>%
5. arrange(Weekday) %>%
6. ggplot(aes(x = Weekday, y = Avg_Sales, group = 1)) +
7. geom_col(fill = "#2E86AB", alpha = 0.8) + 
8. geom_text(aes(label = round(Avg_Sales, 0)), vjust = -0.5, size = 4, color = "black") +
9. labs(title = "Doanh thu trung bình theo thứ trong tuần",subtitle = "Phân tích xu hướng doanh thu theo ngày trong tuần để xác định thời điểm bán hàng cao điểm",x = "Thứ trong tuần",y = "Doanh thu trung bình (VNĐ)",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
10. scale_y_continuous(labels = comma) +
11. theme_minimal(base_size = 13) +
12. theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 14, color = "#2C3E50"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.title = element_text(face = "bold"),axis.text = element_text(color = "black"),panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 1 đến 5, tạo bảng trung bình doanh thu theo ngày trong tuần. Dòng 2 dùng mutate() để thêm cột mới Weekday, xác định thứ trong tuần dựa vào cột Date bằng hàm wday() và week_start = 1 để tuần bắt đầu từ thứ Hai. Dòng 3 nhóm dữ liệu bằng group_by(). Dòng 4 dùng summarise() để tính doanh thu trung bình (Avg_Sales) của từng ngày trong tuần, dòng 5 sắp xếp các ngày trong tuần theo đúng thứ tự thời gian bằng arrange(). Dòng 6 tạo biểu đồ cột với trục X là các ngày trong tuần và trục Y là doanh thu trung bình (Avg_Sales), giúp thể hiện doanh thu trung bình của từng ngày.

Nhận xét: Biểu đồ cho thấy doanh thu trung bình theo các ngày trong tuần tương đối ổn định, dao động nhẹ từ 1,360 VND đến 1,381 VND trong các ngày từ thứ Hai đến Chủ nhật, ngoại trừ mục “NA” có doanh thu thấp nhất là 1,272 VND. Đỉnh điểm doanh thu rơi vào thứ Sáu với 1,381 VND, trong khi Chủ nhật và đầu tuần có mức doanh thu gần như ngang bằng và chỉ thấp hơn một chút. Có thể thấy, thứ sáu là thời điểm tốt nhất để đẩy mạnh các chiến dịch bán hàng hoặc khuyến mãi, vì đây là ngày có doanh thu trung bình cao nhất trong tuần. Tuy nhiên, sự chênh lệch giữa các ngày không quá lớn, cho thấy hành vi mua hàng được phân bố đều. Do đó, doanh nghiệp nên duy trì hoạt động marketing và vận hành ổn định cả tuần.

4.2 Biểu đồ thể hiện xu hướng doanh thu theo thứ

1. weekday_rev <- retail %>%
2. mutate(Weekday = wday(Date, label = TRUE, abbr = FALSE)) %>%
3. group_by(Year, Weekday) %>%
4. summarise(total_revenue = sum(Total_Amount, na.rm = TRUE), .groups = "drop")
5. ggplot(weekday_rev, aes(x = Weekday, y = total_revenue, group = Year, color = factor(Year))) +
6. geom_line(size = 1.2) +
7. geom_point(size = 3) +
8. geom_text(aes(label = comma(round(total_revenue, 0))),vjust = -0.8, size = 3, check_overlap = TRUE) +
9. scale_y_continuous(labels = comma,limits = c(0, max(weekday_rev$total_revenue) * 1.15)) +
10. labs(title = "Xu hướng doanh thu theo thứ trong tuần",subtitle = "Phân tích sự thay đổi doanh thu theo các ngày trong tuần",x = "Thứ",y = "Tổng doanh thu (VNĐ)",color = "Năm",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
11. theme_light(base_size = 13) +
12. theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.text.x = element_text(angle = 45, hjust = 1),axis.title = element_text(face = "bold"),legend.position = "bottom",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 1 đến 4, tạo một data.frame (weekday_rev) dùng hàm mutate() để thêm một cột mới Weekday xác định ngày trong tuần từ biến Date và abbr = FALSE để giữ nguyên tên đầy đủ. Dòng 3 dùng group_by() để nhóm dữ liệu theo 2 biến và dùng summarise() để tính tổng doanh thu (total_revenue) theo từng năm và từng ngày trong tuần. Từ dòng 5 tạo biểu đồ đường với trục X là các ngày trong tuần, trục Y là tổng doanh thu và các đường thể hiện sự thay đổi doanh thu theo từng ngày trong tuần của mỗi năm. Dòng 7 thêm các điểm đánh dấu tại mỗi vị trí giúp biểu đồ trực quan, dễ quan sát giá trị doanh thu cụ thể hơn.

Nhận xét: Biểu đồ thể hiện xu hướng tổng doanh thu theo các ngày trong tuần qua ba nhóm dữ liệu năm 2023, 2024. Trong đó, năm 2023 có mức doanh thu ổn định quanh mức 48-50 triệu VND mỗi ngày từ chủ nhật đến thứ bảy, cao nhất là thứ sáu với hơn 50 triệu. Năm 2024 có doanh thu thấp hơn đáng kể, dao động từ khoảng 8,7 đến hơn 10 triệu VND/ngày, cao nhất vào thứ tư và thứ năm.

4.3 Biểu đồ thể hiện tổng doanh thu theo phân khúc khách hàng

1. retail %>%
2.   group_by(Customer_Segment) %>%
3.   summarise(Total_Sales = sum(Total_Amount, na.rm = TRUE)) %>%
4.   ggplot(aes(x = reorder(Customer_Segment, Total_Sales), y = Total_Sales, fill = Customer_Segment)) +
5.   geom_col(width = 0.7, alpha = 0.85) +
6.   geom_text(aes(label = comma(round(Total_Sales, 0))),vjust = 1.2, size = 3.5, fontface = "bold") +
7.   scale_fill_brewer(palette = "Set3") +
8. labs(title = "Tổng doanh thu theo phân khúc khách hàng",x = "Phân khúc khách hàng",y = "Tổng doanh thu (VNĐ)",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
9.   theme_minimal(base_size = 13) +
10.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.text.x = element_text(angle = 45, hjust = 1),axis.title = element_text(face = "bold"),legend.position = "bottom",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 1 đến 3, tạo bảng dữ liệu nhóm theo từng phân khúc khách hàng (Customer_Segment), dùng summarise() để tính tổng doanh thu (Total_Sales) của từng phân khúc. Dòng 4 tạo biểu đồ cột với trục X là các nhóm khách hàng được sắp xếp theo tổng doanh thu giảm dần, trục Y là tổng doanh thu.

Nhận xét: Biểu đồ cho thấy, phân khúc “Regular” tạo ra tổng doanh thu cao nhất, đạt khoảng 200 triệu VND chiếm phần lớn trong tổng doanh thu toàn bộ hệ thống. Khách hàng “New” cũng đóng góp với gần 125 triệu VND, chứng tỏ tiềm năng từ nhóm khách hàng mới. Ngược lại phân khúc “Premium” thường được kỳ vọng chi tiêu cao hơn nhưng lại chỉ đạt khoảng 88 triệu VND, thấp hơn đáng kể so với nhóm “Regular”. Phân khúc “Nothing” gần như không đóng góp đáng kể, có thể là dữ liệu bị thiếu nhãn hoặc chưa được phân loại đúng.

4.4 Biểu đồ thể hiện doanh thu trung bình theo vùng kinh tế tại hoa kỳ theo phương thức vận chuyển

1. retail_region <- retail %>%
2.   mutate(Region = case_when(
3.       State %in% c(
4.         "Maine", "New Hampshire", "Vermont", "Massachusetts", "Rhode Island", "Connecticut",
5.         "New York", "New Jersey", "Pennsylvania") ~ "Northeast",
6.       State %in% c(
7.         "Ohio", "Indiana", "Illinois", "Michigan", "Wisconsin",
8.         "Minnesota", "Iowa", "Missouri", "North Dakota", "South Dakota", "Nebraska", "Kansas") ~ "Midwest",
9.       State %in% c(
10.         "Delaware", "Maryland", "District of Columbia", "Virginia", "West Virginia",
11.         "North Carolina", "South Carolina", "Georgia", "Florida",
12.         "Kentucky", "Tennessee", "Alabama", "Mississippi", "Arkansas", "Louisiana", "Oklahoma", "Texas") ~ "South",
13.       State %in% c(
14.         "Montana", "Idaho", "Wyoming", "Colorado", "New Mexico",
15.         "Arizona", "Utah", "Nevada", "Washington", "Oregon", "California", "Alaska", "Hawaii") ~ "West",
16.       TRUE ~ "Other"))
17. region_shipping <- retail_region %>%
18.   group_by(Region, Shipping_Method) %>%
19.   summarise(Avg_Revenue = mean(Total_Amount, na.rm = TRUE), .groups = "drop")
20. ggplot(region_shipping, aes(x = Region, y = Avg_Revenue, fill = Shipping_Method)) +
21.   geom_col(position = position_dodge(width = 0.9), width = 0.8) +  
22.   geom_text(aes(label = scales::comma(round(Avg_Revenue, 0))),position = position_dodge(width = 0.9),hjust = -0.25,size = 3,fontface = "bold",color = "black") +
23.   scale_fill_brewer(palette = "Set2") +
24.   labs(title = "Doanh thu trung bình theo vùng",subtitle = "Phân tích theo phương thức giao hàng",x = "Vùng địa lý",y = "Doanh thu trung bình (USD)",fill = "Phương thức",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
25.   coord_flip() +
26.   expand_limits(y = max(region_shipping$Avg_Revenue) * 1.3) +  
27.   theme_minimal(base_size = 13) +
28.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "bottom",panel.grid.minor = element_blank())

Giải thích kỹ thuật:

Nhận xét: Biểu đồ cho thấy doanh thu trung bình cao nhất thuộc về phương thức giao hàng Standard tại khu vực West (1,942 USD), theo sau là Standard tại Northeast (1,605 USD) và Other (1,498 USD). Mức chênh lệch giữa các phương thức trong từng vùng không quá lớn ngoại trừ Standard thường vượt trội rõ rệt. Giao hàng Same-Day, Express và Standard có mức doanh thu tương đối ổn định trên hầu hết các vùng.

Kết luận: Doanh thu vượt trội từ hình thức giao hàng Standard cho thấy đây là phương thức đem lại giá trị đơn hàng cao nhất, đặc biệt tại các khu vực như West và Northeast. Doanh nghiệp nên tập trung đẩy mạnh ưu đãi và trải nghiệm giao hàng Standard tại các vùng này để tối ưu doanh thu, đồng thời rà soát chi phí giao hàng để đảm bảo lợi nhuận biên.

4.5 Biểu đồ thể hiện mối quan hệ giữa thu nhập khách hàng và tổng chi tiêu

1. avg_spend <- retail %>%
2.   group_by(Customer_Segment) %>%
3.   summarise(Avg_Income = mean(Income_Code, na.rm = TRUE),Avg_Spending = mean(Total_Amount, na.rm = TRUE),Avg_Rating = mean(Ratings, na.rm = TRUE))
4. ggplot(avg_spend, aes(x = Avg_Income, y = Avg_Spending, color = Customer_Segment)) +
5.   geom_point(size = 4, alpha = 0.8) + 
6.   geom_smooth(method = "lm", se = TRUE, color = "black", linetype = "dashed") +  
7.   geom_text(aes(label = Customer_Segment), vjust = 1, size = 3.5) +  
8.   geom_hline(yintercept = mean(avg_spend$Avg_Spending), color = "blue", linetype = "dotted") +  
9.   geom_vline(xintercept = mean(avg_spend$Avg_Income), color = "red", linetype = "dotted") +  
10.   labs(title = "Thu nhập và chi tiêu trung bình theo phân khúc khách hàng",x = "Thu nhập trung bình (Income)",y = "Chi tiêu trung bình (Total_Amount)",color = "Phân khúc",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
11.   theme_minimal(base_size = 13) +
12.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "bottom",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 1 đến 3, tạo bảng dữ liệu trung bình (avg_spend) dùng group_by() để nhóm dữ liệu theo từng phân khúc, dùng summarise() để tính ba chỉ tiêu trung bình. Dòng 4 khởi tạo biểu đồ ggplot với trục X thể hiện thu nhập trung bình (Avg_Income), trục Y thể hiện chi tiêu trung bình (Avg_Spending), Dòng 5 thêm các điểm biểu diễn mối quan hệ giữa thu nhập và chi tiêu của từng nhóm. Dòng 6 vẽ đường hồi quy tuyến tính thể hiện xu hướng mối quan hệ giữa thu nhập và chi tiêu. Dòng 8 và 9 thêm các đường trung bình: đường ngang màu xanh thể hiện mức chi tiêu trung bình chung và đường dọc màu đỏ thể hiện mức thu nhập trung bình chung

Nhận xét: Biểu đồ thể hiện xu hướng thu nhập trung bình và chi tiêu trung bình theo phân khúc khách hàng. Có thể thấy phân khúc “Nothing” dù có thu nhập thấp nhất lại chi tiêu cao nhất (~1500), trong khi phân khúc “Regular” có thu nhập cao hơn nhưng lại chi tiêu thấp hơn mức trung bình (~1350). Đường xu hướng đi xuống cho thấy mối quan hệ ngược chiều giữa thu nhập và chi tiêu, tuy chưa rõ rệt nhưng có tồn tại. Doanh nghiệp nên nghiên cứu hành vi tiêu dùng của nhóm thu nhập thấp để thiết kế các chương trình khuyến mãi hoặc gói sản phẩm phù hợp, từ đó tối ưu doanh thu từ nhóm có tiềm năng chi tiêu cao bất chấp mức thu nhập.

4.6 Biểu đồ thể hiện phân bổ chi tiêu theo thu nhập

1. retail_sample <- retail %>% sample_n(min(150000, nrow(data)))
2. ggplot(retail_sample, aes(x = Total_Amount, fill = Income)) +
3.   geom_density(alpha = 0.5, adjust = 0.8) +
4.   geom_vline(aes(xintercept = mean(Total_Amount, na.rm = TRUE)),color = "black", linetype = "dashed", linewidth = 0.8) +
5.   scale_fill_brewer(palette = "Dark2") +
6.   theme_minimal() +
7.   labs(title = "Phân bố chi tiêu theo thu nhập",x = "Tổng chi tiêu", y = "Mật độ", caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
8.   theme_minimal(base_size = 13) +
9.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "bottom",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 1 tạo một data.frame (retail_sample) bằng hàm sample_n(), với số lượng mẫu là nhỏ nhất giữa 150.000 và tổng số dòng hiện có (nrow(data)). Từ dòng 2 tạo biểu đồ mật độ với trục X là giá trị tổng tiền đơn hàng (Total_Amount) biểu diễn phân bố của giá trị Total_Amount theo các nhóm thu nhập. Dòng 4 thêm đường thẳng đứng tại vị trí trung bình của Total_Amount, giúp so sánh phân bố dữ liệu với giá trị trung bình.

Nhận xét: Biểu đồ mật độ cho thấy đa số các phân khúc thu nhập đều tập trung chi tiêu ở mức thấp dưới 1000, với đỉnh phân bố rõ nét. Tuy nhiên, phân khúc thu nhập “Nothing” và “Low” có xu hướng chi tiêu cao hơn trung bình, khi xuất hiện một mật độ lớn ở vùng chi tiêu từ 1500 đến 2500. Ngược lại, các nhóm “Medium” và “High” có mật độ dàn trải hơn nhưng lại ít chi tiêu vượt ngưỡng cao. Các nhóm thu nhập thấp có thể là những khách hàng chi tiêu tích cực. Do đó, doanh nghiệp nên cân nhắc khai thác tốt phân khúc thu nhập thấp qua các chương trình khuyến mãi hoặc ưu đãi chiết khấu để tối ưu doanh thu từ nhóm khách hàng có hành vi chi tiêu mạnh mẽ.

4.7 Biểu đồ thể hiện tổng chi tiêu trung bình theo phương thức thanh toán

1. retail %>%
2.   group_by(Payment_Method) %>%
3.   summarise(Average_Spend = mean(Total_Amount, na.rm = TRUE)) %>%
4.   ggplot(aes(x = reorder(Payment_Method, -Average_Spend), y = Average_Spend,fill = Payment_Method)) +
5.   geom_col(alpha = 0.7, width = 0.6, color = "white") +  
6.   geom_text(aes(label = round(Average_Spend, 0)), vjust = -0.5, size = 4.5, fontface = "bold") +  
7.   geom_hline(yintercept = mean(retail$Total_Amount, na.rm = TRUE), linetype = "dashed", color = "red", size = 0.8) +  
8.   scale_fill_brewer(palette = "Pastel1") +
9.   labs(title = "Chi tiêu trung bình theo phương thức thanh toán",x = "Phương thức thanh toán",y = "Chi tiêu trung bình",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
10.   theme_minimal(base_size = 13) +
11.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "bottom",panel.grid.minor = element_blank()) +
12.   ylim(0, 1800)  

Giải thích kỹ thuật: Từ dòng 1 đến 3, tạo bảng dữ liệu tóm tắt theo phương thức thanh toán (Payment_Method). Dòng 2 dùng group_by() để nhóm dữ liệu theo từng loại phương thức thanh toán. Dòng 3 sử dụng summarise() để tính giá trị chi tiêu trung bình (Average_Spend) cho mỗi phương thức. Từ dòng 4 tạo biểu đồ cột với trục X là tên phương thức thanh toán được sắp xếp theo thứ tự giảm dần của giá trị chi tiêu trung bình, trục Y là chi tiêu trung bình để thể hiện mức chi tiêu trung bình của từng phương thức thanh toán. Dòng 7 thêm đường ngang biểu diễn giá trị chi tiêu trung bình chung của toàn bộ dữ liệu.

Nhận xét: Biểu đồ cho thấy chi tiêu trung bình không có sự khác biệt lớn giữa các phương thức thanh toán: Credit Card (1369), Debit Card (1368), PayPal (1367) và Cash (1366) đều gần như bằng nhau, quanh ngưỡng 1360 – 1370. Nhóm “Nothing” có mức thấp nhất (1342), tuy nhiên cũng không cách biệt nhiều. Có thể nói phương thức thanh toán không ảnh hưởng đáng kể đến mức chi tiêu trung bình của khách hàng. Điều này cho thấy hành vi chi tiêu dường như phụ thuộc nhiều hơn vào đặc điểm khách hàng và hoàn cảnh mua hàng hơn là cách thức thanh toán. Doanh nghiệp nên tập trung cá nhân hóa ưu đãi theo phân khúc khách hàng hơn là theo loại thanh toán.

4.8 Biểu đồ thể hiện tỷ lệ sản phẩm theo loại sản phẩm

1. product_data <- retail %>%
2.   group_by(Product_Category) %>%
3.   summarise(Count = n())
4. ggplot(product_data, aes(x = "", y = Count, fill = Product_Category)) +
5.   geom_bar(stat = "identity", width = 1, color = "white") +                   
6.   coord_polar("y", start = 0) +                                               
7.   geom_text(aes(label = paste0(round(Count / sum(Count) * 100, 1), "%")),position = position_stack(vjust = 0.5), size = 4) +               
8.   scale_fill_brewer(palette = "Set3") +                                       
9.   theme_void() +                                                              
10.   labs(title = "Tỷ lệ loại sản phẩm được mua",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ" ) +
11.   theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 14))

Giải thích kỹ thuật: Từ dòng 1 đến 3, tạo data.frame dùng group_by() để nhóm dữ liệu theo từng loại sản phẩm. Dòng 3 sử dụng summarise() để đếm số giao dịch trong từng nhóm bằng hàm n(). Dòng 4 tạo biểu đồ cột với trục Y là số lượng. Dòng 6 dùng coord_polar(“y”, start = 0) để chuyển biểu đồ cột thành biểu đồ tròn (pie chart) với góc bắt đầu là 0 độ, giúp hiển thị tỷ lệ từng loại sản phẩm trong tổng thể một cách trực quan.

Nhận xét: Biểu đồ tròn thể hiện tỷ lệ mua hàng theo loại sản phẩm cho thấy nhóm Electronics chiếm tỷ lệ cao nhất với 23.6%, theo sau là Grocery (22.1%). Các nhóm Books, Clothing và Home Decor có tỷ lệ tương đương nhau, khoảng 18%, trong khi nhóm “Nothing” gần như không đáng kể (0.1%). Có thể nói khách hàng có xu hướng ưu tiên chi tiêu cho các sản phẩm thiết yếu và giá trị cao như điện tử và hàng tiêu dùng (Grocery). Doanh nghiệp nên tập trung mở rộng nguồn hàng, khuyến mãi hoặc chăm sóc khách hàng đặc biệt cho hai nhóm sản phẩm này nhằm tăng doanh thu hiệu quả.

4.9 Biểu đồ thể hiện phân bố đơn hàng theo phương thức thanh toán và giao hàng

1. ggplot(buying_behavior, aes(x = Shipping_Method, y = Orders, fill = Payment_Method)) +
2.   geom_bar(stat = "identity", position = "dodge", width = 0.7) +
3.   labs(title = "Đơn hàng theo phương thức giao và thanh toán",x = "Phương thức giao hàng",y = "Số lượng đơn hàng",fill = "Hình thức thanh toán",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
4.   scale_fill_brewer(palette = "Set2") +
5.   theme_minimal(base_size = 13) +
6.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"), plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text.x = element_text(angle = 30, hjust = 1, color = "grey20"),axis.title = element_text(face = "bold"),legend.position = "bottom",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 1, 2 tạo biểu đồ cột với trục X là phương thức giao hàng (Shipping_Method), trục Y là số lượng đơn hàng (Orders), biểu đồ này giúp thể hiện mối quan hệ giữa cách khách hàng nhận hàng và cách họ thanh toán. Tham số position = “dodge” giúp các cột của từng nhóm Payment_Method được đặt cạnh nhau thay vì chồng lên nhau, giúp dễ dàng so sánh giữa các phương thức thanh toán trong cùng một phương thức giao hàng.

Nhận xét: Biểu đồ cho thấy phương thức giao hàng Same-Day có số lượng đơn hàng cao nhất, đặc biệt khi khách hàng thanh toán bằng Credit Card, vượt trội so với các hình thức còn lại. Trong khi đó, phương thức giao hàng “Nothing” hầu như không được sử dụng. Hình thức thanh toán PayPal có xu hướng thấp hơn so với các hình thức còn lại ở mọi phương thức giao hàng. Có thể thấy khách hàng có xu hướng ưu tiên giao hàng nhanh (Same-Day), đặc biệt khi sử dụng thẻ tín dụng. Doanh nghiệp nên tiếp tục đầu tư vào logistics giao hàng nhanh và cải thiện trải nghiệm thanh toán qua Credit Card để thúc đẩy doanh số. Đồng thời, cần cân nhắc nâng cao khả năng tiếp cận của các phương thức như PayPal nhằm đa dạng hóa lựa chọn cho khách hàng.

4.10 Biểu đồ thể hiện tổng mua theo quốc gia và danh mục

1. Retail_summary <- retail %>%
2.   group_by(Country, Product_Category) %>%
3.   summarise(Total = sum(Total_Purchases, na.rm = TRUE)) 
4. ggplot(Retail_summary, aes(x = Country, y = Product_Category, fill = Total)) +
5.   geom_tile(color = "white") +                               
6.   geom_text(aes(label = round(Total, 0)), size = 3) +        
7.   scale_fill_gradient(low = "lightblue", high = "darkblue") +
8.   geom_vline(xintercept = 1:length(unique(Retail_summary$Country)) - 0.5, color = "grey80") +                  
9.   geom_hline(yintercept = 1:length(unique(Retail_summary$Product_Category)) - 0.5, color = "grey80") +                             
10.   labs(title = "Heatmap tổng mua theo quốc gia & danh mục",fill = "Tổng mua",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
11.   theme_minimal(base_size = 13) +
12.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "bottom",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 1 đến 3, tạo data.frame (Retail_summary) dùng group_by() để nhóm dữ liệu theo hai biến là Country và Product_Category, dùng summarise() để tính tổng số lần mua hàng cho mỗi cặp nhóm. Từ dòng 4 tạo biểu đồ nhiệt với trục X là các quốc gia, trục Y là danh mục sản phẩm với các ô vuông biểu thị giá trị Total bằng thang màu.

Nhận xét: Biểu đồ heatmap cho thấy Hoa Kỳ (USA) là quốc gia có tổng số lượt mua cao nhất ở tất cả các danh mục sản phẩm, đặc biệt vượt trội ở Grocery (139,693), Electronics (107,667) và Books (87,967). Ngược lại, các quốc gia như Australia, Canada và Germany có tổng mua đồng đều và thấp hơn đáng kể. Quốc gia “Nothing” gần như không đáng kể về số lượt mua. Điều này cho thấy chiến lược tiếp thị và phân phối nên ưu tiên đẩy mạnh tại thị trường Mỹ, đồng thời cân nhắc các chiến dịch quảng bá riêng biệt phù hợp với hành vi tiêu dùng tại các quốc gia còn lại.

4.11 Biểu đồ thể hiện tần suất mua hàng của khách hàng

1. customer_frequency <- retail %>%
2.   group_by(Customer_ID) %>%
3.   summarise(Total_Transactions = n()) %>%
4.   na.omit() 
5. ggplot(customer_frequency, aes(x = Total_Transactions)) +
6.   geom_histogram(binwidth = 1, fill = "#0073C2FF", color = "white", alpha = 0.9) +
7.   scale_y_log10(name = "Số lượng Khách hàng (Thang đo Log)",labels = comma_format()) +
8.   scale_x_continuous(name = "Số lần Giao dịch (Tần suất Mua hàng)",breaks = seq(1, 20, by = 1),limits = c(0.5, 20.5)) +
9.   labs(title = "Phân phối Tần suất Mua hàng của Khách hàng",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
10.   theme_classic() +
11.   geom_vline(aes(xintercept = median(Total_Transactions)),color = "red", linetype = "dashed", size = 1) +
12.  theme_minimal(base_size = 13)  +
13.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "bottom",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 1 đến 4, tạo dataframe (customer_frequency) thể hiện tần suất giao dịch của từng khách hàng, dùng group_by() để nhóm dữ liệu theo từng ID khách hàng, dùng summarise() với hàm n() để đếm tổng số giao dịch (Total_Transactions) của mỗi khách hàng. Từ dòng 8 vẽ biểu đồ tần suất (histogram), mỗi cột biểu diễn số lượng khách hàng có cùng số lần giao dịch, với trục X là số lần giao dịch, trục Y là số lượng khách hàng, được định dạng sang thang đo logarit để dễ quan sát. Dòng 14 vẽ đường trung vị của số lần giao dịch giúp nhấn mạnh mức giao dịch trung bình của khách hàng

Nhận xét: Biểu đồ cho thấy đa số khách hàng chỉ thực hiện từ 1 đến 5 lần giao dịch với số lần mua cao nhất rơi vào khoảng 3 lần mua hàng. Tần suất giảm dần rõ rệt từ lần thứ 6 trở đi, đặc biệt sau lần thứ 10, số lượng khách hàng giảm mạnh Có thể thấy hành vi mua sắm lặp lại còn khá hạn chế, cho thấy mức độ trung thành chưa cao. Do đó, doanh nghiệp nên tập trung vào các chiến lược giữ chân khách hàng như chương trình tích điểm, ưu đãi cho lần mua tiếp theo, hoặc email nhắc nhở để tăng số lần giao dịch.

4.12 Biểu đồ thể hiện doanh thu loại sản phẩm theo tháng

1. Revenue_product_type <- retail %>%
2.   filter(!is.na(Date)) %>%
3.   mutate(Month = floor_date(Date, "month"))
4. Revenue_product_type_month <- Revenue_product_type %>%
5.   group_by(Month, Product_Type) %>%
6.   summarise(Total_Amount = n(), .groups = "drop")
7. top3_type_each_month <- Revenue_product_type_month %>%
8.   group_by(Month) %>%
9.   mutate(rank = dense_rank(desc(Total_Amount))) %>%
10.   filter(rank <= 3) %>%
11.   ungroup()
12. ggplot(top3_type_each_month, aes(x = Month, y = Total_Amount, color = Product_Type, group = Product_Type)) +
13.   geom_line(size = 1.3) +
14.   geom_point(size = 3) +
15.   labs(title = "Top 3 loại sản phẩm bán chạy nhất theo từng tháng",
16.        x = "Tháng", 
17.        y = "Số lần mua",
18.        caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ",
19.        color = "Loại sản phẩm") +
20.   scale_x_date(date_labels = "%b %Y", date_breaks = "1 month") +
21.   theme_minimal(base_size = 13) +
22.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 14),plot.subtitle = element_text(hjust = 0.5, color = "gray40", size = 12),axis.text.x = element_text(angle = 45, hjust = 1),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "bottom",legend.title = element_text(face = "bold", size = 11, color = "black"),legend.text = element_text(size = 10),panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 1 đến 3, tạo dat.frame (Revenue_product_type), lọc bỏ các dòng thiếu ngày rồi dùng mutate() thêm cột Month bằng floor_date() để lấy tháng (loại bỏ ngày). Từ dòng 4 tới 6, nhóm dữ liệu theo Month và Product_Type, sau đó tính tổng số đơn hàng cho mỗi nhóm. Từ dòng 7 tới 11 tạo data.frame mới trong đó: nhóm lại theo Month, tính thứ hạng (rank) của từng loại sản phẩm và lọc ra top 3 sản phẩm bán chạy nhất mỗi tháng, rồi bỏ nhóm (ungroup()). Từ dòng 12 tạo biểu đồ đường biểu diễn xu hướng doanh số theo tháng của top 3 sản phẩm với trục X là tháng (Month), trục Y là tổng số đơn hàng (Total_Amount).

Nhận xét: Biểu đồ cho thấy sự ổn định với sản phẩm non-fiction luôn vượt trội rõ rệt so với ba sản phẩm còn lại, luôn dao động quanh mức 2.000 – 2.100 lượt mua, duy trì vị thế ổn định, chỉ giảm nhẹ vào các tháng 9/2023 và 2/2024. Các sản phẩm còn lại có lượng mua thấp hơn nhưng vẫn có sức tiêu thụ ổn định.

4.13 Biểu đồ thể hiện tỷ lệ khách hàng theo nhóm thu nhập

1. retail %>%
2.   count(Income) %>%
3.   mutate(Percent = n / sum(n) * 100) %>%
4.   ggplot(aes(x = Income, y = Percent, fill = Income)) +
5.   geom_col(color = "white") +
6.   geom_text(aes(label = paste0(round(Percent, 1), "%")), vjust = -0.5, size = 4) +
7.   scale_y_continuous(expand = expansion(mult = c(0, 0.12))) + 
8.   labs(title = "Tỷ lệ khách hàng theo nhóm thu nhập",x = "Nhóm thu nhập",y = "Tỷ lệ (%)",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
9.   theme_minimal(base_size = 13) +
10.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "bottom",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 1 đến 3, tạo data.frame thể hiện tỷ lệ phần trăm khách hàng theo từng nhóm thu nhập, dùng count(Income) để đếm số lượng bản ghi (n) thuộc mỗi nhóm thu nhập, dùng mutate() để tạo thêm cột Percent biết tỷ trọng của từng nhóm thu nhập trong toàn bộ dữ liệu. Từ dòng 4, vẽ biểu đồ cột với trục X là các nhóm thu nhập, trục Y là tỷ lệ phần trăm và mỗi cột thể hiện tỷ lệ phần trăm của nhóm thu nhập tương ứng. Dòng 6 thêm nhãn giá trị, làm tròn 1 chữ số.

Nhận xét: Biểu đồ thể hiện tỷ lệ khách hàng theo nhóm thu nhập cho thấy nhóm thu nhập trung bình chiếm tỷ trọng cao nhất (43,1%), tiếp theo là nhóm thu nhập thấp (31,9%) và thu nhập cao (24,9%). Nhóm không xác định gần như không đáng kể (0,1%). Tỷ lệ khách hàng cao nhất thuộc về nhóm thu nhập trung bình phản ánh đây là phân khúc khách hàng chủ lực cần được duy trì và chăm sóc. Nhóm thu nhập thấp cũng chiếm thị phần đáng kể, có cơ hội mở rộng bằng các chiến lược định giá hợp lý. Tuy tỷ lệ nhóm thu nhập cao thấp hơn nhưng vẫn là đối tượng tiềm năng có sức mua lớn, nên được ưu tiên trong các chiến dịch tiếp thị cá nhân hóa, sản phẩm cao cấp và trải nghiệm dịch vụ chuyên biệt.

4.14 Biểu đồ thể hiện tỷ lệ khách hàng theo phân khúc

1. segment_count <- retail %>%
2.   group_by(Customer_Segment) %>%
3.   summarise(So_KH = n()) %>%
4.   mutate(Percent = So_KH / sum(So_KH) * 100)
5. ggplot(segment_count, aes(x = "", y = So_KH, fill = Customer_Segment)) +
6.   geom_bar(stat = "identity", width = 1) +
7.   coord_polar("y") +
8.   geom_text(aes(label = paste0(round(Percent, 1), "%")),position = position_stack(vjust = 0.5), color = "black", size = 4) +
9.   labs(title = "Tỷ lệ khách hàng theo phân khúc",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
10.   theme_void() +
11.   theme(plot.title = element_text(face = "bold", hjust = 0.5))

Giải thích kỹ thuật: Từ dòng 1 đến 4, tạo data.frame (segment_count) để thống kê số lượng và tỷ lệ khách hàng theo từng nhóm phân khúc, dùng group_by() nhóm dữ liệu theo từng phân khúc khách hàng, dùng summarise() với hàm n() để đếm tổng số khách hàng trong mỗi phân khúc, dùng mutate () tạo thêm cột Percent. Từ dòng 5, vẽ biểu đồ cột với trục Y là số lượng khách hàng, mỗi cột thể hiện tỷ lệ với số lượng khách hàng của phân khúc tương ứng. Dòng 7 sử dụng coord_polar(“y”) để chuyển biểu đồ cột thành biểu đồ tròn theo trục Y.

Nhận xét: Biểu đồ tròn thể hiện tỷ lệ khách hàng theo phân khúc cho thấy nhóm khách hàng thường xuyên (Regular) chiếm tỷ lệ cao nhất với 48,4%, tiếp theo là nhóm khách hàng mới (New) với 30,2%, nhóm khách hàng cao cấp (Premium) chiếm 21,3%, và nhóm không xác định gần như không đáng kể (0,1%). Tỷ lệ cao của nhóm khách hàng thường xuyên cho thấy doanh nghiệp có tệp khách hàng trung thành tương đối lớn, đây là nền tảng vững chắc để duy trì doanh thu ổn định. Tuy nhiên, nhóm khách hàng mới cũng chiếm tỷ lệ lớn, cho thấy tiềm năng phát triển dài hạn nếu có chiến lược giữ chân hợp lý. Đáng chú ý, tỷ lệ khách hàng cao cấp còn tương đối thấp doanh nghiệp nên có các chương trình chăm sóc đặc biệt hoặc sản phẩm cao cấp để nâng cao giá trị vòng đời khách hàng.

4.15 Biểu đồ cột phân loại có phân nhóm theo danh mục sản phẩm trong từng thương hiệu

1. ttt <- retail %>%
2.   group_by(Product_Brand, Product_Category) %>%
3.   summarise(n = n(), .groups = "drop")
4. ggplot(ttt, aes(x = Product_Category, y = n)) +
5.   geom_col(fill = "steelblue") +
6.   facet_wrap(~ Product_Brand, scales = "fixed") +
7.   theme_minimal() +
8.   theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
9.   labs(title = "Số lượng đơn theo danh mục trong từng thương hiệu", x = "Danh mục", y = "Số lượng", caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ" ) +
10. scale_fill_brewer(palette = "Set2") +
11. theme_minimal(base_size = 13) +
12.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.text.x = element_text(angle = 45, hjust = 1),axis.title = element_text(face = "bold"),legend.position = "bottom",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 1 đến 3, tạo data.frame (ttt) thể hiện số lượng sản phẩm bán ra theo từng thương hiệu và danh mục sản phẩm, dùng group_by() để nhóm dữ liệu theo 2 biến, dùng summarise() với hàm n() để đếm tổng số và bỏ nhóm sau khi tổng hợp trước khi vẽ biểu đồ. Từ dòng 4, vẽ biểu đồ cột với trục X thể hiện các danh mục sản phẩm, trục Y thể hiện số lượng sản phẩm và mỗi cột biểu diễn số lượng sản phẩm theo danh mục. Dòng 6 dùng facet để chia biểu đồ thành nhiều ô, mỗi ô tương ứng với một thương hiệu sản phẩm.

Nhận xét: Biểu đồ thể hiện rõ ràng rằng mỗi thương hiệu chỉ tập trung vào một vài danh mục sản phẩm chính, ví dụ như Apple, Sony, Samsung, và Whirepool chủ yếu bán sản phẩm thuộc danh mục Electronics; Adidas, Nike và Zara tập trung vào Clothing, trong khi Coca-Cola, Pepsi và Nestlé nổi bật ở Grocery. Một số nhà xuất bản như Penguin Books, HarperCollins và Random House chỉ hoạt động trong danh mục Books. Sự chuyên môn hóa theo danh mục sản phẩm của từng thương hiệu là chiến lược rõ ràng nhằm định vị thương hiệu và tối ưu hóa lợi thế cạnh tranh. Tuy nhiên, các thương hiệu có thể cân nhắc mở rộng danh mục theo hướng phù hợp để gia tăng doanh thu và độ phủ, đặc biệt với những thương hiệu lớn đã có uy tín cao trên thị trường.

4.16 Biểu đồ cột thể hiện giá trị trung bình có thanh sai số theo danh mục trong từng thương hiệu

1. xxx <- retail %>%
2.   group_by(Product_Brand, Product_Category) %>%
3.   summarise(m = mean(Amount, na.rm = TRUE),sd = sd(Amount, na.rm = TRUE),n = n(),se = sd / sqrt(n),
4.     .groups = "drop")
5. ggplot(xxx, aes(x = Product_Category, y = m, fill = Product_Category)) +
6.   geom_col(show.legend = FALSE, width = 0.7) +                                   
7.   geom_errorbar(aes(ymin = m - se, ymax = m + se), width = 0.2, color = "black") + 
8.   geom_text(aes(label = round(m, 1)), vjust = -0.3, size = 2, color = "black") +
9.   facet_wrap(~ Product_Brand, scales = "fixed") +                               
10.   labs(title = "Giá trị trung bình (Amount) theo danh mục trong từng thương hiệu",x = "Danh mục sản phẩm",y = "Giá trị trung bình",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
11.   theme_minimal(base_size = 13) +
12.   theme(
13. plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),axis.text.x = element_text(angle = 45, hjust = 1),strip.text = element_text(face = "bold", size = 10))

Giải thích kỹ thuật: Từ dòng 1 đến 4, tạo bảng dữ liệu tóm tắt (xxx) thể hiện giá trị trung bình và sai số chuẩn (standard error) của biến doanh thu (Amount) theo từng danh mục và thương hiệu sản phẩm, dùng group() để nhóm dữ liệu theo hai biến, dùng summarise() để tính các thống kê mô tả. Từ dòng 5 tạo biểu đồ cột với trục X là danh mục sản phẩm, trục Y là giá trị trung bình và mỗi cột thể hiện giá trị trung bình. Dòng 7 thêm thanh sai số cho mỗi cột, dòng 9 dùng facet để chia biểu đồ thành nhiều ô nhỏ, mỗi ô tương ứng với một thương hiệu sản phẩm

Nhận xét: Biểu đồ cho thấy giá trị trung bình các đơn hàng theo danh mục trong từng thương hiệu nhìn chung dao động trong khoảng 250 – 270, thể hiện mức độ ổn định giữa các nhóm sản phẩm. Một số thương hiệu nổi bật với giá trị đơn hàng cao như Samsung (Home Decor~288.7), Zara (Home Decor~273.3), Nike (Grocery~272.6), trong khi đó một số thương hiệu có mức giá thấp hơn như Pepsi (Clothing~197.9) và Nike (Clothing~223.3). Điều này phản ánh sự chênh lệch trong chiến lược giá giữa các thương hiệu và danh mục sản phẩm. Sự ổn định tương đối về giá trị trung bình giữa các thương hiệu cho thấy thị trường đang duy trì mức giá cạnh tranh. Tuy nhiên, những thương hiệu có giá trị đơn hàng cao hơn ở một số danh mục nhất định có thể đang hướng tới chiến lược định vị sản phẩm cao cấp. Ngược lại, các thương hiệu có mức giá thấp hơn có khả năng tập trung vào thị trường phổ thông để mở rộng tập khách hàng.

4.17 Biểu đồ thể hiện mức độ đánh giá sản phẩm

1. ggplot(retail, aes(x = Ratings)) +
2.   geom_histogram(bins = 5, fill = "skyblue", color = "black") +
3.   labs(title = "Phân bố điểm đánh giá sản phẩm", x = "Điểm đánh giá", y = "Số lượng", caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
4.   theme_minimal(base_size = 13) +
5.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),strip.text = element_text(face = "bold", size = 10))

Giải thích kỹ thuật: Dòng 1, 2 dùng geom_histogram để vẽ biểu đồ histogram thể hiện mức phân bố điểm đánh giá sản phẩm, với trục X là điểm đánh giá, trục Y là số lượng.

Nhận xét: Biểu đồ cho thấy điểm đánh giá sản phẩm phổ biến nhất là 4 sao, với gần 100.000 lượt đánh giá. Trong khi đó, điểm đánh giá thấp nhất (1 sao) và cao nhất (5 sao) có số lượng đánh giá tương đương nhau (khoảng 40.000 – 50.000). Đáng chú ý, số lượng đánh giá 2 sao và 3 sao dao động ở mức trung bình. Điều này phản ánh xu hướng người tiêu dùng có xu hướng đưa ra đánh giá tích cực (4 sao) nhiều hơn các mức còn lại.

4.18 Biểu đồ thể hiện tỷ lệ trạng thái đơn hàng theo phương thức thanh toán

1. ship_status <- retail %>%
2.   filter(!is.na(Shipping_Method), !is.na(Order_Status)) %>%
3.   group_by(Shipping_Method, Order_Status) %>%
4.   summarise(n = n(), .groups = "drop") %>%
5.   group_by(Shipping_Method) %>%
6.   mutate(percent = n / sum(n))
7. ggplot(ship_status, aes(x = Shipping_Method, y = percent, fill = Order_Status)) +
8.   geom_col(position = "fill", width = 0.65) +
9.   geom_text(aes(label = percent(percent, accuracy = 1)),position = position_stack(vjust = 0.25),color = "black",size = 4) +
10.   scale_y_continuous(labels = percent_format(accuracy = 1)) +
11.   labs(title = "Tỷ lệ trạng thái đơn hàng theo phương thức vận chuyển",
12.     x = "Phương thức vận chuyển",y = "Tỷ lệ (%)",fill = "Trạng thái đơn hàng") +
13.   theme_minimal(base_size = 13) +
14.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 14),
15.     axis.text = element_text(color = "black"),
16.     axis.title = element_text(face = "bold"),
17.     legend.position = "right",
18.     panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 1, 2 để tạo data.frame (ship_status). Dòng 3, 4: Nhóm dữ liệu theo phương thức giao hàng và trạng thái đơn hàng và dùng n() đếm số lượng đơn trong từng nhóm. Dòng 5, 6 nhóm theo Shipping_Method và tính tỷ lệ phần trăm (percent) của mỗi trạng thái đơn hàng trong tổng số đơn của từng phương thức giao hàng. Từ dòng 7 tạo biểu đồ cột chồng để so sánh tỷ trọng các trạng thái đơn hàng trong từng phương thức giao hàng với trục X là phương thức giao hàng, trục Y là tỷ lệ phần trăm.

Nhận xét: Biểu đồ cho thấy sự phân bố khá đồng đều giữa các loại hình giao hàng. Tỷ lệ đơn hàng đã giao (Delivered) chiếm khoảng 40–44% ở tất cả phương thức, phản ánh mức độ hoàn tất tương đối ổn định. Tuy nhiên, nhóm đơn hàng đang xử lý (Processing) và đang giao (Shipped) vẫn chiếm tỷ trọng cao khoảng 35 – 40% tổng đơn hàng cho thấy quy trình xử lý chưa đạt tối ưu. Đáng chú ý, phương thức “Nothing” và “Same-Day” có tỷ lệ đơn chưa hoàn tất cao hơn, gợi ý khả năng phát sinh chậm trễ trong vận hành nhanh.

PHẦN 2: BỘ DỮ LIỆU BÁO CÁO TÀI CHÍNH HPG

CHƯƠNG 1: GIỚI THIỆU BỘ DỮ LIỆU

Bộ dữ liệu được sử dụng trong bài tiểu luận này là báo cáo tài chính hợp nhất của Công ty Cổ phần Tập đoàn Hòa Phát (mã chứng khoán: HPG), được thu thập trong giai đoạn từ năm 2015 đến năm 2024 trên website [https://www.hoaphat.com.vn/].

Dữ liệu được tổng hợp từ các báo cáo tài chính năm do doanh nghiệp công bố công khai, bao gồm ba phần chính:

Bảng cân đối kế toán: phản ánh quy mô tài sản, cơ cấu nguồn vốn và tình hình tài chính của doanh nghiệp tại từng thời điểm cuối năm.

Báo cáo kết quả hoạt động kinh doanh: thể hiện hiệu quả hoạt động sản xuất – kinh doanh qua các chỉ tiêu như doanh thu, giá vốn, lợi nhuận gộp, lợi nhuận sau thuế,…

Báo cáo lưu chuyển tiền tệ: cho thấy sự biến động và khả năng tạo tiền của doanh nghiệp thông qua các dòng tiền từ hoạt động kinh doanh, đầu tư và tài chính.

1.1 Đọc dữ liệu

1. HPG_raw <- read_excel("C:/Users/ASUS/Downloads/HPG.xlsx")
2. head(HPG_raw)
## # A tibble: 6 × 16
##     Năm Danh thu thuần về bán hàng và cung …¹ `Giá vốn hàng bán` `Lợi nhuận gộp`
##   <dbl>                                 <dbl>              <dbl>           <dbl>
## 1  2015                               2.79e13            2.19e13         5.59e12
## 2  2016                               2.79e13            2.19e13         5.59e12
## 3  2017                               3.39e13            2.45e13         8.75e12
## 4  2018                               4.69e13            3.55e13         1.06e13
## 5  2019                               5.66e13            4.42e13         1.17e13
## 6  2020                               9.13e13            7.12e13         1.89e13
## # ℹ abbreviated name: ¹​`Danh thu thuần về bán hàng và cung cấp dịch vụ`
## # ℹ 12 more variables: `Đầu tư tài chính ngắn hạn` <dbl>,
## #   `Tài sản dài hạn` <dbl>, `Lợi nhuận trước thuế` <dbl>,
## #   `Lợi nhuận sau thuế` <dbl>, `Tổng tài sản` <dbl>, `Nợ phải trả` <dbl>,
## #   `Vốn chủ sở hữu` <dbl>, `Tiền và các khoản tương đương tiền` <dbl>,
## #   `Tài sản ngắn hạn` <dbl>,
## #   `Lưu chuyển tiền thuần từ hoạt động kinh doanh` <dbl>, …

1.2 Xem 10 dòng đầu của bộ dữ liệu

1. head(HPG_raw,10)
## # A tibble: 10 × 16
##      Năm Danh thu thuần về bán hàng và cung…¹ `Giá vốn hàng bán` `Lợi nhuận gộp`
##    <dbl>                                <dbl>              <dbl>           <dbl>
##  1  2015                              2.79e13            2.19e13         5.59e12
##  2  2016                              2.79e13            2.19e13         5.59e12
##  3  2017                              3.39e13            2.45e13         8.75e12
##  4  2018                              4.69e13            3.55e13         1.06e13
##  5  2019                              5.66e13            4.42e13         1.17e13
##  6  2020                              9.13e13            7.12e13         1.89e13
##  7  2021                              1.51e14            1.09e14         4.11e13
##  8  2022                              1.43e14            1.25e14         1.68e13
##  9  2023                              1.20e14            1.06e14         1.29e13
## 10  2024                              1.41e14            1.20e14         1.85e13
## # ℹ abbreviated name: ¹​`Danh thu thuần về bán hàng và cung cấp dịch vụ`
## # ℹ 12 more variables: `Đầu tư tài chính ngắn hạn` <dbl>,
## #   `Tài sản dài hạn` <dbl>, `Lợi nhuận trước thuế` <dbl>,
## #   `Lợi nhuận sau thuế` <dbl>, `Tổng tài sản` <dbl>, `Nợ phải trả` <dbl>,
## #   `Vốn chủ sở hữu` <dbl>, `Tiền và các khoản tương đương tiền` <dbl>,
## #   `Tài sản ngắn hạn` <dbl>,
## #   `Lưu chuyển tiền thuần từ hoạt động kinh doanh` <dbl>, …

1.3 Xem 10 dòng cuối cùng của bộ dữ liệu

1. tail(HPG_raw,10)
## # A tibble: 10 × 16
##      Năm Danh thu thuần về bán hàng và cung…¹ `Giá vốn hàng bán` `Lợi nhuận gộp`
##    <dbl>                                <dbl>              <dbl>           <dbl>
##  1  2015                              2.79e13            2.19e13         5.59e12
##  2  2016                              2.79e13            2.19e13         5.59e12
##  3  2017                              3.39e13            2.45e13         8.75e12
##  4  2018                              4.69e13            3.55e13         1.06e13
##  5  2019                              5.66e13            4.42e13         1.17e13
##  6  2020                              9.13e13            7.12e13         1.89e13
##  7  2021                              1.51e14            1.09e14         4.11e13
##  8  2022                              1.43e14            1.25e14         1.68e13
##  9  2023                              1.20e14            1.06e14         1.29e13
## 10  2024                              1.41e14            1.20e14         1.85e13
## # ℹ abbreviated name: ¹​`Danh thu thuần về bán hàng và cung cấp dịch vụ`
## # ℹ 12 more variables: `Đầu tư tài chính ngắn hạn` <dbl>,
## #   `Tài sản dài hạn` <dbl>, `Lợi nhuận trước thuế` <dbl>,
## #   `Lợi nhuận sau thuế` <dbl>, `Tổng tài sản` <dbl>, `Nợ phải trả` <dbl>,
## #   `Vốn chủ sở hữu` <dbl>, `Tiền và các khoản tương đương tiền` <dbl>,
## #   `Tài sản ngắn hạn` <dbl>,
## #   `Lưu chuyển tiền thuần từ hoạt động kinh doanh` <dbl>, …

1.4 Kích thước bộ dữ liệu

1. dim(HPG_raw)
## [1] 10 16

Giải thích kỹ thuật: Để biết được kích thước bộ dữ liệu, dùng hàm dim() để hiển thị bao gồm số dòng (quan sát) và số cột (biến).

Nhận xét: Kết quả cho biết bộ dữ liệu HPG có 10 dòng và 16 cột, tức là có 10 quan sát (thường tương ứng với 10 năm hoặc 10 kỳ báo cáo) và 16 biến tài chính khác nhau.

1.5 Danh sách tên các biến của dữ liệu

1. names(HPG_raw)
##  [1] "Năm"                                           
##  [2] "Danh thu thuần về bán hàng và cung cấp dịch vụ"
##  [3] "Giá vốn hàng bán"                              
##  [4] "Lợi nhuận gộp"                                 
##  [5] "Đầu tư tài chính ngắn hạn"                     
##  [6] "Tài sản dài hạn"                               
##  [7] "Lợi nhuận trước thuế"                          
##  [8] "Lợi nhuận sau thuế"                            
##  [9] "Tổng tài sản"                                  
## [10] "Nợ phải trả"                                   
## [11] "Vốn chủ sở hữu"                                
## [12] "Tiền và các khoản tương đương tiền"            
## [13] "Tài sản ngắn hạn"                              
## [14] "Lưu chuyển tiền thuần từ hoạt động kinh doanh" 
## [15] "Lưu chuyển tiền thuần từ hoạt động đầu tư"     
## [16] "Lưu chuyển tiền thuần từ hoạt động tài chính"

1.6 Cấu trúc dữ liệu

1. str(HPG_raw)
## tibble [10 × 16] (S3: tbl_df/tbl/data.frame)
##  $ Năm                                           : num [1:10] 2015 2016 2017 2018 2019 ...
##  $ Danh thu thuần về bán hàng và cung cấp dịch vụ: num [1:10] 2.79e+13 2.79e+13 3.39e+13 4.69e+13 5.66e+13 ...
##  $ Giá vốn hàng bán                              : num [1:10] 2.19e+13 2.19e+13 2.45e+13 3.55e+13 4.42e+13 ...
##  $ Lợi nhuận gộp                                 : num [1:10] 5.59e+12 5.59e+12 8.75e+12 1.06e+13 1.17e+13 ...
##  $ Đầu tư tài chính ngắn hạn                     : num [1:10] 7.58e+11 7.58e+11 6.93e+11 9.94e+12 3.72e+12 ...
##  $ Tài sản dài hạn                               : num [1:10] 1.03e+13 1.36e+13 1.50e+13 2.00e+13 5.29e+13 ...
##  $ Lợi nhuận trước thuế                          : num [1:10] 3.77e+12 3.99e+12 7.70e+12 9.29e+12 1.01e+13 ...
##  $ Lợi nhuận sau thuế                            : num [1:10] 3.50e+12 3.50e+12 6.61e+12 8.01e+12 8.60e+12 ...
##  $ Tổng tài sản                                  : num [1:10] 2.21e+13 2.55e+13 3.32e+13 5.30e+13 7.82e+13 ...
##  $ Nợ phải trả                                   : num [1:10] 1.01e+13 1.10e+13 1.34e+13 2.06e+13 3.76e+13 ...
##  $ Vốn chủ sở hữu                                : num [1:10] 1.20e+13 1.45e+13 1.99e+13 3.24e+13 4.06e+13 ...
##  $ Tiền và các khoản tương đương tiền            : num [1:10] 2.37e+12 2.37e+12 4.56e+12 4.26e+12 2.52e+12 ...
##  $ Tài sản ngắn hạn                              : num [1:10] 1.17e+13 1.19e+13 1.82e+13 3.31e+13 2.53e+13 ...
##  $ Lưu chuyển tiền thuần từ hoạt động kinh doanh : num [1:10] 2.76e+12 4.54e+12 6.82e+12 6.06e+12 7.64e+12 ...
##  $ Lưu chuyển tiền thuần từ hoạt động đầu tư     : num [1:10] -1.25e+12 -3.76e+12 -3.13e+12 -1.79e+13 -2.05e+13 ...
##  $ Lưu chuyển tiền thuần từ hoạt động tài chính  : num [1:10] NA -4.33e+11 -1.50e+12 1.16e+13 1.11e+13 ...

Giải thích kỹ thuật: Hàm str(HPG) được dùng để hiển thị cấu trúc tổng quát của bộ dữ liệu HPG. Kết quả cho biết đây là một tibble (một dạng mở rộng của data.frame) gồm 10 dòng và 16 cột.

Nhận xét: Bộ dữ liệu HPG bao gồm 16 biến chỉ mang kiểu dữ liệu là numeric phù hợp cho các phân tích định lượng như so sánh, tính tỷ lệ, hoặc phân tích xu hướng tài chính theo thời gian.

1.7 Kiểu dữ liệu cho từng cột

1. sapply(HPG_raw, class)
##                                            Năm 
##                                      "numeric" 
## Danh thu thuần về bán hàng và cung cấp dịch vụ 
##                                      "numeric" 
##                               Giá vốn hàng bán 
##                                      "numeric" 
##                                  Lợi nhuận gộp 
##                                      "numeric" 
##                      Đầu tư tài chính ngắn hạn 
##                                      "numeric" 
##                                Tài sản dài hạn 
##                                      "numeric" 
##                           Lợi nhuận trước thuế 
##                                      "numeric" 
##                             Lợi nhuận sau thuế 
##                                      "numeric" 
##                                   Tổng tài sản 
##                                      "numeric" 
##                                    Nợ phải trả 
##                                      "numeric" 
##                                 Vốn chủ sở hữu 
##                                      "numeric" 
##             Tiền và các khoản tương đương tiền 
##                                      "numeric" 
##                               Tài sản ngắn hạn 
##                                      "numeric" 
##  Lưu chuyển tiền thuần từ hoạt động kinh doanh 
##                                      "numeric" 
##      Lưu chuyển tiền thuần từ hoạt động đầu tư 
##                                      "numeric" 
##   Lưu chuyển tiền thuần từ hoạt động tài chính 
##                                      "numeric"

1.8 Tóm tắt mô tả dữ liệu

1. summary(HPG_raw)
##       Năm       Danh thu thuần về bán hàng và cung cấp dịch vụ
##  Min.   :2015   Min.   :2.786e+13                             
##  1st Qu.:2017   1st Qu.:3.713e+13                             
##  Median :2020   Median :7.393e+13                             
##  Mean   :2020   Mean   :8.389e+13                             
##  3rd Qu.:2022   3rd Qu.:1.355e+14                             
##  Max.   :2024   Max.   :1.509e+14                             
##                                                               
##  Giá vốn hàng bán    Lợi nhuận gộp       Đầu tư tài chính ngắn hạn
##  Min.   :2.186e+13   Min.   :5.594e+12   Min.   :6.935e+11        
##  1st Qu.:2.728e+13   1st Qu.:9.219e+12   1st Qu.:1.500e+12        
##  Median :5.769e+13   Median :1.230e+13   Median :9.032e+12        
##  Mean   :6.788e+13   Mean   :1.504e+13   Mean   :1.097e+13        
##  3rd Qu.:1.079e+14   3rd Qu.:1.806e+13   3rd Qu.:1.879e+13        
##  Max.   :1.246e+14   Max.   :4.111e+13   Max.   :2.627e+13        
##                                                                   
##  Tài sản dài hạn     Lợi nhuận trước thuế Lợi nhuận sau thuế 
##  Min.   :1.034e+13   Min.   :3.770e+12    Min.   :3.504e+12  
##  1st Qu.:1.627e+13   1st Qu.:7.725e+12    1st Qu.:6.655e+12  
##  Median :6.384e+13   Median :9.606e+12    Median :8.230e+12  
##  Mean   :6.034e+13   Mean   :1.186e+13    Mean   :1.055e+13  
##  3rd Qu.:8.839e+13   3rd Qu.:1.279e+13    3rd Qu.:1.117e+13  
##  Max.   :1.378e+14   Max.   :3.706e+13    Max.   :3.452e+13  
##                                                              
##   Tổng tài sản        Nợ phải trả        Vốn chủ sở hữu     
##  Min.   :2.209e+13   Min.   :1.012e+13   Min.   :1.197e+13  
##  1st Qu.:3.818e+13   1st Qu.:1.519e+13   1st Qu.:2.299e+13  
##  Median :1.049e+14   Median :5.495e+13   Median :4.992e+13  
##  Mean   :1.104e+14   Mean   :5.215e+13   Mean   :5.829e+13  
##  3rd Qu.:1.763e+14   3rd Qu.:8.227e+13   3rd Qu.:9.478e+13  
##  Max.   :2.245e+14   Max.   :1.098e+14   Max.   :1.146e+14  
##                                                             
##  Tiền và các khoản tương đương tiền Tài sản ngắn hạn   
##  Min.   :2.373e+12                  Min.   :1.175e+13  
##  1st Qu.:2.953e+12                  1st Qu.:1.996e+13  
##  Median :5.723e+12                  Median :4.491e+13  
##  Mean   :7.972e+12                  Mean   :5.010e+13  
##  3rd Qu.:1.127e+13                  3rd Qu.:8.217e+13  
##  Max.   :2.247e+13                  Max.   :9.415e+13  
##                                                        
##  Lưu chuyển tiền thuần từ hoạt động kinh doanh
##  Min.   :2.762e+12                            
##  1st Qu.:6.196e+12                            
##  Median :7.231e+12                            
##  Mean   :9.366e+12                            
##  3rd Qu.:1.085e+13                            
##  Max.   :2.672e+13                            
##                                               
##  Lưu chuyển tiền thuần từ hoạt động đầu tư
##  Min.   :-2.979e+13                       
##  1st Qu.:-2.032e+13                       
##  Median :-1.821e+13                       
##  Mean   :-1.512e+13                       
##  3rd Qu.:-5.822e+12                       
##  Max.   :-1.250e+12                       
##                                           
##  Lưu chuyển tiền thuần từ hoạt động tài chính
##  Min.   :-1.778e+12                          
##  1st Qu.:-4.328e+11                          
##  Median : 7.276e+12                          
##  Mean   : 6.876e+12                          
##  3rd Qu.: 1.157e+13                          
##  Max.   : 1.781e+13                          
##  NA's   :1

Giải thích kỹ thuật: Lệnh summary dùng để mô tả thống kê cơ bản của từng biến trong bộ dữ liệu HPG bao gồm: Min(Minimun) là giá trị nhỏ nhất; 1st Qu (Quartile 1) là giá trị tại ví trí 25%; Median là giá trị trung vị (50%); Mean là giá trị trung bình; 3rd (Quartile 3) là giá trị tại vị trí 75%; Max (Maximum) là giá trị lớn nhất

Nhận xét: Doanh thu thuần về bán hàng và cung cấp dịch vụ: Biểu thị tổng doanh thu chính từ hoạt động sản xuất – kinh doanh thép sau khi trừ các khoản giảm trừ.Trung bình: 8.39×10¹³ đồng; tăng mạnh qua các năm, đặc biệt giai đoạn 2020–2021 khi nhu cầu thép tăng cao. Min (2015): 2.78×10¹³ đồng; Max (2024): 1.51×10¹⁴ đồng.Doanh thu tăng trưởng liên tục, phản ánh quy mô sản xuất và thị phần mở rộng.

Giá vốn hàng bán: Thể hiện chi phí sản xuất, nguyên vật liệu và vận hành để tạo ra sản phẩm. Với giá trị trung bình 6.79×10¹³ đồng, chiếm khoảng 80–85% doanh thu.Biên lợi nhuận gộp không cao, phù hợp với đặc điểm ngành thép có chi phí đầu vào lớn và biến động giá nguyên liệu.

Lợi nhuận gộp: Là chênh lệch giữa doanh thu thuần và giá vốn hàng bán, phản ánh hiệu quả sản xuất – kinh doanh cốt lõi. Có giá trị trung bình 1.50×10¹³ đồng; dao động mạnh theo chu kỳ giá thép.Mức cao nhất là 4.11×10¹³ đồng.Lợi nhuận gộp tăng mạnh trong giai đoạn bùng nổ 2020–2021, sau đó giảm khi thị trường thép hạ nhiệt.

Đầu tư tài chính ngắn hạn: Phản ánh giá trị các khoản đầu tư ngắn hạn như tiền gửi có kỳ hạn, chứng khoán ngắn hạn.1.09×10¹³ đồng là giá trị trung bình. Xu hướng tăng dần, đặc biệt sau 2020, cho thấy Hòa Phát duy trì lượng tiền nhàn rỗi lớn để tối ưu lợi nhuận tài chính.

Tài sản dài hạn: Bao gồm nhà máy, thiết bị, công trình xây dựng và đầu tư dài hạn khác. Với giá trị trung bình là 6.03×10¹³ đồng.Cấu trúc tài sản cho thấy HPG tập trung đầu tư chiều sâu và mở rộng công suất.

Lợi nhuận trước thuế: Là chỉ tiêu đánh giá kết quả hoạt động kinh doanh tổng thể trước khi tính thuế TNDN. Có giá trị trung bình 1.19×10¹³ đồng. Lợi nhuận có chu kỳ, phản ánh nhạy cảm của ngành thép với thị trường.

Lợi nhuận sau thuế: Phản ánh hiệu quả thực tế mà doanh nghiệp đạt được sau khi nộp thuế. Có giá trị trung bình là 1.05×10¹³ đồng, độ lệch chuẩn cao (≈9.0×10¹²), hệ số biến thiên ≈85%.HPG có giai đoạn lợi nhuận vượt trội (2020–2021), nhưng giảm sâu sau đó, thể hiện tính biến động cao của lợi nhuận ròng.

Tổng tài sản: Thể hiện quy mô hoạt động và nguồn lực tài chính của doanh nghiệp. Có giá trị trung bình 1.10×10¹⁴ đồng; tăng liên tục từ 2.21×10¹³ lên 2.24×10¹⁴.

Nợ phải trả: Bao gồm các nghĩa vụ tài chính với bên ngoài, như vay ngân hàng, trái phiếu, nhà cung cấp. Với trung bình 5.22×10¹³ đồng (~47% tổng tài sản).Cơ cấu vốn có đòn bẩy tài chính trung bình, giúp tăng hiệu quả sinh lời nhưng cũng tiềm ẩn rủi ro khi lãi suất tăng.

Vốn chủ sở hữu: là phần tài sản ròng thuộc về cổ đông, với trung bình 5.83×10¹³ đồng. HPG có nền tảng tài chính vững mạnh, vốn chủ sở hữu tăng song song với lợi nhuận giữ lại và phát hành thêm cổ phiếu.

Tiền và các khoản tương đương tiền: Bao gồm tiền mặt, tiền gửi và khoản đầu tư ngắn hạn có tính thanh khoản cao có giá trị trung bình là 7.97×10¹² đồng. Duy trì mức tiền mặt cao giúp HPG đảm bảo thanh khoản và khả năng ứng phó biến động thị trường.

Tài sản ngắn hạn: Gồm hàng tồn kho, tiền mặt, các khoản phải thu, đầu tư ngắn hạn, có giá trị trung bình là 5.01×10¹³ đồng, chiếm khoảng 45% tổng tài sản. Cơ cấu tài sản cân đối, cho phép HPG linh hoạt trong hoạt động sản xuất – tài chính.

Lưu chuyển tiền thuần từ hoạt động kinh doanh: Đo lường dòng tiền thực từ hoạt động sản xuất kinh doanh. Có trung bình là 9.36×10¹² đồng. Cho thấy HPG có khả năng tạo tiền tốt từ hoạt động cốt lõi, phản ánh hiệu quả vận hành cao.

Lưu chuyển tiền thuần từ hoạt động đầu tư: Phản ánh mức chi tiêu cho mua sắm tài sản, đầu tư mới hoặc thoái vốn. Có giá trị trung bình âm -1.51×10¹³ đồng.

Lưu chuyển tiền thuần từ hoạt động tài chính: Biểu hiện dòng tiền từ việc vay, trả nợ và chia cổ tức. Dao động lớn qua các năm. Giai đoạn 2020–2021, HPG huy động mạnh vốn để mở rộng đầu tư; các năm sau dòng tiền âm do doanh nghiệp hoàn nợ và chi trả cổ tức.

1.9 Đặt tên biến ngắn gọn

1. HPG <- HPG_raw %>%
2.   rename(
3.     Nam = "Năm",
4.     DoanhThu = "Danh thu thuần về bán hàng và cung cấp dịch vụ",
5.     GiaVon = "Giá vốn hàng bán",
6.     LN_Gop = "Lợi nhuận gộp",
7.     DT_TC_NganHan = "Đầu tư tài chính ngắn hạn",
8.     TS_DaiHan = "Tài sản dài hạn",
9.     LN_TruocThue = "Lợi nhuận trước thuế",
10.     LN_SauThue = "Lợi nhuận sau thuế",
11.     Tong_TS = "Tổng tài sản",
12.     No_PhaiTra = "Nợ phải trả",
13.     Von_CSH = "Vốn chủ sở hữu",
14.     Tien = "Tiền và các khoản tương đương tiền",
15.     TS_NganHan = "Tài sản ngắn hạn",
16.     LCTT_KD = "Lưu chuyển tiền thuần từ hoạt động kinh doanh",
17.     LCTT_DT = "Lưu chuyển tiền thuần từ hoạt động đầu tư",
18.     LCTT_TC = "Lưu chuyển tiền thuần từ hoạt động tài chính")

CHƯƠNG 2: XỬ LÝ VÀ MÃ HÓA DỮ LIỆU

2.1 Kiểm tra giá trị trùng lặp

1. sum(duplicated(HPG))
## [1] 0

Giải thích kỹ thuật: dùng sum(duplicate) để đếm tổng số dòng trùng lặp trong bộ dữ liệu.

Nhận xét: Kết quả trả về là 0, nghĩa là không có dòng nào bị trùng lặp. Điều này xác nhận dữ liệu HPG toàn bộ các quan sát đều duy nhất, không cần loại bỏ bản ghi trùng lặp.

2.2 Xử lý giá trị thiếu (Missing Value - NA)

Tổng số quan sát giá trị bị thiếu trong toàn bộ dữ liệu

1. any(is.na(HPG))
## [1] TRUE

Giải thích kỹ thuật: dùng any(is.na) để kiểm tra dữ liệu HPG có bất kỳ giá trị thiếu (NA) nào không.

Nhận xét: Kết quả trả về là TRUE, cho thấy bộ dữ liệu HPG có giá trị NA.

1. sum(is.na(HPG))
## [1] 1

Giải thích kỹ thuật: dùng sum(is.na) để đếm tổng số giá trị thiếu (NA) trong toàn bộ bộ dữ liệu.

Nhận xét: Kết quả cho thấy có một dữ liệu bị thiếu, đó là LCTT_TC của năm 2015.

Số lượng giá trị bị thiếu theo từng cột

1. sapply(HPG,function(HPG) sum(is.na(HPG)))
##           Nam      DoanhThu        GiaVon        LN_Gop DT_TC_NganHan 
##             0             0             0             0             0 
##     TS_DaiHan  LN_TruocThue    LN_SauThue       Tong_TS    No_PhaiTra 
##             0             0             0             0             0 
##       Von_CSH          Tien    TS_NganHan       LCTT_KD       LCTT_DT 
##             0             0             0             0             0 
##       LCTT_TC 
##             1

Giải thích kỹ thuật: dùng sapply để đếm giá trị bị thiếu trong từng cột dữ liệu HPG.

Nhận xét: Kết quả có 1 quan sát bị thiếu ở cột LCTT_TC.

Xử lý dữ liệu bị thiếu - Missing Value (NA)

1. HPG <- HPG %>% mutate( across( .cols = where(is.numeric), .fns = ~ ifelse(is.na(.), mean(., na.rm = TRUE), .)))
2. sapply(HPG,function(HPG) sum(is.na(HPG)))
##           Nam      DoanhThu        GiaVon        LN_Gop DT_TC_NganHan 
##             0             0             0             0             0 
##     TS_DaiHan  LN_TruocThue    LN_SauThue       Tong_TS    No_PhaiTra 
##             0             0             0             0             0 
##       Von_CSH          Tien    TS_NganHan       LCTT_KD       LCTT_DT 
##             0             0             0             0             0 
##       LCTT_TC 
##             0

Giải thích kỹ thuật: và kiểm tra lại bằng hàm sapply

Nhận xét: Sau khi xử lý dữ liệu bị thiếu, giá trị NA trong biến LCTT_TC đã được thay bằng giá trị trung bình của cột đó.

2.3 Kiểm tra giá trị bất thường

1. HPG %>% filter(Tong_TS < 0)
## # A tibble: 0 × 16
## # ℹ 16 variables: Nam <dbl>, DoanhThu <dbl>, GiaVon <dbl>, LN_Gop <dbl>,
## #   DT_TC_NganHan <dbl>, TS_DaiHan <dbl>, LN_TruocThue <dbl>, LN_SauThue <dbl>,
## #   Tong_TS <dbl>, No_PhaiTra <dbl>, Von_CSH <dbl>, Tien <dbl>,
## #   TS_NganHan <dbl>, LCTT_KD <dbl>, LCTT_DT <dbl>, LCTT_TC <dbl>

Giải thích kỹ thuật: Kiểm tra các giá trị âm trong cột Tong_TS của dữ liệu HPG.

Nhận xét: Kết quả trả về 0 dòng, nghĩa là không có giá trị âm nào trong cột Tong_TS. Điều này cho thấy tổng tài sản của HPG không có dữ liệu bất thường.

1. HPG %>% filter(LN_Gop < 0)
## # A tibble: 0 × 16
## # ℹ 16 variables: Nam <dbl>, DoanhThu <dbl>, GiaVon <dbl>, LN_Gop <dbl>,
## #   DT_TC_NganHan <dbl>, TS_DaiHan <dbl>, LN_TruocThue <dbl>, LN_SauThue <dbl>,
## #   Tong_TS <dbl>, No_PhaiTra <dbl>, Von_CSH <dbl>, Tien <dbl>,
## #   TS_NganHan <dbl>, LCTT_KD <dbl>, LCTT_DT <dbl>, LCTT_TC <dbl>

Giải thích kỹ thuật: Kiểm tra các giá trị âm trong cột LN_Gop của dữ liệu HPG.

Nhận xét: Kết quả trả về 0 dòng, nghĩa là không có giá trị âm nào trong cột LN_Gop. Điều này cho thấy lợi nhuận gộp của HPG không có dữ liệu bất thường.

1. HPG %>% filter(LN_SauThue < 0)
## # A tibble: 0 × 16
## # ℹ 16 variables: Nam <dbl>, DoanhThu <dbl>, GiaVon <dbl>, LN_Gop <dbl>,
## #   DT_TC_NganHan <dbl>, TS_DaiHan <dbl>, LN_TruocThue <dbl>, LN_SauThue <dbl>,
## #   Tong_TS <dbl>, No_PhaiTra <dbl>, Von_CSH <dbl>, Tien <dbl>,
## #   TS_NganHan <dbl>, LCTT_KD <dbl>, LCTT_DT <dbl>, LCTT_TC <dbl>

Giải thích kỹ thuật: Kiểm tra các giá trị âm trong cột LN_SauThue của dữ liệu HPG.

Nhận xét: Kết quả trả về 0 dòng, nghĩa là không có giá trị âm nào trong cột LN_SauThue. Điều này cho thấy lợi nhuận sau thuế của HPG không có dữ liệu bất thường.

1. sapply(HPG, class)
##           Nam      DoanhThu        GiaVon        LN_Gop DT_TC_NganHan 
##     "numeric"     "numeric"     "numeric"     "numeric"     "numeric" 
##     TS_DaiHan  LN_TruocThue    LN_SauThue       Tong_TS    No_PhaiTra 
##     "numeric"     "numeric"     "numeric"     "numeric"     "numeric" 
##       Von_CSH          Tien    TS_NganHan       LCTT_KD       LCTT_DT 
##     "numeric"     "numeric"     "numeric"     "numeric"     "numeric" 
##       LCTT_TC 
##     "numeric"

CHƯƠNG 3: THỐNG KÊ CƠ BẢN

3.1 Tính biên lợi nhuận ròng (%)

1. HPG$LN_rong <- HPG$LN_SauThue / HPG$DoanhThu * 100
2. HPG$LN_rong
##  [1] 12.576487 12.576487 19.496012 17.105509 15.200577 14.796566 22.881962
##  [8]  5.914675  5.650264  8.551441

Nhận xét: Biên lợi nhuận ròng của Hòa Phát giai đoạn từ năm 2015 đến năm 2021 cho thấy xu hướng tăng mạnh rồi giảm từ năm 2022 đến năm 2024. Cụ thể, giai đoạn năm 2015 đến 2021, HPG duy trì hiệu quả cao (12–23%), đạt đỉnh tại năm 2021 (22.88%) nhờ thị trường thép thuận lợi và giá bán tăng mạnh. Tuy nhiên, từ năm 2022 đến 2023, biên lợi nhuận giảm còn khoảng 5–6% do giá thép giảm và chi phí đầu vào tăng, phản ánh giai đoạn khó khăn của ngành. Đến 2024, biên lợi nhuận phục hồi nhẹ lên 8.55%, cho thấy tín hiệu tích cực về khả năng cải thiện hiệu quả hoạt động trong tương lai.

3.2 Tính tỷ lệ đòn bẩy tài chính

1. HPG$Debt_to_Equity <- HPG$No_PhaiTra / HPG$Von_CSH
2. HPG$Debt_to_Equity
##  [1] 0.8460909 0.7631354 0.6738597 0.6366094 0.9255866 1.2207347 0.9633751
##  [8] 0.7722434 0.8260319 0.9580871

Nhận xét: Tỷ lệ đòn bẩy tài chính (Debt-to-Equity Ratio) của Hòa Phát (HPG) giai đoạn từ năm 2015 đên 2024 dao động từ 0.63 đến 1.22, cho thấy cơ cấu vốn khá an toàn và ổn định. Phần lớn các năm, tỷ lệ này dưới 1, nghĩa là nợ vay nhỏ hơn vốn chủ sở hữu cho thấy HPG chủ yếu tự tài trợ hoạt động bằng vốn tự có. Năm có tỷ lệ cao nhất là năm 2020 với 1.22 phản ánh mức sử dụng nợ tăng nhẹ nhưng vẫn nằm trong ngưỡng an toàn tài chính. Nhìn chung, HPG duy trì chính sách tài chính thận trọng, khả năng tự chủ vốn cao và ít phụ thuộc vào nguồn nợ bên ngoài.

3.3 Tính tỷ suất sinh lời trên tài sản (ROA)

1. HPG_roa <- HPG %>%
2.   arrange(Nam) %>%                                   
3.   mutate(
4.     TS_kytruoc = lag(Tong_TS, 1),            
5.     TBC_TS  = (TS_kytruoc + Tong_TS) / 2, 
6.     ROA_avg     = LN_SauThue / TBC_TS * 100)
7. HPG_roa$ROA_avg
##  [1]        NA 14.725573 22.495587 18.585215 13.106081 12.879300 22.289714
##  [8]  4.845157  3.797847  5.831109

Giải thích kỹ thuật: dòng 1 tới 6 tạo data.frame, sắp xếp theo năm, và dùng mutate () để tạo các cột để tính trung bình của ROA.

Nhận xét: Kết quả tính tỷ suất sinh lời trên tài sản (ROA) bình quân của Hòa Phát (HPG) giai đoạn từ năm 2015 đến 2024 cho thấy sự biến động rõ rệt, dao động từ 3.8% đến 22.5%. Giai đoạn từ năm 2016 đến 2021, ROA duy trì ở mức cao (12–22%), phản ánh hiệu quả sử dụng tài sản tốt, khả năng tạo lợi nhuận cao. Tuy nhiên, từ năm 2022 trở đi, ROA giảm mạnh xuống 4–6% do ảnh hưởng của biến động giá thép và chi phí đầu vào tăng. Dù vậy, ROA vẫn dương, chứng tỏ doanh nghiệp vẫn duy trì khả năng sinh lợi, thể hiện nền tảng tài chính ổn định và hiệu quả quản trị tài sản vững chắc.

3.4 Tính độ lệch chuẩn của lợi nhuận thuần

1. library(slider)
2. HPG_Net <- HPG %>%
3.   arrange(Nam) %>%
4.   mutate(LN_thuan_SD = slide_dbl(LN_SauThue, sd, .before = 2, .complete = TRUE))
5. HPG_Net %>% select(Nam, LN_SauThue, LN_thuan_SD)
## # A tibble: 10 × 3
##      Nam LN_SauThue LN_thuan_SD
##    <dbl>      <dbl>       <dbl>
##  1  2015    3.50e12    NA      
##  2  2016    3.50e12    NA      
##  3  2017    6.61e12     1.79e12
##  4  2018    8.01e12     2.31e12
##  5  2019    8.60e12     1.03e12
##  6  2020    1.35e13     3.02e12
##  7  2021    3.45e13     1.38e13
##  8  2022    8.44e12     1.38e13
##  9  2023    6.80e12     1.56e13
## 10  2024    1.20e13     2.67e12

Giải thích kỹ thuật: Đoạn code trên tính độ lệch chuẩn động của lợi nhuận ròng theo 3 năm cho HPG. Cụ thể: arrange(Nam) đảm bảo dữ liệu sắp xếp theo thời gian sau đấy mutate(LN_thuan_SD = slide_dbl(LN_SauThue, sd, .before = 2, .complete = TRUE)) sử dụng slider để tính sd() trên mỗi cửa sổ gồm năm hiện tại và 2 năm liền trước, tham số .complete = TRUE yêu cầu đủ 3 quan sát mới trả kết quả, do đó hai năm đầu trả NA.

Nhận xét: Kết quả cho thấy biến động lợi nhuận ròng của HPG trong 3 năm gần nhất khá lớn, đặc biệt giai đoạn từ năm 2020 đến 2023 độ lệch chuẩn tăng mạnh, phản ánh sự dao động đáng kể trong hiệu quả kinh doanh. Nguyên nhân có thể đến từ biến động giá thép, chi phí nguyên vật liệu và nhu cầu thị trường toàn cầu. Dù vậy, năm 2024, độ lệch chuẩn giảm cho thấy hiệu suất tài chính đang dần ổn định trở lại, là tín hiệu tích cực cho chiến lược quản trị rủi ro và tăng trưởng bền vững của doanh nghiệp.

3.5 So sánh hiệu suất trung bình của 2 giai đoạn trước và sau 2018

1. split_year <- 2018
2. period_group <- HPG %>%
3. mutate(roe = LN_SauThue / Von_CSH,
4.        revenue_growth_yoy = (DoanhThu - lag(DoanhThu)) / lag(DoanhThu)) %>%
5.   mutate(giai_doan = ifelse(Nam < split_year, 
6.                        paste0("Truoc_", split_year), 
7.                        paste0("Tu_", split_year, "_Tro_di"))) %>%
8.   group_by(giai_doan) %>%
9.   summarise(
10.     ROE_TB = mean(roe, na.rm = TRUE),
11.     Tang_truong_DT_TB = mean(revenue_growth_yoy, na.rm = TRUE),
12.     Bien_LN_rong_TB = mean(LN_SauThue / DoanhThu, na.rm = TRUE),
13.     So_nam = n())
14. period_group
## # A tibble: 2 × 5
##   giai_doan      ROE_TB Tang_truong_DT_TB Bien_LN_rong_TB So_nam
##   <chr>           <dbl>             <dbl>           <dbl>  <int>
## 1 Truoc_2018      0.289             0.108           0.149      3
## 2 Tu_2018_Tro_di  0.189             0.259           0.129      7

Giải thích kỹ thuật: Đoạn code trên chia dữ liệu tài chính của HPG thành hai giai đoạn: trước năm 2018 và từ năm 2018 trở đi để so sánh hiệu quả hoạt động. Dùng mutate tính tỷ suất sinh lời trên vốn chủ sở hữu (ROE) và tính tốc độ tăng trưởng doanh thu năm sau so với năm trước (revenue_growth_yoy). Sau đó, mutate(giai_doan) tạo cột phân loại giai đoạn, giúp chia dữ liệu thành hai nhóm theo năm. Cuối cùng, group_by(giai_doan) và summarise() được dùng để tính giá trị trung bình của ROE, tăng trưởng doanh thu và biên lợi nhuận ròng cho từng giai đoạn.

Nhận xét: Kết quả cho thấy giai đoạn trước năm 2018, HPG có ROE trung bình cao hơn (28,9%) và biên lợi nhuận ròng đạt 14,9%, phản ánh khả năng sinh lời ổn định và hiệu quả sử dụng vốn tốt. Tuy nhiên, từ năm 2018 trở đi ROE giảm còn 18,9% nhưng doanh nghiệp lại đạt tốc độ tăng trưởng doanh thu cao hơn rõ rệt (25,9%) cho thấy chiến lược mở rộng quy mô và đầu tư phát triển được đẩy mạnh. Điều này cho thấy HPG đã chuyển hướng từ giai đoạn tối ưu lợi nhuận sang giai đoạn tăng trưởng mạnh về doanh thu, tập trung vào mở rộng thị phần và năng lực sản xuất hơn là duy trì biên lợi nhuận cao.

3.6 Phân tích ảnh hưởng của giá vốn lên doanh thu

1. cost_structure <- HPG %>%
2.   mutate(
3.     cogs_as_percent_of_revenue = GiaVon / DoanhThu,
4.     cogs_ratio_change_yoy = cogs_as_percent_of_revenue - lag(cogs_as_percent_of_revenue)
5.   ) %>%
6.   
7.   select(Nam, cogs_as_percent_of_revenue, cogs_ratio_change_yoy)
8. cost_structure
## # A tibble: 10 × 3
##      Nam cogs_as_percent_of_revenue cogs_ratio_change_yoy
##    <dbl>                      <dbl>                 <dbl>
##  1  2015                      0.784             NA       
##  2  2016                      0.784              0       
##  3  2017                      0.724             -0.0605  
##  4  2018                      0.758              0.0344  
##  5  2019                      0.781              0.0222  
##  6  2020                      0.780             -0.000397
##  7  2021                      0.720             -0.0605  
##  8  2022                      0.873              0.153   
##  9  2023                      0.881              0.00780 
## 10  2024                      0.856             -0.0246

Giải thích kỹ thuật: Đoạn code dùng để phân tích mối quan hệ giữa giá vốn và doanh thu qua các năm. Dùng mutate tính tỷ lệ giá vốn trên doanh thu và tính mức thay đổi hằng năm của tỷ lệ này so với năm trước (YoY). Cuối cùng, select() chỉ giữ lại các cột cần phân tích (năm, tỷ lệ, và mức biến động) để dễ quan sát xu hướng chi phí ảnh hưởng đến lợi nhuận.

Nhận xét: Tỷ lệ giá vốn hàng bán trên doanh thu (COGS/Doanh thu) của HPG duy trì quanh mức 72–88%, cho thấy biên lợi nhuận gộp khá ổn định. Tuy nhiên, giai đoạn từ năm 2021 đến 2023 có sự gia tăng mạnh của giá vốn (từ 71,9% lên 88%), phản ánh chi phí đầu vào tăng cao hoặc biên lợi nhuận bị thu hẹp. Năm 2024, tỷ lệ này giảm nhẹ, cho thấy doanh nghiệp đã bắt đầu kiểm soát tốt hơn chi phí sản xuất.

3.7 Phân tích tính thanh khoản

1. liquidity_analysis <- HPG %>%
2.   mutate(current_ratio = TS_NganHan / No_PhaiTra) %>%
3.   select(Nam, TS_NganHan, No_PhaiTra, current_ratio)
4. liquidity_analysis
## # A tibble: 10 × 4
##      Nam TS_NganHan No_PhaiTra current_ratio
##    <dbl>      <dbl>      <dbl>         <dbl>
##  1  2015    1.17e13    1.01e13         1.16 
##  2  2016    1.19e13    1.10e13         1.08 
##  3  2017    1.82e13    1.34e13         1.36 
##  4  2018    3.31e13    2.06e13         1.60 
##  5  2019    2.53e13    3.76e13         0.673
##  6  2020    5.67e13    7.23e13         0.785
##  7  2021    9.42e13    8.75e13         1.08 
##  8  2022    8.05e13    7.42e13         1.08 
##  9  2023    8.27e13    8.49e13         0.974
## 10  2024    8.67e13    1.10e14         0.789

Giải thích kỹ thuật: Đoạn code trên tính tỷ lệ thanh toán hiện hành (Current Ratio), chỉ tiêu phản ánh khả năng doanh nghiệp dùng tài sản ngắn hạn để thanh toán nợ. Dùng mutate tính tỷ lệ thanh toán hiện hành cho từng năm. Và select(Nam, TS_NganHan, No_PhaiTra, current_ratio) để chọn các cột cần thiết để hiển thị kết quả.

Nhận xét: Tỷ lệ thanh khoản của HPG giai đoạn từ năm 2015 đến 2024 dao động quanh mức 0.67–1.60, cho thấy khả năng thanh toán ngắn hạn biến động lớn giữa các năm. Giai đoạn 2018 đạt đỉnh 1.60 thể hiện khả năng thanh khoản tốt, trong khi từ năm 2019 đến 2020 giảm xuống dưới 1, phản ánh rủi ro thanh toán ngắn hạn tăng lên. Và từ năm 2021 trở đi, tỷ lệ phục hồi nhẹ nhưng vẫn quanh mức 1, cho thấy HPG duy trì trạng thái thanh khoản vừa phải.

3.8 Phân tích khả năng trả nợ

1. cash_flow_to_debt <- HPG %>%
2.   mutate(cfo_to_debt_ratio = LCTT_KD / No_PhaiTra) %>%
3.   select(Nam, LCTT_KD, No_PhaiTra, cfo_to_debt_ratio)
4. cash_flow_to_debt
## # A tibble: 10 × 4
##      Nam LCTT_KD No_PhaiTra cfo_to_debt_ratio
##    <dbl>   <dbl>      <dbl>             <dbl>
##  1  2015 2.76e12    1.01e13            0.273 
##  2  2016 4.54e12    1.10e13            0.411 
##  3  2017 6.82e12    1.34e13            0.510 
##  4  2018 6.06e12    2.06e13            0.294 
##  5  2019 7.64e12    3.76e13            0.203 
##  6  2020 1.16e13    7.23e13            0.160 
##  7  2021 2.67e13    8.75e13            0.306 
##  8  2022 1.23e13    7.42e13            0.165 
##  9  2023 8.64e12    8.49e13            0.102 
## 10  2024 6.61e12    1.10e14            0.0602

Giải thích kỹ thuật: Đoạn code tính tỷ lệ dòng tiền hoạt động trên nợ phải trả (CFO to Debt Ratio), chỉ số phản ánh mức độ doanh nghiệp có thể trả nợ bằng dòng tiền từ hoạt động kinh doanh. Dùng mutate để tính cột cfo_to_debt_ratio và select() để giữ lại các cột cần thiết để hiển thị kết quả.

Nhận xét: Kết quả cho thấy tỷ lệ dòng tiền hoạt động trên nợ phải trả của HPG dao động giảm dần qua các năm, từ 0.51 năm 2017 xuống còn 0.06 năm 2024, cho thấy khả năng tạo dòng tiền từ hoạt động kinh doanh để chi trả nợ giảm đáng kể. Giai đoạn từ năm 2015 đên 2018, doanh nghiệp duy trì mức trên 0.2–0.5, nhưng sau năm 2020 tỷ lệ này giảm mạnh, phản ánh áp lực thanh toán nợ tăng và hiệu quả sử dụng vốn lưu động suy yếu.

3.9 Phân tích gánh nặng thuế

1. effective_tax_rate <- HPG %>%
2.   mutate(
3.     income_tax = LN_TruocThue - LN_SauThue,
4.     effective_tax_rate = income_tax / LN_TruocThue) %>%
5.   select(Nam, LN_TruocThue, LN_SauThue, effective_tax_rate)
6. effective_tax_rate
## # A tibble: 10 × 4
##      Nam LN_TruocThue LN_SauThue effective_tax_rate
##    <dbl>        <dbl>      <dbl>              <dbl>
##  1  2015      3.77e12    3.50e12             0.0703
##  2  2016      3.99e12    3.50e12             0.122 
##  3  2017      7.70e12    6.61e12             0.142 
##  4  2018      9.29e12    8.01e12             0.137 
##  5  2019      1.01e13    8.60e12             0.146 
##  6  2020      1.54e13    1.35e13             0.121 
##  7  2021      3.71e13    3.45e13             0.0684
##  8  2022      9.92e12    8.44e12             0.149 
##  9  2023      7.79e12    6.80e12             0.127 
## 10  2024      1.37e13    1.20e13             0.122

Giải thích kỹ thuật: Đoạn code tính tỷ suất thuế thực tế để đo mức thuế thực doanh nghiệp trả so với lợi nhuận trước thuế. Dùng mutate để tính số thuế thực tế đã nộp và tỷ lệ thuế thực tế trên tổng lợi nhuận trước thuế. Dùng select() để giữ các cột cần thiết để hiển thị kết quả.

Nhận xét: Tỷ suất thuế của HPG giai đoạn từ năm 2015 đến 2024 dao động trong khoảng 6.8%–14.9%, thấp hơn mức thuế thu nhập doanh nghiệp chuẩn (20%), cho thấy doanh nghiệp được hưởng ưu đãi thuế hoặc có hiệu quả tối ưu chi phí thuế tốt. Các năm 2017 đến 2019 ghi nhận tỷ suất cao nhất (~14%), phản ánh giai đoạn lợi nhuận tăng mạnh trong khi năm 2021 chỉ còn 6.8% có thể do lợi nhuận giảm hoặc các khoản chi hợp lệ được khấu trừ thuế. HPG duy trì chính sách thuế ổn định và hiệu quả, góp phần hỗ trợ lợi nhuận ròng.

3.10 Thống kê mô tả biến Tong_TS

1. HPG_Tong_TS <- HPG %>%                                  
2.   summarise(
3.     Solieu = n(),                                   
4.     Giatritb = mean(Tong_TS, na.rm = TRUE),     
5.     max = max(Tong_TS, na.rm = TRUE),          
6.     min = min(Tong_TS, na.rm = TRUE),            
7.     Trungvi = median(Tong_TS, na.rm = TRUE),    
8.     Dolechchuan = sd(Tong_TS, na.rm = TRUE),      
9.     Q1 = quantile(Tong_TS, 0.25, na.rm = TRUE),   
10.     Q3 = quantile(Tong_TS, 0.75, na.rm = TRUE)) 
11. HPG_Tong_TS
## # A tibble: 1 × 8
##   Solieu Giatritb     max     min Trungvi Dolechchuan      Q1      Q3
##    <int>    <dbl>   <dbl>   <dbl>   <dbl>       <dbl>   <dbl>   <dbl>
## 1     10  1.10e14 2.24e14 2.21e13 1.05e14     7.67e13 3.82e13 1.76e14

Nhận xét: Kết quả thống kê cho thấy tổng tài sản của HPG trong giai đoạn từ năm 2015 đến 2024 có quy mô rất lớn và biến động mạnh. Giá trị trung bình đạt khoảng 1.10×10¹⁴ VND, trong khi trung vị (giá trị điển hình nhất) là 1.05×10¹⁴ VND, chứng tỏ phân bố tài sản khá cân bằng quanh mức trung bình.

Tài sản nhỏ nhất chỉ khoảng 2.21×10¹³ VND trong khi lớn nhất lên đến 2.24×10¹⁴ VND, cho thấy sự tăng trưởng mạnh mẽ về quy mô tài sản qua các năm.

Độ lệch chuẩn cao (≈7.67×10¹³ VND) phản ánh biến động lớn trong tổng tài sản, phù hợp với xu hướng mở rộng đầu tư và sản xuất của doanh nghiệp.

Tứ phân vị (Q1 = 3.82×10¹³, Q3 = 1.76×10¹⁴) cũng cho thấy phần lớn giá trị tài sản của HPG nằm trong khoảng cao, minh chứng cho sức mạnh tài chính và quy mô ngày càng lớn của tập đoàn.

Kết luận HPG duy trì mức tài sản cao và tăng trưởng ổn định, thể hiện tiềm lực tài chính mạnh và khả năng đầu tư dài hạn vững chắc.

3.11 Tính trung bình, độ lệch chuẩn và hệ số biến động cho các chỉ tiêu chính

1. HPG %>% summarise(
2.   mean_DT = mean(DoanhThu),
3.   sd_DT = sd(DoanhThu),
4.   cv_DT = sd_DT / mean_DT * 100,
5.   mean_LN = mean(LN_SauThue),
6.   sd_LN = sd(LN_SauThue),
7.   cv_LN = sd_LN / mean_LN * 100)
## # A tibble: 1 × 6
##   mean_DT   sd_DT cv_DT mean_LN   sd_LN cv_LN
##     <dbl>   <dbl> <dbl>   <dbl>   <dbl> <dbl>
## 1 8.39e13 5.10e13  60.8 1.06e13 9.00e12  85.3

Giải thích kỹ thuật: Để đánh giá mức độ biến động của doanh thu và lợi nhuận sau thuế của HPG qua các năm, dùng summarise() để tính các chỉ tiêu thống kê cơ bản gồm: giá trị trung bình (mean), độ lệch chuẩn (standard deviation) và hệ số biến động (CoV). Trong đó, mean() cho biết giá trị trung bình của từng biến, sd() đo lường mức độ phân tán của dữ liệu quanh giá trị trung bình, còn hệ số biến động được tính bằng công thức CV = (SD / Mean) × 100, phản ánh mức độ biến động tương đối (%).

Nhận xét: Theo kết quả, doanh thu trung bình của HPG đạt khoảng 83,888 tỷ đồng, với độ lệch chuẩn 51,038 tỷ đồng, tương ứng hệ số biến động 60,84%. Trong khi đó, lợi nhuận sau thuế trung bình đạt khoảng 10,552 tỷ đồng, độ lệch chuẩn 9,000 tỷ đồng, và hệ số biến động lên tới 85,29%. Điều này cho thấy doanh thu của doanh nghiệp có xu hướng tăng trưởng mạnh nhưng chưa ổn định, còn lợi nhuận biến động mạnh hơn nhiều, phản ánh sự nhạy cảm của lợi nhuận đối với biến động giá thép và chi phí đầu vào.

3.12 Tốc độ tăng trưởng kép (CAGR) doanh thu và lợi nhuận sau thuế

1. CAGR_DT <- ((last(HPG$DoanhThu) / first(HPG$DoanhThu))^(1/(nrow(HPG)-1)) - 1) * 100
2. CAGR_LN <- ((last(HPG$LN_SauThue) / first(HPG$LN_SauThue))^(1/(nrow(HPG)-1))-1) * 100
3. print(CAGR_DT)
## [1] 19.69897
1. print(CAGR_LN)
## [1] 14.6772

Giải thích kỹ thuật: Đoạn code được sử dụng để tính tốc độ tăng trưởng kép hàng năm (CAGR - Compound Annual Growth Rate) của doanh thu và lợi nhuận sau thuế của HPG trong giai đoạn 2015-2024. Dùng first() và last() lấy lần lượt giá trị đầu tiên và cuối cùng của chuỗi dữ liệu, còn nrow(HPG) trả về số năm quan sát. Kết quả sau đó được nhân với 100 để chuyển sang đơn vị phần trăm (%).

Nhận xét: Theo kết quả nhận được tốc độ tăng trưởng kép của Doanh thu đạt 19,7%/năm, còn Lợi nhuận sau thuế đạt 14,7%/năm trong giai đoạn phân tích.

Kết quả này cho thấy Doanh thu của Hòa Phát tăng trưởng mạnh mẽ và ổn định hơn lợi nhuận ròng. Mức CAGR gần 20%/năm phản ánh khả năng mở rộng quy mô kinh doanh liên tục trong suốt gần một thập kỷ. Tuy nhiên, tốc độ tăng lợi nhuận chỉ đạt khoảng 14,7%/năm cho thấy biên lợi nhuận của doanh nghiệp có xu hướng giảm nhẹ, có thể do chi phí sản xuất, lãi vay hoặc đầu tư tăng nhanh hơn tốc độ tăng doanh thu.

3.13 Biến động doanh thu qua các năm

1. HPG %>%
2.   arrange(Nam) %>%
3.   mutate(BienDong_DT = DoanhThu - lag(DoanhThu))
## # A tibble: 10 × 19
##      Nam DoanhThu  GiaVon  LN_Gop DT_TC_NganHan TS_DaiHan LN_TruocThue
##    <dbl>    <dbl>   <dbl>   <dbl>         <dbl>     <dbl>        <dbl>
##  1  2015  2.79e13 2.19e13 5.59e12       7.58e11   1.03e13      3.77e12
##  2  2016  2.79e13 2.19e13 5.59e12       7.58e11   1.36e13      3.99e12
##  3  2017  3.39e13 2.45e13 8.75e12       6.93e11   1.50e13      7.70e12
##  4  2018  4.69e13 3.55e13 1.06e13       9.94e12   2.00e13      9.29e12
##  5  2019  5.66e13 4.42e13 1.17e13       3.72e12   5.29e13      1.01e13
##  6  2020  9.13e13 7.12e13 1.89e13       8.13e12   7.48e13      1.54e13
##  7  2021  1.51e14 1.09e14 4.11e13       1.82e13   8.41e13      3.71e13
##  8  2022  1.43e14 1.25e14 1.68e13       2.63e13   8.98e13      9.92e12
##  9  2023  1.20e14 1.06e14 1.29e13       2.22e13   1.05e14      7.79e12
## 10  2024  1.41e14 1.20e14 1.85e13       1.90e13   1.38e14      1.37e13
## # ℹ 12 more variables: LN_SauThue <dbl>, Tong_TS <dbl>, No_PhaiTra <dbl>,
## #   Von_CSH <dbl>, Tien <dbl>, TS_NganHan <dbl>, LCTT_KD <dbl>, LCTT_DT <dbl>,
## #   LCTT_TC <dbl>, LN_rong <dbl>, Debt_to_Equity <dbl>, BienDong_DT <dbl>

3.14 Tỷ lệ tăng trưởng hàng năm của các biến tài chính

1. HPG_tangtruong <- HPG %>%
2.   mutate(across(c(DoanhThu, LN_SauThue, Tong_TS, Von_CSH), 
3.                 ~ (./lag(.) - 1) * 100, 
4.                 .names = "TangTruong_{col}")) %>%
5.   select(Nam, starts_with("TangTruong")) %>%
6.   print()
## # A tibble: 10 × 5
##      Nam TangTruong_DoanhThu TangTruong_LN_SauThue TangTruong_Tong_TS
##    <dbl>               <dbl>                 <dbl>              <dbl>
##  1  2015               NA                    NA                 NA   
##  2  2016                0                     0                 15.5 
##  3  2017               21.6                  88.5               30.3 
##  4  2018               38.3                  21.3               59.6 
##  5  2019               20.8                   7.31              47.5 
##  6  2020               61.3                  57.0               68.1 
##  7  2021               65.3                 156.                35.5 
##  8  2022               -5.37                -75.5               -4.43
##  9  2023              -15.7                 -19.5               10.2 
## 10  2024               16.8                  76.8               19.5 
## # ℹ 1 more variable: TangTruong_Von_CSH <dbl>

Giải thích kỹ thuật: Đoạn mã trên được sử dụng để tính tỷ lệ tăng trưởng hàng năm (%) của các biến tài chính như Doanh thu, Lợi nhuận sau thuế, Tổng tài sản và Vốn chủ sở hữu của Hòa Phát. Hàm mutate() kết hợp với across() trong dplyr giúp áp dụng công thức (Xt/Xt-1 - 1)*100 cho nhiều biến cùng lúc, trong đó lag() lấy giá trị của năm trước để so sánh. Cấu trúc .names = “TangTruong_{col}” tự động đặt tên các cột kết quả, còn select() dùng để giữ lại năm và các biến tăng trưởng.

Nhận xét:

3.15 Phân tổ theo mức tăng trưởng doanh thu

1. HPG_phanTo <- HPG_tangtruong %>%
2.   mutate(Nhom_TangTruong = case_when(
3.       TangTruong_DoanhThu < 0 ~ "Giảm",
4.       TangTruong_DoanhThu < 5 ~ "Ổn định",
5.       TangTruong_DoanhThu < 20 ~ "Tăng nhẹ",
6.       TangTruong_DoanhThu < 50 ~ "Tăng vừa",
7.       TRUE ~ "Tăng mạnh")) %>%
8.   group_by(Nhom_TangTruong) %>%
9.   summarise(Nam = paste(Nam, collapse = ", "),
10.     TB_TangTruong_LN = mean(TangTruong_LN_SauThue, na.rm = TRUE),
11.     TB_TangTruong_TS = mean(TangTruong_Tong_TS, na.rm = TRUE),
12.     TB_TangTruong_VCSH = mean(TangTruong_Von_CSH, na.rm = TRUE))
13. HPG_phanTo
## # A tibble: 5 × 5
##   Nhom_TangTruong Nam       TB_TangTruong_LN TB_TangTruong_TS TB_TangTruong_VCSH
##   <chr>           <chr>                <dbl>            <dbl>              <dbl>
## 1 Giảm            2022, 20…            -47.5             2.90               6.43
## 2 Tăng mạnh       2015, 20…            106.             51.8               49.5 
## 3 Tăng nhẹ        2024                  76.8            19.5               11.5 
## 4 Tăng vừa        2017, 20…             39.0            45.8               41.9 
## 5 Ổn định         2016                   0              15.5               20.9

Giải thích kỹ thuật: đoạn code phân loại và tóm tắt dữ liệu tăng trưởng của doanh nghiệp Hòa Phát (HPG). Hàm mutate() được dùng để tạo một biến mới có tên Nhom_TangTruong, trong đó mỗi năm được gán vào một nhóm tăng trưởng cụ thể dựa trên giá trị phần trăm tăng trưởng doanh thu (TangTruong_Net_revenue). Việc gán nhóm được thực hiện bằng hàm case_when(), cho phép đặt điều kiện logic: nếu tăng trưởng âm thì là “Giảm”, tăng trưởng thấp dưới 5% là “Ổn định”, từ 5–20% là “Tăng nhẹ”, từ 20–50% là “Tăng vừa”, và trên 50% được xếp vào nhóm “Tăng mạnh”. Sau đó, hàm group_by() được dùng để nhóm dữ liệu theo các mức tăng trưởng này, và summarise() giúp tính giá trị trung bình của các biến tài chính khác như tăng trưởng lợi nhuận sau thuế, tăng trưởng tổng tài sản, và tăng trưởng vốn chủ sở hữu. Cuối cùng, hàm paste() kết hợp các năm thuộc cùng một nhóm thành chuỗi ký tự để hiển thị gọn gàng. Nhờ đó, đoạn mã cho phép tổng hợp và so sánh các chỉ tiêu tài chính của HPG theo từng mức độ tăng trưởng doanh thu một cách trực quan và có hệ thống.

Nhận xét: Nhóm “Tăng mạnh” (2015, 2020, 2021) có tốc độ tăng trưởng lợi nhuận bình quân rất cao (106,32%) cùng với tăng mạnh về tài sản (51,83%) và vốn chủ (49,54%), phản ánh giai đoạn mở rộng quy mô và tăng hiệu quả kinh doanh vượt trội.

Nhóm “Tăng nhẹ” (2024) vẫn duy trì đà tăng trưởng lợi nhuận (76,75%) dù doanh thu chỉ tăng dưới 20%, cho thấy biên lợi nhuận được cải thiện.

Ngược lại, giai đoạn “Giảm” (2022–2023) ghi nhận mức sụt giảm lợi nhuận trung bình -47,5%, trong khi tài sản và vốn chủ gần như đi ngang, thể hiện tác động tiêu cực từ biến động thị trường thép sau đại dịch.

Nhóm “Ổn định” và “Tăng vừa” có xu hướng tăng trưởng lợi nhuận – tài sản – vốn chủ tương đối hài hòa, phản ánh giai đoạn duy trì hoạt động ổn định.

Kết quả phân tích cho thấy hiệu quả sinh lời của HPG biến động mạnh theo chu kỳ thị trường, nhưng vẫn duy trì khả năng phục hồi tốt trong các giai đoạn tăng trưởng, đặc biệt khi doanh thu tăng mạnh thường kéo theo hiệu quả tài chính tích cực trên toàn bộ cấu trúc tài sản và vốn chủ sở hữu.

1. HPG_tangtruong_long <- HPG_tangtruong %>%
2.   pivot_longer(cols = -Nam, names_to = "ChiTieu", values_to = "TangTruong")
3. ggplot(HPG_tangtruong_long, aes(x = as.factor(Nam), y = TangTruong, color = ChiTieu, group = ChiTieu)) +
4.   geom_line(size = 1.2) +
5.   geom_point(size = 2) +
6.   geom_hline(yintercept = 0, linetype = "dotted", color = "gray40") +
7.   labs(
8.     title = "Tốc độ tăng trưởng (%) qua các năm của Hòa Phát",
9.     x = "Năm",
10.     y = "Tốc độ tăng trưởng (%)",
11.     color = "Chỉ tiêu",
12.     caption = "Nguồn: Báo cáo tài chính HPG") +
13.   theme_minimal(base_size = 13) +
14.   theme(
15.     plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
16.     legend.position = "right",
17.     plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
18.     axis.text = element_text(color = "black"),
19.     axis.title = element_text(face = "bold"),
20.     panel.grid.minor = element_blank(),
21.     plot.margin = margin(10, 20, 20, 20))

Nhận xét: Biểu đồ thể hiện tốc độ tăng trưởng của Hòa Phát qua các năm với 4 chỉ tiêu chính: lợi nhuận sau thuế, doanh thu thuần, vốn chủ sở hữu và tổng tài sản. Từ năm 2016 đến 2021, tất cả các chỉ tiêu đều tăng trưởng tích cực, nổi bật nhất là năm 2021 khi lợi nhuận sau thuế tăng đột biến lên hơn 150%. Tuy nhiên, năm 2022 ghi nhận mức giảm mạnh, đặc biệt lợi nhuận sau thuế rơi xuống gần -80%. Giai đoạn năm 2023 đến 2024 cho thấy dấu hiệu phục hồi rõ rệt, đặc biệt lợi nhuận sau thuế tăng trở lại ấn tượng trong năm 2024 (~75%), trong khi các chỉ số khác cũng dần ổn định và chuyển sang tăng nhẹ.

Kết luận: Tăng trưởng của Hòa Phát mang tính chu kỳ rõ rệt, phản ánh tác động của các yếu tố thị trường đến hoạt động sản xuất kinh doanh. Giai đoạn năm 22020 đến 2021 là đỉnh cao tăng trưởng, nhưng năm 2022 là cú sốc lớn về hiệu quả kinh doanh. Tuy nhiên, với đà phục hồi ở năm 2024, đặc biệt ở chỉ tiêu lợi nhuận, Hòa Phát đang dần lấy lại đà tăng trưởng. Doanh nghiệp cần tiếp tục kiểm soát rủi ro và đẩy mạnh hiệu quả tài chính để duy trì sự ổn định lâu dài.

3.16 Tạo biến nhóm giai đoạn: 2015-2019 và 2020-2024

1. HPG <- HPG %>%
2.   mutate(GiaiDoan = ifelse(Nam <= 2019, "Trước 2020", "Sau 2020"))

Giải thích kỹ thuật: đoạn code dùng mutate() để tạo thêm một biến mới có tên là GiaiDoan trong bộ dữ liệu HPG. Biến này được xác định dựa trên giá trị của cột Nam: nếu năm nhỏ hơn hoặc bằng 2019 thì được gán nhãn “Trước 2020”, ngược lại là “Sau 2020”. Cụ thể, hàm ifelse() được dùng để kiểm tra điều kiện Nam <= 2019 và gán giá trị tương ứng cho từng quan sát. Kết quả là bộ dữ liệu được chia thành hai giai đoạn rõ ràng: trước và sau năm 2020 để phục vụ cho việc so sánh, phân tích xu hướng tăng trưởng và biến động tài chính của Hòa Phát qua hai thời kỳ khác nhau.

3.17 Trung bình doanh thu và lợi nhuận theo giai đoạn

1. HPG %>%
2.   group_by(GiaiDoan) %>%
3.   summarise(TB_DT = mean(DoanhThu),TB_LN = mean(LN_SauThue))
## # A tibble: 2 × 3
##   GiaiDoan     TB_DT   TB_LN
##   <chr>        <dbl>   <dbl>
## 1 Sau 2020   1.29e14 1.51e13
## 2 Trước 2020 3.86e13 6.05e12

Giải thích kỹ thuật: Dùng group_by() để gom các quan sát theo biến phân nhóm GiaiDoan (hai nhóm: Trước 2020 và Sau 2020). Sau đó summarise() tính giá trị trung bình (mean) của hai chỉ tiêu chính: DoanhThu (TB_DT) và LN_SauThue (TB_LN) cho mỗi nhóm

Nhận xét: Trước năm 2020 có trung bình doanh thu gần 38.6 nghìn tỷ VND. Trung bình lợi nhuận sau thuế khoảng 6.05 nghìn tỷ VND.

Sau năm 2020 với trung bình doanh thu gần 129.2 nghìn tỷ VND. Trung bình lợi nhuận sau thuế khoảng 15.06 nghìn tỷ VND.

Doanh thu trung bình tăng khoảng 234% sau 2020 so với trước 2020. Lợi nhuận trung bình tăng khoảng 149% sau 2020 so với trước 2020.

3.18 Tỷ lệ nợ trung bình theo giai đoạn

1. HPG %>%
2.   group_by(GiaiDoan) %>%
3.   summarise(TyLeNo_TB = mean(No_PhaiTra / Tong_TS) * 100)
## # A tibble: 2 × 2
##   GiaiDoan   TyLeNo_TB
##   <chr>          <dbl>
## 1 Sau 2020        48.4
## 2 Trước 2020      43.3

Giải thích kỹ thuật: Đoạn code được dùng để tính tỷ lệ nợ trung bình theo từng giai đoạn. group_by(GiaiDoan): chia dữ liệu thành hai nhóm: “Trước 2020” và “Sau 2020”. Dùng summarise(…): tính giá trị trung bình cho mỗi nhóm. Nếu có giá trị thiếu, nên thêm na.rm = TRUE để đảm bảo không bị lỗi khi tính trung bình.

Nhận xét: Tỷ lệ nợ trung bình tăng 5.09 điểm phần trăm, tương đương tăng gần 11,7% so với giai đoạn trước. Điều này cho thấy mức độ phụ thuộc vào vốn vay của Hòa Phát tăng nhẹ sau năm 2020.

3.19 So sánh ROE và ROA theo giai đoạn

1. HPG_RO <- HPG %>%
2.   mutate(ROA = LN_SauThue / Tong_TS * 100, ROE = LN_SauThue / Von_CSH * 100) %>%
3.   group_by(GiaiDoan) %>%
4.   summarise(ROA_TB = mean(ROA, na.rm = TRUE), ROE_TB = mean(ROE, na.rm = TRUE))
5. print(HPG_RO)
## # A tibble: 2 × 3
##   GiaiDoan   ROA_TB ROE_TB
##   <chr>       <dbl>  <dbl>
## 1 Sau 2020     8.71   17.3
## 2 Trước 2020  15.1    26.5

Giải thích kỹ thuật: Dùng lệnh mutate() để tạo hai biến mới: ROA và ROE, tương ứng với công thức tính tỷ suất sinh lời trên tổng tài sản và trên vốn chủ sở hữu, đơn vị tính là phần trăm (%). Sau đó, dùng group_by(GiaiDoan) giúp chia dữ liệu thành hai nhóm là Trước 2020 và Sau 2020, cho phép so sánh giữa hai giai đoạn. Tiếp đến, summarise() được dùng để tính giá trị trung bình của hai chỉ tiêu ROA và ROE trong từng giai đoạn.

Nhận xét: ROA trung bình giảm từ 15,12% (trước 2020) xuống còn 8,71% (sau 2020), tức giảm khoảng 6,41 điểm phần trăm, tương đương giảm 42,4% so với giai đoạn trước. Thây được hiệu quả sử dụng tài sản của Hòa Phát đã suy giảm đáng kể, nghĩa là cùng một lượng tài sản nhưng lợi nhuận tạo ra thấp hơn.

ROE trung bình cũng giảm mạnh từ 26,54% xuống 17,34%, giảm 9,2 điểm phần trăm (tương đương giảm 34,7%). Tỷ suất sinh lời trên vốn chủ sở hữu giảm phản ánh hiệu quả đầu tư của cổ đông suy yếu, có thể do chi phí vốn tăng hoặc lợi nhuận bị thu hẹp trong bối cảnh biến động sau dịch Covid-19 và thị trường thép khó khăn.

1. HPG_RO_long <- HPG_RO %>%
2.   pivot_longer(cols = c(ROA_TB, ROE_TB),names_to = "ChiTieu",values_to = "GiaTri")
3. ggplot(HPG_RO_long, aes(x = GiaiDoan, y = GiaTri, fill = ChiTieu)) +
4.   geom_col(position = "dodge", color = "black") +                    
5.   geom_text(aes(label = round(GiaTri, 1)),position = position_dodge(width = 0.9),vjust = -0.5, size = 4) +
6.   geom_hline(yintercept = mean(HPG_RO_long$GiaTri),linetype = "dashed", color = "red", linewidth = 0.8) +
7.   scale_fill_manual(values = c("#4DBBD5FF", "#E64B35FF"),labels = c("ROA trung bình", "ROE trung bình")) +
8.   labs(title = "So sánh ROA và ROE trung bình theo giai đoạn",x = "Giai đoạn",y = "Tỷ suất (%)",fill = "Chỉ tiêu",caption = "Nguồn: Báo cáo tài chính HPG") +
9.   theme_minimal(base_size = 13) +
10.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "top",panel.grid.minor = element_blank())

3.20 Tương quan giữa nợ và lợi nhuận (kiểm tra đòn bẩy tài chính)

1. cor(HPG$No_PhaiTra, HPG$LN_SauThue, use = "complete.obs")
## [1] 0.548036

Giải thích kỹ thuật: lệnh cor trong R tính hệ số tương quan Pearson giữa hai biến No_PhaiTra và LN_SauThue. Hàm cor() đo mức độ tuyến tính giữa hai biến định lượng, giá trị nằm trong khoảng từ -1 đến +1. Tham số use = “complete.obs” yêu cầu R chỉ sử dụng các hàng có dữ liệu đầy đủ ở cả hai biến (loại bỏ những giá trị bị thiếu — NA).

Nhận xét: Kết quả nhận được là 0.548036, nghĩa là có mối tương quan dương trung bình giữa nợ và lợi nhuận. Nói cách khác, khi nợ phải trả tăng, lợi nhuận sau thuế cũng có xu hướng tăng, thể hiện tác động tích cực của đòn bẩy tài chính, doanh nghiệp vay vốn để mở rộng hoạt động, tạo thêm lợi nhuận.

CHƯƠNG 4: TRỰC QUAN HÓA DỮ LIỆU

4.1 Biểu đồ phân tích 3 dòng tiền

1. cash_flow_long <- HPG %>%
2.   select(Nam, LCTT_KD, LCTT_DT, LCTT_TC) %>%
3.   pivot_longer(cols = -Nam, names_to = "cash_flow_type", values_to = "amount")
4. ggplot(cash_flow_long, aes(x = factor(Nam), y = amount, fill = cash_flow_type)) +
5.   geom_col() +
6.   facet_wrap(~ cash_flow_type, scales = "free_y", ncol = 1) +
7.   geom_text(aes(label = scales::number(amount / 1e9, accuracy = 0.1)), vjust = ifelse(cash_flow_long$amount >= 0, -0.5, 1.5), size = 2.5) +
8.    scale_y_continuous(labels = scales::label_number(scale_cut = scales::cut_short_scale()), expand = expansion(mult = c(0.25, 0.25))) +
9.   labs(title = "Phân tích 3 dòng tiền của HPG qua từng năm",
10.     subtitle = "Đơn vị tính: VND (Nhãn trên cột là Tỷ VND)",
11.     x = "Năm",y = "Số tiền (VND)" ) +
12.   theme_bw(base_size = 13) +
13. theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
14. plot.subtitle = element_text(hjust = 0.5, color = "gray40", size = 11),
15. legend.position = "none",
16. strip.text = element_text(face = "bold", size = 10))

Giải thích kỹ thuật: Từ dòng 1 đến dòng 3, tạo 1 data.frame chứa năm, LCTT trong kinh doanh, đầu tư, và tài chính. Sau đó dùng pivot_longer() để chuyển dữ liệu từ dạng rộng sang dài, cho ra 3 cột mới: Nam, cash_flow_type (loại dòng tiền), amount (số tiền). Từ dòng 4, vẽ biểu đồ với trục X là năm, trục Y là số tiền và dùng factor(Nam) để thể hiện từng năm. Dòng 6 dùng facet để tạo 3 biểu đồ riêng biệt cho 3 dòng tiền.

Nhận xét: Biểu đồ cho thấy cơ cấu dòng tiền của Hòa Phát (HPG) trong giai đoạn từ năm 2015 đến năm 2024 có sự biến động mạnh giữa ba dòng tiền kinh doanh (LCTT_KD), đầu tư (LCTT_DT) và tài chính (LCTT_TC). Dòng tiền từ hoạt động kinh doanh luôn đạt giá trị dương, tăng mạnh vào năm 2021 với 26,7 nghìn tỷ trong khi đó dòng tiền từ đầu tư luôn đạt giá trị âm, đặc biệt trong giai đoạn từ năm 2018 đến năm 2024 luôn ghi nhận mức đầu tư cao (âm trên 20 nghìn tỷ/năm), điều đó cũng cho thấy doanh nghiệp mở rộng quy mô và đầu tư mạnh vào tài sản cố định. Bên cạnh đó, dòng tiền tài chính cũng có sự biến động lớn, tăng mạnh vào năm 2020 và 2024 cho thấy HPG chủ động huy động vốn để bù đắp chi đầu tư. Qua biểu đồ 3 dòng tiền, có thể thấy doanh nghiệp vẫn duy trì năng lực tạo tiền tốt từ hoạt động cốt lõi, dù áp lực dòng tiền đầu tư cao.

4.2 Biểu đồ thể hiện doanh thu tích lũy qua các năm

1. library(ggrepel)       
2. cumulative_revenue <- HPG %>%
3.   select(Nam, DoanhThu) %>%
4.   mutate(cumulative_revenue = cumsum(DoanhThu))
5. ggplot(cumulative_revenue, aes(x = Nam, y = cumulative_revenue)) +
6.   geom_area(fill = "#B3E5FC", alpha = 0.6) +
7.   geom_line(color = "#0277BD", size = 1.2) +
8.   geom_point(color = "#0277BD", size = 3) +
9.   geom_text_repel(aes(label = scales::number(cumulative_revenue / 1e9, accuracy = 0, big.mark = ",")), size = 3, nudge_y = 5e12 ) +
10.   scale_y_continuous(labels = scales::label_number(scale_cut = scales::cut_short_scale())) +
11.   labs(title = "Doanh thu tích lũy (Lũy kế) của HPG qua từng năm",
12.     x = "Năm",y = "Doanh thu tích lũy (VND)") +
13.   theme_minimal(base_size = 13) +
14. theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
15. axis.text = element_text(color = "black"),
16. axis.title = element_text(face = "bold"),
17. legend.position = "bottom",
18. panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 2 đến dòng 4, tạo 1 data.frame trong đó tạo thêm một cột mới là tổng lũy kế doanh thu bằng hàm cumsum() giá trị bằng tổng các năm trước đó. Dòng 6 tạo một biểu đồ vùng, dòng 7 và 8 tạo một đường line xanh thể hiện đường xu hướng của doanh thu với các chấm tròn nhấn mạnh những năm nổi bật.

Nhận xét: Biểu đồ cho thấy doanh thu tích lũy của Hòa Phát (HPG) tăng trưởng liên tục và mạnh mẽ qua từng năm. Đường cong có dạng tăng đều, đặc biệt từ sau năm 2019, tốc độ tăng trưởng doanh thu cao và ổn định. Điều này phản ánh hiệu quả hoạt động sản xuất, mức tiêu thụ thép cao, khả năng mở rộng thị trường và tận dụng tốt nhu cầu hạ tầng của doanh nghiệp.

4.3 Biểu đồ thể hiện cấu trúc nguồn vốn và hệ số Debt-to-Equity

1. HPG_plot <- HPG %>%
2.   mutate(Debt_to_Equity = No_PhaiTra / Von_CSH) %>%
3.   select(Nam, No_PhaiTra, Von_CSH, Debt_to_Equity) %>%
4.   arrange(Nam)
5. max_de_ratio <- max(HPG_plot$Debt_to_Equity, na.rm = TRUE)
6. if (is.infinite(max_de_ratio) || is.na(max_de_ratio) || max_de_ratio == 0) max_de_ratio <- 1
7. capital_structure_long <- HPG_plot %>%
8.   pivot_longer(cols = c(No_PhaiTra, Von_CSH), names_to = "loai_nguon_von", values_to = "so_tien") %>%
9.   group_by(Nam) %>%
10.   mutate(pct = so_tien / sum(so_tien, na.rm = TRUE),
11.     ypos = cumsum(pct) - pct / 2 + 0.08) %>%
12.   ungroup()
13. de_line <- HPG_plot %>%
14.   mutate(de_scaled = Debt_to_Equity / max_de_ratio)
15. ggplot(capital_structure_long, aes(x = factor(Nam), y = pct, fill = loai_nguon_von)) +
16.   geom_col(width = 0.7, alpha = 0.9) +
17.   geom_hline(yintercept = 1 / max_de_ratio, linetype = "dashed", color = "gray50", linewidth = 0.7) +
18.   geom_text(aes(y = ypos, label = paste0(round(pct * 100), "%")), color = "black", size = 3, fontface = "bold") +
19.   geom_line(data = de_line, aes(x = factor(Nam), y = de_scaled, group = 1), color = "#C62828", linewidth = 1.3, inherit.aes = FALSE) +
20.   geom_point(data = de_line, aes(x = factor(Nam), y = de_scaled), color = "#C62828", size = 3, inherit.aes = FALSE) +
21.   geom_text_repel( data = de_line, aes(x = factor(Nam), y = de_scaled, label = round(Debt_to_Equity, 2)), nudge_y = -0.08, color = "#B71C1C", fontface = "bold", bg.color = "white", bg.r = 0.1, size = 3.5, segment.color = NA, inherit.aes = FALSE) +
22.   scale_y_continuous(labels = percent_format(accuracy = 1), sec.axis = sec_axis(~ . * max_de_ratio, name = "Debt-to-Equity (Nợ/Vốn)")) +
23.   scale_fill_manual(values = c("No_PhaiTra" = "#EF9A9A", "Von_CSH" = "#A5D6A7"),
24.     labels = c("Nợ Phải Trả", "Vốn Chủ Sở hữu")) +
25.   labs(title = "Cấu trúc nguồn vốn HPG (2015 – 2024) và hệ số Debt-to-Equity",
26.     subtitle = "Thể hiện tỷ trọng Nợ & Vốn chủ sở hữu kèm hệ số đòn bẩy tài chính",x = "Năm",y = "Tỷ lệ (%)",fill = "Nguồn vốn") +
27.   theme_minimal(base_size = 13) +
28.   theme(plot.title = element_text(face = "bold", size = 13, color = "black", hjust = 0.5),
29.     plot.subtitle = element_text(size = 11, color = "gray30", hjust = 0.5),
30.     axis.text = element_text(color = "black"),
31.     axis.title = element_text(face = "bold"),
32.     legend.position = "bottom",
33.     panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 1 đến 4, tạo 1 dataframe(HPG_plot), dùng hàm mutate để tạo thêm biến Debt_to_Equity, hàm select để chọn các biến chính và arrange để sắp xếp theo năm cho việc vẽ biểu đồ. Dòng 5,6 tính giá trị cực đại của Debt to Equity, dùng hàm max để lấy D/E lớn nhất với mục đích chuẩn hóa khi vẽ, dùng if để xử lý những trường hợp dữ liệu lỗi và gán max_de_ratio = 1 để tránh chia cho 0. Dòng 7 đến 13, tạo 1 dataframe (capital_structure_long), dùng privot_longer() để biến đổi dữ liệu từ dạng rộng sang dạng dài để ggplot có thể hiểu. Dòng 14 dùng mutate tạo 1 biến mới từ chuẩn hóa biến Debt_to_Equity để vẽ đường line của D/E. Từ dòng 16 vẽ biểu đồ cột chồng, trục X thể hiện năm, trục Y thể hiện phần trăm của nợ và nguồn vốn so với tổng tiền. Vẽ đường line D/E với tỷ lệ 1 / max_de_ratio vì đã được chia cho giá trị lớn nhất từ bước 4.

Nhận xét: Qua biểu đồ thấy tỷ trọng vốn chủ sở hữu duy trì quanh mức 40–55%, trong khi nợ phải trả biến động tương ứng, phản ánh doanh nghiệp có chiến lược cân bằng giữa tự tài trợ và vay nợ. Xét hệ số Debt-to-Equity (Nợ/Vốn) luôn đạt mức ổn định, tuy có sự tăng mạnh lên 1.22 vào năm 2022 nhưng vẫn giảm dần về mức 0.7-0.8. Qua đó, có thể thấy HPG duy trì 1 cơ cấu vốn lành mạnh với khả năng kiểm soát nợ tốt, phù hợp cho chiến lược phát triển quy mô nhưng vẫn đảm bảo an toàn tài chính dài hạn.

4.4 Biểu đồ thể hiện so sánh lợi nhuận qua các năm

1. profit_structure_long <- HPG %>%
2.   select(Nam, LN_Gop, LN_TruocThue, LN_SauThue) %>%
3.   pivot_longer(cols = -Nam, names_to = "loai_loi_nhuan", values_to = "so_tien")
4. ggplot(profit_structure_long, aes(x = factor(Nam), y = so_tien / 1e12, fill = loai_loi_nhuan)) +
5.   geom_col(position = "stack", width = 0.7, alpha = 0.9) +
6.   geom_text(aes(label = round(so_tien / 1e12, 1)),position = position_stack(vjust = 0.5),color = "black", size = 3, fontface = "bold") +
7.   geom_line(data = HPG, aes(x = factor(Nam), y = LN_SauThue / 1e12, group = 1),color = "#C62828", linewidth = 1, inherit.aes = FALSE) +
8.   geom_point(data = HPG, aes(x = factor(Nam), y = LN_SauThue / 1e12),color = "#C62828", size = 1, inherit.aes = FALSE) +
9.   scale_y_continuous(labels = label_number(scale_cut = cut_short_scale()),expand = expansion(mult = c(0, 0.1))) +
10.   scale_fill_manual(values = c("LN_Gop" = "#81C784", "LN_TruocThue" = "#64B5F6", "LN_SauThue" = "#FFB74D"),
11.     labels = c("Lợi nhuận gộp", "Lợi nhuận trước thuế", "Lợi nhuận sau thuế")) +
12.   labs(title = "Cấu trúc lợi nhuận của HPG (2015 – 2024)",
13.     subtitle = "So sánh Lợi nhuận gộp, trước thuế và sau thuế kèm xu hướng lợi nhuận ròng",x = "Năm",y = "Giá trị (nghìn tỷ VND)",fill = "Loại Lợi nhuận") +
14.   theme_minimal(base_size = 13) +
15.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
16.     plot.subtitle = element_text(hjust = 0.5, size = 11, color = "gray40"),
17.     axis.title = element_text(face = "bold"),
18.     axis.text = element_text(color = "black"),
19.     legend.position = "bottom")

Giải thích kỹ thuật: Từ dòng 1 đến 3, tạo một data.frame (profit_structure_long) dùng select để chọn 3 loại lợi nhuận, sau đấy dùng pivot_longer() để chuyển dạng dữ liệu sang dài. Từ dòng 4, vẽ biểu đồ cột chồng với trục X thể hiện năm, trục Y thể hiện số tiền, dòng 6 dùng để tạo giá trị trên cột, làm tròn 1 chữ số và canh giữa. Dòng 8,9 tạo một đường xu hướng lợi nhuận sau thuế với các điểm tương ứng thể hiện điểm nổi bật của xu hướng lợi nhuận ròng qua các năm.

Nhận xét: Biểu đồ cho thấy xu hướng tăng trưởng mạnh mẽ và biến động rõ rệt theo từng năm. Giai đoạn trước 2021, lợi nhuận tăng đều, ổn định và tăng mạnh, đạt mức kỉ luật tại năm 2021 khi lợi nhuận gộp đạt 41,1 nghìn tỷ và lợi nhuận sau thuế đạt 37,1 nghìn tỷ. Sau đó, lợi nhuận giảm vào năm 2022 khi thị trường thép suy yếu, chi phí đầu vào tăng.

4.5 Biểu đồ thể hiện xu hướng các chỉ số sinh lời

1. HPG_metrics <- HPG %>%
2.   mutate(
3.     LN_rong = LN_SauThue / DoanhThu,
4.     Roa = LN_SauThue / Tong_TS,
5.     Roe = LN_SauThue / Von_CSH,
6.     debt_to_equity = No_PhaiTra / Von_CSH,
7.     current_ratio = TS_NganHan / No_PhaiTra,
8.     TS_turnover = DoanhThu / Tong_TS,
9.     TT_DT_yoy = (DoanhThu - lag(DoanhThu)) / 
10.                            lag(DoanhThu),
11.     TT_LN_yoy = (LN_SauThue - lag(LN_SauThue)) / 
12.                              lag(LN_SauThue))
13. profitability_ratios_long <- HPG_metrics %>%
14.   select(Nam, LN_rong, Roa, Roe) %>%
15.   pivot_longer(cols = -Nam, names_to = "ratio_type", values_to = "percentage")
16. ggplot(profitability_ratios_long, aes(x = Nam, y = percentage, color = ratio_type, group = ratio_type)) +
17.   geom_line(size = 1.2) +
18.   geom_point(size = 3) +
19.   geom_text(aes(label = paste0(round(percentage * 100, 1), "%")), vjust = -0.8, fontface = "bold", size = 3, color = "black", stroke = 0.3, show.legend = FALSE) + 
20.   facet_wrap(~ ratio_type, ncol = 1, scales = "free_y") +
21.   scale_y_continuous(labels = percent_format(accuracy = 1), expand = expansion(mult = c(0.05, 0.4))) +
22.   labs(title = "Xu hướng các chỉ số sinh lời",
23.     subtitle = "Hiệu quả sử dụng Vốn và Tài sản của HPG",
24.     x = "Năm",y = "Tỷ lệ (%)") +
25.   theme_minimal(base_size = 13) +
26.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
27.   plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
28.   axis.text = element_text(color = "black"),
29.   axis.title = element_text(face = "bold"))

Giải thích kỹ thuật: Từ dòng 1 đến 12, tạo một data.frame (HPG_metrics), dùng hàm mutate để tạo các chỉ số tài chính. Dòng 13 đến 15, tạo thêm một data.frame mới, dùng select để giữ 4 cột chính gồm: Nam, LN_rong, Roa, Roe, pivot_longer() để chuyển dữ liệu sang dạng dài. Từ dòng 16, vẽ biều đồ đường thể hiện xu hướng sinh lời với trục X là năm, trục Y là giá trị phần trăm (%). Ở dòng 20 dùng facet để chia biểu đồ thành 3 khung riêng biệt cho 3 loại chỉ số và mỗi biểu đồ nhỏ đều có trục Y riêng.

Nhận xét: Qua biểu đồ, thấy hiệu quả sinh lời của Hòa Phát có tính chu kỳ rõ nét. Giai đoạn từ năm 2015 đến 2020, các chỉ số duy trì ổn định ở mức cao, ROE khoảng 20–30% và ROA trên 10%, phản ánh khả năng sử dụng vốn và tài sản hiệu quả. Năm 2021 đạt đỉnh với ROE đạt 38% và ROA đạt 19,4%. Tuy nhiên, các chỉ số giảm mạnh xuống mức thấp nhất vào năm 2022 do giá thép lao dốc và chi phí sản xuất tăng. Những năm gần đầy, biên lợi nhuận cải thiện nhẹ cho thấy HPG đang phục hồi hiệu quả hoạt động. Có thể thấy doanh nghiệp có năng lực sinh lời tốt nhưng nhạy cảm với biến động chu kỳ thép, cần duy trì quản trị chi phí và đa dạng hóa sản phẩm để ổn định lợi nhuận dài hạn.

4.6 Biểu đồ phân tích đòn bẩy (D/E) vs hiệu quả vốn chủ sở hữu (ROE)

1. ggplot(HPG_metrics, aes(x = debt_to_equity, y = Roe)) +
2.   geom_point(aes(size = LN_SauThue, color = Nam), alpha = 0.7 ) +
3.   geom_text_repel(aes(label = Nam), size = 3.5, color = "black", box.padding = 0.5 ) +
4.   scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
5.   scale_x_continuous(labels = scales::number_format(accuracy = 0.1, suffix = "x")) +
6.   scale_size_continuous(range = c(3, 15), labels = scales::label_number(scale_cut = scales::cut_short_scale())) +
7.   scale_color_gradient(low = "#0288D1", high = "#D32F2F") +
8.   labs(title = "Phân tích đòn bẩy (D/E) vs hiệu quả vốn chủ sở hữu (ROE)",
9.     x = "Tỷ lệ Nợ / Vốn CSH",y = "Tỷ suất sinh lời trên vốn chủ sở hữu (ROE %)",
10.     size = "Quy mô lợi nhuận",color = "Năm") +
11.   theme_bw(base_size = 13) +
12.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),axis.text = element_text(color = "black"),
13.   axis.title = element_text(face = "bold"))

Giải thích kỹ thuật: Vẽ biểu đồ bong bóng từ data.frame (HPG_metrics) với trục X là tỷ lệ nợ trên vốn chủ sở hữu, trục Y là tỷ suất sinh lời. Với mỗi bong bóng thể hiện quy mô lợi nhuận sau thuế. Biểu đồ thêm nhãn năm cho từng điểm ở dòng 3. Dòng 4, 5 lần lượt hiển thị ROE theo tỷ lệ %, D/E theo dạng lần.

Nhận xét: Qua biểu đồ, từ giai đoạn từ năm 2015 đến 2018, HPG duy trì D/E thấp (<0,8) nhưng ROE vẫn cao trên 22% cho thấy doanh nghiệp sử dụng vốn chủ sở hữu hiệu quả mà không cần dựa quá nhiều vào nợ vay. Năm 2021 cả ROE (≈38%) và quy mô lợi nhuận đều đạt đỉnh, dù D/E tăng lên quanh 1,2 lần . Sau đó, những năm cuối, ROE giảm sâu về dưới 15% khi D/E liên tiếp dưới 1.0, cho thấy hiệu quả sử dụng vốn suy giảm. Có thể thấy, HPG đã kiểm soát mức dư nợ an toàn nhưng cần cải thiện hiệu quả sinh lời trên vốn chủ sở hữu để tối ưu hóa lợi nhuận.

4.7 Biểu đồ thể hiện hiệu quả tài sản

1.   df_plot <- HPG_metrics %>%
2.   filter(!is.na(TS_turnover) & !is.na(Roa)) %>%
3.   arrange(Nam)
4. corr_val <- cor(df_plot$TS_turnover, df_plot$Roa, use = "complete.obs")
5. corr_txt <- paste0("r = ", round(corr_val, 2))
6. df_plot <- df_plot %>%
7.   mutate(Size_asset = Tong_TS / 1e12)   
8. ggplot(df_plot, aes(x = TS_turnover, y = Roa)) +
9.   geom_point(aes(size = Size_asset, color = factor(Nam)), alpha = 0.85, stroke = 0.3) +
10.   geom_smooth(method = "lm", se = FALSE, color = "#D32F2F", linewidth = 1) +
11.   geom_text_repel(aes(label = Nam), size = 3.3, fontface = "bold", box.padding = 0.4, point.padding = 0.4, segment.size = 0.4) +
12.   geom_hline(yintercept = mean(df_plot$Roa, na.rm = TRUE), linetype = "dashed", color = "gray40")+
13.   geom_vline(xintercept = mean(df_plot$TS_turnover, na.rm = TRUE), linetype = "dashed", color = "gray40") +
14.   geom_rug(sides = "bl", alpha = 0.4, size = 0.4) +
15.   annotate("label", x = Inf, y = Inf, label = corr_txt, hjust = 1.1, vjust = 1.2, size = 4, fontface = "bold", fill = "white", color = "#D32F2F", label.r = unit(0.2, "lines")) +
16.   scale_x_continuous(name = "Vòng quay tổng tài sản (lần)", labels = number_format(accuracy = 0.01)) +
17.   scale_y_continuous(name = "ROA (%)", labels = percent_format(accuracy = 0.1)) +
18.   scale_size_continuous(name = "Quy mô tổng tài sản (nghìn tỷ)", range = c(3, 10)) +
19.   scale_color_viridis_d(option = "C", name = "Năm") +
20.   labs(title = "Hiệu quả sử dụng tài sản của HPG",
21.     caption = "Nguồn: Dữ liệu báo cáo tài chính HPG (2015–2024)") +
22.   theme_bw(base_size = 13) +
23.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13),
24.     plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
25.     axis.text = element_text(color = "black"),
26.     axis.title = element_text(face = "bold")) +   
27.   coord_fixed(ratio = 5.5)

Giải thích kỹ thuật: Dòng 1 đến 3 tạo 1 data.frame mới từ bộ dữ liệu HPG_metrics, sắp xếp các cột thoe năm để dễ quan sát. Dòng 4 ,5 dùng hàm cor() để tính hệ số tương quan Pearson giữa TS_turnover và Roa và dùng paste0() tạo chuỗi chữ “r = 0.xx” để hiển thị trên biểu đồ. Từ dòng 8 vẽ biểu đồ bong bóng với trục X thể hiện vòng quay tài sản (lần), trục Y thể hiện tỷ suất sinh lời trên tài sản (%) với mỗi điểm thể hiện 1 năm hoạt động của HPG và quy mô tổng tài sản. Dòng 10 vẽ đường hồi quy tuyến tính và ẩn vùng sai số để thể hiện mối quan hệ giữa vòng quay tài sản và ROA. Thêm đường trung bình ở 2 dòng 12, 13 lần lượt là đường trung bình của ROA và vòng quay tài sản.

Nhận xét: Biểu đồ cho thấy hệ số tương quan dương giữa 2 biến vòng quay tài sản và ROA khá chặt chẽ (r=0.65). Qua đó có thể khẳng định khi sử dụng tài sản hiệu quả hơn thì khả năng sinh lợi cũng tăng tương ứng. Giai đoạn từ năm 2015 đến 2018, doanh nghiệp duy trì mức ROA cao (trên 12%) và mức quay vòng tài sản nhanh. Đặc biệt, năm 2021 là đạt đỉnh cả về hiệu suất lẫn lợi nhuận. Nhưng những năm sau đó thì vòng quay tài sản và ROA đều giảm xuống mức thấp.

4.8 Biểu đồ phân tích khả năng chi trả nợ của HPG

1. debt_coverage <- HPG %>%
2.   mutate(debt_coverage_ratio = abs(LCTT_TC) / abs(LCTT_KD)) %>%
3.   filter(!is.na(debt_coverage_ratio))
4. mean_ratio <- mean(debt_coverage$debt_coverage_ratio, na.rm = TRUE)
5. ggplot(debt_coverage, aes(x = Nam, y = debt_coverage_ratio)) +
6.   geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = 1, ymax = Inf), fill = "#FFCDD2", alpha = 0.3, inherit.aes = FALSE) +
7.   geom_line(color = "#1565C0", linewidth = 1.3) +
8.   geom_point(aes(size = abs(LCTT_KD)), color = "#0D47A1", alpha = 0.8) +
9.   geom_hline(yintercept = 1, linetype = "dashed", color = "red", linewidth = 1) +
10.   geom_text_repel(aes(label = scales::percent(debt_coverage_ratio, accuracy = 1)), size = 3.8, fontface = "bold", color = "black", box.padding = 0.5) +
11.   geom_hline(yintercept = mean_ratio, color = "gray40", linetype = "dotted", linewidth = 1) +
12.   scale_y_continuous(labels = scales::percent_format(accuracy = 1), expand = expansion(mult = c(0.05, 0.2))) +
13.   labs(title = "Xu hướng khả năng chi trả nợ của HPG",
14.     x = "Năm",y = "Tỷ lệ chi trả Nợ (%)",size = "Quy mô dòng tiền HĐKD",
15.     caption = "Nguồn: Báo cáo Lưu chuyển tiền tệ HPG (2015–2024)") +
16.   theme_minimal(base_size = 13) +
17.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
18.     plot.subtitle = element_text(hjust = 0.25,size = 11, color = "gray40"),
19.     axis.text = element_text(color = "black"),
20.     axis.title = element_text(face = "bold"),
21.     panel.grid.minor = element_blank(),
22.     panel.grid.major = element_line(color = "gray85"),
23.     plot.background = element_rect(fill = "white", color = NA),
24.     legend.position = "bottom" ,
25.      plot.margin = margin(10, 40, 10, 10),   
26.     legend.margin = margin(t = 5, b = 5, l = 10, r = 30) ) +
27.   coord_cartesian(clip = "off")

Giải thích kỹ thuật: Dòng 1 tới 5, tạo data.frame (debt_coverage), dùng mutate để tạo biến debt_coverage_ratio. Sau đó tính trung bình biến đó ở dòng 6. Từ dòng 8, vẽ một vùng nền màu đỏ nhấn mạnh vùng an toàn, doanh nghiệp có khả năng trả nợ tốt. Dòng 9, 10 tạo đường xu hướng qua các nhau với điểm càng to khả năng trả nợ càng tốt. Dòng 11 tạo một đường ngang đỏ thể hiện ngưỡng an toàn chuẩn mực. Dòng 13 tạo một đường trung bình màu xám giúp doanh nghiệp xác định đang vượt hay thấp hơn trung bình toàn kỳ.

Nhận xét: Qua biểu đồ, xu hướng khả năng chi trả nợ của doanh nghiệp từ năm 2015 đến 2024 biến động khá mạnh. Mặc dù tỷ lệ chi trả nợ luôn dao động quanh mức an toàn nhưng vẫn có sự chênh lệch giữa các năm. Khi năm 2015 và 2024, mức chi trả nợ ở ngưỡng dồi dào thì năm 2020 và 2021 lại giảm sâu. Sau đấy thì tỷ lệ được phục hồi và duy trì ở ngưỡng an toàn.

4.9 Biểu đồ thể hiện mối tương quan trễ giữ Tái đầu tư (Năm T) vs Tăng trưởng doanh thu (Năm T+1)

1. lagged_profitability <- HPG_metrics %>%
2.   mutate(future_roe = lead(Roe, 1),Size_asset = Tong_TS / 1e12,
3.     current_margin = LN_rong) %>%
4.   select(Nam, current_margin, future_roe, Tong_TS, Size_asset) %>%
5.   drop_na()
6. ggplot(lagged_profitability, aes(x = current_margin, y = future_roe)) +
7.   geom_point(aes(size = Size_asset, fill = future_roe),color = "black", shape = 21, alpha = 0.8) +
8.   geom_smooth(method = "lm", se = FALSE, color = "#E64A19",linewidth = 1, linetype = "dashed") +
9.   geom_text_repel(aes(label = Nam), size = 3.8, color = "black", box.padding = 0.5, point.padding = 0.25, nudge_x = 0.005, max.overlaps = 10, force = 1.2) +
10.   scale_x_continuous(labels = percent_format(accuracy = 1), expand = expansion(mult = c(0.05, 0.1))) +
11.   scale_y_continuous(labels = percent_format(accuracy = 1), expand = expansion(mult = c(0.05, 0.1))) +
12.   scale_fill_gradient(low = "#A5D6A7", high = "#2E7D32", name = "ROE năm T+1") +
13.   scale_size_continuous(range = c(4, 14), name = "Tổng tài sản (nghìn tỷ)") +
14.   labs(title = "Mối tương quan trễ: Biên lợi nhuận ròng (Năm T) và ROE (Năm T+1)",subtitle = "Mối quan hệ giữa khả năng sinh lời hiện tại và hiệu quả vốn chủ sở hữu năm kế tiếp",
15.     x = "Biên lợi nhuận ròng (Năm T, %)",y = "ROE (Năm T+1, %)",
16.     caption = "Nguồn: Báo cáo tài chính HPG 2015–2024") +
17.  theme_minimal(base_size = 13) +
18.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13),
19.     plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
20.     axis.title = element_text(face = "bold"),
21.     axis.text = element_text(color = "black"),
22.     legend.position = "bottom",
23.     legend.box = "horizontal",
24.     legend.title = element_text(face = "bold"),
25.     panel.grid.minor = element_blank(),
26.     panel.grid.major = element_line(color = "gray85"),
27.     plot.background = element_rect(fill = "white", color = NA),
28.     plot.margin = margin(20, 30, 20, 30)) +
29.   coord_fixed(ratio = 1/4)

Giải thích kỹ thuật: dòng 1 tới 6 để tạo 1 data.frame (lagged_profitability), dùng mutate() để tạo 2 biến mới. Sau đó dùng select để chọn 5 biến chính: Nam, current_margin, future_roe, Tong_TS, Size_asset. Từ dòng 8, vẽ biểu đồ điểm (bong bóng) với trục X là biên lợi nhuận năm T, trục Y là ROE năm T+1, với điểm thể hiện quy mô tổng tài sản. Dòng 10 vẽ đường hồi quy tuyến tính giúp nhận biết xu hướng giữa biên lợi nhuận và ROE.

Nhận xét: Qua biểu đồ, đường xu hướng dương cho thấy biên lợi nhuận ròng trong năm hiện tại tăng sẽ kéo theo ROE cao trong năm kế tiếp, thể hiện mối quan hệ tích cực giữa khả năng sinh lời và hiệu quả sử dụng vốn của doanh nghiệp. Từ giai đoạn năm 2016 đến 2020, các điểm đều nằm phía trên hoặc gần đường xu hướng, chứng tỏ HPG duy trì được hiệu quả sinh lợi ổn định và bền vững nhưng từ năm 2022 thì biên lợi nhuận ròng giảm xuống quanh 5%, kéo theo ROE năm sau chỉ còn khoảng 10%, cho thấy tác động trễ tiêu cực của suy giảm lợi nhuận.Có thể thấy, doanh nghiệp vẫn duy trì nền tảng tài chính tốt, nhưng cần phục hồi biên lợi nhuận để tái tạo hiệu quả vốn chủ sở hữu trong chu kỳ kinh doanh tiếp theo.

4.10 Biểu đồ phân tích Lưu chuyển tiền thuần và Lợi nhuận sau thuế

1. cash_profit <- HPG %>%
2.   select(Nam, LCTT_KD, LCTT_DT, LCTT_TC, LN_SauThue) %>%
3.   mutate(Tong_LCTT = LCTT_KD + LCTT_DT + LCTT_TC)
4. ggplot(cash_profit, aes(x = factor(Nam))) +
5.   geom_col(aes(y = LCTT_KD / 1e9, fill = "HĐ Kinh doanh"), alpha = 0.85, width = 0.6) +
6.   geom_col(aes(y = LCTT_DT / 1e9, fill = "HĐ Đầu tư"), alpha = 0.85, width = 0.6) +
7.   geom_col(aes(y = LCTT_TC / 1e9, fill = "HĐ Tài chính"), alpha = 0.85, width = 0.6) +
8.   geom_line(aes(y = LN_SauThue / 1e9, group = 1, color = "Lợi nhuận sau thuế"), linewidth = 1.2) +
9.   geom_point(aes(y = LN_SauThue / 1e9, color = "Lợi nhuận sau thuế"), size = 3) +
10.   geom_text(aes(y = LN_SauThue / 1e9, label = round(LN_SauThue / 1e9, 1)), vjust = -1, size = 3.5, color = "black", fontface = "bold", stroke = 0.2) +
11.   scale_fill_manual(values = c("HĐ Kinh doanh" = "#4CAF50", "HĐ Đầu tư" = "#81D4FA", "HĐ Tài chính" = "#FFB74D"), name = "Lưu chuyển tiền thuần") +
12.   scale_color_manual(values = c("Lợi nhuận sau thuế" = "#C62828"), name = "") +
13.   scale_y_continuous(labels = label_number(suffix = " Tỷ", big.mark = ","),
14.     limits = c(min(cash_profit$LCTT_DT, na.rm = TRUE)/1e9 * 1.2, max(cash_profit$LN_SauThue, na.rm = TRUE)/1e9 * 1.3)) +
15.   labs(title = "Phân tích lưu chuyển tiền thuần và lợi nhuận sau thuế của HPG",
16.     subtitle = "So sánh giữa lợi nhuận kế toán và dòng tiền thực tế qua các năm",
17.     x = "Năm",y = "Giá trị (Tỷ đồng)") +
18.   theme_minimal(base_size = 13) +
19.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
20.     plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
21.     axis.text = element_text(color = "black"),
22.     axis.title = element_text(face = "bold"),
23.     legend.position = "bottom",
24.     legend.box = "horizontal",              
25.     legend.text = element_text(size = 11),
26.     legend.title = element_text(size = 11, face = "bold"),
27.     panel.grid.minor = element_blank(),
28.     panel.grid.major.x = element_blank(),
29.     plot.margin = margin(10, 30, 0, 0)) +
30.   coord_cartesian(clip = "off")  

Giải thích kỹ thuật: Dòng 1 tới 3, tạo data.frame (cash_profit) dùng select để chọn những biến từ dòng tiền và lợi nhuận thuần, dùng mutate () để tạo biến tổng 3 dòng tiền. Từ dòng 4, vẽ 3 biểu đồ cột dòng tiền chồng lên nhau với trục X là năm, trục Y đơn vị tỷ đồng. Dòng 8, 9 để vẽ đường lợi nhuận kế toán đánh dấu lợi nhuận nổi bật qua từng năm.

Nhận xét: Qua biểu đồ, cho thấy sự khác biệt rõ giữa lợi nhuận kế toán và dòng tiền thực tế. Từ giai đoạn năm 2015 đến 2020, lợi nhuận tăng đều nhờ hoạt động sản xuất ổn định nhưng dòng tiền đầu tư âm mạnh cho thấy doanh nghiệp tập trung mở rộng quy mô. Năm 2021 đánh dấu đỉnh lợi nhuận (34,5 nghìn tỷ) cùng dòng tiền kinh doanh doanh cao, phản ánh giai đoạn tích cực của chu kỳ thép. Tuy nhiên, từ năm 2022 đến 2024, dù lợi nhuận giảm và phục hồi nhẹ nhưng dòng tiền đầu tư tiếp tục âm sâu cho thấy HPG vẫn tái đầu tư mạnh vào tài sản cố định.

4.11 Biểu đồ thể hiện mối tương quan giữa Tổng tài sản và Lợi nhuận sau thuế

1. ggplot(HPG, aes(x = Tong_TS / 1e3, y = LN_SauThue / 1e3)) +
2.   geom_point(aes(color = Nam, size = DoanhThu), alpha = 0.8) +  
3.   stat_smooth(method = "lm", se = TRUE, color = "black") +    
4.   labs(title = "Mối quan hệ giữa Tổng tài sản và Lợi nhuận HPG",
5.        x = "Tổng tài sản (tỷ đồng)",y = "Lợi nhuận sau thuế (tỷ đồng)",
6.        color = "Năm", size = "Doanh thu") +                   
7.   theme_minimal(base_size = 13) +
8.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
9.     plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
10.     axis.text = element_text(color = "black"),
11.     axis.title = element_text(face = "bold"),
12.     panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 2 dùng để vẽ đồ thị scatter plot với trục X là tổng tài sản, trục Y là lợi nhuận sau thuế. Mỗi điểm trên biểu đồ ứng với 1 năm hoạt đông của HPG và quy mô doanh thu. Ở dòng số 3 vễ đường hồi quy tuyến tính để xem xu hướng giữa tổng tài sản và lợi nhuận, trong đó se = TRUE để hiển thị vùng sai số quanh đường hổi quy.

Nhận xét: Biểu đồ thể hiện mối quan hệ giữa tổng tài sản và lợi nhuận sau thuế của doanh nghiệp là tương quan thuận khi tổng tài sản tăng thì lợi nhuận sau thuế cũng tăng theo. Từ giai đoạn năm 2015 đến 2021, lợi nhuận tăng nhanh cùng tốc độ mở rộng tài sản nhưng sau năm 2022, dù tài sản tiếp tục tăng mà lợi nhuận lại giảm cho thấy hiệu suất sử dụng tài sản chưa tối ưu trong bối cảnh nhu cầu và giá thép suy yếu.

4.12 Biểu đồ so sánh lợi nhuận thuần với dòng tiền hoạt động kinh doanh

1. ggplot(HPG, aes(x = LN_SauThue, y = LCTT_KD)) +
2.   geom_point(aes(color = Nam, size = DoanhThu), alpha = 0.8) +
3.   geom_smooth(method = "lm", se = FALSE, color = "darkgreen") +
4.   geom_abline(intercept = 0, slope = 1, linetype = "dashed", color = "gray40") +
5.   geom_text_repel(aes(label = Nam), size = 3.5) +
6.   scale_x_continuous(labels = label_number(scale_cut = cut_short_scale())) +
7.   scale_y_continuous(labels = label_number(scale_cut = cut_short_scale())) +
8.   scale_color_gradient(low = "#56B1F7", high = "#132B43") +
9.   
10.   labs(title = "Phân tích chất lượng lợi nhuận của HPG",
11.     subtitle = "So sánh Lợi nhuận sau thuế với Dòng tiền từ hoạt động kinh doanh",x = "Lợi nhuận sau thuế (VND)",y = "Dòng tiền từ HĐKD (VND)",
12.     color = "Năm",size = "Doanh thu") +
13.     theme_minimal(base_size = 13) +
14.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
15.     plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
16.     axis.text = element_text(color = "black"),
17.     axis.title = element_text(face = "bold"),
18.     legend.position = "bottom",
19.     legend.text = element_text(angle = 90, size = 10),
20.     panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 2 dùng để vẽ đồ thị scatter plot với trục x là lợi nhuận sau thuế, trục y là dòng tiền từ hoạt động kinh doanh. Dòng 5 vẽ một đường hồi quy tuyến tính giữa 2 biến cho biết xu hướng giữa lợi nhuận và dòng tiền. Và để đánh giá tốt hơn, ở dòng 6 vẽ thêm 1 đường thẳng qua gốc toạ độ với góc 45°hay gọi là đường lợi nhuận lý tưởng khi dòng tiền = lợi nhuận.

Nhận xét: Qua biểu đồ, có thể thấy mối quan hệ giữa lợi nhuận thuần và dòng tiền từ kinh doanh có xu hướng tuyến tính mạnh và tích cực. Phần lớn các điểm dữ liệu nằm gần đường 45 độ chứng tỏ lợi nhuận kế toán tương đồng với dòng tiền thực thu. Trong giai đoạn từ năm 2015 đến 2020, lợi nhuận và dòng tiền tăng song song, đặc biệt tại năm 2021 cả hai cùng đạt đỉnh, phản ánh giai đoạn kinh doanh hiệu quả và có tính thanh khoản cao. Các năm 2022 và 2024, dòng tiền vẫn duy trì ổn định dù lợi nhuận giảm, cho thấy năng lực tạo tiền của doanh nghiệp ít bị ảnh hưởng trong bối cảnh thị trường suy yếu.

4.13 Biểu đồ thể hiện phân phối lợi nhuận sau thuế

1. library(e1071)
2. skew_LN <- skewness(HPG$LN_SauThue, na.rm = TRUE)
3. kurt_LN <- kurtosis(HPG$LN_SauThue, na.rm = TRUE)
4. mean_LN <- mean(HPG$LN_SauThue / 1e9, na.rm = TRUE)
5. ggplot(HPG, aes(x = LN_SauThue / 1e9)) +
6.   geom_histogram(aes(y = ..density..), bins = 10, alpha = 0.7, fill = "skyblue",color = "white") +
7.   geom_density(aes(color = "Đường mật độ"), size = 1.2, adjust = 1.2) +  
8.   geom_vline(aes(xintercept = mean_LN, color = "Trung bình"),linetype = "dashed", linewidth = 1) +
9.   labs(title = paste0("Phân phối lợi nhuận sau thuế của HPG\n(Skew = ", 
10.                    round(skew_LN, 2), ", Kurt = ", round(kurt_LN, 2), ")"),
11.     x = "Lợi nhuận sau thuế (tỷ đồng)",y = "Mật độ (Density)",color = "Chú thích") +
12.   scale_color_manual(values = c("Đường mật độ" = "red", "Trung bình" = "black")) + 
13.   theme_minimal(base_size = 13) +
14.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
15.     plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
16.     axis.text = element_text(color = "black"),
17.     axis.title = element_text(face = "bold"),
18.     legend.position = "bottom",
19.     panel.grid.minor = element_blank())

Giải thích kỹ thuật: Từ dòng 2 đến 4 tính các đặc trưng thống kê gồm độ lệch, độ nhọn, giá trị trung bình. Từ dòng 5 trở đi dùng để vẽ biểu đồ histogram để thể hiện phân phối tần suất lợi nhuận từng năm. Sau đó vẽ 1 đường mật độ xác suất ở dòng 7 để giúp xác định tổng quát dạng phân phối và vẽ thêm 1 đường trung bình nét đứt tại điểm trung bình ở dòng 8.

Nhận xét: Biểu đồ phân phối lợi nhuận sau thuế của Hòa Phát (HPG) cho thấy dữ liệu có độ lệch phải (Skew = 1.78), tức là phần lớn giá trị tập trung ở mức thấp, trong khi một số năm đạt lợi nhuận rất cao kéo đuôi phân phối sang bên phải. Độ nhọn (Kurtosis = 2.11) ở mức dưới 3 cho thấy phân phối có đỉnh thấp và phân tán rộng hơn so với phân phối chuẩn. Điều này phản ánh lợi nhuận của HPG biến động mạnh giữa các năm, không ổn định và có xu hướng có một vài năm đột biến cao về lợi nhuận.

Kết luận: Phân phối lợi nhuận sau thuế của HPG không tuân theo dạng chuẩn mà bị lệch phải và có phân tán rộng, phản ánh mức độ rủi ro nhất định trong hoạt động kinh doanh. Doanh nghiệp có thể trải qua giai đoạn tăng trưởng bùng nổ nhưng cũng có thể gặp thời kỳ suy giảm mạnh, đòi hỏi nhà đầu tư cần đánh giá kỹ chu kỳ ngành và chiến lược quản trị rủi ro của Hòa Phát khi ra quyết định đầu tư.

4.14 Biểu đồ thể hiện cơ cấu tài sản theo năm

1. HPG_area <- HPG %>%
2.   mutate(TS_NganHan = TS_NganHan / Tong_TS * 100,
3.          TS_DaiHan = TS_DaiHan / Tong_TS * 100) %>%
4.   select(Nam, TS_NganHan, TS_DaiHan) %>%
5.   pivot_longer(cols = c(TS_NganHan, TS_DaiHan), names_to = "LoaiTaiSan", values_to = "TyLe")
6. HPG_area$LoaiTaiSan <- recode(HPG_area$LoaiTaiSan,"TS_NganHan" = "Tài sản ngắn hạn","TS_DaiHan" = "Tài sản dài hạn")
7. ggplot(HPG_area, aes(x = factor(Nam), y = TyLe, fill = LoaiTaiSan)) +
8.   geom_bar(stat = "identity", position = position_dodge(width = 0.8), width = 0.7) +
9.   geom_text(aes(label = round(TyLe, 1)),position = position_dodge(width = 0.8), vjust = -0.3, size = 3.5, color = "black") +
10.   scale_fill_manual(values = c("steelblue", "darkorange")) +
11.   labs(title = "Biểu đồ cơ cấu Tài sản ngắn hạn và dài hạn theo năm",
12.        x = "Năm", y = "Tỷ trọng (%)",fill = "Loại tài sản") +
13.   theme_minimal(base_size = 13) +
14.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 14),
15.     axis.title = element_text(face = "bold"),
16.     axis.text.x = element_text(angle = 45, hjust = 1),
17.     legend.position = "bottom")

Giải thích kỹ thuật: Từ dòng 1 đến 5, tạo một data.frame (HPG_area) và dùng hàm mutate tạo các biến tỷ trọng tài sản ngắn hạn, dài hạn, dùng select để chọn 3 biến chính, ppivot_longer() để chuyển dữ liệu sang dạng dài. Dòng thứ 6 dùng để đổi tên các loại tài sản. Từ dòng 7 dùng để vẽ biểu đồ cột với trục X là năm, truc Y là tỷ lệ (%), và cột xanh là tài sản ngắn hạn, cột cam là tài sản dài hạn. Dòng 9 dùng để hiển thị giá trị % trên cột, làm tròn 1 chữ số.

Nhận xét: Biểu đồ thể hiện sự thay đổi rõ rệt về chiến lược phân bổ nguồn lực qua từng năm. Từ giai đoạn năm 2015 đến 2017, tỷ trọng tài sản ngắn hạn và dài hạn khá cân bằng, phản ánh mô hình hoạt động ổn định. Trong 2 năm 2018 và 2019, tài sản dài hạn tăng mạnh và đạt mức 67,6% ở năm 2019, cho thấy HPG tập trung vốn đầu tư vào mở rộng công suất sản xuất. Tuy nhiên từ năm 2020 trở đi, xu hướng đảo chiều khi tỷ trọng tài sản ngắn hạn tăng trở lại khi đạt 61,4% vào năm 2024, thể hiện doanh nghiệp chuyển trọng tâm sang quản trị vốn lưu động và duy trì thanh khoản. Có thể thấy, HPG đang cân bằng giữa đầu tư dài hạn và hiệu quả ngắn hạn, giúp nâng cao khả năng linh hoạt tài chính và ổn định hoạt động trong bối cảnh ngành thép đầy biến động.

4.15 Biểu đồ thể hiện mức độ tài chính doanh nghiệp

1. HPG_avg <- HPG %>%
2.   summarise(DoanhThu = mean(DoanhThu, na.rm = TRUE),LN_SauThue = mean(LN_SauThue, na.rm = TRUE),Tong_TS = mean(Tong_TS, na.rm = TRUE),No_PhaiTra = mean(No_PhaiTra, na.rm = TRUE),Von_CSH = mean(Von_CSH, na.rm = TRUE))
3. HPG_avg_scaled <- as.data.frame(t(HPG_avg / max(HPG_avg) * 100))
4. colnames(HPG_avg_scaled) <- "Giá trị (%)"
5. HPG_avg_scaled$ChỉTiêu <- rownames(HPG_avg_scaled)
6. ggplot(HPG_avg_scaled, aes(x = reorder(ChỉTiêu, `Giá trị (%)`), y = `Giá trị (%)`)) +
7.   geom_bar(stat = "identity", fill = "#0072BC", alpha = 0.7, width = 0.6) +
8.   geom_text(aes(label = round(`Giá trị (%)`, 1)), hjust = -0.1, size = 4.2) +
9.   coord_flip() +
10.   scale_y_continuous(limits = c(0, 110), breaks = seq(0, 100, 25)) +
11.   labs(title = "Biểu đồ thanh: Cấu trúc tài chính trung bình của HPG",
12.     x = "Chỉ tiêu tài chính",y = "Tỷ lệ chuẩn hóa (%)") +
13.   theme_minimal(base_size = 13) +
14.   theme(plot.title = element_text(face = "bold", hjust = 0.5),
15.     axis.title = element_text(face = "bold"),
16.     axis.text = element_text(color = "black"))

Giải thích kỹ thuật: Từ dòng 1 đến 7, tạo một data.frame (HPG_avg) và dùng hàm summarise () để tính giá trị trung bình của các biến. Sau đấy ở dòng 8, chuẩn hóa các giá trị trung bình của từng biến theo phần trăm của giá trị lớn nhất trong dataframe. Từ dòng 11 đến 15 vẽ biểu đồ thanh ngang với truc Y là tỷ lệ chuẩn hóa và trục X là tên các chỉ tiêu vì dùng hàm coord_flip() để hoán trục X/Y.

Nhận xét: Biểu đồ cho thấy cấu trúc tài chính trung bình của Hòa Phát (HPG) được duy trì ở mức cân đối và ổn định. Tổng tài sản được chuẩn hóa ở mức 100%, trong đó doanh thu đạt khoảng 76%, phản ánh hiệu quả khai thác tài sản khá cao. Vốn chủ sở hữu (52,8%) và nợ phải trả (47,2%) tỷ lệ gần tương đương, thể hiện cơ cấu nguồn không quá phụ thuộc vào đòn bẩy tài chính. Lợi nhuận sau thuế đạt trung bình 9,6%, cho thấy biên lợi nhuận ròng của doanh nghiệp ở mức tốt so với đặc thù ngành thép vốn có biên lợi nhuận thấp. Có thể thấy, HPG duy trì tài chính vững vàng, khả năng sinh lợi ổn định và kiểm soát tốt mức dư nợ tạo nền tảng an toàn cho các chiến lược tăng trưởng dài hạn.

4.16 Biểu đồ tương quan giữa các chỉ số tài chính

1. HPG_ratio_alt <- HPG %>%
2.   mutate(Prev_DoanhThu = lag(DoanhThu, 1),Revenue_Growth = (DoanhThu - Prev_DoanhThu) / Prev_DoanhThu,Debt_to_Assets = No_PhaiTra / Tong_TS,Equity_to_Assets = Von_CSH / Tong_TS,Working_Capital = TS_NganHan - No_PhaiTra,Working_Capital_Turnover = DoanhThu / (TS_NganHan - No_PhaiTra)) %>%
3.   select(Debt_to_Assets, Equity_to_Assets, Working_Capital, Working_Capital_Turnover, Revenue_Growth) %>%
4.   drop_na()
5. corr_alt <- cor(HPG_ratio_alt, use = "complete.obs")
6. library(ggcorrplot)
7. ggcorrplot(corr_alt,hc.order = TRUE,lab = TRUE,lab_size = 3,type = "full",
8. ggtheme = ggplot2::theme_minimal(),
9. colors = c("#D32F2F", "white", "#0288D1"),
10. title = "Ma trận Tương quan giữa các Chỉ số Tài chính") +
11. 
12. labs(title = "Heatmap Tương quan: Các Chỉ số Tài chính") +
13.   theme_minimal(base_size = 13) +
14.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13),axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1, color = "black"),axis.text.y = element_text(color = "black"))

Giải thích kỹ thuật: Từ dòng 1 đến 12, tạo một data.frame có các biến chỉ số tài chính được tạo bằng lệnh mutate gồm: Prev_DoanhThu, Revenue_Growth, Debt_to_Assets, Equity_to_Assets, Working_Capital, Working_Capital_Turnover và dùng select () ở dòng 10 để giữ lại 5 biến. Dòng 13 dùng hàm cor() để tính hệ số tương quan Pearson giữa các cặp biến. Từ dòng 15, 16 được dùng để vẽ biểu đồ nhiệt và sắp xếp các biến có mối quan hệ gần nhau, trong đó ô màu đỏ thể hiện mối tương quan âm, ô trắng thể hiện trung tính, ô xanh thể hiện mối tương quan dương.

Nhận xét: Biểu đồ cho thấy mối quan hệ rõ ràng giữa cơ cấu vốn, tăng trưởng và hiệu quả hoạt động. Debt_to_Assets và Equity_to_Assets có tương quan âm cao (-1), phản ánh quy luật tất yếu giữa nợ và vốn chủ sở hữu trong tổng tài sản. Trong khi đó, Debt_to_Assets tương quan dương mạnh với Revenue_Growth (0,45), cho thấy việc sử dụng nợ hợp lý giúp HPG thúc đẩy tăng trưởng doanh thu. Ngược lại, Working_Capital có tương quan âm (-0,73) với Debt_to_Assets, cho thấy khi đòn bẩy tăng, vốn lưu động bị thu hẹp. Mức tương quan yếu giữa Working_Capital_Turnover và các biến khác hàm ý rằng hiệu quả quay vòng vốn không phụ thuộc nhiều vào cấu trúc tài chính.

4.17 Biểu đồ cột chồng phân tích biên lợi nhuận gộp

1. cost_structure_pct <- HPG %>%
2.   select(Nam, GiaVon, LN_Gop) %>%
3.   pivot_longer(cols = c(GiaVon, LN_Gop), names_to = "Thanh_phan", values_to = "So_tien") %>%
4.   group_by(Nam) %>%
5.   mutate(Tong = sum(So_tien),pct = So_tien / Tong) %>%
6.   ungroup()
7. ggplot(cost_structure_pct, aes(x = factor(Nam), y = pct, fill = Thanh_phan)) +
8.   geom_col(position = "fill", width = 0.7, color = "white") +
9.   geom_text(aes(label = ifelse(pct >= 0.03, percent(pct, accuracy = 1), "")),position = position_fill(vjust = 0.5),size = 3.8,color = "white",fontface = "bold") +
10.   scale_fill_manual(values = c("GiaVon" = "#E57373", "LN_Gop" = "#4CAF50"),labels = c("Giá vốn hàng bán", "Lợi nhuận gộp")) +
11.   scale_y_continuous(labels = percent_format(accuracy = 1)) +
12.   labs(title = "Phân tích biên lợi nhuận gộp",subtitle = "Tỷ lệ của giá vốn và lợi nhuận gộp theo từng năm",x = "Năm",y = "Tỷ lệ (%)",fill = "Thành phần") +
13.   theme_minimal(base_size = 13) +
14.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13),
15.     plot.subtitle = element_text(hjust = 0.5, color = "gray40", size = 11),
16.     axis.text = element_text(color = "black"),
17.     axis.title = element_text(face = "bold"),
18.     legend.position = "bottom",
19.     panel.grid.major.x = element_blank())

Giải thích kỹ thuật: Từ dòng 1 đến dòng 7, lập một data.frame (cost_structure_pct), dùng hàm select () để chọn 3 biến gồm: Nam, GiaVon, LN_Gop, sau đó dùng pivot_longer() để chuyển dạng dữ liệu sang dạng dài. Dùng group_by() để tính toán theo năm, và tạo 2 biến mới Tong = tổng số tiền và pct = So_tien / Tong để tính tỷ lệ phần trăm của từng thành phần. Trước khi vẽ ungroup (), dòng 8, 9 vẽ biểu đồ cột chồng với tỷ lệ % với trục X là năm, trục Y là tỷ lệ phần trăm, mỗi cột tổng 100% và chia thành 2 vùng: Giá vốn (đỏ), Lợi nhuận gộp (Xanh). Từ dòng 11 đến 15, gán nhãn % cho mỗi cột, với định dạng làm tròn 1 chữ số.

Nhận xét: Biểu đồ cho thấy xu hướng thay đổi đáng kể theo chu kỳ giá thép. Trong giai đoạn từ năm 2015 đến 2020, biên lợi nhuận gộp duy trì ổn định quanh mức 20–26%, phản ánh hoạt động sản xuất ổn định và khả năng kiểm soát chi phí tốt. Năm 2021 ghi nhận đỉnh cao 27%, nhờ giá thép tăng mạnh và chi phí nguyên liệu được kiểm soát hiệu quả. Tuy nhiên, từ năm 2022 trở đi, biên lợi nhuận giảm mạnh xuống dưới 14% nhu cầu thị trường suy yếu. Mặc dù có phục hồi nhẹ vào 2024, mức biên này vẫn thấp hơn trung bình giai đoạn trước.