PHÂN TÍCH BỘ DỮ LIỆU NEW RETAIL DATA
VÀ PHÂN TÍCH CÁC CHỈ TIÊU TÀI CHÍNH CỦA CTCP TẬP ĐOÀN HÒA PHÁT (HPG) 2015-2024


Giảng viên hướng dẫn: ThS. Trần Mạnh Tường

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.

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 RETAIL DATA

Chương 1: Giới thiệu dữ liệu

1.1 Đọc dữ liệu

1. library(readr)
2. unzip("C:/Users/HP/Downloads/archive (3).zip", exdir = "C:/Users/HP/Downloads/archive_data")
3. data <- read_csv("C:/Users/HP/Downloads/archive_data/new_retail_data.csv")
4. head(data)
## # 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 tôi gọi thư viện readr để sử các hàm đọc dữ liệu csv. Tiếp theo,file nén gốc “archive (3).zip” được giải nén vào thư mục “achive_data” bằng hàm unzip(), cho phép được truy cập file bên trong.Sau đó, file CSV “new_retail_data.csv” sẽ đọc vào R bằng read_csv() và được lưu dưới tên data. Và để xem dữ liệu được đọc đúng chưa tôi dùng lệnh head(data) để hiện thị 6 dòng đầu tiên.

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

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

1. head(data,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(data,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(data)
## [1] 302010     30

Theo kết quả chạy lệnh dim(data) 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ến của dữ liệu

1. names(data)
##  [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 (data)
## 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>

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(data, 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

Bảng giá trị duy nhất

1. options(repos = c(CRAN = "https://cloud.r-project.org"))
2. library(dplyr)
3. library(flextable)
4. unique_info <- data.frame(
5.   Bien = names(data),
6.   So_luong_gia_tri = sapply(data, function(x) length(unique(x))),
7.   Gia_tri_cu_the = sapply(data, function(x) {
8.     vals <- unique(x)
9.     vals <- vals[!is.na(vals)]
10.     if (length(vals) > 5) {
11.       paste(paste(vals[1:5], collapse = ", "), "...", sep = "")} else {paste(vals, collapse = ", ")}}),stringsAsFactors = FALSE)
12. ft <- flextable(unique_info)
13. ft <- theme_vanilla(ft)
14. ft <- bold(ft, part = "header")
15. ft <- fontsize(ft, size = 9, part = "all")
16. ft <- align(ft, align = "left", part = "all")
17. ft <- set_table_properties(ft, layout = "fixed")
18. ft <- width(ft, j = "Bien", width = 2)
19. ft <- width(ft, j = "So_luong_gia_tri", width = 1.2)
20. ft <- width(ft, j = "Gia_tri_cu_the", width = 4)  
21. ft <- height_all(ft, height = 0.3)
22. ft <- set_caption(ft, "Bảng: Giá trị duy nhất của từng biến trong bộ dữ liệu")
23. ft
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

294,462

8691788, 2174773, 6679610, 7232460, 4983775...

Customer_ID

86,767

37249, 69749, 30192, 62101, 27901...

Name

159,391

Michelle Harrington, Kelsey Hill, Scott Jensen, Joseph Miller, Debra Coleman...

Email

52,898

Ebony39@gmail.com, Mark36@gmail.com, Shane85@gmail.com, Mary34@gmail.com, Charles30@gmail.com...

Phone

299,296

1414786801, 6852899987, 8362160449, 2776751724, 9098267635...

Address

299,330

3959 Amanda Burgs, 82072 Dawn Centers, 4133 Young Canyon, 8148 Thomas Creek Suite 100, 5813 Lori Ports Suite 269...

City

131

Dortmund, Nottingham, Geelong, Edmonton, Bristol...

State

55

Berlin, England, New South Wales, Ontario, Virginia...

Zipcode

93,979

77985, 99071, 75929, 88420, 48704...

Country

6

Germany, UK, Australia, Canada, USA

Age

54

21, 19, 48, 56, 22...

Gender

3

Male, Female

Income

4

Low, High, Medium

Customer_Segment

4

Regular, Premium, New

Date

367

9/18/2023, 12/31/2023, 4/26/2023, 5/8/2023, 1/10/2024...

Year

3

2023, 2024

Month

13

September, December, April, May, January...

Time

83,678

22:03:55, 08:42:04, 04:06:29, 14:55:17, 16:54:07...

Total_Purchases

11

3, 2, 7, 4, 1...

Amount

299,298

108.0287567, 403.3539073, 354.4775997, 352.4077173, 124.2765245...

Total_Amount

299,306

324.08627, 806.7078147, 1063.432799, 2466.854021, 248.5530491...

Product_Category

6

Clothing, Electronics, Books, Home Decor, Grocery

Product_Brand

19

Nike, Samsung, Penguin Books, Home Depot, Nestle...

Product_Type

33

Shorts, Tablet, Children's, Tools, Chocolate...

Feedback

5

Excellent, Average, Bad, Good

Shipping_Method

4

Same-Day, Standard, Express

Payment_Method

5

Debit Card, Credit Card, PayPal, Cash

Order_Status

5

Shipped, Processing, Pending, Delivered

Ratings

6

5, 4, 2, 1, 3

products

318

Cycling shorts, Lenovo Tab, Sports equipment, Utility knife, Chocolate cookies...

Giải thích kỹ thuật: tôi gọi hai thư viện: dplyr để xử lý dữ liệu và flextable để trình bày kết quả dữ liệu. Dòng 4 dùng để khởi tạo một bảng mới để lưu thông tin về từng biến trong dữ liệu. Dòng 5 cột đầu tiền dùng để lưu tên từng biến. Dòng 6 dùng để đếm số lượng giá trị khác nhau trong mỗi biến để nhận biết nó đa dạng hay ít thay đổi. Dòng 7 tạo thêm cột để hiển thị một số giá trị cụ thể của biến. Dòng 10 dùng để giới hạn giá trị của biến hiển thị nếu có quá nhiều chỉ hiển thị 5 giá trị đầu tiên nếu ít thì hiển thị toàn bộ.

Bảng mô tả ý nghĩa các biến

1. library(flextable)
2. library(dplyr)
3. variable_description <- data.frame(
4.   Bien = c(
5.     "Transaction_ID", "Customer_ID", "Name", "Email", "Phone", "Address", 
6.     "City", "State", "Zipcode", "Country", "Age", "Gender", "Income", 
7.     "Customer_Segment", "Date", "Year", "Month", "Time", "Total_Purchases", 
8.     "Amount", "Total_Amount", "Product_Category", "Product_Brand", 
9.     "Product_Type", "Feedback", "Shipping_Method", "Payment_Method", 
10.     "Order_Status", "Ratings", "Products"
11.   ),
12.   YNghia = c(
13.     "Mã giao dịch duy nhất cho mỗi đơn hàng.",
14.     "Mã khách hàng duy nhất để định danh từng người mua.",
15.     "Tên khách hàng thực hiện giao dịch.",
16.     "Địa chỉ email của khách hàng.",
17.     "Số điện thoại liên hệ của khách hàng.",
18.     "Địa chỉ nơi khách hàng sinh sống hoặc giao hàng.",
19.     "Thành phố nơi khách hàng sinh sống.",
20.     "Tỉnh hoặc bang tương ứng với địa chỉ khách hàng.",
21.     "Mã bưu điện của địa chỉ khách hàng.",
22.     "Quốc gia của khách hàng.",
23.     "Độ tuổi của khách hàng.",
24.     "Giới tính của khách hàng (Nam/Nữ).",
25.     "Thu nhập của khách hàng.",
26.     "Phân khúc khách hàng.",
27.     "Ngày giao dịch diễn ra.",
28.     "Năm thực hiện giao dịch.",
29.     "Tháng thực hiện giao dịch.",
30.     "Thời gian cụ thể của giao dịch.",
31.     "Tổng số lần mua hàng của khách trong khoảng thời gian nhất định.",
32.     "Số tiền của đơn hàng hiện tại.",
33.     "Tổng số tiền khách hàng đã chi tiêu trong toàn bộ thời gian mua hàng.",
34.     "Danh mục sản phẩm mà khách hàng đã mua.",
35.     "Thương hiệu sản phẩm mà khách hàng đã mua.",
36.     "Loại sản phẩm chi tiết trong danh mục.",
37.     "Phản hồi hoặc đánh giá bằng lời từ khách hàng.",
38.     "Phương thức vận chuyển được lựa chọn.",
39.     "Phương thức thanh toán.",
40.     "Trạng thái đơn hàng.",
41.     "Đánh giá sao khách hàng dành cho sản phẩm/dịch vụ.",
42.     "Tên sản phẩm chi tiết mà khách hàng đã mua."))
43. ft2 <- flextable(variable_description)
44. ft2 <- theme_vanilla(ft2)
45. ft2 <- bold(ft2, part = "header")
46. ft2 <- fontsize(ft2, size = 10, part = "all")
47. ft2 <- align(ft2, align = "left", part = "all")
48. ft2 <- width(ft2, j = "Bien", width = 2.8)
49. ft2 <- width(ft2, j = "YNghia", width = 10)
50. ft2 <- autofit(ft2)
51. ft2 <- set_caption(ft2, "Bảng: Mô tả ý nghĩa các biến trong bộ dữ liệu")
52. ft2
Bảng: Mô tả ý nghĩa các biến trong bộ dữ liệu

Bien

YNghia

Transaction_ID

Mã giao dịch duy nhất cho mỗi đơn hàng.

Customer_ID

Mã khách hàng duy nhất để định danh từng người mua.

Name

Tên khách hàng thực hiện giao dịch.

Email

Địa chỉ email của khách hàng.

Phone

Số điện thoại liên hệ của khách hàng.

Address

Địa chỉ nơi khách hàng sinh sống hoặc giao hàng.

City

Thành phố nơi khách hàng sinh sống.

State

Tỉnh hoặc bang tương ứng với địa chỉ khách hàng.

Zipcode

Mã bưu điện của địa chỉ khách hàng.

Country

Quốc gia của khách hàng.

Age

Độ tuổi của khách hàng.

Gender

Giới tính của khách hàng (Nam/Nữ).

Income

Thu nhập của khách hàng.

Customer_Segment

Phân khúc khách hàng.

Date

Ngày giao dịch diễn ra.

Year

Năm thực hiện giao dịch.

Month

Tháng thực hiện giao dịch.

Time

Thời gian cụ thể của giao dịch.

Total_Purchases

Tổng số lần mua hàng của khách trong khoảng thời gian nhất định.

Amount

Số tiền của đơn hàng hiện tại.

Total_Amount

Tổng số tiền khách hàng đã chi tiêu trong toàn bộ thời gian mua hàng.

Product_Category

Danh mục sản phẩm mà khách hàng đã mua.

Product_Brand

Thương hiệu sản phẩm mà khách hàng đã mua.

Product_Type

Loại sản phẩm chi tiết trong danh mục.

Feedback

Phản hồi hoặc đánh giá bằng lời từ khách hàng.

Shipping_Method

Phương thức vận chuyển được lựa chọn.

Payment_Method

Phương thức thanh toán.

Order_Status

Trạng thái đơn hàng.

Ratings

Đánh giá sao khách hàng dành cho sản phẩm/dịch vụ.

Products

Tên sản phẩm chi tiết mà khách hàng đã mua.

Giải thích kỹ thuật: Từ dòng 3 đến 42 tạo data.frame hai cột Bien và YNghia, cách nhập thủ công để có thể hiểu ý nghĩa từng biến trước khi phân tích. Dòng 43 đến 51 dòng chuyển data.frame sang đối tượng bảng. Dòng đên dòng dùng để định dạng tiêu đề, cỡ chữ, căn lề

Chương 2: Mã hóa và xử lí 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(data))
## [1] 4
1. data[duplicated(data), ]
## # 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>

Kết quả là 4 cho thấy có 4 quan sát bị trùng lặp trong bộ dữ liệu nên trước khi tiến hành phân tích tôi 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 .

Sau khi kiểm tra, tôi sẽ tiến hành loại bỏ các quan sát bị trùng để đảm bảo dữ liệu sạch và chính xác cho các bước phân tích tiếp theo:

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

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 số quan sát 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(data))
## [1] 8382

Trong bộ dữ liệu có 8382 ô bị thiếu.

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

1. colSums(is.na(data))
##   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

Sau khi kiểm tra số quan sát bị thiếu tôi 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. library(dplyr)
2. library(hms)
3. data <- data %>% mutate( across( .cols = where(is.numeric), .fns = ~ ifelse(is.na(.), mean(., na.rm = TRUE), .)))
4. data <- data %>% mutate( across( .cols = where(is.character), ~ ifelse(is.na(.), "Nothing", .)))
5. data$Time <- ifelse(is.na(data$Time), hms::as_hms("00:00:00"),data$Time)
6. colSums(is.na(data))
##   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                0                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

Giải thích kỹ thuật: nạp thư viện hms để hỗ trợ xử lý dữ liệu dạng thời gian. Dòng 3 chọn tất cả các biến dạng numeric thay NA bằng giá trị trung bình của chính cột đó. Dòng 4 thay NA của kiểu character bằng “Nothing”. Dòng 5 nếu cột thời gian bị thiếu thì gán giá trị mặc định “00:00:00”. Dòng 6 kiểm tra lại giá trị thiếu.

2.2 Mã hóa biến

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

1. data <- data %>%
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() để chuyển kiểu dữ liệu cho các biến phân loại từ dạng character sang dạng facto. Riêng biến Icome được chuyển sang factor có thứ tự “Nothing” < “Low” < “Medium” < “High” .

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 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 Chuẩn hóa biến Feedback thành số

1. data <- data %>%
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_
9.     )
10.   )

Giải thích kỹ thuật: Dòng 2 sử dụng mutate() kết hợp với case_when() để mã hóa biến Feedback thành thang điểm số từ 2 đến 5 được lưu với biến mới có tên là FeedbackScore. Cụ thể, các mức đánh giá “Excellent”, “Good”, “Average” và “Bad” được quy đổi lần lượt thành các giá trị số 5, 4, 3 và 2. Trong trường hợp giá trị phản hồi không thuộc bốn nhóm này hoặc bị thiếu, biến mới sẽ nhận giá trị NA.

Nhận xét: Việc chuyển đổi này giúp biến phản hồi ban đầu là dạng văn bản trở thành dạng số, từ đó có thể sử dụng trong các phép phân tích thống kê định lượng như tính điểm trung bình, so sánh giữa các nhóm khách hàng hoặc xây dựng mô hình hồi quy.

2.2.3 Chuẩn hóa biến Income thành số

1. data <- data %>%
2.   mutate(Income_Code = case_when(
3.     Income == "Low" ~ 1,
4.     Income == "Medium" ~ 2,
5.     Income == "High" ~ 3,
6.     TRUE ~ NA_real_
7.   ))

Giải thích kỹ thuật: Dòng 2 được dùng để tạo biến mới Income_Code từ biến Income, hàm case_when() giúp gán giá trị số tương ứng cho từng mức thu nhập: “Low” được mã hóa là 1, “Medium” là 2, và “High” là 3. Các trường hợp không thuộc ba nhóm trên hoặc bị thiếu dữ liệu sẽ được gán giá trị NA.

Nhận xét: Việc mã hóa này giúp chuyển đổi dữ liệu từ dạng chữ sang dạng số, giúp thuận tiện hơn cho việc thống kê mô tả, tính trung bình, hoặc phân tích hồi quy. Đồng thời, việc gán giá trị tăng dần theo mức thu nhập cũng phản ánh được thứ bậc hợp lý giữa các nhóm, qua đó giúp việc so sánh và phân tích xu hướng trở nên dễ dàng và logic hơn.

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

1. library(dplyr)
2. freq_table <- function(x) {
3.   tab <- table(x, useNA = "ifany")
4.   freq <- as.data.frame(tab)
5.   colnames(freq) <- c("Muc_do", "Tan_suat")
6.   freq <- freq %>%
7.     mutate(Ty_le = round(100 * Tan_suat / sum(Tan_suat), 2))
8.   return(freq)}
9. freq_gender <- freq_table(data$Gender)
10. freq_income <- freq_table(data$Income)
11. freq_segment <- freq_table(data$Customer_Segment)
12. freq_category <- freq_table(data$Product_Category)
13. freq_brand <- freq_table(data$Product_Brand)
14. freq_type <- freq_table(data$Product_Type)
15. freq_payment <- freq_table(data$Payment_Method)
16. freq_shipping <- freq_table(data$Shipping_Method)
17. freq_feedback <- freq_table(data$Feedback)
18. freq_status <- freq_table(data$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)
## $`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:Dòng 2 dùng để định nghĩa một hàm để tính tần suất và tỷ lệ phần trăm cho một biến phân loại. Dòng 3 dùng để tạo bảng đếm số lần mỗi giá trị xuất hiện, kể cả giá trị thiếu nếu có.Dòng 4 chuyển đổi bảng tần suất thành dạng data.frame để dễ xử lý và trình bày.Dòng 6,7 bổ sung thêm cột tỷ lệ phần trăm bằng cách lấy tần suất của từng giá trị chia cho tổng số quan sát và nhân với 100, và làm tròn số.Dòng 9-18 dùng để tạo bảng gồm mức độ, tần suất và tỷ lệ xuất hiện cho các biến phân loại.

Nhận xét::
> Đối với biến Gender theo kết quả chạy được ta thấy tỷ lệ khách hàng nam cao hơn đáng kể (62,12%) so với nữ (37,78%). Phản ánh nhóm khách hàng chính là nam, vì vậy doanh nghiệp có thể ưu tiên thiết kế các chiến lược marketing phù hợp nhằm để duy trì tệp khách hàng này,đồng thời vẫn duy trì sự hấp dẫn với khách hàng nữ.
> Đối với Income, nhóm thu nhập trung bình chiếm tỷ lệ lớn nhất (43,12%), tiếp theo là nhóm thu nhập thấp (31,87%) và thu nhập cao (24,91%).

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

2.4.1 Chuyển định dạng Date

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

Giải thích kỹ thuật: Để chuyến sang định dạng Date ta sử dụng hàm as.Date() để chuyển cột Date từ kiểu character sang kiểu Date. Vì dữ liệu ban đầu ngày tháng được lưu dưới dạng chuỗi kí tự, không thể thực hiện các phép toán về thời gian như tính số ngày giữa các giao dịch, trích xuất năm, tháng, thứ, trong tuần hay phân tích xu hướng theo thời gian.

2.4.2 Tách thông tin theo tuần

1. library(lubridate)
2. data <- data %>%
3.   mutate(Date = ymd(Date), weekday = wday(Date, label = TRUE))
4. head(data %>% select(Date, weekday))
## # A tibble: 6 × 2
##   Date       weekday
##   <date>     <ord>  
## 1 2023-09-18 Mon    
## 2 2023-12-31 Sun    
## 3 2023-04-26 Wed    
## 4 2023-05-08 Mon    
## 5 2024-01-10 Wed    
## 6 2023-09-21 Thu
1. data %>%
2.   count(weekday, sort = TRUE)
## # A tibble: 8 × 2
##   weekday     n
##   <ord>   <int>
## 1 Thu     43583
## 2 Wed     43534
## 3 Fri     43004
## 4 Sun     42963
## 5 Tue     42930
## 6 Mon     42847
## 7 Sat     42786
## 8 <NA>      359

Giải thích kỹ thuật: Để tách thông tin theo tuần sử dụng hàm wday() từ gói lubridate để tách thứ trong tuần (weekday) từ cột Date, đồng thời giữ thứ tự sắp xếp theo tuần (label = TRUE). Sau khi tách, cột weekday có kiểu ordered factor, cho phép thống kê số lượng giao dịch theo từng ngày trong tuần.
Giải thích: Kết quả count(weekday, sort = TRUE) cho thấy ngày có nhiều giao dịch nhất là Thursday (43.583), tiếp đến là Wesdnesday (43.534) và Friday (43.004), trong khi Saturday và Monday có số lượng thấp hơn. Việc phân tích giao dịch theo thứ trong tuần giúp doanh nghiệp nhận biết xu hướng mua sắm theo ngày từ đó có thể đánh giá thói quen chi tiêu của khách hàng: ví dụ khách hàng mua nhiều vào giữa tuần hay cuối tuần, từ đó điều chỉnh chiến lược bán hàng và chăm sóc khách hàng.

2.5 Phân nhóm và phân loại khách hàng

2.5.1 Phân nhóm tuổi

1. data <- data %>% mutate(Age_Group = case_when(Age < 25 ~ "Trẻ", Age <= 45 ~ "Trung niên", TRUE ~ "Lớn tuổi"))
2. head(data %>% select(Customer_ID, Age, Age_Group))
## # A tibble: 6 × 3
##   Customer_ID   Age Age_Group
##         <dbl> <dbl> <chr>    
## 1       37249    21 Trẻ      
## 2       69749    19 Trẻ      
## 3       30192    48 Lớn tuổi 
## 4       62101    56 Lớn tuổi 
## 5       27901    22 Trẻ      
## 6       41289    58 Lớn tuổi

Giải thích kỹ thuật: Dòng 1 sử dụng toán tử pipe (%>%) để truyền data vào bước xử lý tiếp theo và gán kết quả ngược lại vào data. Tại đây, biến mới Age_Group được tạo ra bằng hàm case_when(), phân loại độ tuổi thành 3 nhóm: Trẻ, Trung niên và Lớn tuổi dựa trên giá trị Age.Dòng 2 chọn ba cột Customer_ID, Age, Age_Group từ bảng data để kiểm tra kết quả phân nhóm tuổi, sau đó head() hiển thị 6 dòng đầu tiên của bảng này.

1. age_freq <- data %>%
2. count(Age_Group) %>%
3. mutate(Ty_le = round(100 * n / sum(n), 2))
4. age_freq
## # A tibble: 3 × 3
##   Age_Group       n Ty_le
##   <chr>       <int> <dbl>
## 1 Lớn tuổi    97957  32.4
## 2 Trung niên  94746  31.4
## 3 Trẻ        109303  36.2

Giải thích kỹ thuật: Dòng 2 sử dụng count(Age_Group) để đếm số lượng khách hàng trong từng nhóm tuổi và tạo cột n thể hiện tần suất.Dòng 3 tạo thêm cột Ty_le nhằm tính tỷ lệ phần trăm của mỗi nhóm tuổi bằng công thức n / tổng số quan sát * 100 và làm tròn đến hai chữ số thập phân. Dòng 4 hiển thị bảng kết quả cuối cùng, cho biết số lượng và tỷ lệ khách hàng trong từng nhóm tuổi.

2.5.2 Xác định khách hàng VIP

1. data <- data %>%
2.   mutate(high_value = ifelse(Total_Amount > quantile(Total_Amount, 0.9), 1, 0))
3. head(data %>% select(Customer_ID, Total_Amount, high_value))
## # A tibble: 6 × 3
##   Customer_ID Total_Amount high_value
##         <dbl>        <dbl>      <dbl>
## 1       37249         324.          0
## 2       69749         807.          0
## 3       30192        1063.          0
## 4       62101        2467.          0
## 5       27901         249.          0
## 6       41289        1185.          0
1. data %>%
2.   count(high_value) %>%
3.   mutate(Phan_tram = n / sum(n) * 100)
## # A tibble: 2 × 3
##   high_value      n Phan_tram
##        <dbl>  <int>     <dbl>
## 1          0 271805      90.0
## 2          1  30201      10.0

Giải thích kỹ thuật: Dòng 1 sử dụng toán tử pipe %>% để truyền dữ liệu data vào bước xử lý tiếp theo và gán kết quả trở lại data.Dòng 2 dùng mutate() để tạo biến mới high_value. Biến này được xác định bằng ifelse(): nếu Total_Amount của khách hàng lớn hơn phân vị 90% (quantile(Total_Amount, 0.9)) được xem là khách hàng VIP và gán giá trị 1, ngược lại gán 0 khách hàng thường. Dòng 3 dùng head() để xem trước một vài dòng đầu của các cột Customer_ID, Total_Amount và high_value, nhằm kiểm tra xem việc phân nhóm VIP đã thực hiện đúng hay chưa.

2.5.3 Sắp xếp khách hàng theo giá trị mua

1. data <- data %>% arrange(desc(Total_Amount))
2. head(data)
## # A tibble: 6 × 35
##   Transaction_ID Customer_ID Name       Email  Phone Address City  State Zipcode
##            <dbl>       <dbl> <chr>      <chr>  <dbl> <chr>   <chr> <chr>   <dbl>
## 1        3955465       16696 Sarah Smi… Dani… 7.34e9 255 Ni… Port… Engl…   96017
## 2        9671388       23578 Casey Her… Alex… 4.26e9 44959 … New … Kans…   65322
## 3        6851931       80039 Morgan Oc… Kell… 9.49e9 080 Ch… Kitc… Onta…   35277
## 4        7518888       14409 Erica Gre… Aman… 8.30e9 28381 … San … Maine   40543
## 5        6580873       67425 Jesse Hug… Bran… 6.99e9 942 Ca… Nure… Berl…   27224
## 6        3717474       37855 William C… Dyla… 7.27e9 437 Hu… Loui… Arka…   71707
## # ℹ 26 more variables: Country <chr>, Age <dbl>, Gender <fct>, Income <ord>,
## #   Customer_Segment <fct>, Date <date>, Year <dbl>, Month <chr>, Time <dbl>,
## #   Total_Purchases <dbl>, Amount <dbl>, Total_Amount <dbl>,
## #   Product_Category <fct>, Product_Brand <fct>, Product_Type <fct>,
## #   Feedback <fct>, Shipping_Method <fct>, Payment_Method <fct>,
## #   Order_Status <fct>, Ratings <dbl>, products <chr>, FeedbackScore <dbl>,
## #   Income_Code <dbl>, weekday <ord>, Age_Group <chr>, high_value <dbl>

Nhận xét: Sử dụng hàm arrange(desc(Total_Amount)) của dplyr để sắp xếp dữ liệu khách hàng theo tổng giá trị mua (Total_Amout) từ cao xuống thấp. Sau khi sắp xếp những khách hàng có giá trị mua lớn nhất sẽ xuất hiện ở đầu bảng, thuận tiện cho việc nhận diện khách hàng VIP, phân tích mức chi tiêu hoặc lập danh sách ưu tiên chăm sóc khách hàng.

2.6 Thống kê cơ bản các biến numeric

2.6.1 Kiểm tra phân bố biến Amount

1. summary(data$Amount)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    10.0   133.0   255.2   255.2   377.5   500.0
1. sd(data$Amount)
## [1] 141.3068
1. boxplot(data$Amount)

Nhận xét

Biến Amount thể hiện số tiền chi tiêu của khách hàng trong mỗi giao dịch. Kết quả thống kê mô tả cho thấy giá trị nhỏ nhất là 10, lớn nhất là 500, trung bình và trung vị đều đạt 255.2 , trong khi đó độ lệch chuẩn là 141.3. Sự tương đồng giữa trung bình và trung vị cho thấy phân phối của biến khá đối xứng, không bị lệch mạnh về phía nào.

Khoảng dao động từ 10 đến 500 cho thấy mức chi tiêu giữa các giao dịch rất đa dạng. Độ lệch chuẩn tương đối lớn phán ảnh sự khác biệt đáng kể giữa các khách hàng, tức là có nhóm khách hàng chi tiêu thấp (dưới 133) và nhóm khách hàng chi tiêu cao (trên 377).

Về mặt kinh tế cho ta thấy được đang phục vụ nhiều phân khúc khách hàng khách nhau với sức mua và hành vi chi tiêu không đồng nhất.

Boxplot thể hiện dữ liệu phân bố khá ổn định, không có giá trị ngoại lai, hệ thống ghi nhận giao dịch hợp lý và không có sai lệch bất thường. Nhìn chung, biến Amount cho thấy hành vi chi tiêu của khách hàng có sự đa dạng nhưng vẫn duy trì ổn định, đây là dấu hiệu tích cực cho doanh nghiệp trong việc duy trì doanh thu và phân tích nhóm khách hàng tiềm năng.

2.6.2 Kiểm tra phân bố biến Total_Amount

1. summary(data$Total_Amount)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    10.0   439.2  1043.0  1367.6  2027.9  4999.6
1. sd(data$Total_Amount)
## [1] 1128.349
1. boxplot(data$Total_Amount)

Nhận xét

Biến Total_Amount phản ánh tổng số tiền mà khách hàng chi tiêu cho mỗi đơn hàng. Kết quả thống kê mô tả cho thấy giá trị nhỏ nhất là 10, giá trị lớn nhất đạt 4,999.6, trung vị là 1,043, trung bình là 1,367.6, và độ lệch chuẩn lên tới 1,128.3.

Sự chênh lệch lớn giữa trung bình (1,367.6) và trung vị (1,043) cho thấy phân phối dữ liệu bị lệch phải — nghĩa là có một số giao dịch có giá trị rất cao kéo trung bình tăng lên. Biểu đồ boxplot minh họa rõ điều này khi có nhiều điểm dữ liệu nằm trên phần râu phải, đại diện cho các giá trị ngoại lai (outliers) — đây là những khách hàng hoặc đơn hàng có mức chi tiêu vượt trội so với phần lớn còn lại.

Khoảng dao động từ 10 đến gần 5,000 thể hiện mức độ đa dạng lớn về giá trị đơn hàng, trong khi độ lệch chuẩn cao (1,128) phản ánh sự biến động mạnh trong hành vi chi tiêu giữa các khách hàng.

Biến Total_Amount cho thấy được sự không đồng đều trong hành vi chi tiêu của khách hàng. Phân phối lệch phải và nhiều giá trị ngoại lai là tín hiệu quan trọng giúp doanh nghiệp phân khúc thị trường, xác định nhóm khách hàng giá trị cao và tối ưu chiến lược tiếp cận nhằm tăng doanh thu.

2.6.3 Kiểm tra phân bố biến Total_Purchases

1. summary(data$Total_Purchases)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1.00    3.00    5.00    5.36    8.00   10.00
1. sd(data$Total_Purchases)
## [1] 2.866865
1. boxplot(data$Total_Purchases)

Nhận xét

Biến Total_Purchases phản ánh số lượng đơn hàng mà mỗi khách hàng đã mua. Kết quả thống kê mô tả cho thấy giá trị nhỏ nhất là 1, lớn nhất là 10, trung vị là 5, trung bình là 5.36, và độ lệch chuẩn là 2.87.

Phân phối dữ liệu khá đối xứng, khi trung bình và trung vị gần bằng nhau. Điều này cho thấy số lần mua hàng của khách hàng tương đối ổn định, không bị lệch mạnh về nhóm ít mua hoặc mua quá nhiều.

Phạm vi biến động của biến nằm trong khoảng từ 1 đến 10, phản ánh rằng phần lớn khách hàng mua hàng từ 3–8 lần trong giai đoạn khảo sát. Độ lệch chuẩn 2.87 cho thấy sự phân tán vừa phải quanh giá trị trung bình, nghĩa là các khách hàng có hành vi mua hàng khá đồng đều, không có sự chênh lệch quá lớn.

Biểu đồ boxplot, dữ liệu phân bố đều và không có điểm ngoại lai (outlier). Điều này khẳng định rằng tần suất mua hàng của khách hàng có tính ổn định.

Trung bình mỗi khách hàng mua khoảng 5 lần cho thấy doanh nghiệp có mức độ gắn bó khách hàng tương đối tốt. Một số khách hàng chỉ mua 1–2 lần, thể hiện nhóm khách hàng mới hoặc ít trung thành. Trong khi đó, những khách hàng có từ 8–10 lần mua hàng có thể được xem là nhóm khách hàng thân thiết – đây là đối tượng tiềm năng cho các chương trình chăm sóc khách hàng, tích điểm, hoặc ưu đãi riêng.

Chương 3: Thống kê cơ bản

3.1 Phân tích AOV

3.1.1 Theo quốc gia

  • 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
1. aov_region <- data %>%
2.   group_by(Country) %>% 
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: 6 × 5
##   Country   Mean_AOV SD_AOV CoV_AOV IQR_AOV
##   <chr>        <dbl>  <dbl>   <dbl>   <dbl>
## 1 Australia    1370.  1128.    82.3   1588.
## 2 Canada       1363.  1127.    82.7   1581.
## 3 Germany      1367.  1128.    82.5   1589.
## 4 Nothing      1287.  1046.    81.3   1428.
## 5 UK           1376.  1134.    82.5   1607.
## 6 USA          1364.  1126.    82.5   1582.

Giải thích kỹ thuật: Dòng 1–2 nhóm dữ liệu theo từng quốc gia bằng hàm group_by(Country) để chuẩn bị cho việc tính toán thống kê theo từng nhóm. Tiếp đó, từ dòng 3–7 hàm summarise() được sử dụng để tạo ra một bảng tổng hợp trong đó mỗi quốc gia được biểu diễn bởi một hàng kèm theo các chỉ số.

Nhận xét: Kết quả thống kê cho thấy các quốc gia Australia, Canada, Germany, UK và USA đều có Mean_AOV > 1.300, chứng tỏ đây là nhóm thị trường có khả năng chi tiêu cao và tiềm năng lợi nhuận lớn. Doanh nghiệp nên ưu tiên mở rộng sản phẩm, marketing và phân phối tại các khu vực này. Độ lệch chuẩn SD_AOV khoảng 1045 - 1100 và hệ số biến thiên CoV_AOV > 80% cho thấy chi tiêu giữa các khách hàng trong cùng quốc gia có sự khác biệt đáng kể, thể hiện sự tồn tại của nhiều phân khúc chi tiêu khác nhau. IQR_AOV nằm trong khoảng 1.500 – 1.600, chứng tỏ sự chênh lệch giữa nhóm chi tiêu thấp và cao là tương đối ổn định.
Từ đó, doanh nghiệp nên duy trì chiến lược đa dạng hóa sản phẩm và giá bán để phù hợp từng phân khúc khách hàng, đồng thời tập trung đầu tư mạnh hơn vào các thị trường có Mean_AOV cao nhằm tối ưu lợi nhuận.

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

Biểu đồ “So sánh AOV và các chỉ số khác theo quốc gia - Quốc gia có chỉ số AOV cao nhất” minh họa giá trị trung bình đơn hàng (Mean_AOV) của mười thành phố dẫn đầu, kèm theo các chỉ số độ lệch chuẩn (SD), khoảng tứ phân vị (IQR) và hệ số biến thiên (CoV). Trong đó, AOV (Average Order Value) phản ánh mức chi tiêu trung bình trên mỗi đơn hàng, là chỉ tiêu tài chính quan trọng để đánh giá sức mua của khách hàng tại từng khu vực.

Giải thích kỹ thuật: dòng 5–12, dữ liệu được sắp xếp theo Mean_AOV giảm dần, lấy 10 quốc gia có AOV cao nhất (slice_head), đồng thời tạo thêm các biến vị trí nhãn và điểm IQR để bố trí hiển thị hợp lý trên biểu đồ. Từ dòng 13–18, biểu đồ cột được vẽ, trong đó chiều cao cột thể hiện Mean_AOV, và thanh sai số ở dòng 15–16 biểu diễn độ lệch chuẩn, giúp đánh giá mức biến động. Hai điểm đỏ ở dòng 17–18 đánh dấu giới hạn trên và dưới của khoảng tứ phân vị (IQR). Nhãn giá trị Mean_AOV và hệ số biến thiên CoV được thêm bằng geom_text_repel() ở dòng 19–24 và 25–30 để đảm bảo nhãn không bị chồng lên nhau. Đường chuẩn Mean_AOV toàn bộ dữ liệu được vẽ ở dòng 31–32 nhằm so sánh tương quan giữa các quốc gia với mức trung bình chung

Nhận xét: Kết quả từ biểu đồ cho thấy năm quốc gia gồm Australia, Canada, Germany, UK và USA là những thị trường có giá trị đơn hàng trung bình (Mean_AOV) cao, đều trên mức trung bình toàn bộ mẫu dữ liệu. Trong đó, UK dẫn đầu với Mean_AOV ≈ 1375.7, theo sau là Australia (1369.9), Germany (1366.8), USA (1363.9) và Canada (1363.4). Sự chênh lệch giữa quốc gia cao nhất và thấp nhất chỉ khoảng 12 đơn vị, cho thấy hành vi chi tiêu trung bình của khách hàng tại các thị trường này khá tương đồng, đều thuộc nhóm có sức mua mạnh và ổn định.
Xét về độ biến động, chỉ số CoV_AOV của các quốc gia đều nằm trong khoảng 82% ± 0.5%, cho thấy mức độ phân tán trong chi tiêu của khách hàng giữa các khu vực là tương đối đồng đều. Điều này nghĩa là trong mỗi quốc gia vẫn tồn tại cả nhóm khách hàng chi tiêu cao và thấp, nhưng tỷ lệ biến động giữa các nước không khác biệt nhiều. Chỉ số SD_AOV và IQR_AOV cũng củng cố kết quả này khi độ lệch chuẩn và khoảng tứ phân vị giữa các quốc gia khá sát nhau, thể hiện cấu trúc hành vi tiêu dùng khá ổn định trên toàn hệ thống.
Dưới góc độ kinh tế, các quốc gia có Mean_AOV cao và CoV thấp như UK hay Germany là những thị trường tiềm năng để phát triển sản phẩm cao cấp, chiến dịch marketing hướng đến nhóm khách hàng trung – cao cấp, bởi mức chi tiêu trung bình lớn và ổn định. Trong khi đó, các nước có AOV thấp hơn như Canada hay USA có thể tập trung đa dạng hóa sản phẩm, khuyến mãi định kỳ hoặc tối ưu trải nghiệm khách hàng nhằm kích thích chi tiêu và nâng giá trị đơn hàng trung bình.

3.1.2 Theo phân khúc khách hàng

1. aov_customer <- data %>%
2.   group_by(Customer_Segment) %>% 
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_customer
## # A tibble: 4 × 5
##   Customer_Segment Mean_AOV SD_AOV CoV_AOV IQR_AOV
##   <fct>               <dbl>  <dbl>   <dbl>   <dbl>
## 1 New                 1368.  1128.    82.5   1591.
## 2 Nothing             1528.  1164.    76.2   1703.
## 3 Premium             1363.  1126.    82.6   1580.
## 4 Regular             1369.  1130.    82.5   1591.

Giải thích kỹ thuật: Ở dòng 1, dữ liệu được truyền qua toán tử %>% để bắt đầu chuỗi xử lý và kết quả được lưu vào đối tượng aov_customer. Dòng 2 nhóm dữ liệu theo từng phân khúc khách hàng (Customer_Segment) để tính toán riêng cho từng nhóm. Từ dòng 3–7, bảng tóm tắt được tạo ra, trong đó: dòng 4 tính giá trị đơn hàng trung bình (Mean_AOV), dòng 5 tính độ lệch chuẩn (SD_AOV) để xem mức độ biến động chi tiêu, dòng 6 tính hệ số biến thiên CoV nhằm đánh giá mức ổn định của chi tiêu, và dòng 7 tính khoảng tứ phân vị (IQR) để đo độ phân tán dữ liệu theo phân vị.

Nhận xét:Kết quả cho thấy giá trị đơn hàng trung bình (Mean_AOV) giữa các phân khúc khách hàng không chênh lệch nhiều, dao động quanh mức ~1.360–1.370, chứng tỏ mức chi tiêu cơ bản của các nhóm khá tương đồng. Độ lệch chuẩn (SD_AOV) và khoảng tứ phân vị (IQR_AOV) đều ở mức tương đối gần nhau giữa các nhóm, phản ánh mức độ biến động chi tiêu tương đối tương đồng. Tuy nhiên, hệ số biến thiên (CoV_AOV) của các nhóm đều trên 76%, cho thấy hành vi chi tiêu trong từng phân khúc không đồng nhất, tức tồn tại sự khác biệt lớn giữa người chi nhiều và người chi ít trong cùng một nhóm.

1. library(dplyr)
2. library(ggplot2)
3. aov_customer <- data %>%
4.   group_by(Customer_Segment) %>%
5.   summarise(
6.     Mean_AOV = mean(Total_Amount, na.rm = TRUE),
7.     SD_AOV   = sd(Total_Amount, na.rm = TRUE),
8.     CoV_AOV  = (SD_AOV / Mean_AOV) * 100,
9.     IQR_AOV  = IQR(Total_Amount, na.rm = TRUE)) %>%
10.   mutate(
11.     Mean_lbl = round(Mean_AOV, 0),
12.     CoV_lbl  = paste0(round(CoV_AOV, 1), "%"),
13.     IQR_top = Mean_AOV + (IQR_AOV / 2),
14.     IQR_bot = Mean_AOV - (IQR_AOV / 2))
15. ggplot(aov_customer, aes(x = reorder(Customer_Segment, -Mean_AOV), y = Mean_AOV, fill = Customer_Segment)) +
16.   geom_col(width = 0.6, alpha = 0.9, show.legend = FALSE) +
17.   geom_errorbar(aes(ymin = pmax(0, Mean_AOV - SD_AOV), ymax = Mean_AOV + SD_AOV),
18.                 width = 0.18, color = "black", size = 0.9) +
19.   geom_point(aes(y = IQR_top), color = "red", size = 3, shape = 18) +
20.   geom_point(aes(y = IQR_bot), color = "red", size = 3, shape = 18) +
21.   geom_segment(aes(x = as.numeric(factor(Customer_Segment)) - 0.15,
22.                    xend = as.numeric(factor(Customer_Segment)) + 0.15,
23.                    y = IQR_top, yend = IQR_top),
24.                color = "red", size = 0.6) +
25.   geom_segment(aes(x = as.numeric(factor(Customer_Segment)) - 0.15,
26.                    xend = as.numeric(factor(Customer_Segment)) + 0.15,
27.                    y = IQR_bot, yend = IQR_bot),
28.                color = "red", size = 0.6) +
29.   geom_segment(aes(x = as.numeric(factor(Customer_Segment)),
30.                    xend = as.numeric(factor(Customer_Segment)),
31.                    y = IQR_bot, yend = IQR_top),
32.                color = "red", size = 0.4, linetype = "dashed") +
33.   geom_text(aes(label = Mean_lbl), vjust = -0.8, size = 3.8, fontface = "bold") +
34.   geom_text(aes(label = CoV_lbl, y = Mean_AOV + SD_AOV + (0.06 * max(Mean_AOV))),
35.             vjust = 0, size = 3, color = "navy") +
36.   geom_hline(yintercept = mean(aov_customer$Mean_AOV, na.rm = TRUE),
37.              color = "darkgreen", linetype = "dotdash", size = 0.6) +
38.    labs(
39.     title = "AOV (Mean_AOV) theo phân khúc khách hàng",
40.     x = "Phân khúc khách hàng",
41.     y = "Giá trị trung bình đơn hàngvi",
42.     caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ"
43.   ) +
44.   theme_minimal(base_size = 13) +
45.   theme(
46.     plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
47.     axis.title = element_text(face = "bold"),
48.     axis.text.x = element_text(angle = 0, vjust = 0.5),
49.     legend.position = "none",
50.   ) +
51.   scale_y_continuous(labels = function(x) format(x, big.mark = ".", decimal.mark = ","))

Giải thích kỹ thuật: dữ liệu được nhóm theo phân khúc khách hàng (dòng 3–4) và tính các chỉ số gồm giá trị trung bình đơn hàng (Mean_AOV), độ lệch chuẩn (SD_AOV), hệ số biến thiên CoV và khoảng tứ phân vị IQR (dòng 6–9) để đánh giá mức chi tiêu và sự ổn định giữa các phân khúc. Sau đó, các giá trị bổ trợ phục vụ việc trực quan được tạo thêm, như nhãn và vị trí cột IQR (dòng 11–14).Ở dòng 15–35 vẽ cột biểu diễn Mean_AOV, kèm thanh sai số thể hiện SD và đoạn màu đỏ thể hiện IQR, giúp quan sát độ biến động trong từng phân khúc. Đường ngang ở dòng 36–37 biểu diễn mức AOV trung bình toàn thị trường, hỗ trợ so sánh. Các dòng còn lại chủ yếu tiêu đề và chỉnh giao diện hiển thị (dòng 38–51).

Nhận xét: Biểu đồ cho thấy giá trị đơn hàng trung bình (AOV) giữa các phân khúc khách hàng không chênh lệch nhiều, các nhóm Regular, New và Premium có mức AOV gần tương đương nhau. Tuy nhiên, mức độ biến động chi tiêu (độ lệch chuẩn và IQR) khá lớn ở tất cả phân khúc, tức là hành vi chi tiêu trong từng nhóm không đồng đều, có khách hàng chi tiêu rất cao và có người rất thấp. Nhìn chung, phân khúc khách hàng chưa tạo ra sự khác biệt rõ rệt về giá trị chi tiêu trung bình.

3.1.3 Phân tích sự khác biệt chi tiêu theo phân khúc khách hàng (ANOVA)

1. segment_data <- data %>%
2.   filter(Customer_Segment %in% c("Regular", "New", "Premium")) %>%
3.   droplevels()
4. anova_segment <- aov(Total_Amount ~ Customer_Segment, data = segment_data)
5. summary(anova_segment)
##                      Df    Sum Sq Mean Sq F value Pr(>F)
## Customer_Segment      2 1.436e+06  718068   0.564  0.569
## Residuals        301788 3.842e+11 1273103

Giải thích kỹ thuật: Dòng 1 sử dụng pipe để tạo biến segment_data. Dòng 2 lọc dữ liệu chỉ giữ ba phân khúc Regular, New và Premium, nhằm loại bỏ nhóm không hợp lệ. Dòng 3 dùng droplevels() để xóa các mức phân khúc không còn xuất hiện sau khi lọc. Tiếp theo, dòng 4 thực hiện kiểm định ANOVA với mô hình Total_Amount Customer_Segment để kiểm tra xem giá trị đơn hàng trung bình có khác nhau đáng kể giữa các phân khúc hay không. Cuối cùng, dòng 5 hiển thị kết quả ANOVA, trong đó p-value sẽ cho biết sự khác biệt này có ý nghĩa thống kê hay không.

Nhận xét: Giá trị p(Pr(>F)) = 0.55 > 0.05: vì vậy bác bỏ kết luận có sự khác biệt không đủ cơ sở để bác bỏ H₀. Cho thấy giá trị chi tiêu trung bình trên mỗi đơn hàng khác nhau giữa các phân khúc khách hàng. Chi tiêu trung bình của ba nhóm khách hàng là tương đương, không có phân khúc nào chi tiêu cao hơn rõ rệt. Doanh nghiệp không thể hoàn toàn chỉ dựa vào chỉ tiêu phân khúc khách hàng để xây dựng chiến lược marketing nên quan sát và phân tích nhiều chỉ tiêu.

3.1.4 Ảnh hưởng của nhóm tuổi đến hành vi chi tiêu (ANOVA và Tukey HSD)

1. age_freq <- data %>% count(Age_Group) %>% 
2.   mutate(Ty_le = round(100 * n / sum(n), 2))
3. print(age_freq)
## # A tibble: 3 × 3
##   Age_Group       n Ty_le
##   <chr>       <int> <dbl>
## 1 Lớn tuổi    97957  32.4
## 2 Trung niên  94746  31.4
## 3 Trẻ        109303  36.2

Giải thích kỹ thuật: Ở dòng 1, dữ liệu được truyền qua toán tử pipe %>% vào hàm count(Age_Group) để đếm số lượng khách hàng trong từng nhóm tuổi, tạo ra bảng gồm Age_Group và n (tần suất). Tiếp đó ở dòng 2, mutate() được dùng để tạo thêm cột Ty_le, trong đó tỷ lệ phần trăm được tính bằng công thức 100 * n / sum(n) và làm tròn đến 2 chữ số thập phân. Cuối cùng, dòng 3 sử dụng print(age_freq) để hiển thị bảng kết quả phân bố và tỷ lệ các nhóm tuổi.

1. summary(aov(Total_Amount ~ Age_Group, data = data))
##                 Df    Sum Sq   Mean Sq F value Pr(>F)    
## Age_Group        2 2.286e+08 114283974   89.82 <2e-16 ***
## Residuals   302003 3.843e+11   1272422                   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
1. TukeyHSD(aov(Total_Amount ~ Age_Group, data = data))
##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = Total_Amount ~ Age_Group, data = data)
## 
## $Age_Group
##                           diff       lwr        upr     p adj
## Trẻ-Lớn tuổi        -60.492862 -72.12452 -48.861202 0.0000000
## Trung niên-Lớn tuổi  -7.247154 -19.29373   4.799426 0.3356989
## Trung niên-Trẻ       53.245707  41.51056  64.980853 0.0000000

Giải thích kỹ thuật: Dòng 1 mục đích so sánh giá trị trung bình Total_Amount giữa 3 nhóm tuổi để kiểm xem có ít nhất một cặp nhóm có khác biệt trung bình có ý nghĩa thống kê hay không, kết quả sẽ có các cột Df, Sum Sq, Mean Sq, Pr(>F). Dòng 2 sau khi ANOVA cho thấy được sự khác biệt tổng quát, Tukey HSD so sánh cặp đôi giữa các nhóm và trả p-value đã điều chỉnh để kiểm soát error family-wise kết quả xuất ra sẽ có các cột: diff; lwr và upr: biên dưới/biên trên của khoảng tin cậy 95% cho hiệu; p adj: p-value đã hiệu chỉnh.

Nhận xét: Kết quả Tukey HSD cho thấy nhóm Trẻ chi tiêu trung bình thấp hơn nhóm Lớn tuổi khoảng 60 đơn vị, và thấp hơn nhóm Trung niên khoảng 53 đơn vị, với mức ý nghĩa thống kê rất cao (p < 0.001). Trong khi đó, Trung niên và Lớn tuổi không có sự khác biệt chi tiêu đáng kể (p > 0.05).

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

1. library(dplyr)
2. low_brands <- data %>%
3.   group_by(Product_Brand) %>%
4.   summarise(Revenue = sum(Total_Amount, na.rm = TRUE)) %>%
5.   arrange(Revenue) %>%               
6.   slice_head(n = 10)                 
7. low_brands
## # A tibble: 10 × 2
##    Product_Brand   Revenue
##    <fct>             <dbl>
##  1 Nothing         386667.
##  2 BlueStar       3072472.
##  3 Mitsubhisi     9197092.
##  4 Whirepool     10093298.
##  5 IKEA          24549674.
##  6 Apple         24656802.
##  7 Nestle        24747161.
##  8 Home Depot    24811423.
##  9 Random House  24812130.
## 10 Adidas        24854304.

Giải thích kỹ thuật: Ở dòng 1, thư viện dplyr được gọi để sử dụng các hàm xử lý dữ liệu. Tiếp theo, dòng 2 dùng toán tử pipe %>% để truyền dữ liệu vào các bước tiếp theo. Tại dòng 3, dữ liệu được nhóm theo Product_Brand. Ở dòng 4, hàm summarise() tính tổng doanh thu Revenue cho từng thương hiệu, đồng thời bỏ qua giá trị thiếu (na.rm = TRUE). Dòng 5 sắp xếp danh sách thương hiệu theo doanh thu tăng dần. Sau đó, dòng 6 chọn 10 thương hiệu có doanh thu thấp nhất bằng slice_head(n = 10). Cuối cùng, dòng 7 hiển thị bảng low_brands gồm 10 thương hiệu có doanh thu thấp nhất.

Nhận xét: theo kết quả bảng cho thấy các thương hiệu như là “BlueStar” và “Mistubishi” đạt doanh thu rất nhỏ so với các thương hiệu còn lại, phản ảnh rằng thị phần và mức độ tiêu thụ sản phẩm nhóm này rất hạn chế. Ngược lại các thương hiệu lớn như Apple, IKEA, Adidas tuy vẫn trong nhóm thấp nhất nhưng có doanh thu cao hơn đáng kể cho thấy sự chênh lệch lớn về sức mạnh thương hiệu và doanh số giữa các nhóm.Kết quả này giúp doanh nghiệp xác định được nhóm thương hiệu yếu cần tái cấu trúc hoặc thúc đẩy bán hàng.

3.3 Bang có độ lệch doanh thu lớn nhất

1. data %>%
2.   group_by(State) %>%
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: 55 × 4
##    State            SD  Mean    CV
##    <chr>         <dbl> <dbl> <dbl>
##  1 Massachusetts 1131. 1311. 0.863
##  2 Idaho         1168. 1358. 0.861
##  3 South Dakota  1139. 1328. 0.858
##  4 California    1163. 1355. 0.858
##  5 Kentucky      1123. 1317. 0.853
##  6 Utah          1133. 1336. 0.847
##  7 Maryland      1118. 1320. 0.847
##  8 Delaware      1194. 1415. 0.844
##  9 Arkansas      1181. 1406. 0.840
## 10 Minnesota     1132. 1350. 0.838
## # ℹ 45 more rows

Giải thích kỹ thuật:Ở dòng 1, dữ liệu được truyền vào chuỗi thao tác bằng toán tử pipe %>%. Dòng 2 nhóm dữ liệu theo biến State để tính toán riêng cho từng bang. Tại dòng 3 và dòng 4, lần lượt tính độ lệch chuẩn (sd) và giá trị trung bình (mean) của Total_Amount, bỏ qua giá trị thiếu với na.rm = TRUE. Dòng 5 tạo thêm biến CV, tính hệ số biến thiên bằng công thức SD / Mean, giúp đánh giá mức độ biến động tương đối so với trung bình. Cuối cùng, dòng 6 sắp xếp các bang theo CV giảm dần để xác định nơi có mức biến động chi tiêu lớn nhất.

Nhận xét: Bảng trên chỉ hiển thị 10 bang đầu tiên trong danh sách 55 bang để minh họa. Theo kết quả bảng trên ta thấy các bang như Delaware, Arkansas, California, Idaho, và Minnesota có Mean AOV cao hơn khoảng 1.340, phản ánh sức mua tốt và tiềm năng mở rộng sản phẩm trung–cao cấp. Ngược lại, các bang như Massachusetts, Kentucky, South Dakota, Maryland, và Utah có Mean thấp hơn , cho thấy mức chi tiêu trung bình thấp, phù hợp với chiến lược giá mềm và khuyến mãi kích cầu.
Về SD và CV, giá trị SD cao (khoảng 1.100 hơn) cho thấy sự chênh lệch rõ trong chi tiêu giữa các nhóm khách hàng, cần phân khúc thị trường rõ ràng. CV dao động quanh 0.83–0.87, thể hiện mức biến động tương đối cao nhưng đồng đều, do đó doanh nghiệp nên kết hợp nhiều chỉ tiêu chứ không dựa riêng vào Mean khi ra quyết định chiến lược.

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

1. top_customers <- data %>%
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: Dòng 1–5 tạo bảng top_customers bằng cách nhóm theo Customer_ID, tính tổng chi tiêu, sắp xếp giảm dần và tính tỷ lệ tích lũy doanh thu. Dòng 6 lọc nhóm khách hàng đóng góp 80% doanh thu. Dòng 7 tính tỷ lệ số khách trong nhóm này trên tổng khách hàng → cho biết bao nhiêu % khách tạo ra phần lớn doanh thu (quy tắc Pareto 80/20).

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 Phân tích tốc độ tăng trưởng số lượng khách hàng theo tháng

1. data %>% mutate(
2.     Month = tolower(Month),
3.     Month = tools::toTitleCase(Month),
4.     YearMonth = paste0(Year, "-", match(Month, month.name))  ) %>%
5.   mutate(
6.     YearMonth = format(as.Date(paste0(YearMonth, "-01")), "%Y-%m")) %>%
7.   group_by(YearMonth) %>%
8.   summarise(unique_customers = n_distinct(Customer_ID)) %>%
9.   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: Dòng 1 dùng mutate() để chuẩn hóa dữ liệu tháng. Dòng 2 chuyển tên tháng về chữ thường, dòng 3 viết hoa chữ cái đầu để đồng nhất định dạng. Dòng 4 tạo biến YearMonth dạng “Năm-Tháng” bằng cách ghép Year và số thứ tự tháng. Dòng 6 chuyển YearMonth thành định dạng chuẩn YYYY-MM. Dòng 7 nhóm dữ liệu theo YearMonth, dòng 8 tính số khách hàng duy nhất trong mỗi tháng (n_distinct(Customer_ID)), và dòng 9 sắp xếp kết quả theo thời gian tăng dần.

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(data$Total_Purchases, data$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ữ Total_Amount và Age

1. cor(data$Age, data$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 Phân tích giá trị vòng đời khách hàng

1. data %>%
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.

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 <- data %>%
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 1 dùng toán tử pipe để truyền dữ liệu vào bước xử lý tiếp theo và gán vào biến customer_frequency. Dòng 2 nhóm dữ liệu theo từng khách hàng (Customer_ID). Dòng 3 đếm số lượng giao dịch của mỗi khách hàng và lưu vào cột Total_Transactions. Cuối cùng, dòng 4 dùng summary() để mô tả thống kê (min, max, trung bình, median…) về tần suất mua hàng của khách hàng.

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.

Biểu đồ Histogram thể hiện tần suất mua hàng

1. library(ggplot2)
2. library(scales)
3. ggplot(customer_frequency, aes(x = Total_Transactions)) +
4.   geom_histogram(
5.     binwidth = 1, 
6.     aes(fill = ..count..), 
7.     color = "white", 
8.     alpha = 0.9) +
9.   scale_fill_gradient(low = "#9ecae1", high = "#08519c") +   # Gradient đẹp mắt
10.   scale_x_continuous(breaks = seq(0, 50, 5), limits = c(0, 50)) +
11.   scale_y_continuous(labels = function(x) format(x, big.mark = ".", decimal.mark = ",")) +
12.   labs(
13.     title = "Phân bố tần suất mua hàng của khách hàng",
14.     subtitle = "Đa số khách hàng chỉ phát sinh từ 1 đến 5 giao dịch mua hàng",
15.     x = "Số lần mua hàng (Total_Transactions)",
16.     y = "Số lượng khách hàng",
17.     fill = "Tần suất") +
18.   theme_minimal(base_size = 13) +
19.   theme(
20.     plot.title = element_text(face = "bold", hjust = 0.5, size = 14),
21.     plot.subtitle = element_text(hjust = 0.5, color = "gray30"),
22.     axis.title = element_text(face = "bold"),
23.     axis.text = element_text(color = "black"),
24.     legend.position = "right",
25.     panel.grid.minor = element_blank()
26.   )

Giải thích kỹ thuật:Dòng 3 gọi hàm ggplot() để tạo nền biểu đồ từ bảng customer_frequency và chọn biến Total_Transactions làm trục X, đây là biến chính cần phân tích phân bố tần suất mua hàng. Dòng 4–8 sử dụng geom_histogram() để vẽ biểu đồ histogram, trong đó binwidth = 1 giúp mỗi cột biểu diễn số lượng khách hàng có cùng số lần mua hàng. Dòng 9–11 thiết lập thang màu và định dạng trục: màu chuyển từ xanh nhạt đến xanh đậm thể hiện khu vực có số lượng khách thấp đến cao, trục X được giới hạn từ 0–50 để tránh nhiễu từ các giá trị ngoại lai và đặt vạch chia mỗi 5 đơn vị giúp dễ quan sát. Dòng 12–17 dùng labs() để thêm tiêu đề, chú thích và nhãn trục cho biểu đồ.

Nhận xét:
- Có thể nhận thấy rằng phần lớn khách hàng chỉ mua hàng từ 1 đến 5 lần, chiếm tỉ lệ áp đảo so với toàn bộ tập dữ liệu. Sau mốc 5 lần, số lượng khách hàng giảm nhanh chóng và gần như tiệm cận 0 khi số lần mua vượt quá 10. Điều này cho thấy doanh nghiệp đang có lượng lớn khách hàng chỉ giao dịch một vài lần, trong khi nhóm khách hàng trung thành (mua hàng thường xuyên) chiếm tỉ lệ rất nhỏ.
- Về mặt kinh tế - tài chính, có ý nghĩa quan trọng đối với chiến lược marketing và quản trị khách hàng. Một cơ cấu như vậy cho thấy doanh thu có thể đang phụ thuộc mạnh vào lượng khách hàng mới, thay vì được duy trì bởi khách hàng trung thành. Nếu không có chính sách duy trì hiệu quả, chi phí thu hút khách hàng mới sẽ cao, làm giảm biên lợi nhuận.
- Biểu đồ Histogram cho thấy hành vi mua hàng có tính phân tán cao, với đa số khách hàng chỉ giao dịch ít lần. Đây là dấu hiệu cho thấy doanh nghiệp cần tối ưu chiến lược chăm sóc và giữ chân khách hàng hiện hữu, nhằm giảm chi phí thu hút mới và tăng hiệu quả tài chính bền vững trong dài hạn.

Biểu đồ BoxPlot thể hiện phân bố và outlier

1. ggplot(customer_frequency, aes(y = Total_Transactions)) +
2.   geom_boxplot(fill = "#ff7f0e", alpha = 0.7, outlier.color = "red", outlier.shape = 16, outlier.size = 2.5) +
3.   coord_flip() +
4.   labs(
5.     title = "Phân bố và ngoại lệ của tần suất mua hàng",
6.     subtitle = "Các điểm đỏ là khách hàng có số lần mua vượt trội (trung thành)",
7.     x = "",
8.     y = "Số lần mua hàng (Total_Transactions)",
9.     caption = "Nguồn: Dữ liệu bán lẻ (df_retail)"
10.   ) +
11.   theme_minimal(base_size = 13) +
12.   theme(
13.     plot.title = element_text(face = "bold", color = "darkred"),
14.     axis.text = element_text(color = "black")
15.   )

Giải thích kỹ thuật: Dòng 1 tạo biểu đồ với biến Total_Transactions trên trục tung; dòng 2 vẽ biểu đồ hộp để thể hiện trung vị, mức phân tán và tô đỏ các điểm ngoại lệ là khách hàng mua nhiều bất thường; dòng 3 xoay biểu đồ nằm ngang để dễ quan sát; các dòng 4–9 thêm tiêu đề và nhãn.

Nhận xét: Tương tự biểu đồ boxplot cũng cho thấy sự phân bố tần suất mua hàng rất lệch phải, phần lớn khách hàng chỉ thực hiện vài giao dịch, điều này chứng minh rằng doanh nghiệp phụ thuộc phần lớn vào nhóm khách hàng trung thành, và việc tăng tỷ lệ khách hàng quay lại sẽ giúp tăng trưởng doanh thu bền vững mà không cần mở rộng thêm tệp khách hàng mới.

3.9 Nhóm hành vi mua hàng của khách hàng

1. customer_frequency_grouped <- customer_frequency %>%
2.   mutate(
3.     Purchase_Group = case_when(
4.       Total_Transactions == 1 ~ "Mua 1 lần",
5.       Total_Transactions >= 2 & Total_Transactions <= 5 ~ "Mua ít (2-5 lần)", Total_Transactions > 5 ~ "Trung thành (>5 lần)")) %>%
6.   group_by(Purchase_Group) %>%
7.   summarise(
8.     So_khach_hang = n(),
9.     Ti_le = round(100 * n() / nrow(customer_frequency), 2)
10.   ) %>%
11.   arrange(desc(Ti_le))
12. customer_frequency_grouped
## # A tibble: 3 × 3
##   Purchase_Group       So_khach_hang Ti_le
##   <chr>                        <int> <dbl>
## 1 Mua ít (2-5 lần)             64655  74.5
## 2 Trung thành (>5 lần)         11378  13.1
## 3 Mua 1 lần                    10734  12.4

Giải thích kỹ thuật:Dòng 1 dùng để tạo bảng mới từ customer_frequency. Dòng 2–5 tạo biến phân nhóm Purchase_Group: khách mua 1 lần, mua ít (2–5 lần) và khách trung thành (>5 lần). Dòng 6–7 nhóm dữ liệu theo từng nhóm mua hàng. Dòng 8–9 tính số lượng khách hàng và tỷ lệ phần trăm của mỗi nhóm so với tổng. Dòng 11 sắp xếp kết quả theo tỷ lệ giảm dần và dòng 12 hiển thị bảng phân nhóm.

Nhận xét: Phần lớn khách hàng 74,5% thuộc nhóm “Mua ít (2–5 lần)”, cho thấy tệp khách hàng chủ yếu mang tính giao dịch ngắn hạn, chưa trung thành. Chỉ 13,1% là khách hàng trung thành (>5 lần) nhóm này quan trọng để duy trì doanh thu ổn định. Khoảng 12,4% chỉ mua 1 lần, thể hiện mức độ rời bỏ cao hoặc chưa quay lại mua tiếp.

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

1. product_status <- data %>%
2.   count(Product_Category, Order_Status) %>%             
3.   mutate(Status_Type = ifelse(Order_Status %in% c("Pending", "Processing"), "Uncompleted", "Completed")) %>%
4.   group_by(Product_Category, Status_Type) %>%
5.   summarise(Order_Count = sum(n), .groups = "drop") %>%
6.   tidyr::pivot_wider(
7.     names_from = Status_Type,
8.     values_from = Order_Count,
9.     values_fill = 0
10.   ) %>%
11.   mutate(
12.     Total_Orders = Completed + Uncompleted,
13.     Uncompleted_Rate = round(Uncompleted / Total_Orders * 100, 2)
14.   ) %>% arrange(desc(Uncompleted_Rate))
15. product_status
## # A tibble: 6 × 5
##   Product_Category Completed Uncompleted Total_Orders Uncompleted_Rate
##   <fct>                <int>       <int>        <int>            <dbl>
## 1 Nothing                168         115          283             40.6
## 2 Books                34225       20397        54622             37.3
## 3 Clothing             34346       20393        54739             37.2
## 4 Grocery              42084       24700        66784             37.0
## 5 Home Decor           34320       20062        54382             36.9
## 6 Electronics          50564       20632        71196             29.0

Giải thích kỹ thuật: Dòng 1–2 lấy dữ liệu và đếm số lượng đơn theo từng nhóm Product_Category và Order_Status. Dòng 3 gom các trạng thái đơn hàng thành 2 nhóm: Completed (đã hoàn tất) và Uncompleted (chưa hoàn tất như Pending, Processing). Dòng 4–5 gộp lại và tính tổng số đơn theo từng loại trạng thái trong mỗi nhóm sản phẩm. Dòng 6–9 chuyển dữ liệu sang dạng rộng để tách riêng cột Completed và Uncompleted, các giá trị trống được thay bằng 0. Dòng 11–14 tính tổng số đơn của mỗi nhóm sản phẩm và tỷ lệ đơn chưa hoàn tất (Uncompleted_Rate), cuối cùng sắp xếp giảm dần theo tỷ lệ này để dễ nhận diện nhóm sản phẩm có vấn đề nhiều nhất.

Tính tỷ lệ đơn hàng chưa hoàn tất (%) theo công thức:

\[ \text{Uncompleted Rate} = \frac{\text{Uncompleted Orders}}{\text{Total Orders}} \times 100 \]

Nhận xét: Bảng kết quả cho thấy nhóm Books, Clothing, Grocery và Home Decor đều có tỷ lệ đơn hàng chưa hoàn tất khá cao, dao động quanh 36–37%, trong khi nhóm Electronics chỉ ở mức khoảng 29%, thể hiện khả năng xử lý đơn hàng hiệu quả 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 <- data %>%
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: Dòng 1–2 sắp xếp dữ liệu theo từng khách hàng và theo ngày mua để đảm bảo đúng thứ tự thời gian. Dòng 3–4 nhóm theo Customer_ID và tính khoảng cách ngày giữa lần mua hiện tại và lần mua trước bằng hàm difftime(). Dòng 5 tính thời gian trung bình giữa các lần mua của mỗi khách hàng. Dòng 6 loại bỏ giá trị vô hạn do khách chỉ có 1 lần mua. Dòng 7 dùng summary() để mô tả phân bố thời gian trung bình giữa các lần mua.

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á cao giữa các sản phẩm

1. high_rating_compare <- data %>%
2.   filter(!is.na(Ratings)) %>%                              
3.   mutate(High_Rated = Ratings >= 4) %>%                    
4.   group_by(Product_Category) %>%                           
5.   summarise(
6.     So_luot_danh_gia = n(),
7.     So_danh_gia_cao = sum(High_Rated, na.rm = TRUE),
8.     Ty_le_danh_gia_cao = round(mean(High_Rated) * 100, 2)
9.   ) %>% 
10.   arrange(desc(Ty_le_danh_gia_cao))                       
11. high_rating_compare
## # A tibble: 6 × 4
##   Product_Category So_luot_danh_gia So_danh_gia_cao Ty_le_danh_gia_cao
##   <fct>                       <int>           <int>              <dbl>
## 1 Electronics                 71196           36969               51.9
## 2 Nothing                       283             144               50.9
## 3 Grocery                     66784           32400               48.5
## 4 Clothing                    54739           26367               48.2
## 5 Books                       54622           26231               48.0
## 6 Home Decor                  54382           26105               48

Giải thích kỹ thuật: Dòng 2 loại bỏ các dòng không có dữ liệu đánh giá (NA) để tránh sai lệch khi tính toán, tạo cột mới High_Rated, gán giá trị TRUE nếu điểm đánh giá từ 4 trở lên (được xem là đánh giá cao), ngược lại là FALSE. Dòng 4 gom dữ liệu theo từng loại sản phẩm và tính toán thống kê. Dòng 10 Sắp xếp kết quả giảm dần theo tỷ lệ đánh giá cao, giúp xác định loại sản phẩm nào được đánh giá tốt nhất.

Nhận xét: Nhóm có tỷ lệ đánh giá cao nhất là Electronics (51.96%), cho thấy các sản phẩm điện tử nhìn chung đáp ứng kỳ vọng khách hàng tốt, có thể nhờ thông số rõ ràng, chất lượng ổn định và ít sai lệch giữa mô tả và thực tế. Nhóm NA (50.88%) có tỷ lệ khá cao nhưng không đủ thông tin để đưa ra kết luận cụ thể.Các nhóm còn lại như Grocery, Clothing, Books và Home Decor có tỷ lệ đánh giá cao thấp hơn (dao động quanh 48%), điều này cho thấy mức độ hài lòng chỉ ở mức trung bình. Đặc biệt Home Decor (48.04%) và Books (48.05%) có tỷ lệ thấp nhất

3.13 Phân tổ dữ liệu

3.13.1 Phân tổ khách hàng theo độ tuổi và nhóm khách hàng

1. customer_age_segment <- data %>%
2.   group_by(Age_Group, Customer_Segment) %>%
3.   summarise(
4.     So_khach_hang = n_distinct(Customer_ID),
5.     Tong_doanh_thu = sum(Total_Amount, na.rm = TRUE),
6.     TB_chi_tieu = round(mean(Total_Amount, na.rm = TRUE), 2)
7.   ) %>%
8.   arrange(desc(Tong_doanh_thu))
9. customer_age_segment
## # A tibble: 12 × 5
## # Groups:   Age_Group [3]
##    Age_Group  Customer_Segment So_khach_hang Tong_doanh_thu TB_chi_tieu
##    <chr>      <fct>                    <int>          <dbl>       <dbl>
##  1 Trẻ        Regular                  46813      89079033.       1347.
##  2 Trung niên Regular                  34735      61033493.       1380.
##  3 Lớn tuổi   Regular                  29471      50083109.       1397.
##  4 Trẻ        New                      28317      45451857.       1330.
##  5 Lớn tuổi   New                      26361      43677837.       1390 
##  6 Lớn tuổi   Premium                  25738      42435496.       1387.
##  7 Trung niên New                      22206      35591826.       1391.
##  8 Trung niên Premium                  21501      34409386.       1386.
##  9 Trẻ        Premium                   8534      10946656.       1220.
## 10 Trung niên Nothing                     87        147373.       1694.
## 11 Lớn tuổi   Nothing                     99        141386.       1414.
## 12 Trẻ        Nothing                     28         39742.       1419.

Giải thích kỹ thuật: Dòng 1 truyền data làm đối số đầu tiên cho hàm kế tiếp và được gán vào biến customer_age_segement. Dòng 2 tạo nhóm theo hai biến Age_Group và Customer_Segment. Tất cả các phép tổng hợp tiếp theo sẽ được tính riêng cho từng tổ hợp của hai biến này.Dòng suma dữ liệu được tổng hợp để mỗi nhóm chỉ còn một dòng đại diện, thay thế cho dữ liệu chi tiết ban đầu. Biến So_khach_hang được tính bằng n_distinct(Customer_ID) nhằm đếm số khách hàng duy nhất trong từng nhóm, tránh trùng lặp khi một khách hàng có nhiều giao dịch. Tong_doanh_thu được xác định bằng sum(Total_Amount, na.rm = TRUE) để lấy tổng doanh thu, đồng thời bỏ qua các giá trị thiếu. Cuối cùng, TB_chi_tieu được tính bằng trung bình chi tiêu mean(Total_Amount, na.rm = TRUE) và làm tròn đến hai chữ số thập phân.Dòng 8 sắp xếp kết quả theo Tong_doanh_thu giảm dần dòng có tổng doanh thu lớn nhất đứng trên cùng.

Nhận xét: Khách hàng Regular chiếm số lượng và đóng góp doanh thu lớn nhất ở mọi nhóm tuổi. Nhóm Premium ít hơn nhưng chi tiêu trung bình cao, là nhóm khách hàng giá trị cần được ưu tiên chăm sóc. Trong khi đó, nhóm New chi tiêu chưa cao, cần tăng trải nghiệm và khuyến khích mua lại.

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

1. bussiness_efficiency <- data %>%
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.   ) %>%
7.   arrange(desc(Total_Revenue))
8. 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 đầu tiên sử dụng dấu %>% để truyền data làm đầu vào cho các hàm xử lý kế tiếp và kết quả cuối cùng được gán vào biến bussiness_efficiency. Dòng 2 tạo nhóm theo hai biến Customer_Segment và Product_Category, giúp các phép tính phía sau được thực hiện riêng biệt cho từng tổ hợp của hai biến này.Dòng 3, dữ liệu được tổng hợp sao cho mỗi nhóm chỉ còn một dòng: Total_Revenue = sum(Total_Amount, na.rm = TRUE): tính tổng doanh thu của từng nhóm và bỏ qua giá trị thiếu.Avg_Rating = mean(Ratings, na.rm = TRUE): tính điểm đánh giá trung bình cho mỗi nhóm sản phẩm theo phân khúc khách hàng.Cuối cùng, dòng 7 sắp xếp các nhóm theo tổng doanh thu giảm dần, giúp dễ dàng xác định nhóm sản phẩm – phân khúc khách hàng mang lại doanh thu cao nhất.

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 <- data %>%
2.   group_by(Shipping_Method, Payment_Method, Customer_Segment, Product_Category) %>%
3.   summarise(
4.     Orders = n(),
5.     Avg_Amount = mean(Amount, na.rm = TRUE),
6.     Avg_Rating = mean(Ratings, na.rm = TRUE)
7.   ) %>%
8.   arrange(desc(Orders))
9. 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 1–2 nhóm dữ liệu theo hình thức giao hàng, phương thức thanh toán, phân khúc khách hàng và loại sản phẩm để phân tích hành vi mua theo từng tổ hợp. Dòng 3–6 tính số đơn hàng (Orders), giá trị trung bình đơn hàng (Avg_Amount) và điểm đánh giá trung bình (Avg_Rating) cho mỗi nhóm, giúp xác định nhóm khách hàng tiềm năng và xu hướng chi tiêu. Dòng 8 sắp xếp kết quả theo số đơn hàng giảm dần để dễ nhận diện nhóm quan trọng nhất.

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, tôi 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 <- data %>%
2.   mutate(
3.     Age_Group = cut(Age,
4.       breaks = c(18, 25, 40, 60, Inf),
5.       labels = c("18-25", "26-40", "41-60", "60+"),
6.       right = TRUE, 
7.       include.lowest = TRUE
8.     )
9.   )
10. Age_Group_customer <- age_customer %>%
11.   group_by(Customer_Segment, Income, Age_Group) %>%
12.   summarise(
13.     Count = n() 
14.   ) %>%
15.   arrange(desc(Count))
16. 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 1–9 tạo biến Age_Group bằng cách phân chia tuổi thành các nhóm: 18–25, 26–40, 41–60 và 60+ giúp dữ liệu dễ phân tích hơn theo độ tuổi. Dòng 10–11 nhóm dữ liệu theo phân khúc khách hàng (Customer_Segment), mức thu nhập (Income) và nhóm tuổi (Age_Group). Dòng 12–14 đếm số lượng khách hàng trong mỗi nhóm để xem nhóm nào chiếm ưu thế. Cuối cùng, dòng 15 sắp xếp kết quả theo số lượng giảm dần nhằm xác định nhóm tuổi – phân khúc – thu nhập nổi bật nhất.

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 <- data %>%
2.   group_by(Customer_Segment, Income) %>%
3.   summarise(
4.     Mean_Age   = mean(Age, na.rm = TRUE),
5.     Median_Age = median(Age, na.rm = TRUE),
6.     Min_Age    = min(Age, na.rm = TRUE),
7.     Max_Age    = max(Age, na.rm = TRUE),
8.     Count      = n()
9.   ) %>%
10.   arrange(desc(Count))
11. 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 1–2 thực hiện nhóm dữ liệu theo Customer_Segment và Income để phân tích tuổi trong từng nhóm khách cụ thể. Dòng 3–8 tính các thống kê mô tả gồm: tuổi trung bình (Mean_Age), trung vị (Median_Age), tuổi nhỏ nhất (Min_Age), lớn nhất (Max_Age) và số lượng khách hàng (Count) trong mỗi nhóm, giúp đánh giá đặc điểm tuổi tác của từng nhóm khách hàng theo mức thu nhập. Cuối cùng, dòng 10 sắp xếp kết quả theo Count giảm dần để xác định nhóm có số lượng khách hàng đông nhất.

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 Biểu đồ doanh thu trung bình theo tháng

1. library(ggplot2)
2. library(dplyr)
3. data %>%
4.   mutate(Month = format(Date, "%Y-%m")) %>%
5.   group_by(Month) %>%
6.   summarise(Avg_Sales = mean(Total_Amount, na.rm = TRUE)) %>%
7.   ggplot(aes(x = Month, y = Avg_Sales, group = 1)) +
8.   
9.   geom_line(color = "steelblue", size = 1) +
10.   geom_point(color = "darkred", size = 2) +
11.   geom_smooth(method = "loess", se = FALSE, color = "orange") +
12.   labs(
13.     title = "Doanh thu trung bình theo tháng",
14.     x = "Tháng",
15.     y = "Doanh thu trung bình ",
16.     caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ"
17.   ) +
18. scale_y_continuous(labels = function(x) format(x, big.mark = ".", decimal.mark = ",")) +
19.   theme_light(base_size = 13) +
20.   theme(
21.     axis.text.x = element_text(angle = 45, hjust = 1),
22.     plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
23.     plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
24.     axis.text = element_text(color = "black"),
25.     axis.title = element_text(face = "bold"),
26.     legend.position = "bottom",
27.     panel.grid.minor = element_blank()
28.   )

Giải thích kỹ thuật: Dòng 3–6 tạo biến Month từ cột Date và tính doanh thu trung bình theo từng tháng. Dòng 7 gọi hàm ggplot để vẽ biểu đồ với Month trên trục X và Avg_Sales trên trục Y. Dòng 9–11 lần lượt vẽ đường xu hướng, điểm dữ liệu. Dòng 12–16 thêm tiêu đề và nhãn trục giúp biểu đồ dễ hiểu. Dòng 18 định dạng giá trị doanh thu theo dạng có dấu phân tách hàng nghìn. Dòng 19–28 điều chỉnh giao diện: xoay nhãn trục X cho dễ đọc, làm đậm tiêu đề, bỏ bớt lưới nhỏ, giúp biểu đồ trực quan và rõ ràng hơn.

Nhận xét: Biểu đồ cho thấy doanh thu trung bình từ tháng 3/2023 đến tháng 2/2024 có sự biến động theo thời gian. Trong giai đoạn tháng 3–8/2023, doanh thu duy trì ở mức cao và tương đối ổn định (khoảng 1.370–1.380). Tuy nhiên, từ tháng 9/2023 doanh thu bắt đầu giảm và sụt mạnh hơn trong hai tháng đầu năm 2024, có thể do yếu tố mùa vụ hoặc biến động thị trường, chẳng hạn như nhu cầu giảm sau kỳ mua sắm cuối năm hay các tác động kinh tế vĩ mô làm suy yếu sức mua.Về mặt quản trị, biểu đồ giúp doanh nghiệp nhận diện tính mùa vụ, xác định thời điểm cao điểm – thấp điểm để chủ động điều chỉnh kế hoạch hàng tồn, nhân lực và chiến lược marketing. Đồng thời, việc theo dõi doanh thu theo thời gian hỗ trợ đánh giá sức khỏe tài chính ngắn hạn và làm cơ sở cho dự báo, ra quyết định kinh doanh hiệu quả hơn.

4.2 Biều đồ xu hướng doanh thu theo tháng

1. library(lubridate)
2. monthly_rev <- data %>%
3.   mutate(Month = factor(Month, levels = month.name)) %>%
4.   group_by(Year, Month) %>%
5.   summarise(total_revenue = sum(Total_Amount, na.rm = TRUE), .groups = "drop")
6. ggplot(monthly_rev, aes(x = Month, y = total_revenue, group = Year, color = factor(Year))) +
7.   geom_line(size = 1.2) +                                               
8.   geom_point(size = 3) +                                                
9.   geom_text(aes(label = comma(round(total_revenue, 0))),
10.             vjust = -0.8, size = 3, check_overlap = TRUE) +             
11.   scale_y_continuous(labels = function(x) format(x, big.mark = ".", decimal.mark = ","), limits = c(0, max(monthly_rev$total_revenue) * 1.15)) +   
12.   labs(
13.     title = " Xu hướng doanh thu theo tháng",
14.     x = "Tháng",
15.     y = "Tổng doanh thu",
16.     color = "Năm",
17.     caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ"
18.   ) +                                                                   
19.   theme_light(base_size = 13) +
20.   theme(
21.     plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
22.     plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
23.     axis.text = element_text(color = "black"),
24.     axis.text.x = element_text(angle = 45, hjust = 1),
25.     axis.title = element_text(face = "bold"),
26.     legend.position = "bottom",
27.     panel.grid.minor = element_blank())

Giải thích kỹ thuật:Dòng 2–5 tạo bảng monthly_rev bằng cách chuẩn hóa tên tháng ở dòng 3, sau đó nhóm theo Year và Month rồi tính tổng doanh thu mỗi tháng. Dòng 6 khởi tạo biểu đồ với trục X là tháng và trục Y là tổng doanh thu, đồng thời phân biệt các năm bằng màu sắc. Dòng 7–8 vẽ đường xu hướng và các điểm dữ liệu trên từng tháng. Dòng 9–10 thêm nhãn doanh thu lên từng điểm để dễ quan sát giá trị. Dòng 11 định dạng trục Y theo kiểu phân tách hàng nghìn và mở rộng giới hạn để tránh chồng chữ. Dòng 12–17 bổ sung tiêu đề, nhãn trục và chú thích màu theo năm. Dòng 19–27 thiết lập giao diện hiển thị: làm đậm tiêu đề, xoay nhãn trục X cho dễ đọc, bỏ lưới phụ và đặt chú giải ở cuối biểu đồ để biểu đồ rõ ràng và trực quan hơn.

Nhận xét: Về mặt kinh tế, biểu đồ phản ảnh xu hướng doanh thu của doanh nghiệp theo chu kỳ tháng và theo năm, giúp nhận diện các thời điểm cao điểm và thấp điểm trong hoạt động kinh doanh. Cụ thể, ta thấy doanh thu có sự biến động mạnh giữa các tháng, đặc biệt trong một số năm (2023) xuất hiện đỉnh doanh thu rõ rệt vào tháng 4, đạt trên 50 triệu đồng, cho thấy có khả năng đây là giai đoạn khuyến mãi hoặc nhu cầu tiêu dùng tăng mạnh. Ngược lại, doanh thu các tháng cuối năm như tháng 10–12 có xu hướng giảm nhẹ, phản ánh hiện tượng suy giảm sức mua hoặc điều chỉnh chiến lược bán hàng của doanh nghiệp. Ngoài ra, sự khác biệt rõ rệt giữa các đường doanh thu của các năm cho thấy tác động của yếu tố thời vụ và biến động kinh tế vĩ mô, chẳng hạn như tăng trưởng tiêu dùng, thu nhập khả dụng hoặc chính sách chi tiêu. Việc doanh thu giảm mạnh ở một số tháng nhất định (ví dụ tháng 6–7) có thể gợi ý doanh nghiệp cần điều chỉnh chính sách marketing, phân bổ nguồn hàng và chiến lược giá để cân bằng hiệu quả kinh doanh trong năm.

4.3 Biểu đồ tổng doanh thu theo loại sản phẩm

1. library(scales)
2. data %>%
3.   group_by(Product_Category) %>%
4.   summarise(Total_Sales = sum(Total_Amount, na.rm = TRUE)) %>%
5.   ggplot(aes(x = reorder(Product_Category, Total_Sales), y = Total_Sales, fill = Product_Category)) +
6.   geom_col(alpha = 0.8, width = 0.7) +
7.   geom_text(aes(label = comma(round(Total_Sales, 0))),
8.             vjust = 1, size = 3.5, family = "Arial", fontface = "bold") +
9.   scale_fill_brewer(palette = "Set2") +
10.   labs(
11.     title = "Tổng doanh thu theo loại sản phẩm",
12.     x = "Loại sản phẩm",
13.     y = "Tổng doanh thu",
14.     caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
15.   scale_y_continuous(labels = function(x) format(x, big.mark = ".", decimal.mark = ",")) +
16.   theme_minimal(base_size = 13) +
17.   theme(
18.     plot.title = element_text(
19.       hjust = 0.5, color = "black", face = "bold", size = 13),
20.     plot.subtitle = element_text(
21.       hjust = 0.5, color = "#6C757D", size = 11, margin = margin(b = 10)
22.     ),
23.     axis.title.y = element_text(
24.       color = "#000000", face = "bold", size = 11),
25.     axis.text.x = element_text(
26.       angle = 45, hjust = 1, size = 9),
27.     axis.text.y = element_text(size = 9),
28.     legend.position = "none",
29.     panel.grid.major.x = element_blank()
30.   )

Giải thích kỹ thuật: Dòng 2–4 thực hiện nhóm dữ liệu theo Product_Category và tính tổng doanh thu của từng nhóm. Dòng 5 khởi tạo biểu đồ cột, sắp xếp loại sản phẩm theo doanh thu tăng dần và dùng cột doanh thu làm trục Y. Dòng 6 vẽ các cột thể hiện mức doanh thu, còn dòng 7–8 thêm nhãn giá trị doanh thu trực tiếp lên đầu cột để dễ quan sát. Dòng 9 chọn bảng màu Set2 giúp biểu đồ hài hòa. Dòng 10–14 thêm tiêu đề và nhãn trục giúp biểu đồ có ý nghĩa rõ ràng. Dòng 15 định dạng trục Y theo dạng phân tách hàng nghìn. Cuối cùng, dòng 16–30 điều chỉnh giao diện hiển thị: làm đậm tiêu đề, xoay nhãn trục X để tránh chồng chữ, ẩn chú giải và bỏ lưới dọc để biểu đồ nhìn gọn và dễ đọc hơn.

Nhận xét: Biểu đồ cho thấy doanh thu phân hóa rõ rệt giữa các nhóm sản phẩm, phản ánh chiến lược tiêu thụ và hành vi mua sắm của khách hàng. Trong đó, nhóm “Electronics” đạt doanh thu cao nhất với hơn 97,5 triệu đồng, kế đến là “Grocery” với khoảng 91,1 triệu đồng. Hai nhóm này chiếm tỷ trọng lớn nhất trong tổng doanh thu toàn doanh nghiệp, chứng tỏ đây là nguồn thu chủ lực và có nhu cầu ổn định trên thị trường. Các nhóm như “Home Decor”, “Books”, “Clothing” có doanh thu khá tương đồng (khoảng 74–75 triệu đồng), cho thấy mức tiêu thụ vừa phải, đóng vai trò ổn định nhưng không vượt trội. Ý nghĩa nó mang lại về mặt tài chính - kinh tế, doanh nghiệp có thể ưu tiên đầu tư và mở rộng danh mục ở nhóm sản phẩm mang lại lợi nhuận cao như hàng điện tử và hàng tiêu dùng nhanh, đồng thời xem xét cắt giảm hoặc tái cấu trúc các nhóm có doanh thu thấp. Ngoài ra, việc các nhóm sản phẩm có doanh thu gần bằng nhau trong phân khúc tầm trung cũng là tín hiệu tích cực, cho thấy sự đa dạng hóa sản phẩm giúp ổn định doanh thu và giảm rủi ro phụ thuộc vào một nhóm hàng duy nhất.

4.4 Doanh thu trung bình theo vùng kinh tế của Hoa Kỳ

Mục tiêu tiến hành phân tích sự khác biệt về doanh thu trung bình (Total_Amount) giữa các vùng địa lý của Hoa Kỳ, đồng thời xem xét sự khác biệt giữa các nhóm khách hàng (Customer_Segment) trong từng vùng.

1. library(dplyr)
2. data <- data %>%
3.   mutate(
4.     Region = case_when(
5.       State %in% c(
6.         "Maine", "New Hampshire", "Vermont", "Massachusetts", "Rhode Island", "Connecticut",
7.         "New York", "New Jersey", "Pennsylvania") ~ "Northeast",
8.       State %in% c(
9.         "Ohio", "Indiana", "Illinois", "Michigan", "Wisconsin",
10.         "Minnesota", "Iowa", "Missouri", "North Dakota", "South Dakota", "Nebraska", "Kansas") ~ "Midwest",
11.       State %in% c(
12.         "Delaware", "Maryland", "District of Columbia", "Virginia", "West Virginia",
13.         "North Carolina", "South Carolina", "Georgia", "Florida",
14.         "Kentucky", "Tennessee", "Alabama", "Mississippi", "Arkansas", "Louisiana", "Oklahoma", "Texas") ~ "South",
15.       State %in% c(
16.         "Montana", "Idaho", "Wyoming", "Colorado", "New Mexico",
17.         "Arizona", "Utah", "Nevada", "Washington", "Oregon", "California", "Alaska", "Hawaii") ~ "West",
18.       TRUE ~ "Other"))

Đầu tiên, các bang trong biến State được phân chia thành bốn vùng kinh tế lớn của Hoa Kỳ dựa trên chuẩn phân loại của U.S. Census Bureau, bao gồm: - Northeast (Đông Bắc): Maine, New Hampshire, Vermont, Massachusetts, Rhode Island, Connecticut, New York, New Jersey, Pennsylvania - Midwest (Trung Tây): Ohio, Indiana, Illinois, Michigan, Wisconsin, Minnesota, Iowa, Missouri, North Dakota, South Dakota, Nebraska, Kansas - South (Miền Nam): Delaware, Maryland, Virginia, North Carolina, South Carolina, Georgia, Florida, Texas, v.v. - West (Miền Tây): California, Washington, Oregon, Colorado, Nevada, Arizona, Hawaii, Alaska, v.v. - Các giá trị không thuộc lãnh thổ Hoa Kỳ như “England”, “Berlin”, “Ontario”, “New South Wales”, “Nothing” được gán vào nhóm Other để loại bỏ sai lệch dữ liệu.

1. library(ggplot2)
2. ggplot(data, aes(x = Region, y = Total_Amount, fill = Customer_Segment)) +
3.   stat_summary(fun = mean, geom = "bar", position = position_dodge(width = 0.9)) +
4.   stat_summary(fun = mean, 
5.                geom = "text",
6.                aes(label = round(..y.., 0)),
7.                position = position_dodge(width = 0.9),
8.                vjust = -0.5, size = 3) +
9.   labs(
10.     title = "Doanh thu trung bình theo vùng địa lý và nhóm khách hàng",
11.     subtitle = "So sánh doanh thu theo vùng địa lý tại Hoa Kỳ và nhóm khách hàng",
12.     x = "Vùng địa lý",
13.     y = "Doanh thu trung bình (USD)",
14.     caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ"
15.   ) +
16.   theme_minimal(base_size = 13) +
17.   theme(
18.     plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),
19.     plot.subtitle = element_text(hjust = 0.5, color = "gray40"),
20.     axis.text = element_text(color = "black"),
21.     axis.title = element_text(face = "bold"),
22.     legend.position = "bottom",
23.     panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 2 gọi hàm ggplot() để tạo nền biểu đồ, trong đó Region được chọn làm trục X, Total_Amount làm trục Y và màu sắc đại diện cho Customer_Segment để so sánh giữa các nhóm khách hàng. Dòng 3 dùng stat_summary(fun = mean, geom = “bar”) để vẽ biểu đồ cột thể hiện doanh thu trung bình theo từng nhóm, đồng thời position_dodge() giúp các cột của các nhóm khách hàng đặt cạnh nhau thay vì chồng lên nhau. Dòng 4–8 tiếp tục dùng stat_summary(geom = “text”) để hiển thị giá trị trung bình làm tròn ngay trên đầu từng cột, giúp người xem dễ đọc số liệu trực tiếp. Dòng 9–15 sử dụng labs() để thêm tiêu đề, nhãn trục và chú thích nguồn dữ liệu, giúp biểu đồ rõ ràng và có ý nghĩa. Cuối cùng, dòng 16–23 áp dụng giao diện theme_minimal, chỉnh lại kiểu chữ, màu sắc, căn giữa tiêu đề, đặt chú giải ở cuối biểu đồ

Nhận xét: Biểu đồ cho thấy doanh thu trung bình giữa các vùng có sự khác biệt, trong đó Midwest và Northeast đạt mức cao hơn so với South và West. Các nhóm khách hàng (New, Premium, Regular) có mức chi tiêu tương đối đồng đều, chỉ khác nhau nhẹ tùy từng vùng, phản ánh sự khác biệt về thu nhập và thói quen tiêu dùng theo khu vực.Về mặt kinh tế – tài chính, doanh nghiệp có thể ưu tiên mở rộng hoặc tập trung marketing tại Midwest và Northeast do sức mua cao hơn, trong khi South và West phù hợp với chiến lược duy trì ổn định và chăm sóc khách hàng lâu dài. Điều này giúp tối ưu phân bổ nguồn lực và nâng cao hiệu quả kinh doanh.

4.5 Biểu đồ quan hệ giữa thu nhập, chi tiêu và mức độ hài lòng

Phân tích xem thu nhập (Income) của khách hàng ảnh hưởng như thế nào đến tổng chi tiêu (Total_Amount), đồng thời xem xét phân khúc khách hàng (Customer_Segment) và mức độ hài lòng (Ratings).

1. avg_spend <- data %>%
2.   group_by(Customer_Segment) %>%
3.   summarise(
4.     Avg_Income = mean(Income_Code, na.rm = TRUE),
5.     Avg_Spending = mean(Total_Amount, na.rm = TRUE),
6.     Avg_Rating = mean(Ratings, na.rm = TRUE))
7. ggplot(avg_spend, aes(x = Avg_Income, y = Avg_Spending)) +
8.   geom_point(aes(color = Customer_Segment, size = Avg_Rating), alpha = 0.75) +
9.   geom_text_repel(aes(label = Customer_Segment), size = 3, fontface = "bold",box.padding = 0.4, point.padding = 0.5) +
10.   geom_smooth(method = "lm", se = TRUE, color = "black", linetype = "dashed", color = "black", alpha = 0.2) +
11. scale_color_manual(name = "Phân khúc khách hàng",values = c("New" = "#4A90E2","Nothing" = "#F5C04A","Premium" = "#FF7F7F","Regular" = "#B983FF")) +
12. scale_size_continuous(name = "Mức độ hài lòng (Ratings)") +
13.   geom_hline(yintercept = mean(avg_spend$Avg_Spending), linetype = "dotted", color = "blue") +
14.   geom_vline(xintercept = mean(avg_spend$Avg_Income), linetype = "dotted", color = "red") +
15.   labs(title = "Quan hệ giữa thu nhập, chi tiêu và mức độ hài lòng",x = "Thu nhập trung bình (Income)",y = "Chi tiêu trung bình (Total Amount)",color = "Phân khúc khách hàng",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
16.   theme_minimal(base_size = 13) +
17.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 14),plot.subtitle = element_text(hjust = 0.5, color = "gray40", size = 12),legend.position = "right",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Đầu tiên dòng 1–6, dữ liệu được nhóm theo Customer_Segment để tính trung bình thu nhập (Avg_Income), chi tiêu (Avg_Spending) và mức độ hài lòng (Avg_Rating) cho từng phân khúc. Sau đó dòng 7–8, biểu đồ được vẽ với trục X là thu nhập trung bình và trục Y là chi tiêu trung bình, trong đó màu sắc phân biệt từng phân khúc khách hàng và kích thước điểm thể hiện mức độ hài lòng. Dòng 9 sử dụng geom_text_repel để ghi nhãn các điểm mà không bị chồng chữ. Dòng 10 thêm đường hồi quy tuyến tính nhằm thể hiện xu hướng mối quan hệ giữa thu nhập và chi tiêu. Dòng 11–12 tùy chỉnh màu và kích thước điểm theo phân khúc và mức độ hài lòng để tăng tính trực quan. Dòng 13–14 thêm hai đường tham chiếu ngang và dọc dựa trên giá trị trung bình chung, giúp xác định phân khúc nằm trên hoặc dưới mức trung bình. Cuối cùng dòng 15–1), biểu đồ được đặt tiêu đề, nhãn trục và chỉnh theme.

Nhận xét: Biểu đồ cho thấy thu nhập tăng nhưng chi tiêu trung bình không tăng tương ứng, thậm chí có xu hướng giảm nhẹ (thể hiện qua đường hồi quy dốc xuống). Phân khúc Regular có thu nhập cao nhất nhưng chi tiêu trung bình lại thấp hơn so với nhóm Nothing và New. Trong khi đó, nhóm Nothing có chi tiêu trung bình cao nhất, dù thu nhập không cao tương ứng. Phân khúc Premium chi tiêu và thu nhập đều ở mức trung bình, nhưng mức độ hài lòng (kích thước bong bóng) không vượt trội so với nhóm khác. Điều này gợi ý rằng mức chi tiêu không phụ thuộc trực tiếp vào thu nhập, mà có thể chịu ảnh hưởng từ thói quen mua sắm hoặc mức độ trung thành của khách hàng.

4.6 Biểu đồ phân bố chi tiêu theo giới tính

1. data_sample <- data %>% sample_n(min(150000, nrow(data)))
2. ggplot(data_sample, aes(x = Total_Amount, fill = Gender)) +
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 giới tính",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 lấy mẫu ngẫu nhiên tối đa 150,000 quan sát để giảm tải khi vẽ nhưng vẫn đảm bảo tính đại diện dữ liệu. Dòng 2 thiết lập biểu đồ mật độ KDE với biến chi tiêu Total_Amount và tô màu theo giới tính. Dòng 3 sử dụng geom_density() để hiển thị đường mật độ giúp quan sát phân bố chi tiêu giữa nam và nữ, trong đó alpha = 0.5 tạo độ trong suốt để hai lớp chồng lên dễ so sánh. Dòng 4 thêm đường thẳng đứng biểu thị giá trị chi tiêu trung bình chung, giúp nhận diện vị trí trung tâm phân bố. Dòng 5 thiết lập bảng màu trực quan hơn cho từng giới tính. Dòng 6 và 8 áp dụng giao diện tối giản theme_minimal để biểu đồ rõ ràng dễ đọc. Dòng 7 đặt tiêu đề, nhãn trục và chú thích nguồn dữ liệu. Cuối cùng, dòng 9 chỉnh phông chữ, vị trí chú giải và bỏ lưới nhỏ.

Nhận xét: Kết quả biểu đồ cho thấy cả hai giới tính có phân bố chi tiêu khá tương đồng, tập trung chủ yếu ở khoảng dưới 1.000 đơn vị chi tiêu, phản ánh rằng phần lớn khách hàng chỉ chi tiêu ở mức thấp đến trung bình. Tuy nhiên, phần đuôi bên phải của biểu đồ kéo dài cho thấy một bộ phận nhỏ khách hàng chi tiêu cao hơn đáng kể, có thể là nhóm khách hàng trung thành hoặc có thu nhập cao. Mức chi tiêu trung bình (đường nét đứt màu đen) nằm gần trung tâm phân bố, cho thấy cơ cấu chi tiêu giữa hai giới khá cân bằng, không có sự chênh lệch rõ rệt về giới tính trong hành vi mua hàng. Từ góc nhìn kinh tế, điều này gợi ý rằng giới tính không phải yếu tố quyết định chính trong hành vi chi tiêu, thay vào đó, doanh nghiệp nên tập trung vào phân khúc hành vi (như tần suất mua, loại sản phẩm, hoặc thu nhập) để thiết kế các chiến lược tiếp thị và chăm sóc khách hàng hiệu quả hơn.

4.7 Biểu đồ chi tiêu trung bình theo phương thức giao hàng

1. data %>%
2.   group_by(Shipping_Method) %>%
3.   summarise(Average_Spend = mean(Total_Amount, na.rm = TRUE)) %>%
4.   ggplot(aes(x = reorder(Shipping_Method, Average_Spend),y = Average_Spend)) +
5.   geom_segment(aes(x = reorder(Shipping_Method, Average_Spend),xend = reorder(Shipping_Method, Average_Spend),y = 0, yend = Average_Spend),linewidth = 1.3, color = "#6BA8A9") +
6.   geom_point(size = 6, color = "#FF7F50") +
7.   geom_text(aes(label = round(Average_Spend,0)), 
8.             vjust = -0.8, fontface = "bold", size = 4) +
9.   labs(title = "Chi tiêu trung bình theo phương thức giao hàng",x = "Phương thức giao hàng",y = "Chi tiêu trung bình (đơn vị tiền)",caption = "Nguồn: Bộ 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", size = 11),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "none", panel.grid.minor = element_blank()) +
12.   ylim(0,1800)

Giải thích kỹ thuật:Dòng 1–3 tiến hành nhóm dữ liệu theo Shipping_Method và tính chi tiêu trung bình Average_Spend cho mỗi phương thức giao hàng, bỏ qua giá trị thiếu với na.rm = TRUE. Dòng 4 tạo biểu đồ với trục hoành là các phương thức giao hàng được sắp xếp theo giá trị chi tiêu tăng dần và trục tung là mức chi tiêu trung bình. Dòng 5 dùng geom_segment() để vẽ các cột dạng đường dọc từ 0 đến mức chi tiêu tương ứng nhằm nhấn mạnh độ cao từng giá trị. Dòng 6 vẽ điểm đánh dấu trên đầu mỗi cột giúp trực quan hơn. Dòng 7–8 thêm nhãn số lên mỗi điểm, được làm tròn và đặt phía trên để dễ đọc. Dòng 9 thêm tiêu đề, tên trục và chú thích nguồn dữ liệu.Dòng 12 giới hạn trục tung từ 0 đến 1800 để định dạng biểu diễn trực quan và tránh biểu đồ bị nén.

Nhận xét: Ba phương thức giao hàng phổ biến gồm Standard, Same-Day và Express đều có mức chi tiêu trung bình tương đương nhau, dao động quanh 1367–1368. Điều này cho thấy lựa chọn hình thức giao hàng không ảnh hưởng nhiều đến mức chi tiêu của khách hàng.Doanh nghiệp vì vậy có thể duy trì đa dạng tùy chọn giao hàng mà không làm thay đổi đáng kể hành vi mua hàng.

4.8 Biểu đồ tỷ trọng sản phẩm theo thương hiệu

1. library(treemapify)
2. brand_data <- data %>%
3.   group_by(Product_Brand) %>%
4.   summarise(Count = n())
5. ggplot(brand_data, aes(area = Count,fill = Product_Brand,
6.   label = paste0(Product_Brand, "\n(", comma(Count), ")")
7. )) +
8.   geom_treemap(color = "black", linewidth = 1) +
9.   geom_treemap_text(fontface = "bold",colour = "black",place = "centre",grow = TRUE,min.size = 0.25) +
10.   scale_fill_brewer(palette = "Pastel2") +  
11.   labs(title = "Tỷ trọng sản phẩm theo thương hiệu",caption = "Nguồn: Bộ dữ liệu bán lẻ") +
12.   theme(legend.position = "none",plot.title = element_text(hjust = 0.5, face = "bold", size = 16))

Giải thích kỹ thuật: Dòng 2–4 nhóm dữ liệu theo Product_Brand và đếm số lượng sản phẩm mỗi thương hiệu để tạo bảng tần suất. Dòng 5–7 gọi ggplot() và thiết lập treemap, trong đó area = Count biểu diễn diện tích ô theo số lượng sản phẩm, còn label hiển thị tên thương hiệu kèm số lượng. Dòng 8 sử dụng geom_treemap() để vẽ các ô thương hiệu có viền màu đen giúp phân tách rõ ràng. Dòng 9 dùng geom_treemap_text() để hiển thị nhãn chữ to và tự động co giãn trong từng ô, đảm bảo dễ đọc. Dòng 10 áp dụng bảng màu nhạt từ Pastel2. Cuối cùng, dòng 11–12 thêm tiêu đề biểu đồ, nguồn dữ liệu và loại bỏ legend để biểu đồ gọn và dễ nhìn hơn.

Nhận xét:Biểu đồ cho thấy số lượng sản phẩm phân bố khá đồng đều giữa các thương hiệu, ngoại trừ Pepsi có tỷ trọng lớn hơn đáng kể so với các thương hiệu còn lại, thể hiện mức độ xuất hiện sản phẩm cao hơn trong dữ liệu. Các thương hiệu như Zara, Samsung, Coca-Cola, HarperCollins, Sony, Adidas và Nike có quy mô sản phẩm tương đối tương đương nhau. Trong khi đó, Whirlpool và Mitsubishi chiếm tỷ trọng nhỏ hơn rõ rệt, cho thấy mức độ hiện diện sản phẩm thấp hơn.

4.9 Biểu đồ tỷ lệ hình thức thanh toán trong từng loại giao hàng

1. plot_data <- data %>%
2.   group_by(Shipping_Method, Payment_Method) %>%
3.   summarise(Orders = n()) %>%
4.   group_by(Shipping_Method) %>%
5.   mutate(Percent = Orders / sum(Orders))
6. ggplot(plot_data, aes(x = Shipping_Method, y = Percent, fill = Payment_Method)) +
7.   geom_col(width = 0.65) +
8.   geom_text(aes(label = percent(Percent, accuracy = 1)),position = position_stack(vjust = 0.5),size = 4, fontface = "bold", color = "black") +
9.   scale_y_continuous(labels = scales::percent_format()) +
10.   scale_fill_brewer(palette = "Pastel2") +
11.   labs(title = "Tỷ lệ hình thức thanh toán trong từng phương thức giao hàng",x = "Phương thức giao hàng",y = "Tỷ lệ (%)",fill = "Hình thức thanh toán") +
12.   theme_minimal(base_size = 13) +
13.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13, color = "black"),axis.text.x = element_text(angle = 25, hjust = 1),axis.title = element_text(face = "bold"),legend.position = "right",panel.grid.minor = element_blank())

Giải thích kỹ thuật:Dòng 1–5 thực hiện xử lý dữ liệu: nhóm theo Shipping_Method và Payment_Method, đếm số lượng đơn hàng (Orders), sau đó tiếp tục nhóm theo từng phương thức giao hàng để tính tỷ lệ % của mỗi phương thức thanh toán trong cùng nhóm (Percent = Orders / tổng Orders). Dòng 6–7 vẽ biểu đồ cột chồng thể hiện tỷ lệ các hình thức thanh toán trên từng phương thức giao hàng. Dòng 8 thêm nhãn giá trị tỷ lệ phần trăm ngay trên cột để dễ quan sát. Dòng 9 chuyển trục Y sang dạng phần trăm.

Nhận xét: Biểu đồ cho thấy Credit Card và Debit Card chiếm tỷ lệ cao nhất trong mọi phương thức giao hàng, cho thấy xu hướng thanh toán không tiền mặt. Tuy vậy, Cash vẫn còn phổ biến, đặc biệt ở giao hàng nhanh, phản ánh nhu cầu kiểm tra hàng trước khi trả. Doanh nghiệp nên duy trì đa dạng hình thức thanh toán và khuyến khích không tiền mặt để tối ưu quy trình.

4.10 Số lượng khách hàng theo quốc gia

1. data_country <- data %>%
2.   group_by(Country) %>%
3.   summarise(Customer_Count = n_distinct(Customer_ID)) %>%
4.   arrange(Customer_Count)
5. ggplot(data_country, aes(x = Customer_Count, y = reorder(Country, Customer_Count), fill = Customer_Count)) +
6.   geom_col(width = 0.65, color = "white") +
7.   geom_text(aes(label = scales::label_number(big.mark = ".")(Customer_Count)),hjust = -0.2, size = 4, fontface = "bold", color = "black") +
8.   scale_fill_gradient(low = "#B3D7F2", high = "#005F9E") +
9.   labs(title = "Số lượng khách hàng theo quốc gia",x = "Số khách hàng",y = "Quốc gia",fill = "Số khách hàng",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 = 14, 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 = "right",panel.grid.minor = element_blank() ) +
12.   expand_limits(x = max(data_country$Customer_Count) * 1.12)

Giải thích kỹ thuật:Dòng 1–4 xử lý dữ liệu: nhóm theo Country, đếm số lượng khách hàng khác nhau bằng n_distinct(Customer_ID) rồi sắp xếp tăng dần theo Customer_Count để biểu đồ dễ quan sát hơn. Dòng 5 thiết lập ggplot với trục X là số khách hàng và trục Y là tên quốc gia được reorder theo giá trị, giúp quốc gia có ít khách nhất nằm trên cùng. Dòng 6 vẽ biểu đồ cột ngang, mỗi cột biểu diễn số khách hàng theo quốc gia. Dòng 12 mở rộng giới hạn trục X để tránh trường hợp nhãn số lượng bị tràn ra ngoài biểu đồ.

Nhận xét: > Quan sát biểu đồ cho thấy có sự khác biệt rõ rệt giữa các quốc gia trong cơ cấu mua sắm. Mỹ (USA) là thị trường có tổng giá trị mua hàng cao nhất ở hầu hết các danh mục, đặc biệt nổi bật trong nhóm hàng tạp hóa (Grocery) với tổng giá trị lên đến khoảng 139.693 — mức cao nhất toàn bộ bảng. > Tiếp đến là nhóm điện tử (Electronics) với 107.667 và trang trí nội thất (Home Decor) với 86.633. Điều này phản ánh quy mô tiêu dùng lớn và sức mua mạnh mẽ của thị trường Mỹ. > Ngược lại, các quốc gia như Australia, Canada, và Germany có tổng giá trị mua thấp hơn đáng kể, dao động trong khoảng 44.000–69.000 ở hầu hết các danh mục. > Xét về mặt kinh tế - tài chính, biểu đồ heatmap cung cấp thông tin quan trọng về sức mua và tiềm năng thị trường. Việc các danh mục như Grocery và Electronics chiếm tỷ trọng cao tại các quốc gia phát triển (như Mỹ và Anh) cho thấy nhu cầu ổn định và liên quan đến các mặt hàng thiết yếu, đồng thời phản ánh mức chi tiêu tiêu dùng cao. Ngược lại, các quốc gia có tổng mua thấp hơn có thể đại diện cho thị trường đang phát triển hoặc mức độ thâm nhập thấp, gợi ý tiềm năng mở rộng trong tương lai.

4.11 Phân phối tần suất mua hàng của khách hàng

1. customer_frequency <- data %>%
2.   group_by(Customer_ID) %>%
3.   summarise(Total_Transactions = n()) %>%
4.   na.omit() %>%
5.   mutate(Customer_Type = ifelse(Total_Transactions >= 3,"Khách hàng trung thành (≥3 lần)","Khách hàng thông thường (1–2 lần)"))
6. med_value <- median(customer_frequency$Total_Transactions)
7. ggplot(customer_frequency, aes(x = Total_Transactions, fill = Customer_Type)) +
8.   geom_histogram(binwidth = 1, color = "black", alpha = 0.9) +
9.   stat_bin(binwidth = 1, geom = "text",aes(label = comma(..count..)),vjust = -0.3, size = 2, color = "black") +
10.   scale_y_log10(
11.     name = "Số lượng Khách hàng (Thang đo Log)",
12.     labels = function(x) format(x, big.mark = ".", decimal.mark = ",")) +
13.   scale_x_continuous(name = "Số lần Giao dịch (Tần suất Mua hàng)",breaks = seq(1, 20, 1),limits = c(0.5, 20.5)) +
14.   scale_fill_manual(values = c("#A5C9F9", "#0073C2FF")) +
15.   labs(title = "Phân phối Tần suất Mua hàng của Khách hàng",subtitle = "Nhóm mua ≥ 3 lần đại diện cho khách hàng trung thành — đóng vai trò quan trọng",fill = "Phân loại",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
16.   geom_vline(xintercept = med_value, color = "red", linetype = "dashed", size = 1) +
17.   annotate("text",x = med_value + 0.3,y = max(table(customer_frequency$Total_Transactions)) * 5,label = paste("Median =", med_value),color = "red", fontface = "bold", hjust = 0, size = 3) +
18.   theme_minimal(base_size = 13) +
19.   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–4 xử lý dữ liệu: nhóm theo Customer_ID, tính số lần giao dịch của mỗi khách bằng n(), loại bỏ giá trị thiếu rồi phân loại thành hai nhóm theo ngưỡng ≥3 giao dịch để xác định khách hàng trung thành. Dòng 6 tính giá trị trung vị của tần suất mua để dùng làm mốc tham chiếu trực quan. Dòng 7 thiết lập biểu đồ với trục X là số lần giao dịch và màu sắc theo nhóm khách hàng. Dòng 8–9 vẽ biểu đồ histogram và hiển thị số lượng khách tương ứng trên từng cột, giúp dễ đọc phân bố. Dòng 10–13 điều chỉnh trục tung sang thang log và thiết lập giới hạn.Dòng 14 gán màu phân biệt hai nhóm khách hàng. Dòng 16–17 kẻ đường đứng tại giá trị trung vị và hiển thị nhãn để nhấn mạnh ngưỡng phổ biến trong hành vi mua.

Nhận xét: Biểu đồ cho thấy phần lớn khách hàng chỉ mua từ 1–3 lần, sau đó số lượng giảm mạnh khi tần suất tăng. Điều này phản ánh đa số là khách hàng mua ngắn hạn, trong khi nhóm mua lặp lại nhiều lần (≥8 hoặc ≥10 lần) chiếm tỷ lệ nhỏ nhưng có giá trị cao. Do đó, doanh nghiệp nên tập trung các chiến lược giữ chân khách hàng như ưu đãi quay lại, tích điểm, hoặc chăm sóc cá nhân hóa để tăng số lần mua. Bên cạnh đó, nhóm khách hàng trung thành tuy ít nhưng đóng góp doanh thu lớn hơn và chi phí duy trì thấp hơn, vì vậy cần được nhận diện và chăm sóc đặc biệt để tối ưu giá trị vòng đời khách hàng.

4.12 Phân bố khách hàng theo nhóm thu nhập

1. income_category <- data %>%
2.   group_by(Income, Product_Category) %>%
3.   summarise(Total_Customers = n(), .groups = "drop")
4. ggplot(income_category, aes(x = Income, y = Product_Category, fill = Total_Customers)) +
5.   geom_tile(color = "black") +
6.   geom_text(aes(label = scales::label_number(big.mark = ".")(Total_Customers)), color = "black", size = 4) +
7.   scale_fill_distiller(palette = "YlGnBu", direction = 1) +
8.   labs(title = "Mức độ mua theo nhóm thu nhập và danh mục sản phẩm", x = "Nhóm thu nhập", y = "Danh mục sản phẩm",fill = "Số khách hàng",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 = "right",panel.grid.minor = element_blank() ) 

Giải thích kỹ thuật: Dòng 1–3 nhóm dữ liệu theo Income và Product_Category rồi đếm số khách hàng trong từng nhóm để xác định mức độ mua sắm theo thu nhập và danh mục sản phẩm. Dòng 4 tạo biểu đồ heatmap, trong đó trục X là nhóm thu nhập, trục Y là danh mục sản phẩm, màu sắc thể hiện số lượng khách hàng. Dòng 5 vẽ các ô màu đại diện cho mỗi cặp giá trị thu nhập – danh mục sản phẩm. Dòng 6 thêm nhãn số khách hàng trực tiếp trên từng ô giúp so sánh dễ dàng. Dòng 7 dùng thang màu từ nhạt đến đậm để biểu thị mức độ khác biệt về số lượng khách hàng. Dòng 8 thêm tiêu đề và nhãn trục.

Nhận xét: Từ kết quả biểu đồ ta có thể thấy nhóm Medium chiếm tỷ trọng lớn nhất, cho thất phần lớn khách hàng thuộc tầng lớn trung lưu -> điều này gợi ý cho doanh nghiệp nên tập trung vào các sản phẩm, dịch vụ phổ thông hoặc trung cấp, phù hợp với khả năng chi trả của tệp khách hàng này. Nhóm Low cũng chiếm tỷ lệ đáng kể, chứng tỏ vẫn còn có lượng khách hàng có thu nhập hạn chế, doanh nghiệp nên có thể xem cét chính sách giá linh hoạt, khuyến mãi hoặc sản phẩm giá rẻ để có thể dễ dàng tiếp cận nhóm này. Nhóm High dù chiếm tỷ lệ nhỏ, đây là phân khúc có khả năng chi tiêu lớn, phù hợp để phát triển sản phẩm cao cấp hoặc các dịch vụ các nhân hóa.

4.13 Tỷ lệ khách hàng theo nhóm thu nhập

1. data %>%
2.   count(Income) %>%
3.   mutate(Percent = n / sum(n) * 100) %>%
4.   ggplot(aes(x = Income, y = Percent, fill = Income)) +
5.   geom_col(color = "white", width = 0.7) +
6.   geom_text(aes(label = paste0(round(Percent, 1), "%")),  vjust = -0.6, size = 4.2, fontface = "bold") +
7.   scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
8.   scale_fill_brewer(palette = "Set2") +
9.   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ẻ") +
10.   theme_minimal(base_size = 13) +
11.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 14),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "none",panel.grid.minor = element_blank())

Giải thích kỹ thuật:Dòng 1–3 nhóm dữ liệu theo Income và tính tỷ lệ phần trăm khách hàng trong từng nhóm thu nhập. Dòng 4 thiết lập biểu đồ cột với trục X là nhóm thu nhập và trục Y là tỷ lệ khách hàng. Dòng 5 vẽ các cột thể hiện tỷ lệ từng nhóm thu nhập. Dòng 6 thêm nhãn phần trăm trên đầu cột.Dòng 7 điều chỉnh trục Y để chừa khoảng trống cho nhãn hiển thị rõ ràng.

Nhận xét: Kết quả cho thấy nhóm Medium chiếm tỷ lệ lớn nhất (khoảng 43.1%), tiếp theo là nhóm Low (~31.9%) và nhóm High chiếm khoảng 24.9%. Cấu trúc này cho thấy phần lớn khách hàng thuộc nhóm thu nhập trung bình, là nhóm mục tiêu chính cho các chiến lược tiếp thị tổng quát và các chương trình khuyến mãi. Nhóm thu nhập cao tuy ít hơn nhưng có thể đóng góp giá trị đơn hàng lớn hơn; do đó doanh nghiệp cần cân bằng giữa chính sách thu hút khách hàng trung bình (tăng số lượng giao dịch) và chiến lược chăm sóc khách hàng cao cấp (tăng giá trị trên mỗi giao dịch).

4.14 Tỷ lệ khách hàng theo phân khúc

1. segment_count <- data %>%
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 = 2, y = So_KH, fill = Customer_Segment)) +
6.   geom_col(color = "white", width = 1) +
7.   coord_polar(theta = "y") +
8.   xlim(0.5, 2.5) +
9.   geom_text(aes(label = paste0(round(Percent, 1), "%")),position = position_stack(vjust = 0.5),color = "black", size = 4, fontface = "bold") +
10.   scale_fill_manual(values = c("#6BAED6", "#9ECAE1", "#C6DBEF", "#08306B")) +
11.   labs(title = "Tỷ lệ khách hàng theo phân khúc",fill = "Phân khúc khách hàng",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
12.   theme_void() +
13.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 14),legend.position = "right")

Giải thích kỹ thuật: Dòng 1–4 nhóm dữ liệu theo Customer_Segment, đếm số khách hàng mỗi phân khúc và tính tỷ lệ phần trăm để so sánh cơ cấu. Dòng 5–6 thiết lập biểu đồ với trục y là số lượng khách hàng và fill thể hiện từng phân khúc. Dòng 7 chuyển biểu đồ cột thành biểu đồ tròn bằng coord_polar, dòng 8 căn chỉnh bán kính để biểu đồ cân đối. Dòng 9 thêm nhãn phần trăm ngay trên từng phần của vòng tròn.

Nhận xét: Biểu đồ cho thấy nhóm Regular chiếm tỷ trọng lớn nhất, tiếp theo là New và cuối cùng là Premium. Điều này phản ánh doanh nghiệp có lượng khách hàng duy trì ổn định và vẫn thu hút được khách hàng mới, nhưng nhóm Premium còn thấp. Doanh nghiệp nên đẩy mạnh chương trình chăm sóc và ưu đãi để tăng tỷ trọng Premium,đồng thời tiếp tục duy trì hoạt động thu hút khách hàng mới để đảm bảo tăng trưởng dài hạn.

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 <- data %>%
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.   geom_text(aes(label = label_number(big.mark = ".")(n)), vjust = -0.3, size = 4, fontface = "bold") +
7.   facet_wrap(~ Product_Brand, scales = "fixed") +
8.   theme_minimal() +
9.   theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
10.   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ẻ" ) +
11. scale_fill_brewer(palette = "Set2") +
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.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: Dòng 1–3 nhóm dữ liệu theo Product_Brand và Product_Category rồi đếm số lượng đơn mỗi nhóm, tạo bảng ttt dùng cho vẽ. Dòng 4 thiết lập ggplot với trục X là danh mục sản phẩm và trục Y là số lượng đơn. Dòng 5 vẽ cột biểu diễn số đơn theo từng danh mục. Dòng 6 dùng facet_wrap để chia biểu đồ thành nhiều ô, mỗi ô đại diện cho một thương hiệu, giúp so sánh dễ hơn. Dòng 8 xoay nhãn trục X để tránh chồng chữ. Dòng 9 đặt tiêu đề và tên trục. Dòng 11–12 điều chỉnh giao diện

Nhận xét: Biểu đồ cho thấy mỗi thương hiệu có xu hướng tập trung vào một số danh mục sản phẩm chủ lực: Nike và Zara nổi bật ở Clothing, Apple – Samsung – Sony tập trung vào Electronics, trong khi Coca-Cola và Pepsi chủ yếu thuộc Grocery. Một số thương hiệu như IKEA hay Home Depot phân bố ở nhiều danh mục hơn, phản ánh chiến lược đa dạng hóa sản phẩm giúp giảm rủi ro và duy trì doanh thu ổn định.Về mặt kinh doanh – tài chính, số lượng đơn cao ở danh mục chủ lực cho thấy thương hiệu có định vị rõ ràng và nhu cầu thị trường ổn định. Tuy nhiên, số lượng đơn chưa phản ánh doanh thu hay lợi nhuận, vì giá trị đơn hàng giữa các danh mục khác nhau (điện tử thường có giá trị cao hơn sách hay tiêu dùng nhanh). Do đó, để đánh giá hiệu quả chính xác hơn, doanh nghiệp cần kết hợp thêm chỉ tiêu như giá trị đơn hàng trung bình (AOV) hoặc biên lợi nhuận theo sản phẩm, từ đó tối ưu phân bổ vốn, hàng tồn kho và chiến lược marketing phù hợp.

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 <- data %>%
2.   group_by(Product_Brand, Product_Category) %>%
3.   summarise(
4.     m = mean(Amount, na.rm = TRUE),
5.     sd = sd(Amount, na.rm = TRUE),
6.     n = n(),
7.     se = sd / sqrt(n),
8.     .groups = "drop")
9. ggplot(xxx, aes(x = Product_Category, y = m, fill = Product_Category)) +
10.   geom_col(show.legend = FALSE, width = 0.7) +                          
11.   geom_errorbar(aes(ymin = m - se, ymax = m + se), width = 0.2, color = "black") + 
12.   geom_text(aes(label = round(m, 1)), vjust = -0.3, size = 2, color = "black") +   
13.   facet_wrap(~ Product_Brand, scales = "fixed") +  
14.   scale_fill_brewer(palette = "Set3") +
15.   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ẻ") +
16.   theme_minimal(base_size = 13) +
17.   theme(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:Dòng 1–8 tính toán giá trị trung bình và sai số: dữ liệu được nhóm theo Product_Brand và Product_Category, sau đó tính trung bình (m), độ lệch chuẩn (sd), số lượng quan sát (n) và sai số chuẩn (se) để dùng cho biểu đồ cột có thanh sai số. Dòng 9 thiết lập ggplot với trục X là danh mục sản phẩm và trục Y là giá trị trung bình. Dòng 10 vẽ cột biểu diễn giá trị trung bình của Amount. Dòng 11 thêm thanh sai số (error bar) cho biết mức biến động quanh giá trị trung bình. Dòng 12 hiển thị giá trị trung bình lên trên mỗi cột. Dòng 13 tách biểu đồ thành nhiều ô theo từng thương hiệu, giúp so sánh rõ ràng giữa các brand.

Nhận xét: Biểu đồ cho thấy mức chi tiêu trung bình giữa các thương hiệu có sự khác biệt, nhưng nhìn chung tập trung quanh khoảng 250 đơn vị. Một số thương hiệu như Pepsi, Penguin Books và IKEA có mức chi tiêu trung bình cao hơn, phản ánh sản phẩm có giá trị hóa đơn lớn hoặc khách hàng có xu hướng mua nhiều hơn trong mỗi đơn. Ngược lại, các thương hiệu như Coca-Cola hoặc BlueStar có mức chi tiêu trung bình thấp hơn do đặc thù nhóm hàng tiêu dùng nhanh, giá trị đơn hàng nhỏ nhưng bù lại số lượng giao dịch cao. Ý nghĩa kinh doanh: Thương hiệu có mức chi tiêu trung bình cao thường đạt biên lợi nhuận tốt và có định vị sản phẩm rõ ràng; trong khi các thương hiệu có mức trung bình thấp cần tập trung mở rộng thị phần hoặc gia tăng tần suất mua để đảm bảo hiệu quả doanh thu. Đồng thời, độ dài thanh sai số cho thấy mức ổn định của chi tiêu: sai số lớn doanh thu còn biến động, cần xem xét điều chỉnh chiến lược giá hoặc khuyến mãi để ổn định tăng trưởng.

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

1. data <- data %>%
2.   mutate(Ratings = round(Ratings))
3. ratings_summary <- data %>%
4.   count(Ratings) %>%
5.   mutate(perc = n / sum(n))
6. ggplot(ratings_summary, aes(x = factor(Ratings), y = perc, fill = factor(Ratings))) +
7.   geom_col(width = 0.6, color = NA) +
8.   geom_text(aes(label = paste0(round(perc*100,1), "%")),
9.             vjust = -0.6, size = 4, fontface = "bold") +
10.   scale_y_continuous(labels = percent_format(accuracy = 1), expand = expansion(mult = c(0, 0.1))) +
11.   scale_fill_brewer(palette = "Blues") +
12.   labs(title = "Mức độ đánh giá sản phẩm",subtitle = "Phân bố tỷ lệ các mức điểm đánh giá (1–5)",x = "Điểm đánh giá",y = "Tỷ lệ (%)",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
13.   theme_minimal(base_size = 13) +
14.   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 = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "none",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 2, hàm round(Ratings) được dùng để làm tròn điểm đánh giá về dạng số nguyên để dễ phân loại. Dòng 4 sử dụng count(Ratings) để đếm số lượng đánh giá ở mỗi mức điểm. Dòng 5 tính tỷ lệ phần trăm của từng mức bằng cách lấy số lượng chia cho tổng số. Ở dòng 6, biểu đồ cột được tạo, lấy trục x là mức điểm đánh giá và trục y là tỷ lệ. Dòng 8 thêm nhãn phần trăm ngay trên mỗi cột để biểu diễn trực quan mức độ phân bố. Cuối cùng, dòng 10 chuyển giá trị tỷ lệ thành định dạng phần trăm và điều chỉnh khoảng trống phía trên biểu đồ

Nhận xét:Biểu đồ cho thấy điểm đánh giá của khách hàng tập trung chủ yếu ở mức 4 sao, thể hiện mức độ hài lòng tương đối cao. Các mức 2–3 sao xuất hiện ở mức trung bình, còn 1 và 5 sao khá thấp, cho thấy chỉ có một nhóm nhỏ khách hàng không hài lòng hoặc đánh giá xuất sắc. Phân bố này thiên về mức điểm cao, phản ánh trải nghiệm người dùng nhìn chung là tích cực. Về mặt kinh doanh, tỷ lệ cao ở mức 4 sao giúp doanh nghiệp duy trì uy tín thương hiệu, ổn định doanh thu và tăng khả năng mua lại, từ đó nâng cao giá trị vòng đời khách hàng. Tuy nhiên, việc mức 5 sao chưa chiếm tỷ trọng lớn cho thấy vẫn còn dư địa cải thiện trải nghiệm, đặc biệt trong chất lượng dịch vụ hoặc sản phẩm. Đồng thời, nhóm khách hàng cho điểm thấp (1–2 sao) cần được xem xét kỹ để xác định nguyên nhân không hài lòng, nhằm giảm rủi ro mất khách và cải thiện hiệu quả dài hạn.

4.18 Biểu đồ điểm đánh giá theo thương hiệu

1. library(ggridges)
2. library(forcats)
3. top5_brands <- data %>%
4.   group_by(Product_Brand) %>%
5.   summarise(mean_feedback = mean(FeedbackScore, na.rm = TRUE)) %>%
6.   arrange(desc(mean_feedback)) %>%
7.   slice(1:5) %>%
8.   pull(Product_Brand)
9. data_top5 <- data %>%
10.   filter(Product_Brand %in% top5_brands) %>%
11.   mutate(Product_Brand = fct_reorder(Product_Brand, FeedbackScore, .fun = mean, .desc = TRUE))
12. ggplot(data_top5, aes(x = FeedbackScore, y = Product_Brand, fill = after_stat(x))) +
13.   stat_density_ridges(geom = "density_ridges_gradient",scale = 1.4,rel_min_height = 0.01,alpha = 0.9,color = "white",size = 0.6) +
14.   scale_fill_gradientn(colors = c("#7E57C2", "#42A5F5", "#26A69A", "#FFCA28", "#EF5350")) +
15.   labs(title = "Phân bố điểm phản hồi của Top 5 thương hiệu",subtitle = "Màu sắc thể hiện mức điểm: màu càng nóng điểm phản hồi càng cao",x = "Điểm phản hồi",y = "Thương hiệu",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ") +
16.   theme_minimal(base_size = 13) +
17.   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 = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "none",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 3–8 tính điểm phản hồi trung bình theo thương hiệu, sắp xếp giảm dần và chọn ra Top 5 thương hiệu có mức phản hồi cao nhất. Dòng 9–11 lọc dữ liệu chỉ giữ các thương hiệu này và dùng fct_reorder để sắp xếp lại thứ tự thương hiệu theo điểm phản hồi trung bình, giúp biểu đồ trực quan hơn. Dòng 12–13 vẽ biểu đồ ridge plot, trong đó trục X là điểm phản hồi, trục Y là thương hiệu, và đường phân bố thể hiện mật độ điểm, phần tô màu thể hiện giá trị điểm, màu càng nóng nghĩa là điểm càng cao.

Nhận xét: Biểu đồ cho thấy cả 5 thương hiệu đều có xu hướng điểm phản hồi tập trung quanh mức từ 4 đến 5, thể hiện mức độ hài lòng khá cao của khách hàng. Trong đó, BlueStar và Mitsubishi có mật độ tập trung rõ nhất ở điểm 5, cho thấy khách hàng đánh giá rất tích cực. Ngược lại, Pepsi và Samsung có phân bố trải rộng hơn, xuất hiện nhiều điểm thấp hơn, cho thấy trải nghiệm khách hàng giữa các nhóm sản phẩm có sự không đồng đều. Biểu đồ giúp doanh nghiệp xác định thương hiệu nào đang duy trì chất lượng phản hồi tốt và thương hiệu nào cần cải thiện tính ổn định trong trải nghiệm khách hàng.

4.19 Biểu đồ doanh số từng tháng của loại sản phẩm

1. library(lubridate)
2. data <- data %>%
3.   filter(!is.na(Date)) %>%
4.   mutate(Month = floor_date(Date, "month"))
5. data_month <- data %>%
6.   group_by(Month, Product_Type) %>%
7.   summarise(Total_Amount = n(), .groups = "drop")
8. top3_type_each_month <- data_month %>%
9.   group_by(Month) %>%
10.   mutate(rank = dense_rank(desc(Total_Amount))) %>%
11.   filter(rank <= 3) %>%
12.   ungroup()
13. ggplot(top3_type_each_month, aes(x = Month, y = Total_Amount, color = Product_Type, group = Product_Type)) +
14.   geom_line(size = 1.3) +
15.   geom_point(size = 3) +
16.   labs(title = "Top 3 loại sản phẩm bán chạy nhất theo từng tháng",x = "Tháng", y = "Số lần mua",caption = "Nguồn: Báo cáo phân tích dữ liệu bán lẻ",color = "Loại sản phẩm") +
17.   scale_x_date(date_labels = "%b %Y", date_breaks = "1 month") +
18.   theme_minimal(base_size = 13) +
19.   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 = "none",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 3–4 làm sạch dữ liệu, loại bỏ các giá trị thiếu ở biến Date và tạo biến Month bằng cách làm tròn ngày về đầu tháng để phục vụ phân tích theo tháng. Dòng 5–7 nhóm dữ liệu theo tháng và loại sản phẩm, sau đó tính tổng số lượt mua (Total_Amount) trong từng nhóm. Dòng 8–12 tiếp tục nhóm theo tháng, tính thứ hạng số lượt mua bằng dense_rank(), lọc ra Top 3 loại sản phẩm bán chạy nhất mỗi tháng, rồi bỏ nhóm để chuẩn bị vẽ biểu đồ. Dòng 13–15 vẽ biểu đồ đường, trong đó trục X là thời gian theo tháng, trục Y là số lượt mua, mỗi đường biểu diễn một loại sản phẩm, kết hợp thêm điểm đánh dấu để dễ quan sát xu hướng.

Nhận xét: Biểu đồ thể hiện 3 loại sản phẩm bán chạy nhất theo từng tháng, trong đó có một loại sản phẩm luôn duy trì số lượt mua cao vượt trội so với hai loại còn lại, cho thấy vai trò sản phẩm chủ lực trong doanh thu. Hai loại sản phẩm còn lại giữ mức tiêu thụ ổn định, biến động nhẹ theo thời gian. Xu hướng này cho thấy doanh nghiệp có cơ cấu tiêu thụ tương đối ổn định, nhưng phụ thuộc đáng kể vào một nhóm sản phẩm chính; do đó có thể xem xét mở rộng hoặc thúc đẩy nhóm sản phẩm thứ hai và thứ ba để giảm rủi ro phụ thuộc.

4.20 Biểu đồ phương thức vận chuyển và trạng thái đơn hàng

1. ship_status <- data %>%
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",x = "Phương thức vận chuyển",y = "Tỷ lệ (%)",fill = "Trạng thái đơn hàng") +
12.   theme_minimal(base_size = 13) +
13.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 14),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "right",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 1–6 lọc dữ liệu để chỉ giữ những dòng có đầy đủ thông tin về phương thức vận chuyển và trạng thái đơn hàng, sau đó nhóm theo Shipping_Method và Order_Status để đếm số lượng đơn từng nhóm, rồi tiếp tục nhóm theo Shipping_Method để tính tỷ lệ phần trăm trạng thái trong mỗi phương thức vận chuyển. Dòng 7–9 vẽ biểu đồ cột chồng theo tỷ lệ (position = “fill”), trục X là phương thức vận chuyển, trục Y là tỷ lệ từng trạng thái đơn hàng, đồng thời thêm nhãn phần trăm cho từng phần cột. Dòng 10–13 định dạng trục, tiêu đề.

Nhận xét: Biểu đồ cho thấy ở tất cả các phương thức vận chuyển, tỷ lệ đơn hàng đã giao chiếm tỷ lệ cao nhất (khoảng 42–44%), chứng tỏ quy trình giao hàng nhìn chung hoạt động hiệu quả. Tuy nhiên, nhóm đơn đang xử lý hoặc chờ xử lý vẫn chiếm khoảng 16–21%, cho thấy còn tồn đọng nhất định trong quy trình xử lý kho và chuẩn bị hàng.


PHẦN 2: BỘ DỮ LIỆU MÃ CHỨNG KHOÁN HPG

Chương 1: Giới thiệu bộ dữ liệu mà chứng khoán HPG

  • 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. install.packages("readxl")
2. library(readxl)
3. HPG <- read_excel("C:/Users/HP/OneDrive - UFM/HPG.xlsx")
4. head(HPG)
## # 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>, …

Giải thích kỹ thuật: Để đọc dữ liệu tôi sử dụng gói readxl đọc dữ liệu tài chính từ file excel vào môi trường phân tích. Cụ thể, lệnh install.packages(“readxl”) được dùng để cài đặt gói hỗ trợ đọc file Excel, còn library(readxl) giúp kích hoạt gói này để sử dụng. Hàm read_excel() đọc dữ liệu từ đường dẫn chỉ định và lưu vào biến HPG dưới dạng bảng dữ liệu (data frame), giúp R nhận diện và xử lý các cột số liệu, ký tự, ngày tháng một cách tự động. Cuối cùng, lệnh head(HPG) hiển thị sáu dòng đầu tiên của bảng nhằm kiểm tra dữ liệu đã được nhập đúng hay chưa.

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

1. head(HPG,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,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)
## [1] 10 16

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

Nhận xét: Ta nhận được kết quả [1] 10 16 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 (như Doanh thu, Lợi nhuận, Tổng tài sản, Nợ, Vốn chủ sở hữu, v.v.).

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

1. names(HPG)
##  [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)
## 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

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

1. library(flextable)
2. HPG_type <- sapply(HPG, class)
3. df <- data.frame(Variable = names(HPG_type), Type = HPG_type, row.names = NULL)
4. flextable(df) |> autofit()

Variable

Type

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)
##       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; 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

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 Mô tả ý nghĩa từng biến

1. library(flextable)
2. library(dplyr)
3. mo_ta_bien <- data.frame(
4.   Ten_Bien = c(
5.     "Năm",
6.     "Doanh thu thuần về bán hàng và cung cấp dịch vụ",
7.     "Giá vốn hàng bán",
8.     "Lợi nhuận gộp",
9.     "Đầu tư tài chính ngắn hạn",
10.     "Tài sản dài hạn",
11.     "Lợi nhuận trước thuế",
12.     "Lợi nhuận sau thuế",
13.     "Tổng tài sản",
14.     "Nợ phải trả",
15.     "Vốn chủ sở hữu",
16.     "Tiền và các khoản tương đương tiền",
17.     "Tài sản ngắn hạn",
18.     "Lưu chuyển tiền thuần từ hoạt động kinh doanh",
19.     "Lưu chuyển tiền thuần từ hoạt động đầu tư",
20.     "Lưu chuyển tiền thuần từ hoạt động tài chính"),
21.   Y_Nghia = c(
22.     "Năm tài chính mà dữ liệu được ghi nhận.",
23.     "Tổng doanh thu thuần từ hoạt động bán hàng và cung cấp dịch vụ của doanh nghiệp.",
24.     "Tổng chi phí sản xuất hoặc mua hàng hóa, dịch vụ đã bán trong kỳ.",
25.     "Chênh lệch giữa doanh thu thuần và giá vốn hàng bán, phản ánh hiệu quả hoạt động cốt lõi.",
26.     "Giá trị các khoản đầu tư tài chính ngắn hạn (chứng khoán, tiền gửi ngắn hạn...).",
27.     "Tài sản dài hạn như máy móc, thiết bị, tài sản cố định và đầu tư dài hạn.",
28.     "Lợi nhuận đạt được trước khi trừ thuế thu nhập doanh nghiệp.",
29.     "Lợi nhuận còn lại sau khi trừ thuế thu nhập doanh nghiệp.",
30.     "Tổng tài sản của doanh nghiệp tại thời điểm báo cáo.",
31.     "Tổng nghĩa vụ nợ phải trả bao gồm nợ ngắn hạn và dài hạn.",
32.     "Giá trị vốn góp và lợi nhuận giữ lại của cổ đông trong doanh nghiệp.",
33.     "Tiền mặt và các khoản có thể chuyển đổi nhanh thành tiền.",
34.     "Giá trị tài sản ngắn hạn có thể chuyển thành tiền trong vòng một năm.",
35.     "Dòng tiền thuần từ hoạt động sản xuất – kinh doanh.",
36.     "Dòng tiền thuần từ hoạt động đầu tư.",
37.     "Dòng tiền thuần từ hoạt động tài chính như vay nợ, trả nợ, chia cổ tức."),Don_Vi_Tinh = c("Năm", rep("VND", 15)))
38. tbl <- flextable(mo_ta_bien) |>
39.   autofit() |>
40.   align(align = "left", part = "all") |>
41.   theme_vanilla() |>
42.   set_caption("Bảng 1.9: Mô tả ý nghĩa các biến trong bộ dữ liệu HPG (2015–2024)") |>
43.   fontsize(size = 10, part = "all") |>
44.   width(width = c(2.5, 4.8, 1))   # chỉnh độ rộng cột
45. tbl
Bảng 1.9: Mô tả ý nghĩa các biến trong bộ dữ liệu HPG (2015–2024)

Ten_Bien

Y_Nghia

Don_Vi_Tinh

Năm

Năm tài chính mà dữ liệu được ghi nhận.

Năm

Doanh thu thuần về bán hàng và cung cấp dịch vụ

Tổng doanh thu thuần từ hoạt động bán hàng và cung cấp dịch vụ của doanh nghiệp.

VND

Giá vốn hàng bán

Tổng chi phí sản xuất hoặc mua hàng hóa, dịch vụ đã bán trong kỳ.

VND

Lợi nhuận gộp

Chênh lệch giữa doanh thu thuần và giá vốn hàng bán, phản ánh hiệu quả hoạt động cốt lõi.

VND

Đầu tư tài chính ngắn hạn

Giá trị các khoản đầu tư tài chính ngắn hạn (chứng khoán, tiền gửi ngắn hạn...).

VND

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

Tài sản dài hạn như máy móc, thiết bị, tài sản cố định và đầu tư dài hạn.

VND

Lợi nhuận trước thuế

Lợi nhuận đạt được trước khi trừ thuế thu nhập doanh nghiệp.

VND

Lợi nhuận sau thuế

Lợi nhuận còn lại sau khi trừ thuế thu nhập doanh nghiệp.

VND

Tổng tài sản

Tổng tài sản của doanh nghiệp tại thời điểm báo cáo.

VND

Nợ phải trả

Tổng nghĩa vụ nợ phải trả bao gồm nợ ngắn hạn và dài hạn.

VND

Vốn chủ sở hữu

Giá trị vốn góp và lợi nhuận giữ lại của cổ đông trong doanh nghiệp.

VND

Tiền và các khoản tương đương tiền

Tiền mặt và các khoản có thể chuyển đổi nhanh thành tiền.

VND

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

Giá trị tài sản ngắn hạn có thể chuyển thành tiền trong vòng một năm.

VND

Lưu chuyển tiền thuần từ hoạt động kinh doanh

Dòng tiền thuần từ hoạt động sản xuất – kinh doanh.

VND

Lưu chuyển tiền thuần từ hoạt động đầu tư

Dòng tiền thuần từ hoạt động đầu tư.

VND

Lưu chuyển tiền thuần từ hoạt động tài chính

Dòng tiền thuần từ hoạt động tài chính như vay nợ, trả nợ, chia cổ tức.

VND

Giải thích kỹ thuật: đoạn code sử dụng ác thư viện knitr và kableExtra để tạo bảng mô tả ý nghĩa các biến trong bộ dữ liệu HPG. Đầu tiên, dữ liệu được khởi tạo bằng hàm data.frame() với ba cột gồm tên biến, ý nghĩa và đơn vị tính. Sau đó, hàm kable() được dùng để hiển thị bảng, kết hợp với kable_styling() nhằm định dạng lại cho bảng có giao diện đẹp hơn. Kết quả là bảng mô tả gồm 16 biến phản ánh toàn diện các chỉ tiêu tài chính chính yếu của Tập đoàn Hòa Phát giai đoạn 2015–2024.

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

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

Giải thích kỹ thuật: Để đặt lại tên biến cho ngắn gọn đoạn code sử dụng dplyr::rename() để đổi các tên cột dài, có dấu và khoảng trắng thành tên ngắn gọn, thuận tiện cho việc xử lý và lập biểu đồ. Việc đổi tên chỉ tác động lên tên cột mà không thay đổi nội dung hay kiểu dữ liệu; sau khi thực hiện cần kiểm tra lại thông tin bằng names() hoặc glimpse().

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à Net cash flow from financing 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 Net cash flow from financing.

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

1. library(dplyr)
2. HPG <- HPG %>% mutate( across( .cols = where(is.numeric), .fns = ~ ifelse(is.na(.), mean(., na.rm = TRUE), .)))
3. 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

Nhận xét: Sau khi xử lý dữ liệu bị thiếu, giá trị NA trong biến Net cash flow from financing đã đượ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 thuần sau thuế của HPG không có dữ liệu bất thường.

Chương 3: Thống kê cơ bản

3.1 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(mean_DT = mean(DoanhThu),sd_DT = sd(DoanhThu),cv_DT = sd_DT / mean_DT * 100,mean_LN = mean(LN_SauThue),sd_LN = sd(LN_SauThue),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, tôi sử dụng hàm summarise() trong R để 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 (coefficient of variation – CV). 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 (%). Các phép tính này giúp đánh giá mức ổn định và rủi ro trong hoạt động kinh doanh của doanh nghiệp.

Nhận xét: Theo kết quả ta thấy 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.Nhìn trên phương diện kinh tế ta có thể thấy Hòa Phát là doanh nghiệp có quy mô doanh thu lớn, song hiệu quả lợi nhuận chịu tác động mạnh của chu kỳ ngành và biến động thị trường. Mức CV cao ở lợi nhuận cho thấy rủi ro lợi nhuận cao hơn, hàm ý rằng doanh nghiệp cần kiểm soát tốt chi phí sản xuất và chi phí tài chính để ổn định kết quả kinh doanh trong các giai đoạn tiếp theo.

3.2 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
  • Đ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.

Công thức tính CAGR là:

\[ \mathrm{CAGR} \;=\; \left( \frac{\text{Giá trị cuối}}{\text{Giá trị đầu}} \right)^{\frac{1}{\,n-1\,}} - 1 \]

Giải thích kỹ thuật: Trong đó, 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 – thấp hơn đáng kể so với doanh thu – 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.

Ta có thể thấy được từ kết quả này rằng dù Hòa Phát tăng trưởng quy mô ấn tượng, nhưng để nâng cao hiệu quả và tính bền vững, doanh nghiệp cần tập trung cải thiện năng suất, tối ưu chi phí và quản trị tài chính nhằm chuyển hóa tăng trưởng doanh thu thành tăng trưởng lợi nhuận thực chất hơn.

3.3 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 × 17
##      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
## # ℹ 10 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>, BienDong_DT <dbl>

Giải thích kỹ thuật: Dòng 1–2 đầu tiên dữ liệu HPG được sắp xếp theo cột Nam để đảm bảo thứ tự thời gian đúng dòng 2, rồi truyền tiếp vào bước tiếp theo. Dòng 3 tạo cột mới BienDong_DT bằng hiệu tuyệt đối giữa DoanhThu hiện tại và DoanhThu của kỳ trước (dùng lag() để lấy giá trị liền trước)

Nhận xét: Dữ liệu cho thấy doanh thu của HPG tăng mạnh từ 2015 đến 2021, đặc biệt giai đoạn 2020–2021 tăng đột biến. Tuy nhiên từ 2022 doanh thu giảm và phục hồi nhẹ trở lại năm 2024. Lợi nhuận gộp và lợi nhuận trước thuế biến động cùng chiều với doanh thu, nghĩa là hiệu quả kinh doanh cốt lõi phụ thuộc trực tiếp vào quy mô tiêu thụ thép. Tổng tài sản tăng đều qua các năm, cho thấy doanh nghiệp mở rộng quy mô.Tuy nhiên giai đoạn 2022–2023 lợi nhuận suy giảm đáng kể dù doanh thu vẫn ở mức lớn, phản ánh ảnh hưởng của chu kỳ ngành thép và chi phí sản xuất tăng.

3.4 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), ~ (./lag(.) - 1) * 100, .names = "TangTruong_{col}")) %>%
3.   select(Nam, starts_with("TangTruong")) %>%
4.   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:Dòng 1 tạo bảng mới HPG_tangtruong từ dữ liệu gốc HPG. Dòng 2 sử dụng mutate() kết hợp across() để tính tỷ lệ tăng trưởng hằng năm (%) cho các biến tài chính quan trọng, bằng công thức (giá trị năm hiện tại / giá trị năm trước - 1) * 100, trong đó lag() được dùng để lấy giá trị của năm liền trước, và .names đặt tên cột theo dạng TangTruong_. Dòng 3 chỉ giữ lại cột Nam và các cột tăng trưởng để bảng kết quả gọn và dễ so sánh theo thời gian. Dòng 4 in bảng kết quả

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

1. HPG_phanTo <- HPG_tangtruong %>%
2.   mutate(Nhom_TangTruong = case_when(TangTruong_DoanhThu < 0 ~ "Giảm",TangTruong_DoanhThu < 5 ~ "Ổn định",TangTruong_DoanhThu < 20 ~ "Tăng nhẹ",TangTruong_DoanhThu < 50 ~ "Tăng vừa",TRUE ~ "Tăng mạnh")) %>%
3.   group_by(Nhom_TangTruong) %>%
4.   summarise(Nam = paste(Nam, collapse = ", "),TB_TangTruong_LN = mean(TangTruong_LN_SauThue, na.rm = TRUE),TB_TangTruong_TS = mean(TangTruong_Tong_TS, na.rm = TRUE),TB_TangTruong_VCSH = mean(TangTruong_Von_CSH, na.rm = TRUE))
5. print(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 mức tăng trưởng theo doanh thu. Dòng 2, case_when() được dùng để tạo biến Nhom_TangTruong và chia tốc độ tăng doanh thu thành các mức: giảm, ổn định, tăng nhẹ, tăng vừa và tăng mạnh. Dòng 3 nhóm các năm theo các mức tăng trưởng này. Dòng 4 tính trung bình mức tăng trưởng của lợi nhuận sau thuế, tổng tài sản và vốn chủ sở hữu cho từng nhóm, đồng thời liệt kê các năm thuộc mỗi nhóm. Dòng 5 hiển thị bảng kết quả.

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.

3.6 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 sử dụng mutate() để tạo biến mới GiaiDoan. Hàm ifelse() được dùng để phân loại theo năm: nếu Nam <= 2019 thì gán là “Trước 2020”, ngược lại là “Sau 2020”, bộ dữ liệu được chia thành hai giai đoạn để thuận tiện cho việc so sánh và phân tích biến động giữa trước và sau năm 2020.

3.7 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: sử dụng hàm 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à Lợi nhuận sau thuế (TB_LN) cho mỗi nhóm

Nhận xét:

Trước năm 2020 có trung bình doanh thu ≈ 3.86×10¹³ VND (≈ 38.6 nghìn tỷ VND). Trung bình lợi nhuận sau thuế ≈ 6.05×10¹² VND (≈ 6.05 nghìn tỷ VND).

Sau năm 2020 với trung bình doanh thu ≈ 1.292×10¹⁴ VND (≈ 129.2 nghìn tỷ VND). Trung bình lợi nhuận sau thuế ≈ 1.506×10¹³ VND (≈ 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.

Dưới góc độ kinh tế ta có thể thấy được sự tăng mạnh về doanh thu và lợi nhuận sau 2020 phản ánh quá trình mở rộng quy mô sản xuất và kinh doanh của Hòa Phát. Mức tăng lợi nhuận thấp hơn so với tỷ lệ tăng doanh thu cho thấy biên lợi nhuận không tăng tương xứng — có thể do tăng chi phí đầu vào, chi phí tài chính, hoặc chi phí khấu hao,đầu tư lớn.

3.8 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”. summarise(…): tính giá trị trung bình cho mỗi nhóm. No_PhaiTra / Tong_TS: là tỷ lệ nợ trên tổng tài sản, phản ánh mức độ sử dụng vốn vay trong tổng nguồn vốn.Nhân với 100 để chuyển đổi sang đơn vị phần tră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.9 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
  • Thực hiện việc so sánh hiệu quả sinh lời của doanh nghiệp Hòa Phát (HPG) giữ ahai giai đoạn: trước năm 2020 và sau năm 2020, thông qua hai chỉ tiêu tài chính quan trọng — ROA và ROE.

  • Tỷ suất sinh lời trên tổng tài sản (ROA) được xác định theo công thức:

\[ ROA = \frac{\text{Lợi nhuận sau thuế}}{\text{Tổng tài sản}} \times 100 \]

  • Tỷ suất sinh lời trên vốn chủ sở hữu (ROE) được xác định theo công thức:

\[ ROE = \frac{\text{Lợi nhuận sau thuế}}{\text{Vốn chủ sở hữu}} \times 100 \]

Giải thích kỹ thuật: Dòng 1–2 dùng mutate() để tạo hai biến hiệu suất: ROA và ROE. Dòng 3 group_by(GiaiDoan) ghép các quan sát theo hai nhóm giai đoạn (“Trước 2020” / “Sau 2020”) để tính tóm tắt riêng cho mỗi nhóm. Dòng 4 summarise(…) tính giá trị trung bình của ROA và ROE cho từng giai đoạn, dùng na.rm = TRUE nhằm bỏ qua giá trị thiếu khi tính trung bình. Dòng 5 in ra bảng kết quả.

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.

3.10 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() tính hệ số tương quan Pearson giữa nợ phải trả và lợi nhuận sau thuế, cho biết mức độ quan hệ tuyến tính giữa hai biến (giá trị từ -1 đến +1). Tham số use = “complete.obs” giúp loại bỏ các dòng có dữ liệu thiếu, chỉ dùng các quan sát đầy đủ để tính.

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.

3.11 Tương quan giữa doanh thu và tài sản

1. cor(HPG$DoanhThu, HPG$Tong_TS, use = "complete.obs")
## [1] 0.9674947

Nhận xét: Kết quả thu được là 0.9674947, tức là mối tương quan dương rất mạnh (gần như hoàn hảo) giữa doanh thu và tổng tài sản. Điều này có nghĩa là khi tài sản của doanh nghiệp tăng, doanh thu cũng tăng gần tương ứng. Về mặt kinh tế, điều này cho thấy Hòa Phát đang khai thác tài sản một cách hiệu quả, tức là các khoản đầu tư vào tài sản đã góp phần trực tiếp thúc đẩy tăng trưởng doanh thu.

3.12 Hiệu quả sử dụng vốn

1. HPG <- HPG %>%
2.   mutate(VongQuay_TS = DoanhThu / Tong_TS)
3. head(HPG,10)
## # A tibble: 10 × 18
##      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
## # ℹ 11 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>, GiaiDoan <chr>, VongQuay_TS <dbl>

Giải thích kỹ thuật: Lệnh mutate(VongQuay_TS = DoanhThu / Tong_TS) trong gói dplyr tạo thêm một biến mới tên là VongQuay_TS trong bảng dữ liệu HPG.

Nhận xét:

  • Biến vòng quay tài sản được tính theo công thức:

\[ \text{Vòng quay tài sản} = \frac{\text{Doanh thu thuần}}{\text{Tổng tài sản bình quân}} \]

  • Chỉ tiêu này phản ánh mức độ hiệu quả trong việc sử dụng tài sản để tạo ra doanh thu. Giá trị càng cao cho thấy doanh nghiệp khai thác tài sản càng hiệu quả, mỗi đồng tài sản đầu tư tạo ra nhiều doanh thu hơn.

  • Về mặt kinh tế, quan sát kết quả cho thấy chỉ số vòng quay tài sản của Hòa Phát dao động trong khoảng 0.6 – 1.3 lần, nghĩa là trung bình 1 đồng tài sản tạo ra từ 0,6 đến 1,3 đồng doanh thu. Xu hướng giảm dần sau 2020 hàm ý hiệu quả sử dụng vốn có phần chậm lại, có thể do quy mô tài sản tăng nhanh hơn doanh thu — đặc trưng của giai đoạn mở rộng đầu tư hoặc chu kỳ suy giảm của ngành thép.

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

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

Giải thích kỹ thuật: Dòng 1 tạo biến mới Net_Margin trong bảng HPG bằng công thức lợi nhuận sau thuế chia cho doanh thu nhân 100 để ra tỷ suất lợi nhuận ròng (%) cho mỗi hàng (mỗi năm)

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.14 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.15 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,revenue_growth_yoy = (DoanhThu - lag(DoanhThu)) / lag(DoanhThu)
4.   ) %>%
5.   mutate(giai_doan = ifelse(Nam < split_year, paste0("Truoc_", split_year), paste0("Tu_", split_year, "_Tro_di"))
6.   ) %>%
7.   group_by(giai_doan) %>%
8.   summarise(ROE_trung_binh = mean(roe, na.rm = TRUE),Tang_truong_DT_trung_binh = mean(revenue_growth_yoy, na.rm = TRUE),Bien_LN_rong_trung_binh = mean(LN_SauThue / DoanhThu, na.rm = TRUE),So_nam = n())
9. period_group
## # A tibble: 2 × 5
##   giai_doan  ROE_trung_binh Tang_truong_DT_trung…¹ Bien_LN_rong_trung_b…² So_nam
##   <chr>               <dbl>                  <dbl>                  <dbl>  <int>
## 1 Truoc_2018          0.289                  0.108                  0.149      3
## 2 Tu_2018_T…          0.189                  0.259                  0.129      7
## # ℹ abbreviated names: ¹​Tang_truong_DT_trung_binh, ²​Bien_LN_rong_trung_binh

Giải thích kỹ thuật: Dòng đặt mốc phân chia năm là 2018. Sau đó, từ dòng 2 bắt đầu xử lý dữ liệu với HPG. Tại dòng 3, hai chỉ tiêu quan trọng được tạo: ROE và tốc độ tăng trưởng doanh thu năm sau so với năm trước (DoanhThu - lag(DoanhThu)) chia cho lag(DoanhThu). Tiếp theo, dòng 5 gán nhãn giai đoạn cho mỗi quan sát: nếu năm nhỏ hơn 2018 thì xếp vào nhóm “Truoc_2018”, ngược lại thuộc nhóm “Tu_2018_Tro_di”. Dòng 7 nhóm dữ liệu theo hai giai đoạn này. Cuối cùng, dòng 8 tính ROE trung bình, tăng trưởng doanh thu trung bình và biên lợi nhuận ròng trung bình của từng giai đoạn, đồng thời xác định số năm quan sát. Kết quả giúp đánh giá xem hiệu suất tài chính của doanh nghiệp thay đổi như thế nào trước và sau năm 2018.

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.16 Phân tích ảnh hưởng của giá vốn lên doanh thu

1. cost_structure <- HPG %>%
2.   mutate(Ty_le_GVHB_DTT = GiaVon / DoanhThu,Bien_dong_Ty_le = Ty_le_GVHB_DTT - lag(Ty_le_GVHB_DTT)
3.   ) %>%
4.   select(Nam, Ty_le_GVHB_DTT, Bien_dong_Ty_le)
5. cost_structure
## # A tibble: 10 × 3
##      Nam Ty_le_GVHB_DTT Bien_dong_Ty_le
##    <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: Dòng 1 tạo đối tượng cost_structure từ bảng HPG; Dòng 2 trong mutate() tính tỷ lệ giá vốn trên doanh thu Ty_le_GVHB_DTT = GiaVon / DoanhThu và biến động tỷ lệ so với kỳ trước Bien_dong_Ty_le = Ty_le_GVHB_DTT - lag(Ty_le_GVHB_DTT) (lag lấy giá trị kỳ liền trước); Dòng 4 giữ lại các cột cần thiết Nam, Ty_le_GVHB_DTT, Bien_dong_Ty_le để phân tích; Dòng 5 trả về bảng cost_structure chứa tỷ lệ giá vốn và sự biến động theo năm dùng để kiểm tra ảnh hưởng thay đổi giá vốn lên doanh thu theo thời gian.

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.17 Phân tích 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: Dòng 1, dữ liệu gốc HPG được đưa vào chuỗi xử lý với %>%. Dòng 2 dùng mutate() để tính current_ratio (tỷ số thanh toán hiện hành) bằng cách lấy TS_NganHan / No_PhaiTra, phản ánh khả năng doanh nghiệp dùng tài sản ngắn hạn để chi trả nợ phải trả. Dòng 3 chỉ giữ lại các cột quan trọng gồm Nam, TS_NganHan, No_PhaiTra và current_ratio. Dòng 4 in ra kết quả dưới dạng bảng, phục vụ cho việc đánh giá mức độ an toàn tài chính theo từng năm.

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.18 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) %>% select(Nam, LCTT_KD, No_PhaiTra, cfo_to_debt_ratio)
3. 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: Dòng 1, dữ liệu HPG được đưa vào xử lý bằng toán tử %>%. Dòng 2 dùng để tạo biến mới cfo_to_debt_ratio bằng cách chia LCTT_KD (lưu chuyển tiền thuần từ hoạt động kinh doanh) cho No_PhaiTra, nhằm đo lường mức độ dòng tiền có thể trang trải nợ phải trả. Đồng thời, select() chọn ra các cột cần phân tích gồm: Nam, LCTT_KD, No_PhaiTra và cfo_to_debt_ratio. Dòng 3 hiển thị bảng kết quả để thuận tiện cho việc đánh giá mức độ bền vững tài chính qua từng năm.

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.19 Phân tích gánh nặng thuế

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

Giải thích kỹ thuật: Đoạn code tính tỷ suất thuế thực tế (Effective Tax Rate) để đ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ế (Effective Tax Rate) 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.20 Thống kê mô tả biến Tổng tài sản

1. HPG_totalassets <- 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_totalassets
## # 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

Giải thích kỹ thuật: Dòng 1, dữ liệu HPG được gọi và chuyển vào hàm xử lý. Dòng 2 tạo ra bảng thống kê tổng hợp. Dòng 3 tính số lượng quan sát (Solieu). Dòng 4 tính giá trị trung bình của Tổng tài sản. Dòng 5 và 6 tìm giá trị lớn nhất và nhỏ nhất trong chuỗi dữ liệu. Dòng 7 tính trung vị, phản ánh giá trị nằm giữa phân phối. Dòng 8 tính độ lệch chuẩn, đo mức độ biến động của tổng tài sản qua các năm. Dòng 9 và 10 xác định Q1 và Q3 nhằm đánh giá phân bố dữ liệu theo tứ phân vị. Cuối cùng, dòng 11 hiển thị bảng kết quả, giúp người phân tích đánh giá quy mô và mức biến động tài sản của HPG theo thời gian.

Nhận xét: Kết quả thống kê cho thấy tổng tài sản (Total_assets) 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.

Chương 4: Trực quan hóa dữ liệu

4.1 Biểu đồ lợi nhuận tích lũy qua các năm

1. cumulative_gross_profit <- HPG %>%
2.   select(Nam, LN_Gop) %>%  
3.   mutate(LN_Gop_LuyKe = cumsum(LN_Gop))  
4. ggplot(cumulative_gross_profit, aes(x = Nam, y = LN_Gop_LuyKe)) +
5.   geom_area(fill = "#A5D6A7", alpha = 0.6) +
6.   geom_line(color = "#388E3C", size = 1.2) +
7.   geom_point(color = "#388E3C", size = 3) +
8.   geom_text_repel(
9.     aes(label = scales::number(LN_Gop_LuyKe / 1e9, accuracy = 0, big.mark = ",")),size = 3,nudge_y = 5e11) +
10.   scale_y_continuous(labels = label_number(scale_cut = cut_short_scale())) +
11.   labs(title = "Lợi nhuận gộp lũy kế của HPG qua các năm (2015–2024)", subtitle = "Thể hiện xu hướng tích lũy lợi nhuận gộp qua thời gian", x = "Năm", y = "Lợi nhuận gộp lũy kế (VND)") +
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: Dòng 1–3, dữ liệu được chọn và tính thêm biến lợi nhuận gộp lũy kế theo năm bằng hàm cumsum(), nhằm thể hiện tổng lợi nhuận tích lũy qua thời gian. Dòng 4 khởi tạo biểu đồ với biến năm trên trục X và lợi nhuận gộp lũy kế trên trục Y. Các dòng 5–7 lần lượt vẽ phần diện tích, đường xu hướng và điểm đánh dấu để làm nổi bật xu hướng tăng trưởng. Tiếp đó, dòng 8–9 chèn nhãn giá trị bằng geom_text_repel(). dòng 10–13 điều chỉnh định dạng trục, tiêu đề và giao diện tổng thể nhằm đảm bảo biểu đồ trực quan.

Nhận xét: Lợi nhuận gộp lũy kế của HPG tăng đều qua các năm, đặc biệt gia tốc mạnh từ 2020–2021, cho thấy giai đoạn đó công ty đạt hiệu quả hoạt động vượt trội; sau 2021 tốc độ tích lũy vẫn tiếp tục nhưng chậm hơn, phản ánh cả yếu tố chu kỳ ngành và ổn định quy mô. Tổng thể biểu đồ cho thấy khả năng sinh lợi ổn định và tăng trưởng bền vững theo thời gian.

4.2 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)",
6.        y = "Lợi nhuận sau thuế (tỷ đồng)",
7.        color = "Năm", size = "Doanh thu") +                    
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"),panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 1 tạo biểu đồ tán xạ, trong đó Tổng tài sản và Lợi nhuận sau thuế được chia cho 1e3 để đổi sang tỷ đồng. Dòng 2 sử dụng geom_point() để vẽ các điểm dữ liệu, đồng thời mã hóa Năm bằng màu và Doanh thu bằng kích thước điểm, giúp quan sát xu hướng theo thời gian và quy mô doanh thu. Dòng 3 thêm đường hồi quy tuyến tính để thể hiện xu hướng quan hệ giữa hai biến. Dòng 4–7 đặt tiêu đề, tên trục và chú giải. Dòng 8–9 điều chỉnh giao diện biểu đồ.

Nhận xét: Đường hồi quy có xu hướng đi lên rõ rệt, cho thấy mối quan hệ thuận chiều giữa tổng tài sản và lợi nhuận sau thuế – tức là khi tổng tài sản của doanh nghiệp tăng, lợi nhuận cũng có xu hướng tăng theo. Xét về phương diện kinh tế điều này minh chứng rằng việc Hòa Phát mở rộng quy mô đầu tư, đặc biệt là trong các dự án lớn như khu liên hợp thép Dung Quất, đã góp phần nâng cao lợi nhuận trong giai đoạn tăng trưởng. Tuy nhiên, một số điểm dữ liệu ở các năm 2022–2023 nằm thấp hơn đường xu hướng, cho thấy hiệu quả sử dụng tài sản giảm sút do ảnh hưởng từ suy thoái ngành thép và biến động kinh tế toàn cầu. Nhìn chung, biểu đồ khẳng định rằng sự gia tăng quy mô tài sản có tác động tích cực đến lợi nhuận của Hòa Phát, dù hiệu quả có thể biến động tùy theo điều kiện thị trường và chu kỳ kinh doanh.

4.3 Biểu đồ thể hiện cấu trúc vốn

1. capital_structure_long <- HPG %>%
2.   select(Nam, No_PhaiTra, Von_CSH) %>%  # Dùng đúng tên biến của bạn
3.   pivot_longer(cols = -Nam, names_to = "Loai_nguon_von", values_to = "So_tien")
4. ggplot(capital_structure_long, aes(x = Nam, y = So_tien, fill = Loai_nguon_von)) +
5.   geom_area(position = "fill", alpha = 0.8) +
6.   scale_y_continuous(labels = percent_format()) +
7.   scale_fill_manual(
8.     values = c("No_PhaiTra" = "#E57373", "Von_CSH" = "#81C784"),
9.     labels = c("Nợ phải trả", "Vốn chủ sở hữu")) +
10.   labs(title = "Cấu trúc nguồn vốn của HPG qua các năm (2015–2024)",subtitle = "Thể hiện tỷ trọng giữa Nợ phải trả và Vốn chủ sở hữu trong tổng nguồn vốn",x = "Năm",y = "Tỷ lệ phân bổ (%)",fill = "Loại nguồn vốn") +
11.   theme_minimal(base_size = 13) +
12.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13), plot.subtitle = element_text(hjust = 0.5, color = "gray40"),legend.position = "bottom", axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"))

Giải thích kỹ thuật:Dòng 1–3 tạo dữ liệu dạng dài bằng pivot_longer(), giúp gộp hai biến Nợ phải trả và Vốn chủ sở hữu vào cùng một cột để dễ vẽ so sánh theo thời gian. Dòng 4–5 vẽ biểu đồ diện tích chồng và dùng position = “fill” để chuyển thành tỷ trọng (%). Dòng 6–9 điều chỉnh hiển thị trục Y theo phần trăm và đặt màu cùng nhãn tên rõ ràng cho từng loại nguồn vốn. Dòng 10–12 thêm tiêu đề, nhãn trục và chỉnh theme .

Nhận xét: Biểu đồ thể hiện cấu trúc nguồn vốn của Hòa Phát (HPG) qua các năm, cho thấy tỷ lệ giữa nợ phải trả và vốn chủ sở hữu luôn duy trì quanh mức cân bằng tương đối. Giai đoạn 2015–2019, tỷ trọng nợ có xu hướng tăng dần, đạt đỉnh vào năm 2018–2019. Sau đó, từ năm 2020 trở đi, tỷ lệ nợ giảm dần, cho thấy HPG đã giảm dần mức sử dụng đòn bẩy tài chính. Việc duy trì cơ cấu vốn cân đối và xu hướng giảm dần tỷ lệ nợ thể hiện chiến lược tài chính thận trọng của HPG, đặc biệt trong bối cảnh thị trường biến động. Điều này giúp doanh nghiệp giảm áp lực trả lãi, tăng khả năng chống chịu rủi ro và bảo vệ lợi ích cổ đông. HPG đang dần dịch chuyển từ chiến lược tăng trưởng dựa vào vốn vay sang mô hình tài chính ổn định và tự chủ hơn trong dài hạn.

4.4 Biểu đồ thể hiện cấu trúc tài sản

1. asset_structure_long <- HPG %>%
2.   select(Nam, TS_NganHan, TS_DaiHan) %>%
3.   pivot_longer(cols = -Nam, names_to = "Loai_Tai_San", values_to = "So_Tien")
4. ggplot(asset_structure_long, aes(x = Nam, y = So_Tien, fill = Loai_Tai_San)) +
5.   geom_area(position = "stack", alpha = 0.8) +
6.   scale_y_continuous(labels = scales::label_number(scale_cut = scales::cut_short_scale())) +
7.   scale_fill_brewer(palette = "Pastel1", labels = c("Tài sản ngắn hạn", "Tài sản dài hạn")) +
8.   labs(title = "Cấu trúc tài sản của HPG qua các năm (2015–2024)",subtitle = "Phân bổ giữa tài sản ngắn hạn và tài sản dài hạn trong tổng tài sản",x = "Năm",y = "Tổng tài sản (VND)",fill = "Loại tài sản") +
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"),panel.grid.minor = element_blank())

Nhận xét: Dòng 1–3 chọn các biến tổng tài sản theo kỳ hạn và chuyển dữ liệu sang dạng dài bằng pivot_longer() để thuận tiện cho việc so sánh. Dòng 4–5 vẽ biểu đồ diện tích chồng, thể hiện sự phân bổ giữa tài sản ngắn hạn và tài sản dài hạn theo từng năm. Dòng 6–7 chuẩn hóa cách hiển thị giá trị trên trục tung và thiết lập bảng màu. Dòng 8–10 bổ sung tiêu đề, nhãn, cùng chỉnh sửa giao diện biểu đồ để nội dung trực quan và dễ trình bày.

Kết luận: HPG đã có chiến lược đầu tư quy mô lớn vào tài sản dài hạn trong giai đoạn tăng trưởng cao, cho thấy tầm nhìn dài hạn và cam kết mở rộng sản xuất. Việc tài sản ngắn hạn tăng trở lại những năm gần đây phản ánh sự chủ động trong quản trị vốn lưu động và thanh khoản. Cấu trúc tài sản linh hoạt và hợp lý giữa ngắn và dài hạn giúp HPG cân bằng giữa tăng trưởng dài hạn và khả năng ứng phó với biến động ngắn hạn của thị trường. Đây là yếu tố tích cực trong việc duy trì sức khỏe tài chính và hiệu quả vận hành.

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

1. HPG_metrics <- HPG %>%
2.   mutate(
3.     bien_loi_nhuan_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.     asset_turnover = DoanhThu / Tong_TS,
9.     revenue_growth_yoy = (DoanhThu - lag(DoanhThu)) / lag(DoanhThu),
10.     profit_growth_yoy = (LN_SauThue - lag(LN_SauThue)) / lag(LN_SauThue))
11. risk_efficiency_ratios_long <- HPG_metrics %>%
12.   select(Nam, debt_to_equity, current_ratio, asset_turnover) %>%
13.   pivot_longer(cols = -Nam, names_to = "chi_so", values_to = "gia_tri")
14. ggplot(risk_efficiency_ratios_long, aes(x = Nam, y = gia_tri, color = chi_so, group = chi_so)) +
15.   geom_line(size = 1.2) +
16.   geom_point(size = 3) +
17.   facet_wrap(
18.     ~ factor(chi_so, levels = c("asset_turnover", "current_ratio", "debt_to_equity")),ncol = 1,scales = "free_y") +
19.   geom_text_repel(aes(label = scales::number(gia_tri, accuracy = 0.1, suffix = "x")),size = 3.5,show.legend = FALSE,box.padding = 0.4,nudge_y = 0.05,segment.size = 0.2,max.overlaps = Inf     ) +
20.   scale_y_continuous(labels = scales::number_format(accuracy = 0.1)) +
21.   labs(title = "Xu hướng các Chỉ số Tài chính của HPG",subtitle = "Gồm Đòn bẩy, Thanh khoản và Hiệu quả sử dụng tài sản", x = "Năm",y = "Giá trị (lần)") +
22.   scale_color_brewer(palette = "Set1") +
23.   theme_minimal(base_size = 13) +
24.   theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 13),plot.subtitle = element_text(hjust = 0.5, color = "gray40"),axis.text = element_text(color = "black"),axis.title = element_text(face = "bold"),legend.position = "none",panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 1–10 tính thêm các chỉ số tài chính như biên lợi nhuận ròng, ROA, ROE, hệ số nợ/vốn chủ, khả năng thanh toán và vòng quay tài sản bằng hàm mutate(). Dòng 11–13 chọn các chỉ số cần phân tích và chuyển dữ liệu sang dạng dài bằng pivot_longer() để vẽ biểu đồ. Dòng 14–16 tạo biểu đồ đường thể hiện xu hướng các chỉ số theo thời gian. Dòng 17–18 để tách từng chỉ số thành biểu đồ riêng, giúp so sánh rõ ràng hơn. Dòng 21–24 thêm tiêu đề, nhãn và chỉnh sửa giao diện nhằm tăng tính trực quan và dễ trình bày.

Nhận xét:

Asset turnover (vòng quay tài sản): giảm từ ~1.3x (2015) xuống ~0.6–0.7x gần đây — cho thấy hiệu quả sử dụng tài sản đã suy giảm, doanh thu tạo ra trên mỗi đồng tài sản ít đi.

Current ratio (khả năng thanh toán): biến động, đạt ~1.6x ở đỉnh rồi giảm xuống ~0.7–0.8x và phục hồi nhẹ — cảnh báo từng thời điểm thanh khoản kém nhưng gần đây đã cải thiện nhẹ.

Debt to equity (đòn bẩy): giảm giai đoạn đầu, tăng mạnh tới ~1.2x năm 2020 rồi hạ xuống và ổn định quanh ~0.8–1.0x — cho thấy công ty có thời kỳ tăng vay nhưng sau đó giảm đòn bẩy, chuyển về cấu trúc vốn cân bằng hơn.

HPG vẫn có tăng trưởng nhưng cần chú ý nâng cao hiệu quả sử dụng tài sản và duy trì thanh khoản ổn định; quản lý đòn bẩy đã cải thiện sau giai đoạn tăng nợ.

4.6 Biểu đồ thể hiện sự tương quan giữa các chỉ số tài chính

1. ratio_data_for_corr <- HPG_metrics %>%
2.   select(
3.     bien_loi_nhuan_rong, roa, roe, 
4.     debt_to_equity, current_ratio, 
5.     asset_turnover, revenue_growth_yoy) %>%
6.   drop_na() 
7. corr_matrix <- cor(ratio_data_for_corr, use = "complete.obs")
8. library(ggcorrplot) 
9. ggcorrplot(
10.   corr_matrix,hc.order = TRUE,lab = TRUE,lab_size = 3,type = "full", ggtheme = ggplot2::theme_minimal(),colors = c("#D32F2F", "white", "#0288D1"),
11.   title = "Ma trận Tương quan giữa các Chỉ số Tài chính"
12. ) +
13.   labs(title = "Heatmap Tương quan: Các Chỉ số Tài chính")

Nhận xét: Dòng 1–6 chọn các chỉ số tài chính quan trọng và dùng drop_na() để loại bỏ các quan sát thiếu dữ liệu nhằm đảm bảo tính toán chính xác. Dòng 7 sử dụng hàm cor() để tạo ma trận tương quan, đo mức độ quan hệ tuyến tính giữa các chỉ số. Dòng 8–12 dùng thư viện ggcorrplot để trực quan hóa ma trận này dưới dạng heatmap, với màu sắc biểu thị mức độ tương quan từ âm đến dương, kèm nhãn giá trị.

Kết luận: Biểu đồ cho thấy cơ cấu vốn có ảnh hưởng lớn đến khả năng thanh toán và hiệu quả sử dụng tài sản. Doanh nghiệp có thể phải đánh đổi giữa việc tăng vay nợ để tài trợ tăng trưởng và duy trì khả năng thanh khoản. Đồng thời, nhóm chỉ số sinh lời có liên hệ rất mạnh với nhau, khẳng định rằng khi biên lợi nhuận cải thiện thì hiệu quả tổng thể (ROA, ROE) cũng tăng theo. Đây là cơ sở quan trọng để HPG tối ưu chiến lược tài chính: cân bằng giữa lợi nhuận, hiệu quả sử dụng vốn và rủi ro đòn bẩy tài chính.

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

1. ggplot(HPG_metrics, aes(x = asset_turnover, y = bien_loi_nhuan_rong)) +
2.   geom_point(aes(color = factor(Nam), size = Tong_TS), alpha = 0.7) +
3.   geom_text_repel(aes(label = Nam), size = 3.5, color = "black") +
4.   geom_hline(yintercept = mean(HPG_metrics$bien_loi_nhuan_rong, na.rm = TRUE), linetype = "dashed", color = "gray") +
5.   geom_vline(xintercept = mean(HPG_metrics$asset_turnover, na.rm = TRUE), linetype = "dashed", color = "gray") +
6.   scale_x_continuous(labels = scales::number_format(suffix = "x")) +
7.   scale_y_continuous(labels = scales::percent_format()) +
8.   labs(title = "Phân tích Hiệu quả: Biên Lợi nhuận vs. Vòng quay Tài sản",subtitle = "Kích thước bong bóng = Tổng Tài sản",x = "Vòng quay Tổng Tài sản (Asset Turnover - Lần)", y = "Biên Lợi nhuận Ròng (Net Profit Margin - %)", color = "Năm", size = "Tổng Tài sản") +
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"), panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 1–2 vẽ biểu đồ phân tán, trong đó trục X là vòng quay tài sản và trục Y là biên lợi nhuận ròng, đồng thời kích thước điểm thể hiện tổng tài sản theo từng năm. Dòng 3 thêm nhãn năm để dễ nhận biết từng điểm dữ liệu. Dòng 4–5 kẻ hai đường tham chiếu trung bình theo chiều ngang và dọc, giúp chia biểu đồ thành bốn vùng so sánh hiệu suất (cao-thấp). Dòng 6–7 định dạng giá trị trục X và Y theo dạng dễ đọc (lần và %). Dòng 8–10 bổ sung tiêu đề, nhãn chú thích và tùy chỉnh giao diện giúp biểu đồ rõ ràng và trực quan hơn.

Nhận xét: Biểu đồ cho thấy giai đoạn từ năm 2019 đến 2021 là thời kỳ HPG đạt hiệu quả hoạt động tối ưu, khi vừa sử dụng tài sản hiệu quả, vừa duy trì được lợi nhuận cao. Tuy nhiên, sau năm 2021 dù tổng tài sản tiếp tục tăng nhưng hiệu suất sử dụng và khả năng sinh lời suy giảm rõ rệt, cho thấy dấu hiệu giảm hiệu quả đầu tư và vận hành. Doanh nghiệp cần rà soát lại chiến lược tăng trưởng, nâng cao hiệu quả sử dụng tài sản và kiểm soát chi phí để phục hồi biên lợi nhuận trong tương lai.

4.8 Phân tích 3 dòng tiền

1. profit_components_long <- HPG %>%
2.   select(Nam, `Doanh thu` = DoanhThu, `Giá vốn hàng bán` = GiaVon, `Lợi nhuận gộp` = LN_Gop) %>%
3.   pivot_longer(cols = -Nam, names_to = "component_type", values_to = "amount")
4. ggplot(profit_components_long, aes(x = factor(Nam), y = amount, fill = component_type)) +
5.   geom_col() +
6.   facet_wrap(~ factor(component_type, levels = c("Doanh thu", "Giá vốn hàng bán", "Lợi nhuận gộp")), scales = "free_y", ncol = 1) +
7.   geom_text(aes(label = scales::number(amount / 1e9, accuracy = 0.1)), vjust = -0.5, size = 2.5) +
8.   scale_y_continuous(labels = label_number(scale_cut = cut_short_scale()),expand = expansion(mult = c(0, 0.2))) +
9.   labs(title = "Phân tích 3 dòng tiền của HPG qua các năm",subtitle = "Đơn vị tính: Tỷ VND",x = "Năm",y = "Giá trị (VND)") +
10.   theme_bw() +
11.   theme(legend.position = "none",strip.text = element_text(face = "bold", size = 10),plot.title = element_text(face = "bold", hjust = 0.5))

Giải thích kỹ thuật: Dòng 1–3 chọn 3 biến (Doanh thu, Giá vốn, Lợi nhuận gộp) và chuyển dữ liệu sang dạng dài để dễ vẽ. Dòng 4–6 vẽ biểu đồ cột và tách thành 3 ô để so sánh từng thành phần theo năm. Dòng 7–8 thêm nhãn giá trị và định dạng trục để dễ đọc. Dòng 9–11 đặt tiêu đề và điều chỉnh giao diện biểu đồ cho trình bày rõ ràng.

Nhận xét: Doanh thu của HPG tăng mạnh từ năm 2015 đến 2021, đạt đỉnh năm 2021, sau đó giảm nhẹ rồi phục hồi năm 2024. Giá vốn hàng bán biến động cùng chiều, phản ánh quy mô sản xuất ổn định. Lợi nhuận gộp tăng nhanh giai đoạn 2019–2021, giảm sau đó nhưng phục hồi gần đây, cho thấy biên lợi nhuận chịu ảnh hưởng chu kỳ ngành nhưng nhìn chung HPG vẫn duy trì hiệu quả kinh doanh tốt.

4.9 So sánh Doanh thu và ROE

1. HPG <- HPG %>%
2.   mutate(ROE = LN_SauThue / Von_CSH * 100)
3. ggplot(HPG, aes(x = as.factor(Nam))) +
4.   geom_col(aes(y = DoanhThu / 1e12), fill = "skyblue", alpha = 0.7) + 
5.   geom_line(aes(y = ROE / 5, group = 1, color = "ROE (%)"), size = 1.2) +
6.   geom_point(aes(y = ROE / 5, color = "ROE (%)"), size = 2) +
7.   scale_y_continuous(
8.     name = "Doanh thu (nghìn tỷ đồng)",
9.     sec.axis = sec_axis(~.*5, name = "ROE (%)")  
10.   ) +
11.   scale_color_manual(values = c("ROE (%)" = "red")) +
12.   labs(title = "Doanh thu và ROE của HPG theo năm",x = "Năm",color = "") +
13.     theme_minimal(base_size = 13, base_family = "Times New Roman") +
14.   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–2, hàm mutate() được dùng để tạo biến ROE bằng công thức Lợi nhuận sau thuế / Vốn chủ sở hữu × 100. Đến dòng 3, biểu đồ được khởi tạo theo năm. Dòng 4 vẽ cột biểu diễn Doanh thu và chuyển đổi sang đơn vị nghìn tỷ đồng. Ở dòng 5–6, đường và điểm thể hiện ROE được thêm vào, trong đó ROE được chia cho 5 để đặt lên cùng trục với Doanh thu. Dòng 7–10 thiết lập trục tung kép, trục chính cho Doanh thu và trục phụ hoàn nguyên ROE về giá trị phần trăm. Dòng 11–12 chỉnh màu và nhãn biểu đồ, còn dòng 13–14 dùng theme tối giản, căn chỉnh tiêu đề và ẩn bớt grid cho biểu đồ rõ ràng, dễ đọc.

Nhận xét:

Trục hoành thể hiện năm, trục tung bên trái biểu thị doanh thu (nghìn tỷ đồng), còn trục tung bên phải biểu thị ROE (%). Cột màu xanh nhạt mô tả quy mô doanh thu từng năm, trong khi đường đỏ biểu diễn sự biến động của ROE.

Từ kết quả biểu đồ ta có thể thấy doanh thu của Hòa Phát tăng mạnh và ổn định trong giai đoạn 2015–2021, đặc biệt đạt đỉnh vào năm 2021 khi doanh thu vượt 150 nghìn tỷ đồng. Tuy nhiên, ROE không tăng tương ứng với doanh thu — điều này cho thấy mặc dù quy mô hoạt động mở rộng, nhưng hiệu quả sử dụng vốn chủ sở hữu chưa thật sự cải thiện. Sau năm 2021, ROE sụt giảm rõ rệt, phản ánh giai đoạn lợi nhuận suy giảm do giá thép giảm, chi phí nguyên liệu tăng và thị trường bất động sản chững lại.

Giai đoạn 2022–2024, doanh thu có dấu hiệu phục hồi nhẹ, nhưng ROE vẫn duy trì ở mức thấp, cho thấy doanh nghiệp đang trong quá trình tái cơ cấu và thích ứng với biến động thị trường. Nhìn chung, biểu đồ thể hiện rằng Hòa Phát có sức tăng trưởng doanh thu ấn tượng, song cần cải thiện hiệu quả sử dụng vốn chủ sở hữu để tối ưu hóa lợi nhuận trong những năm tới.

4.10 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 = ", round(skew_LN, 2), ", Kurt = ", round(kurt_LN, 2), ")"),x = "Lợi nhuận sau thuế (tỷ đồng)",y = "Mật độ (Density)",color = "Chú thích") +
10.   scale_color_manual(values = c("Đường mật độ" = "red", "Trung bình" = "black")) + 
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 = "top",panel.grid.minor = element_blank())

Giải thích kỹ thuật: dòng 1, thư viện e1071 được gọi để tính độ lệch (skewness) và độ nhọn (kurtosis). Dòng 2–3 lần lượt tính hệ số lệch và độ nhọn của lợi nhuận sau thuế, giúp đánh giá dạng phân phối. Dòng 4 tính giá trị trung bình của lợi nhuận sau thuế và chuyển về đơn vị tỷ đồng. Dòng 5 khởi tạo biểu đồ histogram với biến lợi nhuận sau thuế. Dòng 6 vẽ biểu đồ tần suất dạng cột và chuẩn hóa thành mật độ. Dòng 7 thêm đường mật độ để biểu diễn hình dạng phân phối mượt hơn. Dòng 8 kẻ đường thẳng đứng thể hiện giá trị trung bình, giúp so sánh trực quan vị trí của trung bình trong phân phối. Dòng 9 đặt tiêu đề kèm hiển thị trực tiếp giá trị Skew và Kurt để dễ giải thích. Dòng 10 tùy chỉnh màu sắc cho đường mật độ và đường trung bình. Cuối cùng, dòng 11–12 áp dụng theme tối giản và căn chỉnh nhãn, tiêu đề, legend để biểu đồ rõ ràng.

Nhận xét

Biểu đồ phân phối lợi nhuận sau thuế của HPG cho thấy dữ liệu có độ lệch phải (Skew = 1,78) và độ nhọn trung bình (Kurt = 2,11). Điều này có nghĩa là phần lớn các giá trị lợi nhuận của HPG tập trung ở mức thấp đến trung bình, trong khi vẫn tồn tại một số năm có lợi nhuận rất cao, kéo phần đuôi của phân phối về phía bên phải. Đường mật độ màu đỏ có đỉnh nghiêng về phía bên trái cho thấy các năm có lợi nhuận thấp xuất hiện thường xuyên hơn.

Giá trị trung bình (đường nét đứt màu đen) nằm lệch về bên phải của vùng tập trung cột histogram, điều này càng khẳng định xu hướng lệch phải của dữ liệu — tức là một vài năm có mức lợi nhuận đột biến đã làm tăng giá trị trung bình.

Phân phối lợi nhuận của HPG chưa ổn định, có sự chênh lệch lớn giữa các năm. Các năm đạt lợi nhuận cao bất thường có thể đến từ giai đoạn thị trường thép tăng trưởng mạnh hoặc các yếu tố chu kỳ ngành. Điều này cho thấy doanh nghiệp chịu ảnh hưởng đáng kể từ biến động thị trường, và cần có chiến lược duy trì lợi nhuận ổn định hơn trong tương lai.

4.11 Cơ cấu tài sản theo năm

1. HPG_area <- HPG %>%
2.   mutate(TS_NganHan = TS_NganHan / Tong_TS * 100, TS_DaiHan = TS_DaiHan / Tong_TS * 100) %>%
3.   select(Nam, TS_NganHan, TS_DaiHan) %>%
4.   tidyr::pivot_longer(cols = c(TS_NganHan, TS_DaiHan),names_to = "LoaiTaiSan", values_to = "TyLe")
5. ggplot(HPG_area, aes(x = Nam, y = TyLe, fill = LoaiTaiSan)) +
6.   geom_area(alpha = 0.8) +
7.   labs(title = "Cơ cấu tài sản ngắn hạn và dài hạn qua các năm",x = "Năm", y = "Tỷ trọng (%)") +
8.   scale_fill_manual(values = c("skyblue", "orange")) +
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: Dòng 1–2, dữ liệu được chuẩn hóa khi tính tỷ trọng tài sản ngắn hạn và dài hạn bằng cách chia cho tổng tài sản và nhân 100 để chuyển về dạng phần trăm. Dòng 3 chỉ giữ lại các biến cần phân tích. Dòng 4 chuyển dữ liệu sang dạng dài (pivot_longer) để mỗi năm có hai dòng tương ứng với hai loại tài sản, thuận tiện cho việc vẽ biểu đồ. Dòng 5 khởi tạo biểu đồ với trục hoành là năm và trục tung là tỷ lệ tài sản. Dòng 6 dùng geom_area() để vẽ biểu đồ diện tích chồng, giúp thể hiện sự thay đổi cơ cấu tài sản theo thời gian. Dòng 7 đặt tiêu đề và nhãn trục. Dòng 8 tùy chỉnh màu để phân biệt hai loại tài sản rõ ràng. Cuối cùng, dòng 9–10 áp dụng giao diện tối giản và định dạng lại tiêu đề, trục, chú thích nhằm làm biểu đồ rõ ràng.

Nhận xét: Về mặt kinh tế biểu đồ này cho thấy sự thay đổi cơ cấu tài sản của Hòa Phát: giai đoạn trước 2019 tỷ trọng tài sản ngắn hạn chiếm một phần lớn, sau đó tỷ trọng tài sản dài hạn tăng lên trong những năm mở rộng đầu tư (phản ánh đầu tư vào nhà máy, thiết bị, dự án dài hạn), còn sự sụt giảm tỷ trọng dài hạn vào một số năm cho thấy phân bổ vốn dịch chuyển về tài sản ngắn hạn hoặc tăng nợ ngắn hạn để tài trợ.

4.12 Mức độ tăng trưởng qua các năm

1. library(fmsb)
2. HPG_radar <- HPG %>%
3.   summarise(
4.     DoanhThu = mean(DoanhThu, na.rm = TRUE),
5.     LN = mean(LN_SauThue, na.rm = TRUE),
6.     TS = mean(Tong_TS, na.rm = TRUE),
7.     No = mean(No_PhaiTra, na.rm = TRUE),
8.     Von = mean(Von_CSH, na.rm = TRUE))
9. HPG_radar_scaled <- as.data.frame(lapply(HPG_radar, function(x) (x / max(HPG_radar) * 100)))
10. HPG_radar_scaled <- rbind(rep(100, 5), rep(0, 5), HPG_radar_scaled)
11. par(mar = c(2, 2, 3, 2))  
12. par(cex.axis = 0.8)     
13. radarchart(HPG_radar_scaled,axistype = 1,pcol = "#0072BC",pfcol = alpha("#0072BC", 0.4),plwd = 3,cglcol = "gray60", cglty = 3,axislabels = seq(0, 100, 25),cglwd = 0.8,vlcex = 1.1,                             title = "Biểu đồ radar thể hiện cấu trúc tài chính trung bình của HPG") +
14. theme_minimal(base_size = 13) +
15.   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())

## NULL

Giải thích kỹ thuật: Dòng 1 tải gói fmsb để vẽ biểu đồ radar. Dòng 2–8 tính giá trị trung bình của các chỉ tiêu tài chính chính (Doanh thu, LNST, Tài sản, Nợ, Vốn CSH). Dòng 9 chuẩn hóa dữ liệu về thang 0–100 để các biến có thể so sánh. Dòng 10 thêm hàng giá trị tối đa và tối thiểu theo định dạng chuẩn của biểu đồ radar. Dòng 11–12 chỉnh bố cục hiển thị. Dòng 13 vẽ biểu đồ radar thể hiện cấu trúc tài chính trung bình của HPG, qua đó cho thấy mức độ tương quan giữa quy mô tài sản, doanh thu, lợi nhuận và cấu trúc vốn.

Nhận xét:

Hình dạng của radar phản ánh cấu trúc tài chính trung bình của Hòa Phát trên 5 chỉ tiêu: Tổng tài sản (TS) là điểm mạnh nhất (điểm gần 100), tiếp theo là DoanhThu, rồi Vốn chủ sở hữu (Von) và Nợ (No) ở mức trung bình — còn Lợi nhuận (LN) có giá trị tương đối thấp so với trục lớn nhất.

HPG có quy mô tài sản rất lớn, doanh thu cũng cao tương ứng, nhưng lợi nhuận trung bình không đạt tỷ lệ tương xứng so với tài sản — điều này phù hợp với các phân tích trước: doanh thu tăng nhanh nhưng lợi nhuận biến động ít hơn.

4.13 Biểu đồ tương quan

1. install.packages("ggcorrplot")
2. library(ggcorrplot)
3. HPG_corr <- HPG %>%
4.   select(DoanhThu, LN_SauThue, Tong_TS, Von_CSH, No_PhaiTra)
5. corr_matrix <- cor(HPG_corr, use = "complete.obs")
6. ggcorrplot(corr_matrix, method = "circle", lab = TRUE, lab_size = 3,colors = c("blue", "white", "red"),title = "Biểu đồ tương quan giữa các chỉ tiêu tài chính của HPG",ggtheme = theme_minimal()) +
7. theme_minimal(base_size = 13) +
8.   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–2, ta nạp thư viện ggcorrplot dùng để trực quan hóa tương quan. Tiếp đó, dòng 3–4 chọn ra các biến tài chính quan trọng của HPG gồm: DoanhThu, LN_SauThue, Tong_TS, Von_CSH và No_PhaiTra để phân tích mối liên hệ giữa chúng. Ở dòng 5, hàm cor() để tính ma trận tương quan, cho biết mức độ các chỉ tiêu biến động cùng nhau mạnh hay yếu. Cuối cùng, dòng 6 dùng ggcorrplot() để vẽ biểu đồ tương quan dưới dạng vòng tròn có màu sắc, giá trị hiển thị trực tiếp giúp dễ nhận diện mối quan hệ thuận (+) hay nghịch (-). Các dòng 7–8 tinh chỉnh giao diện: căn tiêu đề, màu chữ và bố cục giúp biểu đồ trở nên rõ ràng.

Nhận xét:

Biểu đồ tương quan cho thấy Các hệ số tương quan đều cao và dương (gần 1) giữa hầu hết các chỉ tiêu. Điều này chứng tỏ các yếu tố tài chính của Hòa Phát tăng giảm cùng chiều rất mạnh một đặc điểm phổ biến của các doanh nghiệp sản xuất lớn.

Doanh thu – Tổng tài sản (r ≈ 0.97) và Doanh thu – Vốn chủ sở hữu (r ≈ 0.97) có tương quan rất cao, nghĩa là khi HPG mở rộng quy mô tài sản và vốn, doanh thu tăng tương ứng.

Tổng tài sản – Nợ phải trả (r ≈ 0.99) cho thấy HPG sử dụng đòn bẩy tài chính mạnh, tức là khi tổng tài sản tăng thì nợ cũng tăng gần tương ứng.

Lợi nhuận sau thuế (LN_SauThue) cũng có tương quan dương với các chỉ tiêu khác, nhưng thấp hơn (r ≈ 0.5–0.6), phản ánh rằng tăng quy mô tài sản hay doanh thu chưa hoàn toàn chuyển hóa thành lợi nhuận, có thể do chi phí đầu tư và chi phí vốn lớn.

Xét trên phương diện kinh tế - tài chính biểu đồ cung cấp cho chúng ta thông tin rằng HPG là doanh nghiệp tăng trưởng mạnh về quy mô, thể hiện qua mối quan hệ chặt giữa tài sản, vốn và doanh thu. Tuy nhiên, hiệu quả sinh lời (LN_SauThue) chưa tăng tương xứng với quy mô, cho thấy hiệu suất sử dụng vốn và tài sản cần được cải thiện. Mối tương quan cao giữa nợ và tài sản gợi ý rằng HPG phụ thuộc khá nhiều vào nguồn vốn vay, nên doanh nghiệp cần quản lý rủi ro tài chính và chi phí lãi vay hiệu quả hơn.

4.14 Biểu đồ cột chồng giữa tài sản và nợ phải trả

1. gg2 <- HPG %>%
2.   ggplot(aes(x = as.factor(Nam))) +
3.   geom_bar(aes(y = Tong_TS/1e9, fill = "Tổng tài sản"), stat = "identity", alpha = 0.8) +
4.   geom_bar(aes(y = -No_PhaiTra/1e9, fill = "Nợ phải trả"), stat = "identity", alpha = 0.8) +
5.   labs(title = "Cơ cấu Tài sản & Nợ phải trả theo năm",
6.        x = "Năm", y = "Tỷ đồng", fill = "Thành phần") +
7.   theme_minimal(base_size = 13)+
8.   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())
9. gg2

Giải thích kỹ thuật: Dòng 1–2 khởi tạo biểu đồ bằng việc đưa dữ liệu HPG vào hàm ggplot(), trục hoành là năm được chuyển thành dạng phân loại (as.factor(Nam)). Tiếp đến, dòng 3 vẽ cột biểu diễn Tổng tài sản, được chia theo đơn vị tỷ đồng và hiển thị hướng dương trên trục tung. Ở dòng 4, biểu đồ chồng thêm cột biểu diễn Nợ phải trả, nhưng giá trị được đổi dấu âm để hiển thị theo hướng ngược lại, cho phép quan sát rõ chênh lệch quy mô giữa tài sản và nợ. Dòng 5–6 bổ sung tiêu đề, nhãn trục và chú thích giúp người xem hiểu được ý nghĩa từng thành phần. Cuối cùng, dòng 7–8 dùng theme_minimal() và chỉnh sửa font, màu, vị trí chú giải giúp biểu đồ trực quan, rõ ràng.

Nhận xét: biểu đồ cho thấy quy mô tổng tài sản của HPG tăng rõ rệt từ 2015 đến 2024, đặc biệt sau 2019 — điều này phản ánh quá trình mở rộng đầu tư, tăng công suất và tích lũy tài sản cố định. Đồng thời, mức nợ tuyệt đối cũng tăng mạnh, đặc biệt ở các năm 2023 và 2024, khi các cột nợ kéo dài xuống sâu hơn, cho thấy doanh nghiệp đã gia tăng sử dụng đòn bẩy (vay nợ) để tài trợ cho tài sản.

4.15 Biểu đồ phân tích tái đầu tư

1. reinvestment_analysis <- HPG %>%
2.   mutate(
3.     reinvestment_ratio = abs(LCTT_DT) / LCTT_KD
4.   ) %>%
5.   filter(!is.na(reinvestment_ratio))
6. ggplot(reinvestment_analysis, aes(x = factor(Nam), y = reinvestment_ratio)) +
7.   geom_col(fill = "#00695C") +
8.   geom_text(aes(label = scales::percent(reinvestment_ratio, accuracy = 1)),vjust = -0.5, size = 3) +
9.   geom_hline(yintercept = 1.0, linetype = "dashed", color = "red") +
10.   scale_y_continuous(labels = scales::percent_format()) +
11.   labs(title = "Phân tích Tái đầu tư (Dòng tiền Đầu tư / Dòng tiền HĐKD)",subtitle = "Tỷ lệ >100% (đỏ): HPG đầu tư vượt dòng tiền HĐKD",x = "Năm",y = "Tỷ lệ Tái đầu tư (%)") +
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: Dòng 1–5 tạo biến reinvestment_analysis và tính tỷ lệ tái đầu tư dòng 3 bằng cách lấy dòng tiền đầu tư chia dòng tiền hoạt động, đồng thời loại bỏ giá trị thiếu. Dòng 6–8 vẽ biểu đồ cột theo năm và hiển thị nhãn phần trăm trên mỗi cột. Dòng 9 thêm đường ngang tại mức 1.0 để đánh dấu ngưỡng đầu tư vượt khả năng tạo tiền từ hoạt động kinh doanh. Dòng 10–13 định dạng trục, tiêu đề và giao diện.

Nhận xét: Biểu đồ thể hiện tỷ lệ tái đầu tư của Hòa Phát (HPG), tính bằng cách lấy dòng tiền đầu tư chia cho dòng tiền từ hoạt động kinh doanh (HĐKD). Có thể thấy rằng trong các năm như 2018, 2019 và đặc biệt là 2024, tỷ lệ này vượt xa ngưỡng 100%, cho thấy công ty đã đầu tư nhiều hơn cả số tiền tạo ra từ HĐKD. Năm 2024 là điểm đáng chú ý nhất với mức đầu tư lên đến 451%, mức cao nhất trong toàn bộ chuỗi thời gian. Tỷ lệ tái đầu tư cao cho thấy HPG đang trong giai đoạn mở rộng, ưu tiên rót vốn để tăng quy mô và năng lực sản xuất. Tuy vậy, khi tỷ lệ vượt 100% kéo dài (như năm 2024), dòng tiền hoạt động không đủ bù chi cho đầu tư, tạo áp lực thanh khoản và rủi ro tài chính. Doanh nghiệp cần theo dõi hiệu quả đầu tư để đảm bảo dòng tiền tương lai đủ bù đắp chi phí hiện tại.

4.16 Phân tích tương quan tái đầu tư và tăng trưởng doanh thu

1. lagged_analysis <- HPG_metrics %>%
2.   mutate(
3.     future_revenue_growth = lead(revenue_growth_yoy, 1),
4.     current_reinvestment = abs(LCTT_DT) / LCTT_KD
5.   ) %>%
6.   select(Nam, future_revenue_growth, current_reinvestment) %>%
7.   drop_na() 
8. ggplot(lagged_analysis, aes(x = current_reinvestment, y = future_revenue_growth)) +
9.   geom_point(color = "#009E73", size = 3) +
10.   geom_smooth(method = "lm", se = FALSE, color = "#D55E00", linetype = "dashed") +
11.   geom_text_repel(aes(label = Nam), size = 3) +
12.   scale_x_continuous(labels = scales::percent_format()) +
13.   scale_y_continuous(labels = scales::percent_format()) +
14.   labs(title = "Phân tích Tương quan Trễ (1 Năm)",subtitle = "Tái đầu tư (Năm T) ảnh hưởng Tăng trưởng Doanh thu (Năm T+1) như thế nào?",x = "Tỷ lệ Tái đầu tư (CFI/CFO) của Năm T (%)",y = "Tăng trưởng Doanh thu YoY của Năm T+1 (%)") +
15.   theme_minimal(base_size = 13) +
16.   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–5 tạo biến lagged_analysis và tính hai chỉ tiêu: tỷ lệ tái đầu tư năm T và tăng trưởng doanh thu của năm T+1 bằng hàm lead(). Dòng 6–7 giữ lại các cột cần phân tích và loại bỏ giá trị thiếu. Dòng 8–11 vẽ biểu đồ phân tán, gắn nhãn năm và thêm đường hồi quy để thể hiện xu hướng tương quan giữa hai biến. Dòng 12–13 chuẩn hóa hai trục về định dạng phần trăm giúp dễ so sánh. Dòng 14–16 thiết lập tiêu đề, nhãn trục và chỉnh giao diện để biểu đồ rõ ràng và dễ trình bày.

Nhận xét: Đường hồi quy có xu hướng đi lên nhẹ, cho thấy mối liên hệ dương, thể hiện việc đầu tư nhiều ở năm hiện tại có thể dẫn đến tăng trưởng doanh thu vào năm sau. Tuy nhiên, sự phân tán giữa các điểm dữ liệu là khá lớn, ví dụ năm 2018 có mức tái đầu tư cao nhưng tốc độ tăng trưởng năm sau lại không tương xứng, trong khi năm 2020 có tăng trưởng vượt trội dù đầu tư mức vừa phải.

4.17 Biểu đồ phân tích chất lượng doanh thu

1. ggplot(HPG, aes(x = DoanhThu, y = LCTT_KD)) +
2.   geom_point(
3.     aes(color = Nam, size = Tong_TS),
4.     alpha = 0.8) +
5.   geom_smooth(method = "lm", se = FALSE, color = "red") +
6.   geom_abline(
7.     intercept = 0, 
8.     slope = mean(HPG$LCTT_KD / HPG$DoanhThu),
9.     linetype = "dashed", color = "blue") +
10.   geom_text_repel(aes(label = Nam), size = 3) +
11.   scale_x_continuous(labels = scales::label_number(scale_cut = scales::cut_short_scale())) +
12.   scale_y_continuous(labels = scales::label_number(scale_cut = scales::cut_short_scale())) +
13.   scale_color_gradient(low = "blue", high = "red") +
14.   labs(title = "Phân tích 'Chất lượng' Doanh thu",
15.     subtitle = "So sánh Doanh thu (Kế toán) vs. Dòng tiền HĐKD (Tiền mặt)",x = "Doanh thu (VND)",y = "Dòng tiền từ HĐKD (VND)",color = "Năm",size = "Tổng Tài sản") +
16.   theme_minimal(base_size = 13) +
17.   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"),panel.grid.minor = element_blank())

Giải thích kỹ thuật: Dòng 1–4 vẽ đồ thị phân tán giữa Doanh thu và Dòng tiền HĐKD, với màu biểu thị năm và kích thước điểm biểu thị quy mô tài sản.Dòng 5 thêm đường hồi quy để thể hiện xu hướng tương quan.Dòng 6–9 thêm đường chuẩn dựa trên tỷ lệ trung bình LCTT_KD/DoanhThu nhằm đánh giá chất lượng dòng tiền so với doanh thu.

Nhận xét: Biểu đồ “Chất lượng Doanh thu” cho thấy trong giai đoạn từ năm 2015 đến 2021, Hòa Phát (HPG) duy trì sự tương quan tích cực giữa doanh thu kế toán và dòng tiền thu được từ hoạt động kinh doanh (HĐKD), đặc biệt năm 2021 ghi nhận dòng tiền vượt xa kỳ vọng, đây là một điểm sáng về hiệu quả tài chính. Tuy nhiên, từ năm 2022 đến 2024, xu hướng này suy giảm đáng kể khi doanh thu tiếp tục tăng nhưng dòng tiền từ HĐKD giảm mạnh, đặc biệt năm 2024 xuất hiện khoảng cách lớn nhất, thể hiện dấu hiệu dòng tiền không theo kịp doanh thu kế toán.

4.18 Boxplot so sánh phân bố Doanh thu và Lợi nhuận

1. ggplot(HPG, aes(x = "DoanhThu", y = DoanhThu)) +
2.   geom_boxplot(fill = "skyblue") +
3.   geom_boxplot(aes(x = "LN_SauThue", y = LN_SauThue), fill = "lightgreen") +
4.   labs(title = "Phân bố Doanh thu và Lợi nhuận sau thuế của HPG",x = "Biến số",y = "Giá trị (VND)",caption = "Nguồn: Báo cáo tài chính HPG")+
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 = 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–3 vẽ hai biểu đồ boxplot, trong đó Doanh thu và Lợi nhuận sau thuế được biểu diễn dưới dạng phân bố để so sánh trực tiếp. Dòng 4 thiết lập tiêu đề, nhãn trục và chú thích nguồn dữ liệu. Cuối cùng, các dòng 5–6 áp dụng giao diện trình bày đơn giản và căn chỉnh lại kiểu chữ, màu sắc và bố cục. Nhận xét:

Biểu đồ cho thấy khoảng giá trị (IQR) và median của Doanh thu lớn hơn rất nhiều so với Lợi nhuận, nghĩa là quy mô doanh thu của HPG gấp nhiều lần lợi nhuận ròng. Hộp Doanh thu trải rộng, có độ phân tán lớn và whisker dài — phản ánh biến động đáng kể về quy mô bán hàng qua các năm.

Hộp Lợi nhuận lại có quy mô nhỏ hơn nhưng vẫn xuất hiện điểm bất thường (outlier), cho thấy có một vài năm lợi nhuận khác biệt rõ rệt so với phần còn lại (điểm này tương thích với hệ số biến động lợi nhuận cao đã tính trước đó).

Từ kết quả nhận được cho ta thấy Hòa Phát có quy mô doanh thu lớn và tăng trưởng mạnh nhưng lợi nhuận ròng nhỏ hơn nhiều và biến động cao. Outlier lợi nhuận có thể do các sự kiện đặc biệt (lợi nhuận bất thường hoặc khoản chi/thu một lần) hoặc tác động từ các dự án đầu tư lớn.

4.19 Biểu đồ trung bình ROA và ROE theo giai đoạn

1. HPG_RO_long <- HPG_RO %>%
2.   pivot_longer(cols = c(ROA_TB, ROE_TB),
3.                names_to = "ChiTieu",
4.                values_to = "GiaTri")
5. ggplot(HPG_RO_long, aes(x = GiaiDoan, y = GiaTri, fill = ChiTieu)) +
6.   geom_col(position = "dodge", color = "black") +                   
7.   geom_text(aes(label = round(GiaTri, 1)),                            
8.             position = position_dodge(width = 0.9),
9.             vjust = -0.5, size = 4) +
10.   geom_hline(yintercept = mean(HPG_RO_long$GiaTri),                   
11.              linetype = "dashed", color = "red", linewidth = 0.8) +
12.   scale_fill_manual(values = c("#4DBBD5FF", "#E64B35FF"),             
13.                     labels = c("ROA trung bình", "ROE trung bình")) +
14.   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") +
15.   theme_minimal(base_size = 13) +
16.   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())

Giải thích kỹ thuật: Dòng 1–4 chuyển dữ liệu ROA và ROE về dạng long để thuận tiện cho việc so sánh trên cùng biểu đồ. Dòng 5–6 tạo biểu đồ cột nhóm, mỗi giai đoạn có hai cột đại diện cho ROA và ROE. Dòng 7–9 thêm nhãn giá trị lên các cột. Dòng 10 kẻ đường trung bình toàn kỳ nhằm so sánh mức hiệu quả tương đối giữa các giai đoạn. Dòng 12–14 tùy chỉnh màu sắc và nhãn hiển thị, còn dòng 15–16 điều chỉnh giao diện và bố cục để biểu đồ rõ ràng.

Nhận xét: Biểu đồ cho thấy ROE của HPG luôn cao hơn ROA ở cả hai giai đoạn, phản ánh việc doanh nghiệp sử dụng đòn bẩy tài chính để tăng lợi nhuận cho cổ đông. Trước năm 2020, ROA (15.1%) và ROE (26.5%) đều ở mức cao, cho thấy hoạt động kinh doanh hiệu quả và khả năng sinh lời mạnh. Tuy nhiên, sau năm 2020, cả hai chỉ tiêu giảm đáng kể, đặc biệt ROA giảm còn 8.7%, cho thấy hiệu quả sử dụng tài sản suy giảm rõ rệt trong bối cảnh thị trường thép biến động. Tuy vậy, ROE sau 2020 vẫn duy trì ở mức 17.3%, chứng tỏ doanh nghiệp vẫn giữ được khả năng tạo giá trị cho cổ đông, dù thấp hơn giai đoạn trước.

4.20 Biểu đồ tốc độ tăng trưởng (%) qua các năm của Hòa Phát

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

Giải thích kỹ thuật: Dòng 1–5, dữ liệu HPG_tangtruong được chuyển từ dạng rộng sang dạng dài bằng pivot_longer(), trong đó giữ nguyên cột Nam và gom các biến tăng trưởng vào hai cột mới là ChiTieu và TangTruong. Tiếp theo, từ dòng 6, hàm ggplot() được sử dụng để vẽ biểu đồ đường theo năm, với màu sắc phân biệt từng chỉ tiêu và nối các điểm bằng đường dòng 6–8. Một đường ngang giá trị 0 được thêm vào ở dòng 9 để cho thấy ranh giới tăng hay giảm. Cuối cùng, dòng 10–12 thiết lập tiêu đề, tên trục, chú thích, bố cục và kiểu hiển thị.

Nhận xét:

Quan sát biểu đồ cho thấy tốc độ tăng trưởng doanh thu, lợi nhuận, tổng tài sản và vốn chủ sở hữu của Tập đoàn Hòa Phát có sự biến động khá mạnh qua các năm, phản ánh chu kỳ tăng – giảm rõ rệt trong hoạt động kinh doanh.

Giai đoạn 2015–2020, các chỉ tiêu nhìn chung tăng trưởng tích cực, đặc biệt năm 2020 ghi nhận mức tăng mạnh nhất ở cả doanh thu và lợi nhuận, cho thấy Hòa Phát đạt được hiệu quả cao trong sản xuất và tiêu thụ sản phẩm (đặc biệt là thép).

Tuy nhiên, năm 2022 là giai đoạn suy giảm rõ rệt, tốc độ tăng trưởng lợi nhuận sau thuế rơi xuống mức âm sâu, phản ánh tác động của giá thép giảm mạnh, chi phí đầu vào tăng và nhu cầu thị trường suy yếu.

Năm 2023 - 2024, xu hướng phục hồi xuất hiện khi cả bốn chỉ tiêu đều có dấu hiệu tăng nhẹ trở lại, tuy chưa đạt mức cao như giai đoạn trước đại dịch. Điều này cho thấy doanh nghiệp đang dần ổn định hoạt động sau giai đoạn khó khăn.