1 CHƯƠNG 1: PHÂN TÍCH BỘ DỮ LIỆU VỀ DOANH SỐ BÁN HÀNG

Bộ dữ liệu “Orders_Sales_Data” là tập hợp toàn diện các giao dịch và thông tin khách hàng, được thu thập nhằm mục đích phân tích chuyên sâu hiệu suất bán hàng và hành vi mua sắm trong một khoảng thời gian cụ thể. Đây là nền tảng để đánh giá chiến lược kinh doanh, tối ưu hóa danh mục sản phẩm và đưa ra quyết định dựa trên dữ liệu.Phân tích bộ dữ liệu trên giúp các nhà đầu tư lựa chọn danh mục hàng hóa nên đầu tư mạnh và ngược lại.

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

1.1.1 Đọc dữ liệu

data <- read.csv("C:/Users/adminn/Downloads/Sales_Orders_Data.csv", header = TRUE)

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

# Kiểm tra cấu trúc cơ bản của data
cat("=== THÔNG TIN CƠ BẢN VỀ BỘ DỮ LIỆU ===\n")
## === THÔNG TIN CƠ BẢN VỀ BỘ DỮ LIỆU ===
cat("Kích thước bộ dữ liệu:", dim(data), "\n")
## Kích thước bộ dữ liệu: 1048575 11

Giải thích Hàm dim() trong R trả về kích thước (dimension) của một đối tượng dạng bảng, chẳng hạn như data frame, matrix hoặc tibble.

Nhận xét Bộ dữ liệu có 1.048.575 dòng (quan sát) và có 11 cột (biến số).

1.1.3 Kiểm tra 10 dòng đầu tiên

cat("=== 10 DÒNG ĐẦU TIÊN CỦA DỮ LIỆU ===\n")
## === 10 DÒNG ĐẦU TIÊN CỦA DỮ LIỆU ===
head(data, 10)
##    Order_ID Customer_ID Customer_Type            Product            Category
## 1      ORD1     CUS1496           B2B         Vio Wasser               Water
## 2      ORD1     CUS1496           B2B              Evian               Water
## 3      ORD1     CUS1496           B2B             Sprite         Soft Drinks
## 4      ORD1     CUS1496           B2B Rauch Multivitamin              Juices
## 5      ORD1     CUS1496           B2B       Gerolsteiner               Water
## 6      ORD2     CUS2847           B2C    Sauvignon Blanc Alcoholic Beverages
## 7      ORD3     CUS1806           B2B       Tomato Juice              Juices
## 8      ORD3     CUS1806           B2B             Vittel               Water
## 9      ORD3     CUS1806           B2B     San Pellegrino               Water
## 10     ORD3     CUS1806           B2B              Evian               Water
##    Unit_Price Quantity Discount Total_Price             Region Order_Date
## 1        1.66       53     0.10       79.18  Baden-Württemberg 23/08/2023
## 2        1.56       90     0.10      126.36  Baden-Württemberg 23/08/2023
## 3        1.17       73     0.05       81.14  Baden-Württemberg 23/08/2023
## 4        3.22       59     0.10      170.98  Baden-Württemberg 23/08/2023
## 5        0.87       35     0.10       27.40  Baden-Württemberg 23/08/2023
## 6        9.09        2     0.00       18.18 Schleswig-Holstein 16/03/2023
## 7        2.14       44     0.10       84.74            Hamburg 20/11/2022
## 8        0.43       13     0.05        5.31            Hamburg 20/11/2022
## 9        1.21       92     0.10      100.19            Hamburg 20/11/2022
## 10       1.38        3     0.05        3.93            Hamburg 20/11/2022

🔹 Giải thích

Hàm head(data, 10) lấy 10 dòng đầu tiên của data frame data.

🔹 Ý nghĩa thống kê

Giúp xem cấu trúc dữ liệu thô: các tên cột, định dạng từng cột (số, chữ, ngày, …). Phát hiện dòng bị lỗi hoặc thiếu dữ liệu (NA) ngay từ đầu.

1.1.4 Kiểm tra 10 dòng cuối

cat("=== 10 DÒNG CUỐI CÙNG CỦA DỮ LIỆU ===\n")
## === 10 DÒNG CUỐI CÙNG CỦA DỮ LIỆU ===
tail(data, 10)
##          Order_ID Customer_ID Customer_Type            Product
## 1048566 ORD349189     CUS3703           B2C     Hohes C Orange
## 1048567 ORD349190     CUS8480           B2C      Granini Apple
## 1048568 ORD349191     CUS6311           B2C    Cranberry Juice
## 1048569 ORD349192       CUS25           B2C Rauch Multivitamin
## 1048570 ORD349192       CUS25           B2C        Havana Club
## 1048571 ORD349192       CUS25           B2C            Bacardi
## 1048572 ORD349192       CUS25           B2C         Fritz-Kola
## 1048573 ORD349193     CUS2035           B2C       Volvic Touch
## 1048574 ORD349193     CUS2035           B2C             Vittel
## 1048575 ORD349193     CUS2035           B2C              Fanta
##                    Category Unit_Price Quantity Discount Total_Price
## 1048566              Juices       1.80        3        0        5.40
## 1048567              Juices       1.69       15        0       25.35
## 1048568              Juices       3.56       10        0       35.60
## 1048569              Juices       2.38        8        0       19.04
## 1048570 Alcoholic Beverages      12.96        9        0      116.64
## 1048571 Alcoholic Beverages      13.84        3        0       41.52
## 1048572         Soft Drinks       2.05        2        0        4.10
## 1048573               Water       1.46       11        0       16.06
## 1048574               Water       0.59        2        0        1.18
## 1048575         Soft Drinks       1.23       15        0       18.45
##                 Region Order_Date
## 1048566        Sachsen 26/10/2022
## 1048567        Sachsen 09/09/2023
## 1048568         Bremen 20/12/2022
## 1048569  Niedersachsen 27/08/2022
## 1048570  Niedersachsen 27/08/2022
## 1048571  Niedersachsen 27/08/2022
## 1048572  Niedersachsen 27/08/2022
## 1048573 Sachsen-Anhalt 05/11/2023
## 1048574 Sachsen-Anhalt 05/11/2023
## 1048575 Sachsen-Anhalt 05/11/2023

🔹 Giải thích

tail(data, 10) lấy 10 dòng cuối cùng trong bảng dữ liệu.

🔹 Ý nghĩa thống kê

Kiểm tra phần cuối dữ liệu xem có dòng bị trống, lặp hoặc lỗi nhập liệu không.

1.1.5 Kiểm tra số quan sát và số biến

cat("Số quan sát (dòng):", nrow(data), "\n")
## Số quan sát (dòng): 1048575
cat("Số biến (cột):", ncol(data), "\n")
## Số biến (cột): 11

1.1.6 Kiểm tra các biến định lượng

cat("Các biến định lượng:", sum(sapply(data, is.numeric)), "\n")
## Các biến định lượng: 4

1.1.7 Kiểm tra các biến định tính

cat("Các biến định tính:", sum(sapply(data, is.character) | sapply(data, is.factor)),"\n" )
## Các biến định tính: 7

🔹 Giải thích

nrow(data) → đếm số hàng (số lượng quan sát/giao dịch).

ncol(data) → đếm số cột (số lượng biến/thuộc tính).

sapply(data, is.numeric) → kiểm tra cột nào là dạng số (numeric), kết quả trả về TRUE/FALSE cho từng cột.

sum(sapply(data, is.numeric)) → đếm tổng số biến định lượng.

sapply(data, is.character) | sapply(data, is.factor) → kiểm tra cột nào là dạng ký tự hoặc phân loại (categorical).

sum(…) → đếm tổng số biến định tính.

🔹 Ý nghĩa thống kê

Giúp hiểu sơ bộ quy mô và cấu trúc dữ liệu:

Có bao nhiêu dòng (quan sát)

Có bao nhiêu cột (biến)

Loại biến nào chiếm ưu thế (định lượng hay định tính)?

1.1.8 Tên các biến trong bộ dữ liệu

cat("Tên các biến:", names(data), "\n")
## Tên các biến: Order_ID Customer_ID Customer_Type Product Category Unit_Price Quantity Discount Total_Price Region Order_Date

1.1.9 Kiểm tra kiểu dữ liệu của các cột

cat("=== KIỂU DỮ LIỆU CỦA CÁC CỘT ===\n")
## === KIỂU DỮ LIỆU CỦA CÁC CỘT ===
str(data)
## 'data.frame':    1048575 obs. of  11 variables:
##  $ Order_ID     : chr  "ORD1" "ORD1" "ORD1" "ORD1" ...
##  $ Customer_ID  : chr  "CUS1496" "CUS1496" "CUS1496" "CUS1496" ...
##  $ Customer_Type: chr  "B2B" "B2B" "B2B" "B2B" ...
##  $ Product      : chr  "Vio Wasser" "Evian" "Sprite" "Rauch Multivitamin" ...
##  $ Category     : chr  "Water" "Water" "Soft Drinks" "Juices" ...
##  $ Unit_Price   : num  1.66 1.56 1.17 3.22 0.87 9.09 2.14 0.43 1.21 1.38 ...
##  $ Quantity     : int  53 90 73 59 35 2 44 13 92 3 ...
##  $ Discount     : num  0.1 0.1 0.05 0.1 0.1 0 0.1 0.05 0.1 0.05 ...
##  $ Total_Price  : num  79.2 126.4 81.1 171 27.4 ...
##  $ Region       : chr  "Baden-Württemberg" "Baden-Württemberg" "Baden-Württemberg" "Baden-Württemberg" ...
##  $ Order_Date   : chr  "23/08/2023" "23/08/2023" "23/08/2023" "23/08/2023" ...

🔹 Giải thích

Hàm str() hiển thị cấu trúc đối tượng, bao gồm:

Kiểu dữ liệu từng cột (numeric, character, factor, Date, …)

Một vài giá trị mẫu của mỗi cột.

🔹 Ý nghĩa thống kê

Giúp xác định:

Cột nào là biến định lượng (số, có thể tính trung bình, tổng, …)

Cột nào là biến định tính (phân loại: vùng, giới tính, loại khách hàng

###Thống kê mô tả tổng quan

cat("=== THỐNG KÊ MÔ TẢ TỔNG QUAN ===\n")
## === THỐNG KÊ MÔ TẢ TỔNG QUAN ===
summary(data)
##    Order_ID         Customer_ID        Customer_Type        Product         
##  Length:1048575     Length:1048575     Length:1048575     Length:1048575    
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##    Category           Unit_Price         Quantity         Discount      
##  Length:1048575     Min.   :  0.320   Min.   :  1.00   Min.   :0.00000  
##  Class :character   1st Qu.:  1.050   1st Qu.:  6.00   1st Qu.:0.00000  
##  Mode  :character   Median :  1.750   Median : 11.00   Median :0.00000  
##                     Mean   :  5.847   Mean   : 23.14   Mean   :0.02973  
##                     3rd Qu.:  3.210   3rd Qu.: 30.00   3rd Qu.:0.05000  
##                     Max.   :160.440   Max.   :100.00   Max.   :0.15000  
##   Total_Price          Region           Order_Date       
##  Min.   :    0.30   Length:1048575     Length:1048575    
##  1st Qu.:    8.40   Class :character   Class :character  
##  Median :   21.14   Mode  :character   Mode  :character  
##  Mean   :  130.98                                        
##  3rd Qu.:   69.77                                        
##  Max.   :12682.78

🔹 Giải thích

summary() tự động tạo bảng thống kê mô tả cho mỗi cột:

Với biến số: hiển thị Min, 1st Qu., Median, Mean, 3rd Qu., Max

Với biến phân loại: đếm tần suất từng giá trị.

🔹 Ý nghĩa thống kê

Mean (trung bình) → giá trị đại diện chung.

Median (trung vị) → giá trị giữa, ít bị ảnh hưởng bởi ngoại lệ.

Min / Max → phạm vi dao động của dữ liệu.

1st Qu. / 3rd Qu. → phân vị 25% và 75%, thể hiện độ phân tán.

1.1.10 Ý nghĩa các biến trong bộ dữ liệu

library(knitr)

thong_tin_bien <- data.frame(
  "Tên Biến" = c("Order_ID", "Customer_ID", "Customer_Type", "Product", 
                 "Category", "Unit_Price", "Quantity", "Discount",
                 "Total_Price", "Region", "Order_Date"),
  "Mô Tả" = c(
    "Mã đơn hàng (định danh duy nhất cho mỗi đơn hàng)",
    "Mã khách hàng (định danh khách hàng)",
    "Phân loại khách hàng (B2B - Doanh nghiệp/B2C - Cá nhân)",
    "Tên sản phẩm",
    "Danh mục sản phẩm",
    "Đơn giá sản phẩm",
    "Số lượng sản phẩm trong đơn hàng",
    "Tỷ lệ chiết khấu áp dụng (%)",
    "Tổng giá trị đơn hàng (sau chiết khấu)",
    "Khu vực địa lý",
    "Ngày đặt hàng"
  )
)

cat("=== Ý NGHĨA CÁC BIẾN TRONG DATASET ===\n")
## === Ý NGHĨA CÁC BIẾN TRONG DATASET ===
kable(thong_tin_bien, caption = "THÔNG TIN MÔ TẢ CÁC BIẾN TRONG BỘ DỮ LIỆU")
THÔNG TIN MÔ TẢ CÁC BIẾN TRONG BỘ DỮ LIỆU
Tên.Biến Mô.Tả
Order_ID Mã đơn hàng (định danh duy nhất cho mỗi đơn hàng)
Customer_ID Mã khách hàng (định danh khách hàng)
Customer_Type Phân loại khách hàng (B2B - Doanh nghiệp/B2C - Cá nhân)
Product Tên sản phẩm
Category Danh mục sản phẩm
Unit_Price Đơn giá sản phẩm
Quantity Số lượng sản phẩm trong đơn hàng
Discount Tỷ lệ chiết khấu áp dụng (%)
Total_Price Tổng giá trị đơn hàng (sau chiết khấu)
Region Khu vực địa lý
Order_Date Ngày đặt hàng

###Kiểm tra số lượng giá trị duy nhất trong các cột phân loại

cat("=== SỐ LƯỢNG GIÁ TRỊ DUY NHẤT THEO CỘT ===\n")
## === SỐ LƯỢNG GIÁ TRỊ DUY NHẤT THEO CỘT ===
sapply(data[, c("Customer_Type", "Category", "Region")], function(x) length(unique(x)))
## Customer_Type      Category        Region 
##             2             4            16

🔹 Giải thích

Câu lệnh trên sử dụng hàm sapply() để lặp qua các cột “Customer_Type”, “Category” và “Region”.

Với mỗi cột, hàm unique(x) lấy ra các giá trị khác nhau (không trùng lặp).

Sau đó, length(unique(x)) đếm số lượng giá trị duy nhất trong cột đó.

Kết quả là một bảng nhỏ hiển thị số lượng loại khác nhau trong từng biến phân loại.

🔹 Ý nghĩa thống kê

Giúp xác định mức độ đa dạng của dữ liệu phân loại:

Có bao nhiêu loại khách hàng (Customer_Type)

Có bao nhiêu danh mục sản phẩm (Category)

Có bao nhiêu khu vực bán hàng (Region)

Nếu quá nhiều, cần xem xét gộp nhóm hoặc mã hóa lại khi phân tích hoặc trực quan hóa.

1.2 XỬ LÍ VÀ MÃ HÓA DỮ LIỆU

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

cat("Số quan sát trùng lặp:", sum(duplicated(data)), "\n")
## Số quan sát trùng lặp: 0
cat("\n")

🔹 Giải thích:

Hàm duplicated(data) → tìm các dòng trùng lặp trong bộ dữ liệu.

Hàm sum() → đếm số dòng trùng đó.

Hàm cat() → in kết quả ra màn hình.

🔹 Ý nghĩa thống kê:

Giúp phát hiện và loại bỏ các quan sát trùng lặp, nhằm đảm bảo dữ liệu độc lập, chính xác,và tránh sai lệch trong phân tích thống kê.

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

cat("DỮ LIỆU THIẾU THEO TỪNG CỘT:\n")
## DỮ LIỆU THIẾU THEO TỪNG CỘT:
missing_summary <- sapply(data, function(x) sum(is.na(x)))
print(missing_summary)
##      Order_ID   Customer_ID Customer_Type       Product      Category 
##             0             0             0             0             0 
##    Unit_Price      Quantity      Discount   Total_Price        Region 
##             0             0             0             0             0 
##    Order_Date 
##             0
cat("\n")

🔹 Giải thích:

Hàm is.na(x) → kiểm tra ô nào bị trống (NA).

Hàm sum(is.na(x)) → đếm bao nhiêu ô trống trong một cột.

Hàm sapply(data, …) → lặp qua tất cả các cột trong bảng data để tính số ô trống của từng cột.

Biến missing_summary → lưu kết quả đó lại.

Hàm print(missing_summary) → in kết quả ra màn hình.

🔹 Ý nghĩa thống kê:

Giúp phát hiện mức độ thiếu dữ liệu của từng biến, từ đó quyết định xử lý (loại bỏ hoặc điền giá trị) trước khi phân tích thống kê.

1.2.3 Chuyển đổi kiểu dữ liệu

if (nrow(data) == 0) stop("⚠️ File CSV rỗng hoặc không đọc được! Kiểm tra lại đường dẫn và định dạng.")
date_col <- grep("Date", names(data), value = TRUE)
if (length(date_col) == 0) stop("⚠️ Không tìm thấy cột ngày trong dữ liệu!")

data$Order_Date <- as.Date(data[[date_col]], tryFormats = c("%d/%m/%Y", "%Y-%m-%d", "%m/%d/%Y"))
data$Order_Date <- as.Date(data$Order_Date, format = "%d/%m/%Y")
data$Customer_Type <- as.factor(data$Customer_Type)
data$Category <- as.factor(data$Category)
data$Region <- as.factor(data$Region)
# Kiểm tra lại cấu trúc sau khi chuyển đổi
cat("=== CẤU TRÚC DỮ LIỆU SAU KHI CHUYỂN ĐỔI ===\n")
## === CẤU TRÚC DỮ LIỆU SAU KHI CHUYỂN ĐỔI ===
str(data)
## 'data.frame':    1048575 obs. of  11 variables:
##  $ Order_ID     : chr  "ORD1" "ORD1" "ORD1" "ORD1" ...
##  $ Customer_ID  : chr  "CUS1496" "CUS1496" "CUS1496" "CUS1496" ...
##  $ Customer_Type: Factor w/ 2 levels "B2B","B2C": 1 1 1 1 1 2 1 1 1 1 ...
##  $ Product      : chr  "Vio Wasser" "Evian" "Sprite" "Rauch Multivitamin" ...
##  $ Category     : Factor w/ 4 levels "Alcoholic Beverages",..: 4 4 3 2 4 1 2 4 4 4 ...
##  $ Unit_Price   : num  1.66 1.56 1.17 3.22 0.87 9.09 2.14 0.43 1.21 1.38 ...
##  $ Quantity     : int  53 90 73 59 35 2 44 13 92 3 ...
##  $ Discount     : num  0.1 0.1 0.05 0.1 0.1 0 0.1 0.05 0.1 0.05 ...
##  $ Total_Price  : num  79.2 126.4 81.1 171 27.4 ...
##  $ Region       : Factor w/ 16 levels "Baden-Württemberg",..: 1 1 1 1 1 15 6 6 6 6 ...
##  $ Order_Date   : Date, format: "2023-08-23" "2023-08-23" ...

🔹 Giải thích:

Hàm nrow() → đếm số dòng trong data. Nếu số dòng = 0, hàm stop() sẽ dừng chương trình và báo lỗi “File CSV rỗng hoặc không đọc được”.

Hàm grep() → tìm trong tên cột (names(data)) cột nào có chữ “Date”, rồi lưu tên đó vào biến date_col. Nếu không tìm thấy, stop() sẽ báo lỗi “Không tìm thấy cột ngày”.

Hàm as.Date() → chuyển cột ngày sang kiểu dữ liệu ngày tháng, đồng thời thử nhiều định dạng ngày khác nhau (%d/%m/%Y, %Y-%m-%d, %m/%d/%Y) để tránh lỗi.

data\(Order_Date <- as.Date(data\)Order_Date, format = “%d/%m/%Y”) → đảm bảo toàn bộ cột ngày ở định dạng chuẩn ngày/tháng/năm.

Hàm as.factor() → chuyển các cột Customer_Type, Category, Region thành biến phân loại (factor) — cần thiết khi vẽ biểu đồ hoặc chạy mô hình thống kê.

Hàm str() → hiển thị cấu trúc dữ liệu gồm số dòng, số cột, và kiểu dữ liệu của từng biến (numeric, factor, Date…).

🔹 Ý nghĩa thống kê:

Đoạn code giúp kiểm tra dữ liệu đầu vào, xác định và chuẩn hóa cột ngày,đồng thời chuyển các biến định tính thành dạng phân loại (factor), → giúp chuẩn bị dữ liệu sạch, đúng định dạng, sẵn sàng cho phân tích và mô hình hóa thống kê.

1.2.4 Tạo biến thời gian mới

library(dplyr)
data <- data %>%
  mutate(
    Month = format(Order_Date, "%Y-%m"),
    Year = format(Order_Date, "%Y"),
    Quarter = quarters(Order_Date),
    Day_of_Week = weekdays(Order_Date)
  )

🔹 Giải thích:

Hàm mutate() → dùng để tạo thêm cột mới hoặc tính lại giá trị cột cũ trong bảng data.

Dấu %>% → là toán tử pipe, dùng để chuyển kết quả của bước trước sang bước sau.

Hàm format() → lấy tháng và năm từ cột ngày (Order_Date).

Hàm quarters() → cho biết quý của từng ngày.

Hàm weekdays() → trả về thứ trong tuần tương ứng với ngày đó.

1.2.5 Tạo biến mùa trong năm

data <- data %>%
  mutate(
    Season = case_when(
      format(Order_Date, "%m") %in% c("10", "11", "12") ~ "Winter",
      format(Order_Date, "%m") %in% c("01", "02", "03") ~ "Spring",
      format(Order_Date, "%m") %in% c("04", "05", "06") ~ "Summer",
      TRUE ~ "Autumn"
    )
  )

1.2.6 Tạo biến doanh thu và chiết khấu

library(dplyr)
data <- data %>%
  mutate(
    Revenue_Before_Discount = Unit_Price * Quantity,
    Discount_Amount = Revenue_Before_Discount * Discount
  )

🔹 Giải thích:

Revenue_Before_Discount = Unit_Price * Quantity → tính doanh thu trước chiết khấu (đơn giá × số lượng).

Discount_Amount = Revenue_Before_Discount * Discount → tính số tiền chiết khấu (doanh thu × tỷ lệ giảm giá).

1.2.7 Mã hóa cột chiết khấu

library(dplyr)
data <- data %>%
  mutate(
    Is_High_Discount = Discount > 0.1,
    Discount_Category = case_when(
      Discount == 0 ~ "No Discount",
      Discount <= 0.05 ~ "Low Discount",
      Discount <= 0.1 ~ "Medium Discount",
      TRUE ~ "High Discount"
    ))

🔹 Giải thích:

Is_High_Discount = Discount > 0.1 → tạo cột logic (TRUE/FALSE):

TRUE nếu mức giảm giá > 10%

FALSE nếu ≤ 10%

Hàm case_when() → dùng để phân loại dữ liệu theo nhiều điều kiện khác nhau, ở đây gán nhãn chuỗi chữ cho từng mức giảm giá:

Discount == 0 → “Không giảm giá”

Discount ≤ 0.1 → “Giảm nhẹ”

Discount > 0.1 → “Giảm mạnh”

🔹 Ý nghĩa thống kê:

Đoạn code giúp phân loại mức độ giảm giá của từng giao dịch, từ đó có thể so sánh doanh thu giữa các nhóm giảm giá, và phân tích hành vi khách hàng khi giảm giá cao hoặc thấp.

1.2.8 Phân loại kích thước đơn hàng

library(dplyr)
data <- data %>%
  mutate(
    Order_Size = case_when(
      Total_Price < 100 ~ "Small",
      Total_Price < 500 ~ "Medium",
      Total_Price < 1000 ~ "Large",
      TRUE ~ "Very Large"
    )
  )

🔹 Giải thích:

Hàm mutate() → giúp tạo thêm cột mới trong bảng dữ liệu, ở đây là cột Order_Size.

Hàm case_when() → hoạt động giống câu lệnh if–else, dùng để phân loại giá trị của Total_Price thành 4 nhóm

Hàm head(data, 5) → hiển thị 5 dòng đầu tiên để xem kết quả sau khi thêm cột mới.

🔹 Ý nghĩa thống kê:

Đoạn code giúp phân loại đơn hàng theo quy mô giá trị, từ đó có thể phân tích hành vi mua sắm của khách hàng theo từng nhóm (Small, Medium, Large, Very Large).

1.2.9 Phân tổ theo Loại khách hàng và Khu vực

library(dplyr)

# Phân tích hiệu suất bán hàng theo loại khách hàng và khu vực
customer_region_summary <- data %>%
  group_by(Customer_Type, Region) %>%
  summarise(
    Total_Orders = n_distinct(Order_ID),        # Tổng số đơn hàng
    Total_Revenue = sum(Total_Price),           # Tổng doanh thu
    Avg_Order_Value = mean(Total_Price),        # Giá trị đơn hàng trung bình
    .groups = 'drop'
  )
customer_region_summary$Total_Revenue <-format(customer_region_summary$Total_Revenue, big.mark = ".", decimal.mark = ",", scientific = FALSE)
customer_region_summary$Avg_Order_Value <- format(round(customer_region_summary$Avg_Order_Value, 2), big.mark = ".", decimal.mark = ",", scientific = FALSE)

cat("=== PHÂN TÍCH HIỆU SUẤT THEO LOẠI KHÁCH HÀNG VÀ KHU VỰC ===\n")
## === PHÂN TÍCH HIỆU SUẤT THEO LOẠI KHÁCH HÀNG VÀ KHU VỰC ===
print(customer_region_summary)
## # A tibble: 32 × 5
##    Customer_Type Region               Total_Orders Total_Revenue Avg_Order_Value
##    <fct>         <fct>                       <int> <chr>         <chr>          
##  1 B2B           Baden-Württemberg            7399 6.296.401     281,87         
##  2 B2B           Bayern                       7453 6.426.283     285,68         
##  3 B2B           Berlin                       7725 6.880.328     297,98         
##  4 B2B           Brandenburg                  7403 6.525.847     291,51         
##  5 B2B           Bremen                       7977 5.761.768     240,87         
##  6 B2B           Hamburg                      8705 7.480.221     287,49         
##  7 B2B           Hessen                       8337 7.249.384     288,65         
##  8 B2B           Mecklenburg-Vorpomm…         8225 7.227.687     294,51         
##  9 B2B           Niedersachsen                7248 6.109.817     277,85         
## 10 B2B           Nordrhein-Westfalen          7523 6.060.823     269,89         
## # ℹ 22 more rows

🔹 Giải thích:

Hàm group_by(Customer_Type, Region) → gom nhóm dữ liệu theo loại khách hàng và khu vực.

Hàm summarise() → tính các chỉ số tổng hợp cho từng nhóm:

Hàm cat() và print() → in tiêu đề và kết quả ra màn hình.

🔹 Ý nghĩa thống kê:

Giúp so sánh hiệu suất bán hàng giữa các loại khách hàng và khu vực, qua đó xác định khu vực hoặc nhóm khách hàng mang lại doanh thu cao nhất.

1.2.10 Phân tổ theo Danh mục sản phẩm và Tháng

# Phân tích xu hướng bán hàng theo danh mục và thời gian
category_monthly_summary <- data %>%
  group_by(Category, Month) %>%
  summarise(
    Total_Quantity = sum(Quantity),             # Tổng số lượng bán ra
    Total_Revenue = sum(Total_Price),           # Tổng doanh thu
    Avg_Unit_Price = mean(Unit_Price),          # Giá bán trung bình
    .groups = 'drop'
  )
category_monthly_summary$Total_Quantity <- format(category_monthly_summary$Total_Quantity, big.mark = ".", scientific = FALSE)
category_monthly_summary$Total_Revenue <- format(category_monthly_summary$Total_Revenue, big.mark = ".", scientific = FALSE)
category_monthly_summary$Avg_Unit_Price <- format(round(category_monthly_summary$Avg_Unit_Price, 2), big.mark = ".", decimal.mark = ",", scientific = FALSE)
cat("=== PHÂN TÍCH THEO DANH MỤC SẢN PHẨM VÀ THÁNG (10 DÒNG ĐẦU) ===\n")
## === PHÂN TÍCH THEO DANH MỤC SẢN PHẨM VÀ THÁNG (10 DÒNG ĐẦU) ===
print(head(category_monthly_summary, 10))
## # A tibble: 10 × 5
##    Category            Month   Total_Quantity Total_Revenue Avg_Unit_Price
##    <fct>               <chr>   <chr>          <chr>         <chr>         
##  1 Alcoholic Beverages 2021-01 170.963        2.973.048.1   17,37         
##  2 Alcoholic Beverages 2021-02 156.497        2.683.921.7   17,79         
##  3 Alcoholic Beverages 2021-03 168.305        2.812.859.7   17,71         
##  4 Alcoholic Beverages 2021-04 170.120        2.815.951.8   17,58         
##  5 Alcoholic Beverages 2021-05 167.744        2.865.023.1   17,50         
##  6 Alcoholic Beverages 2021-06 172.310        2.910.453.9   17,45         
##  7 Alcoholic Beverages 2021-07 171.715        2.841.054.7   17,31         
##  8 Alcoholic Beverages 2021-08 170.586        2.948.308.8   17,52         
##  9 Alcoholic Beverages 2021-09 162.690        2.784.813.1   17,34         
## 10 Alcoholic Beverages 2021-10 170.464        2.906.880.4   17,71

🔹 Giải thích:

group_by(Category, Month) → gom nhóm dữ liệu theo danh mục sản phẩm và tháng bán hàng.

summarise() → tính toán các chỉ số cho từng nhóm:

head(…, 10) → hiển thị 10 dòng đầu tiên của kết quả.

🔹 Ý nghĩa thống kê:

Giúp phân tích xu hướng bán hàng theo thời gian và so sánh giữa các danh mục sản phẩm,từ đó nhận biết mùa cao điểm – thấp điểm, và danh mục mang lại doanh thu lớn nhất theo từng tháng.

1.2.11 Phân tổ theo Mức chiết khấu

# Phân tích hiệu quả của các mức chiết khấu khác nhau
discount_analysis <- data %>%
  group_by(Discount_Group = cut(Discount, 
                                breaks = c(-0.1, 0, 0.05, 0.1, 0.15, 1),
                                labels = c("0%", "0-5%", "5-10%", "10-15%", ">15%"))) %>%
  summarise(
    Number_of_Orders = n(),                     # Số lượng đơn hàng
    Total_Revenue = sum(Total_Price),           # Tổng doanh thu
    Avg_Order_Value = mean(Total_Price),        # Giá trị đơn hàng trung bình
    .groups = 'drop'
  )
discount_analysis$Number_of_Orders <- format(discount_analysis$Number_of_Orders, big.mark = ".", scientific = FALSE)
discount_analysis$Total_Revenue    <- format(discount_analysis$Total_Revenue, big.mark = ".", scientific = FALSE)
discount_analysis$Avg_Order_Value  <- format(round(discount_analysis$Avg_Order_Value, 2), big.mark = ".", decimal.mark = ",", scientific = FALSE)
cat("=== PHÂN TÍCH HIỆU QUẢ CHIẾT KHẤU ===\n")
## === PHÂN TÍCH HIỆU QUẢ CHIẾT KHẤU ===
print(discount_analysis)
## # A tibble: 4 × 4
##   Discount_Group Number_of_Orders Total_Revenue Avg_Order_Value
##   <fct>          <chr>            <chr>         <chr>          
## 1 0%             "674.968"        32.189.768    " 47,69"       
## 2 0-5%           "168.122"        28.801.144    "171,31"       
## 3 5-10%          "161.028"        57.373.493    "356,30"       
## 4 10-15%         " 44.457"        18.976.217    "426,84"

🔹 Giải thích:

Hàm cut() → chia biến Discount thành 5 nhóm mức chiết khấu:

group_by(Discount_Group) → gom nhóm dữ liệu theo từng mức chiết khấu.

cat() và print() → hiển thị tiêu đề và kết quả ra màn hình.

🔹 Ý nghĩa thống kê:

Giúp đánh giá tác động của các mức chiết khấu đến doanh thu và giá trị đơn hàng,từ đó xác định mức chiết khấu tối ưu — vừa thu hút khách hàng, vừa đảm bảo lợi nhuận.

1.2.12 Phân tổ theo doanh thu và khu vực

# Tạo bảng phan_to_doanh_thu
phan_to_doanh_thu <- data %>%
  group_by(Region) %>%
  summarise(
    Tong_doanh_thu = sum(Total_Price, na.rm = TRUE),
    Doanh_thu_trung_binh = mean(Total_Price, na.rm = TRUE),
    So_don_hang = n(),
    .groups = 'drop'
  ) %>%
  arrange(desc(Tong_doanh_thu))

# Định dạng dấu phân cách cho các cột số
phan_to_doanh_thu$Tong_doanh_thu        <- format(phan_to_doanh_thu$Tong_doanh_thu, big.mark = ".", scientific = FALSE)
phan_to_doanh_thu$Doanh_thu_trung_binh  <- format(round(phan_to_doanh_thu$Doanh_thu_trung_binh, 2), big.mark = ".", decimal.mark = ",", scientific = FALSE)
phan_to_doanh_thu$So_don_hang           <- format(phan_to_doanh_thu$So_don_hang, big.mark = ".", scientific = FALSE)

print(phan_to_doanh_thu)
## # A tibble: 16 × 4
##    Region                 Tong_doanh_thu Doanh_thu_trung_binh So_don_hang
##    <fct>                  <chr>          <chr>                <chr>      
##  1 Hamburg                9.619.253      136,81               70.310     
##  2 Hessen                 9.181.452      144,65               63.475     
##  3 Mecklenburg-Vorpommern 9.120.188      142,42               64.038     
##  4 Saarland               9.020.347      136,14               66.260     
##  5 Rheinland-Pfalz        9.011.789      132,82               67.849     
##  6 Berlin                 8.879.189      138,71               64.014     
##  7 Thüringen              8.734.228      134,42               64.979     
##  8 Bayern                 8.430.479      130,42               64.643     
##  9 Brandenburg            8.402.955      135,58               61.977     
## 10 Niedersachsen          8.320.694      122,98               67.657     
## 11 Sachsen-Anhalt         8.251.296      128,26               64.333     
## 12 Baden-Württemberg      8.237.277      128,21               64.249     
## 13 Sachsen                8.213.791      123,11               66.721     
## 14 Schleswig-Holstein     8.193.415      124,44               65.841     
## 15 Nordrhein-Westfalen    8.139.463      123,75               65.772     
## 16 Bremen                 7.584.805      114,13               66.457

🔹 Giải thích:

group_by(Region) → gom nhóm dữ liệu theo khu vực bán hàng.

summarise() → tính các chỉ số tóm tắt cho từng khu vực:

Tong_doanh_thu: tổng doanh thu (bỏ qua giá trị thiếu bằng na.rm = TRUE)

Doanh_thu_trung_binh: doanh thu trung bình mỗi đơn hàng

So_don_hang: số lượng đơn hàng trong khu vực

arrange(desc(Tong_doanh_thu)) → sắp xếp kết quả theo doanh thu giảm dần.

print() → in kết quả ra màn hình.

🔹 Ý nghĩa thống kê:

Giúp so sánh mức doanh thu giữa các khu vực,xác định khu vực mạnh – yếu, từ đó hỗ trợ ra quyết định phân bổ nguồn lực và chiến lược bán hàng hiệu quả hơn.

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

1.3.1 Phân tích biến Doanh thu (Total_Price)

1.3.1.1 Thống kê mô tả

library(dplyr)
library(ggplot2)
library(scales)
library(moments)

cat("=== THỐNG KÊ MÔ TẢ BIẾN TOTAL_PRICE ===\n")
## === THỐNG KÊ MÔ TẢ BIẾN TOTAL_PRICE ===
summary(data$Total_Price)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
##     0.30     8.40    21.14   130.98    69.77 12682.78
cat("Trung bình:", mean(data$Total_Price, na.rm = TRUE), "\n")
## Trung bình: 130.9783
cat("Trung vị:", median(data$Total_Price, na.rm = TRUE), "\n")
## Trung vị: 21.14
cat("Phương sai:", var(data$Total_Price, na.rm = TRUE), "\n")
## Phương sai: 261024.3
cat("Độ lệch chuẩn:", sd(data$Total_Price, na.rm = TRUE), "\n")
## Độ lệch chuẩn: 510.9054
cat("Khoảng tứ phân vị:", IQR(data$Total_Price, na.rm = TRUE), "\n")
## Khoảng tứ phân vị: 61.37
cat("Phân vị 10% & 90%:", quantile(data$Total_Price, probs = c(0.1, 0.9), na.rm = TRUE), "\n\n")
## Phân vị 10% & 90%: 3.67 212.28
skew_value <- skewness(data$Total_Price, na.rm = TRUE)
cat("Độ lệch (skewness):", round(skew_value, 3), "\n")
## Độ lệch (skewness): 9.955

🔹 Giải thích:

summary(data$Total_Price) → hiển thị các chỉ tiêu mô tả cơ bản gồm: giá trị nhỏ nhất, trung vị, trung bình, tứ phân vị và lớn nhất.

mean() → tính trung bình doanh thu, phản ánh mức doanh thu điển hình.

median() → tính trung vị, giúp đánh giá xu hướng trung tâm ít bị ảnh hưởng bởi giá trị ngoại lệ.

var() → tính phương sai, đo độ biến động của doanh thu quanh giá trị trung bình.

sd() → tính độ lệch chuẩn, cho biết doanh thu dao động nhiều hay ít.

IQR() → tính khoảng tứ phân vị (Q3 - Q1), thể hiện phạm vi tập trung của 50% dữ liệu giữa.

quantile(…, probs = c(0.1, 0.9)) → lấy phân vị 10% và 90%, xác định biên dưới – biên trên của phần lớn doanh thu.

🔹 Ý nghĩa thống kê:

Giúp mô tả đặc điểm phân phối của doanh thu:

Đánh giá mức độ tập trung và biến động của doanh thu giữa các đơn hàng.

So sánh giữa trung bình và trung vị để nhận biết dữ liệu có bị lệch (skewed) không.

Độ lệch chuẩn và IQR cho biết độ ổn định của doanh thu.

Phân vị 10% và 90% cho phép xác định khoảng giá trị doanh thu phổ biến, loại bỏ ảnh hưởng của ngoại lệ.

1.3.1.2 Phân loại doanh thu theo loại khách hàng

customer_summary <- data %>%
  group_by(Customer_Type) %>%
  summarise(
    Mean_Revenue = mean(Total_Price, na.rm = TRUE),
    Total_Revenue = sum(Total_Price, na.rm = TRUE),
    So_Don_Hang = n(),
    .groups = 'drop'
  ) %>%
  arrange(desc(Mean_Revenue)) %>%
  mutate(
    Mean_Revenue = comma(Mean_Revenue, accuracy = 1),
    Total_Revenue = comma(Total_Revenue, accuracy = 1),
    So_Don_Hang = comma(So_Don_Hang)
  )
customer_summary %>%
  kable(col.names = c("Loại khách hàng", "Doanh thu TB", "Tổng doanh thu", "Số đơn hàng"),
        align = "c")
Loại khách hàng Doanh thu TB Tổng doanh thu Số đơn hàng
B2B 281 105,150,854 373,607
B2C 48 32,189,768 674,968

🔹 Giải thích

group_by(Customer_Type) → gom nhóm dữ liệu theo từng loại khách hàng

summarise() → tính các chỉ tiêu thống kê cơ bản cho từng nhóm:

arrange(desc(Mean_Revenue)) → sắp xếp kết quả theo doanh thu trung bình giảm dần để dễ so sánh nhóm có doanh thu cao nhất.

print() → in bảng kết quả ra màn hình.

🔹 Ý nghĩa thống kê

Giúp so sánh hiệu quả kinh doanh giữa các loại khách hàng, xác định:

Nhóm khách hàng nào mang lại doanh thu cao nhất.

Nhóm nào có nhiều đơn hàng nhưng giá trị thấp.

Từ đó doanh nghiệp có thể đưa ra chiến lược chăm sóc khách hàng và định hướng marketing phù hợp hơn.

1.3.1.3 Xu hướng doanh thu theo thời gian

data <- data %>%
  mutate(Year = format(as.Date(Order_Date), "%Y"))
# Tổng hợp doanh thu theo năm
yearly_revenue <- data %>%
  group_by(Year) %>%
  summarise(Total_Revenue = sum(Total_Price, na.rm = TRUE))

# Vẽ biểu đồ xu hướng doanh thu theo năm
ggplot(yearly_revenue, aes(x = as.factor(Year), y = Total_Revenue, fill = Year)) +
  geom_col(width = 0.6) +
  geom_text(aes(label = scales::comma(Total_Revenue)),
            vjust = -0.5, size = 3.5) +
  scale_y_continuous(labels = scales::comma) +
  labs(
    title = "Doanh thu từng năm",
    x = "Năm",
    y = "Tổng doanh thu"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 0, hjust = 0.5),
    plot.title = element_text(face = "bold", size = 14)
  )

🔹 Giải thích:

group_by(Customer_Type) → gom nhóm dữ liệu theo loại khách hàng

summarise() → tính các chỉ số tóm tắt cho từng nhóm khách hàng:

arrange(desc(Mean_Revenue)) → sắp xếp kết quả giảm dần theo doanh thu trung bình để xem nhóm nào mang lại giá trị cao nhất.

🔹 Ý nghĩa thống kê:

Phân tích này giúp so sánh hiệu suất giữa các loại khách hàng, xem nhóm nào mang lại doanh thu trung bình cao nhất hoặc tổng doanh thu lớn nhất.→ Hỗ trợ doanh nghiệp trong việc xác định nhóm khách hàng tiềm năng, ưu tiên chăm sóc hoặc chiến lược khuyến mãi phù hợp, từ đó tối ưu hóa doanh thu và lợi nhuận.

1.3.1.4 Phân tích tương quan với giảm giá

if ("Discount" %in% names(data)) {
  cat("\n=== TƯƠNG QUAN GIỮA DOANH THU VÀ GIẢM GIÁ ===\n")
  corr <- cor(data$Total_Price, data$Discount, use = "complete.obs")
  cat("Hệ số tương quan:", round(corr, 3), "\n")
}
## 
## === TƯƠNG QUAN GIỮA DOANH THU VÀ GIẢM GIÁ ===
## Hệ số tương quan: 0.248

🔹 Giải thích:

if (“Discount” %in% names(data)) → kiểm tra xem biến “Discount” có tồn tại trong bộ dữ liệu hay không.

cor(data\(Total_Price, data\)Discount, use = “complete.obs”) → tính hệ số tương quan (correlation) giữa doanh thu và tỷ lệ chiết khấu, bỏ qua giá trị bị thiếu.

geom_point() → vẽ biểu đồ tán xạ (scatter plot), mỗi điểm thể hiện một đơn hàng.

geom_smooth(method = “lm”) → thêm đường hồi quy tuyến tính, cho thấy xu hướng mối quan hệ giữa chiết khấu và doanh thu.

labs() → đặt tiêu đề và nhãn trục cho biểu đồ.

theme_minimal() → hiển thị biểu đồ rõ ràng, đơn giản.

🔹 Ý nghĩa thống kê:

Hệ số tương quan (corr) cho biết mức độ và chiều hướng quan hệ giữa chiết khấu và doanh thu:

Nếu corr > 0 → doanh thu tăng khi chiết khấu tăng (chiết khấu giúp kích cầu).

Nếu corr < 0 → doanh thu giảm khi chiết khấu tăng (mức giảm giá quá cao làm giảm lợi nhuận).

Nếu corr ≈ 0 → không có mối quan hệ rõ ràng giữa hai biến.

1.3.1.5 Phân tổ doanh thu

data <- data %>%
  mutate(
    Revenue_Group = cut(
      Total_Price,
      breaks = c(0, 100, 500, 1000, Inf),
      labels = c("Thấp", "Trung bình", "Cao", "Rất cao")
    )
  )

# Tóm tắt theo nhóm
revenue_group_summary <- data %>%
  group_by(Revenue_Group) %>%
  summarise(
    So_Don_Hang = n(),
    Doanh_Thu_Trung_Binh = mean(Total_Price, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(
    So_Don_Hang = comma(So_Don_Hang),
    Doanh_Thu_Trung_Binh = comma(Doanh_Thu_Trung_Binh, accuracy = 1)
  )
cat("\n=== PHÂN LOẠI DOANH THU THEO NHÓM ===\n")
## 
## === PHÂN LOẠI DOANH THU THEO NHÓM ===
revenue_group_summary %>%
  kable(
    col.names = c("Nhóm doanh thu", "Số đơn hàng", "Doanh thu trung bình (VNĐ)"),
    align = "c"
  )
Nhóm doanh thu Số đơn hàng Doanh thu trung bình (VNĐ)
Thấp 842,596 23
Trung bình 155,134 202
Cao 24,442 699
Rất cao 26,403 2,626

🔹 Giải thích:

mutate() → thêm một biến mới vào bộ dữ liệu tên là Revenue_Group, thể hiện mức doanh thu của từng đơn hàng

cut() → phân loại dữ liệu liên tục (Total_Price) thành các nhóm rời rạc theo khoảng giá trị:

breaks = c(0, 100, 500, 1000, Inf) → chia thành 4 khoảng doanh thu

labels = c(“Thấp”, “Trung bình”, “Cao”, “Rất cao”) → đặt tên cho các nhóm tương ứng.

group_by(Revenue_Group) → gom nhóm dữ liệu theo từng mức doanh thu.

summarise() → tính toán thống kê tóm tắt cho từng nhóm:

🔹 Ý nghĩa thống kê:

Giúp phân khúc khách hàng hoặc đơn hàng theo giá trị doanh thu, dễ dàng nhận diện nhóm khách hàng giá trị cao (VIP) hoặc nhóm mua thấp.

Hỗ trợ doanh nghiệp xây dựng chiến lược marketing hoặc khuyến mãi riêng cho từng nhóm:

Nhóm thấp/trung bình → tập trung tăng tần suất mua hàng.

Nhóm cao/rất cao → duy trì, chăm sóc đặc biệt để giữ chân.

1.3.2 Phân tích biến Loại khách hàng (Customer_Type)

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

cat("=== THỐNG KÊ CƠ BẢN THEO LOẠI KHÁCH HÀNG ===\n")
## === THỐNG KÊ CƠ BẢN THEO LOẠI KHÁCH HÀNG ===
customer_stats <- data %>%
  group_by(Customer_Type) %>%
  summarise(
    So_Don_Hang = n(),
    Tong_Doanh_Thu = sum(Total_Price, na.rm = TRUE),
    Doanh_Thu_Trung_Binh = mean(Total_Price, na.rm = TRUE),
    .groups = 'drop'
  ) %>%
  mutate(Ty_Le_Don_Hang = round(So_Don_Hang / sum(So_Don_Hang) * 100, 2)) %>%
  arrange(desc(Tong_Doanh_Thu))

print(customer_stats)
## # A tibble: 2 × 5
##   Customer_Type So_Don_Hang Tong_Doanh_Thu Doanh_Thu_Trung_Binh Ty_Le_Don_Hang
##   <fct>               <int>          <dbl>                <dbl>          <dbl>
## 1 B2B                373607     105150854.                281.            35.6
## 2 B2C                674968      32189768.                 47.7           64.4

🔹 Giải thích:

group_by(Customer_Type) → gom dữ liệu theo từng loại khách hàng.

summarise() → tính các chỉ số mô tả:

mutate() + Ty_Le_Don_Hang → tính tỷ lệ phần trăm số đơn hàng theo loại khách.

arrange(desc(…)) → sắp xếp giảm dần theo doanh thu.

🔹 Ý nghĩa thống kê:

Giúp doanh nghiệp xác định:

Loại khách hàng nào đóng góp doanh thu lớn nhất.

Nhóm khách hàng nào chiếm tỷ trọng nhiều nhất trong tổng số đơn.

Từ đó, có thể ưu tiên chăm sóc hoặc khuyến mãi cho nhóm sinh lợi cao.

1.3.2.2 Biểu đồ trực quan dạng cột

ggplot(customer_stats, aes(x = reorder(Customer_Type, -So_Don_Hang), y = So_Don_Hang, fill = Customer_Type)) +
  geom_col(show.legend = FALSE) +
  geom_text(aes(label = format(So_Don_Hang, big.mark = ".", scientific = FALSE)), 
            vjust = -0.2, size = 5) +
  labs(title = "Số lượng đơn hàng theo loại khách hàng",
       x = "Loại khách hàng", y = "Số đơn hàng") +
  theme_minimal()

🔹 Giải thích:

ggplot() → tạo biểu đồ cột, trục x là loại khách hàng, trục y là số lượng đơn hàng, sắp xếp giảm dần theo số đơn hàng, màu cột theo loại khách hàng.

geom_col(show.legend = FALSE) → vẽ cột, ẩn chú giải màu.

labs(title = “Số lượng đơn hàng theo loại khách hàng”, x = “Loại khách hàng”, y = “Số đơn hàng”) → đặt tiêu đề và nhãn trục.

🔹 Ý nghĩa thống kê:

Biểu đồ thể hiện số lượng đơn hàng của từng loại khách hàng, giúp dễ dàng so sánh mức độ mua hàng giữa các nhóm.

Có thể nhanh chóng nhận ra nhóm khách hàng đóng góp nhiều đơn hàng nhất hoặc ít nhất, từ đó hỗ trợ ra quyết định marketing, khuyến mãi hay quản lý khách hàng.

1.3.2.3 Biểu đồ trực quan dạng tròn

customer_stats <- customer_stats %>%
  mutate(
    label = paste0(round(Ty_Le_Don_Hang, 1), "%")
  )

ggplot(customer_stats, aes(x = "", y = Ty_Le_Don_Hang, fill = Customer_Type)) +
  geom_col(width = 1, color = "white") +
  coord_polar(theta = "y") +
  geom_text(
    aes(label = label),
    position = position_stack(vjust = 0.5),
    color = "white",
    size = 5,
    fontface = "bold"
  ) +
  labs(title = "Tỷ lệ loại khách hàng (%)") +
  theme_void() +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5, size = 14),
    legend.title = element_text(face = "bold")
  )

🔹 Giải thích code:

ggplot() → tạo biểu đồ, trục y là tỷ lệ đơn hàng của từng loại khách hàng, fill màu theo loại khách hàng, trục x để trống (““) vì vẽ tròn.

geom_col(width = 1) → vẽ cột tròn, chiều rộng cột = 1 để đủ làm tròn.

coord_polar(theta = “y”) → chuyển từ biểu đồ cột sang biểu đồ tròn (pie chart) theo trục y.

labs(title = “Tỷ lệ loại khách hàng (%)”) → đặt tiêu đề biểu đồ.

🔹 Ý nghĩa thống kê:

Biểu đồ thể hiện tỷ trọng phần trăm đơn hàng của từng loại khách hàng trong tổng số.Giúp nhanh chóng nhận ra nhóm khách hàng nào chiếm tỷ lệ cao nhất hoặc thấp nhất, thuận tiện cho việc phân tích chiến lược bán hàng, chăm sóc khách hàng và phân bổ nguồn lực.

1.3.2.4 So sánh hiệu suất giữa các loại khách hàng

customer_summary <- data %>%
  group_by(Customer_Type) %>%
  summarise(
    Count = n(),                                # Số lượng giao dịch
    Percentage = n()/nrow(data)*100,           # Tỷ lệ phần trăm
    Total_Revenue = sum(Total_Price),           # Tổng doanh thu
    Avg_Transaction_Value = mean(Total_Price)   # Giá trị giao dịch trung bình
  )

cat("=== PHÂN TÍCH THEO LOẠI KHÁCH HÀNG ===\n")
## === PHÂN TÍCH THEO LOẠI KHÁCH HÀNG ===
print(customer_summary)
## # A tibble: 2 × 5
##   Customer_Type  Count Percentage Total_Revenue Avg_Transaction_Value
##   <fct>          <int>      <dbl>         <dbl>                 <dbl>
## 1 B2B           373607       35.6    105150854.                 281. 
## 2 B2C           674968       64.4     32189768.                  47.7

1.3.2.5 So sánh doanh thu 2 loại khách hàng

ggplot(customer_summary, aes(x = Customer_Type, y = Total_Revenue, fill = Customer_Type)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = format(Total_Revenue, big.mark = ".", scientific = FALSE)),
            vjust = -0.5, size = 5, color = "black") +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.12))) +
  labs(title = "SO SÁNH DOANH THU THEO LOẠI KHÁCH HÀNG",
       subtitle = "B2B vs B2C",
       x = "Loại Khách Hàng", 
       y = "Tổng Doanh Thu") +
  theme_minimal() +
  theme(legend.position = "none")

🔹 Giải thích code:

group_by(Customer_Type) → gom các dòng dữ liệu theo từng loại khách hàng (B2B, B2C, …).

summarise(…) → tạo bảng tổng hợp với các chỉ số

aes() → trục X là loại khách hàng, trục Y là doanh thu, mỗi cột được tô màu theo loại khách hàng.

geom_bar(stat = “identity”) → vẽ cột với chiều cao chính xác bằng Total_Revenue.

scale_y_continuous(labels = comma) → hiển thị số trên trục Y với dấu phẩy ngăn cách hàng nghìn.

labs(…) → thêm tiêu đề, tiêu đề phụ, tên trục.

🔹 Ý nghĩa thống kê:

Mặc dù số lượng giao dịch của khách hàng B2C (64.4%) nhiều hơn gần gấp đôi so với B2B (35.6%), nhưng tổng doanh thu từ B2B lại cao hơn gấp 3 lần. Điều này khẳng định khách hàng doanh nghiệp có giá trị chiến lược quan trọng hơn về mặt doanh thu.

1.3.3 Phân tích biến Khu vực (Region)

region_summary <- data %>%
  group_by(Region) %>%
  summarise(
    Total_Orders = n_distinct(Order_ID),        # Tổng số đơn hàng
    Total_Revenue = sum(Total_Price, na.rm = TRUE),   # Tổng doanh thu
    Avg_Order_Value = mean(Total_Price, na.rm = TRUE),# Giá trị đơn hàng TB
    .groups = 'drop'
  ) %>%
  arrange(desc(Total_Revenue)) %>%
  mutate(
    Total_Orders = comma(Total_Orders),
    Total_Revenue = comma(Total_Revenue, accuracy = 1),
    Avg_Order_Value = comma(Avg_Order_Value, accuracy = 1)
  )

cat("=== PHÂN TÍCH HIỆU SUẤT THEO KHU VỰC ===\n")
## === PHÂN TÍCH HIỆU SUẤT THEO KHU VỰC ===
region_summary %>%
  kable(
    col.names = c("Khu vực", "Tổng đơn hàng", "Tổng doanh thu (VNĐ)", "Giá trị TB/đơn (VNĐ)"),
    align = "c"
  )
Khu vực Tổng đơn hàng Tổng doanh thu (VNĐ) Giá trị TB/đơn (VNĐ)
Hamburg 23,426 9,619,253 137
Hessen 21,071 9,181,452 145
Mecklenburg-Vorpommern 21,414 9,120,188 142
Saarland 22,011 9,020,347 136
Rheinland-Pfalz 22,668 9,011,789 133
Berlin 21,284 8,879,189 139
Thüringen 21,830 8,734,228 134
Bayern 21,476 8,430,479 130
Brandenburg 20,570 8,402,955 136
Niedersachsen 22,428 8,320,694 123
Sachsen-Anhalt 21,416 8,251,296 128
Baden-Württemberg 21,317 8,237,277 128
Sachsen 22,213 8,213,791 123
Schleswig-Holstein 21,976 8,193,415 124
Nordrhein-Westfalen 21,978 8,139,463 124
Bremen 22,115 7,584,805 114

Bằng cách nhóm và sắp xếp dữ liệu theo khu vực, biểu đồ cột cho thấy Hamburg và Hessen là hai khu vực mang lại doanh thu cao nhất. Ngược lại, Bremen là khu vực có doanh thu thấp nhất. Thông tin này giúp doanh nghiệp xác định các thị trường trọng điểm để tập trung nguồn lực marketing và bán hàng.

###Phân tích tương quan

cat("=== TƯƠNG QUAN GIỮA TOTAL_PRICE VÀ UNIT_PRICE ===\n")
## === TƯƠNG QUAN GIỮA TOTAL_PRICE VÀ UNIT_PRICE ===
correlation1 <- cor(data$Total_Price, data$Unit_Price)
print(correlation1)
## [1] 0.6194355
cat("=== TƯƠNG QUAN GIỮA TOTAL_PRICE VÀ QUANTITY ===\n")
## === TƯƠNG QUAN GIỮA TOTAL_PRICE VÀ QUANTITY ===
correlation2 <- cor(data$Total_Price, data$Quantity)
print(correlation2)
## [1] 0.3128655

🔹 Giải thích

Hàm cor(x, y) trong R tính hệ số tương quan Pearson (Pearson correlation coefficient) giữa hai biến số.Giá trị kết quả nằm trong khoảng từ -1 đến +1:

+1 → tương quan tuyến tính hoàn toàn dương (biến này tăng thì biến kia tăng).

0 → không có mối tương quan tuyến tính rõ rệt.

-1 → tương quan tuyến tính hoàn toàn âm (biến này tăng thì biến kia giảm).

🔹 Ý nghĩa thống kê

Tương quan giữa Total_Price và Unit_Price

Giá trị 0.6194 > 0.6, cho thấy mối tương quan dương ở mức trung bình – khá mạnh giữa giá bán đơn vị và tổng giá trị đơn hàng.Khi đơn giá sản phẩm tăng, doanh thu đơn hàng cũng có xu hướng tăng theo. Tuy nhiên, mối quan hệ không hoàn toàn tuyến tính vì doanh thu còn phụ thuộc vào số lượng (Quantity) và mức chiết khấu (Discount).

Tương quan giữa Total_Price và Quantity

Giá trị 0.3129 thể hiện mối tương quan dương yếu – trung bình giữa số lượng bán và doanh thu.Khi số lượng mua tăng, tổng doanh thu có xu hướng tăng, nhưng mức độ không mạnh.

###Phân tích theo thời gian

cat("=== PHÂN TÍCH THEO QUÝ ===\n")
## === PHÂN TÍCH THEO QUÝ ===
quarter_freq <- table(data$Quarter)
quarter_percentage <- prop.table(quarter_freq) * 100
quarter_freq_fmt <- format(quarter_freq, big.mark = ",", scientific = FALSE)
quarter_percentage_fmt <- format(round(quarter_percentage, 2), big.mark = ".", decimal.mark = ",", scientific = FALSE)

print(quarter_freq_fmt)
## 
##        Q1        Q2        Q3        Q4 
## "258,889" "264,162" "263,115" "262,409"
print(quarter_percentage_fmt)
## 
##      Q1      Q2      Q3      Q4 
## "24,69" "25,19" "25,09" "25,03"
cat("=== PHÂN TÍCH THEO MÙA ===\n")
## === PHÂN TÍCH THEO MÙA ===
season_analysis <- data %>%
  group_by(Season) %>%
  summarise(
    Total_Orders = n_distinct(Order_ID),
    Total_Revenue = sum(Total_Price)
  )
season_analysis$Total_Orders  <- format(season_analysis$Total_Orders, big.mark = ".", scientific = FALSE)
season_analysis$Total_Revenue <- format(season_analysis$Total_Revenue, big.mark = ".", scientific = FALSE)
print(season_analysis)
## # A tibble: 4 × 3
##   Season Total_Orders Total_Revenue
##   <chr>  <chr>        <chr>        
## 1 Autumn 87.841       34.872.401   
## 2 Spring 86.292       33.642.674   
## 3 Summer 87.641       34.211.047   
## 4 Winter 87.419       34.614.499
cat("=== PHÂN TÍCH THEO NGÀY TRONG TUẦN ===\n")
## === PHÂN TÍCH THEO NGÀY TRONG TUẦN ===
weekday_analysis <- data %>%
  group_by(Day_of_Week) %>%
  summarise(
    Total_Orders = n_distinct(Order_ID),
    Total_Revenue = sum(Total_Price)
  ) %>%
  arrange(desc(Total_Revenue))

# Định dạng các số với dấu phân cách hàng nghìn
weekday_analysis$Total_Orders  <- format(weekday_analysis$Total_Orders, big.mark = ".", scientific = FALSE)
weekday_analysis$Total_Revenue <- format(weekday_analysis$Total_Revenue, big.mark = ".", scientific = FALSE)
print(weekday_analysis)
## # A tibble: 7 × 3
##   Day_of_Week Total_Orders Total_Revenue
##   <chr>       <chr>        <chr>        
## 1 Saturday    50.202       19.767.776   
## 2 Monday      50.039       19.764.753   
## 3 Thursday    49.602       19.700.979   
## 4 Sunday      50.152       19.667.161   
## 5 Tuesday     49.715       19.572.899   
## 6 Wednesday   49.898       19.459.571   
## 7 Friday      49.585       19.407.483

🔹 Giải thích

Tỷ lệ đơn hàng theo quý (Quarter)

Sử dụng table() để đếm số đơn hàng theo từng quý (Q1, Q2, Q3, Q4).

Dùng prop.table() tính tỷ lệ phần trăm đơn hàng mỗi quý trong tổng thể. Giúp nhận diện thời điểm hoạt động bán hàng cao nhất/nhiều đơn nhất.

Phân tích theo mùa (Season)

Dùng group_by(Season) để nhóm dữ liệu theo mùa: Winter, Spring, Summer, Autumn.

n_distinct(Order_ID) đếm số đơn hàng duy nhất trong mỗi mùa.

sum(Total_Price) tính tổng doanh thu mỗi mùa.

Giúp nhận biết mùa nào bán chạy nhất và đóng góp nhiều doanh thu nhất.

Phân tích theo ngày trong tuần (Day_of_Week)

Nhóm theo biến Day_of_Week (ví dụ: Monday, Tuesday, …).

Tính tổng số đơn hàng và doanh thu tương tự.

Dùng arrange(desc(Total_Revenue)) để sắp xếp thứ tự từ ngày doanh thu cao nhất đến thấp nhất.

🔹 Ý nghĩa thống kê

Tỷ lệ đơn hàng theo quý (Quarter)

Số lượng đơn hàng giữa các quý gần như cân bằng nhau, dao động quanh 25%. Quý 2 (tháng 4–6) có lượng đơn hàng cao nhất (25.19%), cho thấy hoạt động bán hàng có thể tăng nhẹ vào giữa năm. Giúp doanh nghiệp biết ngày nào trong tuần có doanh thu cao nhất → hỗ trợ lên kế hoạch marketing hoặc khuyến mãi.

Phân tích theo mùa (Season)

Doanh thu cao nhất vào mùa Hè (Summer) → khả năng khách hàng chi tiêu nhiều hơn trong giai đoạn này (có thể do nhu cầu du lịch, giải trí hoặc khuyến mãi giữa năm). Các mùa còn lại có doanh thu khá tương đồng (~34.1 triệu) → không có mùa thấp điểm rõ rệt.

Phân tích theo ngày trong tuần (Day_of_Week)

Thứ Bảy và Thứ Hai là hai ngày có doanh thu cao nhất, đều khoảng 19.76 triệu. Thứ Sáu có doanh thu thấp nhất, nhưng chênh lệch không lớn (~1.8%). Xu hướng này cho thấy doanh nghiệp hoạt động ổn định cả tuần, tuy nhiên có thể tập trung quảng cáo hoặc khuyến mãi vào cuối tuần để tối ưu doanh thu

1.3.4 Phân tích biến giảm giá

1.3.4.1 Tổng quan về giảm giá

cat("Tỷ lệ đơn hàng có giảm giá:", round(mean(data$Discount > 0) * 100, 2), "%\n")
## Tỷ lệ đơn hàng có giảm giá: 35.63 %
cat("Số đơn có giảm giá:", sum(data$Discount > 0), "/", nrow(data), "\n")
## Số đơn có giảm giá: 373607 / 1048575
cat("Phạm vi giảm giá:", min(data$Discount), "-", max(data$Discount), "\n")
## Phạm vi giảm giá: 0 - 0.15
cat("Trung bình giảm giá:", round(mean(data$Discount), 4), "\n")
## Trung bình giảm giá: 0.0297
cat("Median giảm giá:", median(data$Discount), "\n")
## Median giảm giá: 0
cat("Độ lệch chuẩn giảm giá:", round(sd(data$Discount), 4), "\n")
## Độ lệch chuẩn giảm giá: 0.0448

Nhận xét

  • Tỷ lệ đơn hàng có giảm giá:Có 35.63% đơn hàng được áp dụng giảm giá, tương đương 373,607 trên tổng số 1,048,575 đơn hàng.→ Điều này cho thấy chính sách khuyến mãi được áp dụng khá thường xuyên, chiếm hơn 1/3 tổng số đơn hàng.

  • Phạm vi giảm giá:Mức giảm giá dao động từ 0 đến 0.15 → Hầu hết mức giảm nằm trong khoảng thấp, cho thấy doanh nghiệp kiểm soát mức chiết khấu ở mức vừa phải

  • Độ lệch chuẩn = 0.0448, cho thấy mức độ phân tán vừa phải.→ Có sự khác biệt nhất định giữa các đơn hàng về mức chiết khấu, nhưng nhìn chung các giá trị vẫn tập trung quanh mức thấp (0–5%).

1.3.4.2 Giảm giá theo từng loại khách hàng

cat("\ GIẢM GIÁ THEO LOẠI KHÁCH HÀNG\n")
##  GIẢM GIÁ THEO LOẠI KHÁCH HÀNG
discount_by_customer_type <- data %>%
  group_by(Customer_Type) %>%
  summarise(
    Count = n(),
    Discount_Rate = mean(Discount > 0) * 100,
    Avg_Discount = mean(Discount),
    Avg_Discount_When_Applied = mean(Discount[Discount > 0]),
    Total_Discount_Value = sum(Unit_Price * Quantity * Discount)
  )
# Định dạng các số để dễ đọc hơn
discount_by_customer_type$Count <- format(discount_by_customer_type$Count, big.mark = ",", scientific = FALSE)
discount_by_customer_type$Discount_Rate <- format(round(discount_by_customer_type$Discount_Rate, 2), big.mark = ",", decimal.mark = ".", scientific = FALSE)
discount_by_customer_type$Avg_Discount <- format(round(discount_by_customer_type$Avg_Discount, 4), big.mark = ",", decimal.mark = ".", scientific = FALSE)
discount_by_customer_type$Avg_Discount_When_Applied <- format(round(discount_by_customer_type$Avg_Discount_When_Applied, 4), big.mark = ",", decimal.mark = ".", scientific = FALSE)
discount_by_customer_type$Total_Discount_Value <- format(discount_by_customer_type$Total_Discount_Value, big.mark = ",", scientific = FALSE)
print(discount_by_customer_type)
## # A tibble: 2 × 6
##   Customer_Type Count   Discount_Rate Avg_Discount Avg_Discount_When_Applied
##   <fct>         <chr>   <chr>         <chr>        <chr>                    
## 1 B2B           373,607 "100"         0.0834       "0.0834"                 
## 2 B2C           674,968 "  0"         0.0000       "   NaN"                 
## # ℹ 1 more variable: Total_Discount_Value <chr>

Giải thích group_by(Customer_Type) → Chia dữ liệu thành từng nhóm khách hàng (ví dụ: B2B và B2C).

Count = n()→ Đếm tổng số dòng (đơn hàng) trong mỗi nhóm khách hàng.

mean() → Tính giá trị trung bình.

sum() → Tính tổng các giá trị trong nhóm.

format() → Dùng để định dạng hiển thị cho đẹp, dễ đọc.

round() → Làm tròn số đến số chữ số thập phân mong muốn.

1.3.4.3 Giảm giá theo doanh mục sản phẩm

cat("\ GIẢM GIÁ THEO DANH MỤC SẢN PHẨM\n")
##  GIẢM GIÁ THEO DANH MỤC SẢN PHẨM
discount_by_category <- data %>%
  group_by(Category) %>%
  summarise(
    Total_Items = n(),
    Discount_Rate = mean(Discount > 0) * 100,
    Avg_Discount = mean(Discount),
    Max_Discount = max(Discount),
    Total_Discount_Amount = sum(Total_Price * Discount / (1 - Discount))
  ) %>%
  arrange(desc(Avg_Discount))

# Định dạng các cột số 
discount_by_category$Total_Items           <- format(discount_by_category$Total_Items, big.mark = ".", scientific = FALSE)
discount_by_category$Discount_Rate         <- format(round(discount_by_category$Discount_Rate, 2), big.mark = ".", decimal.mark = ",", scientific = FALSE)
discount_by_category$Avg_Discount          <- format(round(discount_by_category$Avg_Discount, 4), big.mark = ".", decimal.mark = ",", scientific = FALSE)
discount_by_category$Max_Discount          <- format(round(discount_by_category$Max_Discount, 4), big.mark = ".", decimal.mark = ",", scientific = FALSE)
discount_by_category$Total_Discount_Amount <- format(round(discount_by_category$Total_Discount_Amount), big.mark = ".", decimal.mark = ",", scientific = FALSE)
print(discount_by_category)
## # A tibble: 4 × 6
##   Category            Total_Items Discount_Rate Avg_Discount Max_Discount
##   <fct>               <chr>       <chr>         <chr>        <chr>       
## 1 Alcoholic Beverages 262.451     35,66         0,0298       0,15        
## 2 Water               261.612     35,67         0,0297       0,15        
## 3 Soft Drinks         262.592     35,63         0,0297       0,15        
## 4 Juices              261.920     35,56         0,0297       0,15        
## # ℹ 1 more variable: Total_Discount_Amount <chr>

Giải thích code

group_by(Category)→ Nhóm dữ liệu theo danh mục sản phẩm (Category) — để tính toán riêng từng nhóm.

summarise() → Tạo bảng tóm tắt với các chỉ số

arrange(desc(Avg_Discount))→ Sắp xếp kết quả theo mức giảm giá trung bình giảm dần

1.3.4.4 Giảm giá theo khu vực

cat("\ GIẢM GIÁ THEO KHU VỰC\n")
##  GIẢM GIÁ THEO KHU VỰC
discount_by_region <- data %>%
  group_by(Region) %>%
  summarise(
    Orders = n(),
    Discount_Rate = mean(Discount > 0) * 100,
    Avg_Discount = mean(Discount),
    Total_Discount_Value = sum(Unit_Price * Quantity * Discount)
  ) %>%
  arrange(desc(Avg_Discount)) 

# Định dạng dấu phân cách số theo chuẩn Việt Nam
discount_by_region$Orders               <- format(discount_by_region$Orders, big.mark = ".", scientific = FALSE)
discount_by_region$Discount_Rate        <- format(round(discount_by_region$Discount_Rate, 2), big.mark = ".", decimal.mark = ",", scientific = FALSE)
discount_by_region$Avg_Discount         <- format(round(discount_by_region$Avg_Discount, 4), big.mark = ".", decimal.mark = ",", scientific = FALSE)
discount_by_region$Total_Discount_Value <- format(round(discount_by_region$Total_Discount_Value), big.mark = ".", decimal.mark = ",", scientific = FALSE)

print(discount_by_region)
## # A tibble: 16 × 5
##    Region                 Orders Discount_Rate Avg_Discount Total_Discount_Value
##    <fct>                  <chr>  <chr>         <chr>        <chr>               
##  1 Hessen                 63.475 39,57         0,0331       769.901             
##  2 Mecklenburg-Vorpommern 64.038 38,32         0,0320       775.522             
##  3 Saarland               66.260 37,77         0,0316       757.674             
##  4 Hamburg                70.310 37,01         0,0308       804.160             
##  5 Rheinland-Pfalz        67.849 36,33         0,0303       746.976             
##  6 Brandenburg            61.977 36,12         0,0303       693.923             
##  7 Berlin                 64.014 36,07         0,0301       737.951             
##  8 Bremen                 66.457 35,99         0,0301       612.317             
##  9 Thüringen              64.979 35,75         0,0298       712.336             
## 10 Sachsen-Anhalt         64.333 35,49         0,0296       674.104             
## 11 Bayern                 64.643 34,80         0,0291       699.183             
## 12 Baden-Württemberg      64.249 34,77         0,0289       668.347             
## 13 Nordrhein-Westfalen    65.772 34,14         0,0285       640.649             
## 14 Sachsen                66.721 32,84         0,0274       639.960             
## 15 Schleswig-Holstein     65.841 32,81         0,0274       654.470             
## 16 Niedersachsen          67.657 32,50         0,0271       651.956

Giải thích

group_by(Region)→ Nhóm dữ liệu theo khu vực bán hàng (Region)

summarise() → Tạo bảng tóm tắt gồm các chỉ số cho từng khu vực

arrange(desc(Avg_Discount))→ Sắp xếp các khu vực theo mức giảm giá trung bình giảm dần

format() → Dùng để hiển thị số đẹp

round() → Làm tròn số cho gọn

1.3.4.5 *Mối quan hệ giữa giảm giá và số lượng

quantity_discount_analysis <- data %>%
  mutate(Quantity_Group = cut(Quantity, 
                            breaks = c(0, 10, 50, 100, Inf),
                            labels = c("1-10", "11-50", "51-100", "100+"))) %>%
  group_by(Quantity_Group) %>%
  summarise(
    Orders = n(),
    Avg_Discount = mean(Discount),
    Discount_Rate = mean(Discount > 0) * 100
  )

# Định dạng kết quả với dấu phân cách số
quantity_discount_analysis$Orders        <- format(quantity_discount_analysis$Orders, big.mark = ".", scientific = FALSE)
quantity_discount_analysis$Avg_Discount  <- format(round(quantity_discount_analysis$Avg_Discount, 4), big.mark = ".", decimal.mark = ",", scientific = FALSE)
quantity_discount_analysis$Discount_Rate <- format(round(quantity_discount_analysis$Discount_Rate, 2), big.mark = ".", decimal.mark = ",", scientific = FALSE)

print(quantity_discount_analysis)
## # A tibble: 3 × 4
##   Quantity_Group Orders  Avg_Discount Discount_Rate
##   <fct>          <chr>   <chr>        <chr>        
## 1 1-10           486.919 0,0048       "  7,70"     
## 2 11-50          374.681 0,0277       " 39,81"     
## 3 51-100         186.975 0,0986       "100,00"

Giải thích

cut() chia biến Quantity (số lượng mua) thành các nhóm

group_by(Quantity_Group) → Gom nhóm dữ liệu theo cột Quantity_Group

summarise() → Tạo bảng tóm tắt gồm các chỉ số theo từng nhóm số lượng

format() + round() → Dùng để hiển thị kết quả dễ đọc

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

library(ggplot2)
library(dplyr)
library(tidyr)
library(lubridate)
library(scales)
library(gridExtra)
library(RColorBrewer)
library(kableExtra)

1.4.1 Doanh thu theo Loại khách hàng (B2B vs B2C)

p1 <- data %>%
  group_by(Customer_Type) %>%
  summarise(Total_Revenue = sum(Total_Price)) %>%
  ggplot(aes(x = Customer_Type, y = Total_Revenue, fill = Customer_Type)) +
  geom_col() +
  geom_text(aes(label = comma(Total_Revenue)), vjust = -0.5) +
  labs(title = "Doanh thu theo Loại khách hàng",
       x = "Loại khách hàng", y = "Tổng doanh thu") +
  scale_y_continuous(labels = comma) +
  theme_minimal()

print(p1)

🔸 Giải thích code:

group_by(Region) → gom nhóm dữ liệu theo khu vực.

summarise(Total_Revenue = sum(Total_Price)) → tính tổng doanh thu của từng khu vực.

ggplot(aes(…)) → khởi tạo đồ thị.

geom_col() → vẽ biểu đồ cột thể hiện doanh thu.

coord_flip() → xoay ngang giúp đọc tên khu vực rõ hơn.

geom_text() → chèn nhãn số doanh thu lên từng cột.

theme_minimal() → dùng giao diện tối giản, đẹp và rõ.

📊 Nhận xét:

Sự chênh lệch lớn về Doanh thu: Có một sự khác biệt rất lớn về tổng doanh thu giữa hai loại khách hàng.Doanh thu B2B chiếm ưu thế vượt trội: Khách hàng loại B2B (Business-to-Business) mang lại doanh thu là 105,150,854, cao hơn rất nhiều so với khách hàng loại B2C (Business-to-Consumer).

Doanh thu B2C thấp hơn đáng kể: Khách hàng loại B2C chỉ đóng góp doanh thu là 32,189,768.

1.4.2 Doanh thu theo Khu vực

p2 <- data %>%
  group_by(Region) %>%
  summarise(Total_Revenue = sum(Total_Price)) %>%
  arrange(desc(Total_Revenue)) %>%
  ggplot(aes(x = reorder(Region, Total_Revenue), y = Total_Revenue, fill = Region)) +
  geom_col() +
  geom_text(aes(label = comma(round(Total_Revenue, 0))),
            hjust = -0.1, size = 3.5, color = "black") +
  coord_flip() +
  labs(title = "Doanh thu theo Khu vực",
       x = "Khu vực", y = "Tổng doanh thu") +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.15))) +
  theme_minimal() +
  theme(legend.position = "none")

print(p2)

🔸 Giải thích:

group_by(Region): Gom nhóm dữ liệu theo từng khu vực.

summarise(Total_Revenue = sum(Total_Price)): Tính tổng doanh thu (Total_Revenue) cho mỗi khu vực.

arrange(desc(Total_Revenue)): Sắp xếp khu vực theo thứ tự giảm dần doanh thu.

ggplot(…) + geom_col(): Vẽ biểu đồ cột với trục X là tên khu vực, trục Y là tổng doanh thu.

coord_flip(): Lật ngang biểu đồ để dễ đọc khi có nhiều khu vực.

scale_y_continuous(labels = comma): Hiển thị số liệu có dấu phẩy phân cách hàng nghìn.

theme_minimal(): Giao diện biểu đồ tối giản, sạch đẹp.

📊 Nhận xét:

Khu vực dẫn đầu: Hamburg là khu vực có tổng doanh thu cao nhất, vượt trội hơn hẳn so với các khu vực khác.

Các khu vực đóng góp lớn: Sau Hamburg, các khu vực như Hessen, Mecklenburg-Vorpommern, Saarland, Rheinland-Pfalz, và Berlin cũng là những nơi có doanh thu rất cao, nằm trong top đầu.

Khu vực có doanh thu thấp nhất: Bremen có vẻ là khu vực có tổng doanh thu thấp nhất trong danh sách.

1.4.3 Top 10 khách hàng có doanh thu cao nhất

p3 <- data %>%
  group_by(Customer_ID) %>%
  summarise(Total_Revenue = sum(Total_Price)) %>%
  arrange(desc(Total_Revenue)) %>%
  head(10) %>%
  ggplot(aes(x = reorder(Customer_ID, Total_Revenue), y = Total_Revenue, fill = Customer_ID)) +
  geom_col() +
  geom_text(aes(label = comma(round(Total_Revenue, 0))),
            hjust = -0.1, size = 3.5, color = "black") +
  coord_flip() +
  labs(title = "Top 10 khách hàng doanh thu cao nhất",
       x = "Mã khách hàng", y = "Doanh thu") +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.15))) +
  theme_minimal() +
  theme(legend.position = "none")

print(p3)

🔹 Giải thích code:

group_by(Customer_ID) → Gom nhóm dữ liệu theo từng mã khách hàng.

summarise(Total_Revenue = sum(Total_Price)) → Tính tổng doanh thu của mỗi khách hàng.

arrange(desc(Total_Revenue)) → Sắp xếp danh sách theo doanh thu giảm dần.

head(10) → Lấy 10 khách hàng đầu tiên, tức Top 10 khách hàng doanh thu cao nhất.

ggplot(…) + geom_col() → Vẽ biểu đồ cột thể hiện doanh thu của từng khách hàng.

coord_flip() → Lật ngang biểu đồ để dễ quan sát mã khách hàng.

scale_y_continuous(labels = comma) → Hiển thị số doanh thu có dấu phẩy phân cách hàng nghìn.

📊 Nhận xét:

Khách hàng số 1: Mã khách hàng CUS3005 là khách hàng quan trọng nhất, mang lại doanh thu cao nhất, vượt xa các khách hàng còn lại. Doanh thu của CUS3005 nằm ở khoảng 75,000 đơn vị (có thể là tiền tệ).

Top 3 Khách hàng: Ba khách hàng hàng đầu là CUS3005, CUS7626, và CUS7825. Ba khách hàng này tạo ra sự khác biệt rõ rệt về doanh thu so với nhóm khách hàng còn lại. CUS7626 và CUS7825 có doanh thu lần lượt khoảng 70,000 và 67,000.

1.4.4 Doanh thu theo Tháng/Năm

p4 <- data %>%
  mutate(
    Date = as.Date(Order_Date, format = "%d/%m/%Y"),
    Year = format(Date, "%Y"),
    Quarter = paste0("Q", ceiling(as.numeric(format(Date, "%m"))/3)),
    YearQuarter = paste(Year, Quarter, sep = "-")
  ) %>%
  group_by(YearQuarter) %>%
  summarise(Quarterly_Revenue = sum(Total_Price), .groups = "drop") %>%
  ggplot(aes(x = YearQuarter, y = Quarterly_Revenue, group = 1)) +
  geom_line(color = "steelblue", size = 1) +
  geom_point(color = "steelblue") +
  labs(title = "Doanh thu theo Quý",
       x = "Quý-Năm", y = "Doanh thu") +
  scale_y_continuous(labels = scales::comma) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

print(p4)

🔹 Giải thích code:

mutate()→ chuyển cột Order_Date sang định dạng ngày-tháng-năm, sau đó trích xuất năm-tháng (YYYY-MM) để tổng hợp doanh thu theo từng tháng. group_by(YearMonth) → Gom nhóm dữ liệu theo từng tháng-năm.

summarise(Monthly_Revenue = sum(Total_Price)) → Tính tổng doanh thu của mỗi tháng.

ggplot(aes(x = YearMonth, y = Monthly_Revenue, group = 1)) → Khởi tạo biểu đồ, trục X là tháng-năm, trục Y là doanh thu.

geom_line(color = “steelblue”, size = 1) → Vẽ đường biểu diễn doanh thu theo thời gian (đường màu xanh thép).

geom_point(color = “steelblue”) → Thêm các điểm dữ liệu để dễ quan sát từng tháng . labs(…) → Đặt tiêu đề và tên cho trục X/Y.

scale_y_continuous(labels = scales::comma) → Hiển thị dấu phẩy ngăn cách hàng nghìn trên trục doanh thu.

📊 Nhận xét:

Xu hướng Tăng trưởng: Nhìn chung, doanh thu có một xu hướng tăng nhẹ qua các năm. Mặc dù có nhiều biến động, mức doanh thu trung bình hàng tháng đã cao hơn trong giai đoạn cuối (năm 2023) so với giai đoạn đầu (năm 2021).

Tháng 12/2022 là đỉnh cao nhất.

Tháng 01/2023 sụt giảm mạnh từ đỉnh.

1.4.5 Số lượng đơn hàng theo Khu vực

p5 <- data %>%
  distinct(Order_ID, Region) %>%
  count(Region) %>%
  ggplot(aes(x = reorder(Region, n), y = n, fill = Region)) +
  geom_col() +
  coord_flip() +
  labs(title = "Số lượng đơn hàng theo Khu vực",
       x = "Khu vực", y = "Số đơn hàng") +
  theme_minimal() +
  theme(legend.position = "none")

print(p5)

🔹 Giải thích code:

distinct(Order_ID, Region) → Giữ lại các đơn hàng duy nhất

count(Region) → Đếm số lượng đơn hàng của từng khu vực.

ggplot(aes(x = reorder(Region, n), y = n, fill = Region)) → Khởi tạo biểu đồ, trục X là khu vực, trục Y là số đơn hàng.

Hàm reorder() giúp sắp xếp khu vực theo số lượng đơn hàng tăng hoặc giảm.

geom_col() → Tạo biểu đồ cột, chiều cao của mỗi cột thể hiện số lượng đơn hàng.

coord_flip() → Lật ngang biểu đồ, giúp dễ đọc tên khu vực khi nhiều nhãn.

📊 Nhận xét:

Vị trí số 1: Hamburg tiếp tục là khu vực dẫn đầu, giống như trong biểu đồ Doanh thu, với số lượng đơn hàng cao nhất, vượt qua mốc 20,000 đơn hàng.

Top tiếp theo: Rheinland-Pfalz và Niedersachsen là hai khu vực có số lượng đơn hàng cao tiếp theo, sát sao với Hamburg.

1.4.6 Doanh thu theo Nhóm sản phẩm

p6 <- data %>%
  group_by(Category) %>%
  summarise(Total_Revenue = sum(Total_Price)) %>%
  ggplot(aes(x = reorder(Category, Total_Revenue), y = Total_Revenue, fill = Category)) +
  geom_col() +
  coord_flip() +
  labs(title = "Doanh thu theo Nhóm sản phẩm",
       x = "Nhóm sản phẩm", y = "Doanh thu") +
  scale_y_continuous(labels = comma) +
  theme_minimal() +
  theme(legend.position = "none")

print(p6)

🔹 Giải thích code:

group_by(Category) → Gom nhóm dữ liệu theo từng nhóm sản phẩm

summarise(Total_Revenue = sum(Total_Price)) → Tính tổng doanh thu của mỗi nhóm sản phẩm.

ggplot(aes(x = reorder(Category, Total_Revenue), y = Total_Revenue, fill = Category)) → Thiết lập biểu đồ, trục X là nhóm sản phẩm, trục Y là tổng doanh thu.

Hàm reorder() giúp sắp xếp nhóm theo giá trị doanh thu tăng dần hoặc giảm dần.

geom_col() → Vẽ biểu đồ cột, chiều cao của cột thể hiện doanh thu.

coord_flip() → Lật biểu đồ nằm ngang giúp dễ đọc tên sản phẩm.

labs(…) → Đặt tiêu đề và tên trục rõ ràng, dễ hiểu.

📊 Nhận xét:

Alcoholic Beverages” (Đồ uống có cồn) là nhóm sản phẩm thống trị hoàn toàn về doanh thu. Thanh ngang của nhóm này dài hơn đáng kể so với tổng doanh thu của ba nhóm còn lại cộng lại.

Doanh thu từ “Alcoholic Beverages” ước tính nằm ở mức khoảng 105,000,000 (tương đương với tổng doanh thu B2B đã phân tích trước đó).

“Juices” (Nước ép/Nước trái cây) là nhóm sản phẩm đứng thứ hai về doanh thu, nhưng chỉ đạt khoảng 15,000,000 (chênh lệch rất lớn so với nhóm dẫn đầu).

“Soft Drinks” (Nước ngọt/Nước giải khát) đứng thứ ba, với doanh thu thấp hơn “Juices”, khoảng 10,000,000.

“Water” (Nước uống đóng chai) là nhóm sản phẩm có doanh thu thấp nhất, chỉ khoảng 7,000,000.

1.4.7 Mối quan hệ giữa Chiết khấu và Doanh thu

p7 <- data %>%
  ggplot(aes(x = Discount, y = Total_Price)) +
  geom_point(alpha = 0.6, color = "steelblue") +
  geom_smooth(method = "lm", color = "red", se = FALSE) +
  labs(title = "Mối quan hệ: Chiết khấu vs Doanh thu",
       x = "Tỷ lệ chiết khấu", y = "Doanh thu") +
  scale_y_continuous(labels = comma) +
  theme_minimal()

print(p7)

🔹 Giải thích code: ggplot(aes(x = Discount, y = Total_Price)) →Thiết lập dữ liệu cho biểu đồ:

geom_point(alpha = 0.6, color = “steelblue”) → Vẽ biểu đồ phân tán (scatter plot), mỗi điểm là một đơn hàng.

alpha = 0.6: làm trong suốt các điểm để dễ nhìn khi chồng lấp.

color = “steelblue”: chọn màu xanh dịu cho các điểm.

geom_smooth(method = “lm”, color = “red”, se = FALSE) → Thêm đường hồi quy tuyến tính (linear model) để thể hiện xu hướng tổng thể giữa chiết khấu và doanh thu.

📊 Nhận xét:

Các mức chiết khấu phổ biến: Dữ liệu tập trung gần như hoàn toàn ở bốn mức chiết khấu rời rạc: 0%, 5% (0.05), 10% (0.10), và 15% (0.15). Điều này cho thấy công ty chỉ áp dụng các mức chiết khấu cố định, không có các mức chiết khấu lẻ tẻ khác.

Chiết khấu cao nhất: Mức 15% là mức chiết khấu cao nhất được áp dụng.

Không có mối quan hệ tuyến tính rõ rệt: Biểu đồ cho thấy doanh thu không tăng theo tỷ lệ chiết khấu một cách rõ ràng.

Xu hướng yếu: Đường hồi quy tuyến tính (màu đỏ) nằm gần như nằm ngang, chỉ dốc lên một chút.

1.4.8 Top 10 sản phẩm có doanh thu cao nhất

p8 <- data %>%
  group_by(Product) %>%
  summarise(Total_Revenue = sum(Total_Price)) %>%
  arrange(desc(Total_Revenue)) %>%
  head(10) %>%
  ggplot(aes(x = reorder(Product, Total_Revenue), y = Total_Revenue, fill = Product)) +
  geom_col() +
  geom_text(aes(label = format(round(Total_Revenue, 0), big.mark = ".", scientific = FALSE)),
            hjust = -0.1, size = 4, color = "black") +
  coord_flip() +
  labs(title = "Top 10 sản phẩm doanh thu cao nhất",
       x = "Sản phẩm", y = "Doanh thu") +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.15))) +
  theme_minimal() +
  theme(legend.position = "none")

print(p8)

🔹 Giải thích code:

group_by(Product) → Gom nhóm dữ liệu theo từng sản phẩm riêng biệt.

summarise(Total_Revenue = sum(Total_Price)) → Tính tổng doanh thu của mỗi sản phẩm.

arrange(desc(Total_Revenue)) → Sắp xếp doanh thu giảm dần, từ cao nhất đến thấp nhất.

head(10) → Giữ lại 10 sản phẩm đầu tiên — tức là top 10 có doanh thu cao nhất.

fill = Product: tô màu khác nhau cho từng sản phẩm.

geom_col() → Vẽ biểu đồ cột, chiều cao thể hiện doanh thu.

coord_flip() → Lật biểu đồ nằm ngang để dễ đọc tên sản phẩm.

📊 Nhận xét:

Thống trị của Champagne/Rượu mạnh: Toàn bộ 7 sản phẩm đứng đầu đều là các loại đồ uống có cồn (Champagne, Scotch, Whiskey, Gin, Rum), khẳng định lại nhận xét từ biểu đồ “Doanh thu theo Nhóm sản phẩm” trước đó: công ty phụ thuộc rất lớn vào nhóm sản phẩm “Alcoholic Beverages”.

1.4.9 Phân bổ Doanh thu theo Loại KH và Khu vực (Heatmap)

p9 <- data %>%
  group_by(Region, Customer_Type) %>%
  summarise(Total_Revenue = sum(Total_Price)) %>%
  ggplot(aes(x = Region, y = Customer_Type, fill = Total_Revenue)) +
  geom_tile() +
  scale_fill_gradient(low = "white", high = "steelblue", labels = comma) +
  labs(title = "9. Heatmap: Doanh thu theo Khu vực & Loại KH",
       x = "Khu vực", y = "Loại khách hàng", fill = "Doanh thu") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

print(p9)

🔹 Giải thích code:

group_by(Region, Customer_Type) → Gom nhóm dữ liệu theo từng cặp Khu vực – Loại khách hàng.

summarise(Total_Revenue = sum(Total_Price)) → Tính tổng doanh thu cho mỗi nhóm vừa được tạo.

ggplot(aes(x = Region, y = Customer_Type, fill = Total_Revenue)) → Xác định các trục của heatmap:

fill: giá trị màu thể hiện mức doanh thu (màu đậm = doanh thu cao, màu nhạt = thấp).

geom_tile() → Vẽ ô vuông (tile) tương ứng với từng cặp giá trị (Region – Customer_Type).

📊 Nhận xét:

Doanh thu B2B: Hàng ngang đại diện cho B2B (Business-to-Business) có màu sắc đậm đồng đều trên tất cả các khu vực, cho thấy doanh thu từ phân khúc này là rất cao ở mọi nơi.

Doanh thu B2C: Hàng ngang đại diện cho B2C (Business-to-Consumer) có màu sắc rất nhạt (gần như trắng) trên tất cả các khu vực, xác nhận rằng doanh thu từ phân khúc này là không đáng kể hoặc rất thấp.

1.4.10 Doanh thu trung bình theo Khu vực

p10 <- data %>%
  group_by(Region) %>%
  summarise(Avg_Revenue = mean(Total_Price)) %>%
  ggplot(aes(x = reorder(Region, Avg_Revenue), y = Avg_Revenue, fill = Region)) +
  geom_col() +
  coord_flip() +
  labs(title = " Doanh thu trung bình theo Khu vực",
       x = "Khu vực", y = "Doanh thu trung bình") +
  scale_y_continuous(labels = comma) +
  theme_minimal() +
  theme(legend.position = "none")

print(p10)

🔹 Giải thích code: group_by(Region) → Gom nhóm dữ liệu theo từng khu vực địa lý

summarise(Avg_Revenue = mean(Total_Price)) → Tính doanh thu trung bình trên mỗi đơn hàng trong từng khu vực.

ggplot(aes(x = reorder(Region, Avg_Revenue), y = Avg_Revenue, fill = Region)) → Thiết lập trục

fill = Region: tô màu riêng cho từng khu vực.

geom_col() → Vẽ biểu đồ cột, chiều cao thể hiện doanh thu trung bình.

coord_flip() → Lật trục để biểu đồ nằm ngang → dễ đọc tên khu vực hơn.

📊 Nhận xét:

Dẫn đầu về Giá trị Trung bình: Các khu vực Hessen và Mecklenburg-Vorpommern là hai nơi có doanh thu trung bình trên mỗi giao dịch cao nhất, vượt xa các khu vực khác.

1.4.11 Phân tích Doanh thu theo Kênh bán hàng (giả định)

set.seed(123)
data$Sales_Channel <- sample(c("Online", "Offline", "Partner", "Direct"), 
                            nrow(data), replace = TRUE, 
                            prob = c(0.4, 0.3, 0.2, 0.1))
p11 <- data %>%
  group_by(Sales_Channel) %>%
  summarise(Total_Revenue = sum(Total_Price)) %>%
  ggplot(aes(x = reorder(Sales_Channel, Total_Revenue), y = Total_Revenue, fill = Sales_Channel)) +
  geom_col() +
  geom_text(aes(label = format(round(Total_Revenue, 0), big.mark = ".", scientific = FALSE)),
            hjust = 1.1, size = 4, color = "white") + # Số nằm trong cột, chữ màu trắng nổi bật
  coord_flip() +
  labs(title = "Doanh thu theo Kênh bán hàng",
       x = "Kênh bán hàng", y = "Doanh thu") +
  scale_y_continuous(labels = comma) +
  theme_minimal() +
  theme(legend.position = "none")

print(p11)

🔹 Giải thích code:

set.seed(123) → Giữ kết quả ngẫu nhiên cố định (để chạy lại cho ra cùng kết quả).

sample(…) → Tạo ngẫu nhiên cột “Sales_Channel” gồm 4 loại kên

prob = c(0.4, 0.3, 0.2, 0.1) → Xác suất phân bổ (40% đơn hàng là online, 30% offline, 20% partner, 10% direct).

replace = TRUE → Cho phép chọn lặp lại để đảm bảo đủ số dòng cho toàn bộ dataset.

📊 Nhận xét:

Kênh Online Dẫn đầu Tuyệt đối: Kênh Online mang lại doanh thu cao nhất, đạt khoảng 52,000,000 đơn vị. Điều này cho thấy công ty đã tận dụng rất hiệu quả các nền tảng kỹ thuật số hoặc thương mại điện tử.

Kênh Offline Quan trọng: Kênh Offline (bán hàng truyền thống/trực tiếp tại cửa hàng) đứng thứ hai với doanh thu khoảng 42,000,000. Đây là một kênh đóng góp đáng kể và là trụ cột quan trọng thứ hai.

1.4.12 Doanh thu theo Mức chiết khấu (Boxplot)

p12 <- data %>%
  mutate(Discount_Group = cut(Discount, breaks = c(-0.1, 0, 0.05, 0.1, 0.15, 1), 
                            labels = c("0%", "1-5%", "6-10%", "11-15%", ">15%"))) %>%
  ggplot(aes(x = Discount_Group, y = Total_Price, fill = Discount_Group)) +
  geom_boxplot() +
  labs(title = "Phân phối Doanh thu theo Mức chiết khấu",
       x = "Mức chiết khấu", y = "Doanh thu") +
  scale_y_continuous(labels = comma) +
  theme_minimal() +
  theme(legend.position = "none")

print(p12)

🔹 Giải thích code: cut() → chia biến Discount thành 5 nhóm phần trăm chiết khấu:

geom_boxplot() → hiển thị phân bố doanh thu trong từng nhóm chiết khấu

Đường giữa hộp là trung vị

Hộp là khoảng tứ phân vị (Q1–Q3)

Điểm ngoài hộp là ngoại lệ

📊 Nhận xét:

Phân phối doanh thu cực thấp: Tại tất cả các mức chiết khấu (0%, 1-5%, 6-10%, 11-15%), phần lớn các giao dịch đều có doanh thu rất thấp. Điều này có nghĩa là 50% số giao dịch ở mỗi mức chiết khấu đều có doanh thu xấp xỉ 0 hoặc rất gần 0 (doanh thu rất nhỏ).

Tại các mức chiết khấu 1-5%, 6-10%, và 11-15%, có một số lượng lớn các điểm dữ liệu nằm rất xa hộp (các chấm đen). Những điểm này đại diện cho các giao dịch có doanh thu rất cao, lên tới trên 12,500. Điều này khẳng định nhận xét từ biểu đồ phân tán trước đó: các giao dịch mang lại doanh thu cao nhất (đơn hàng lớn) đều yêu cầu phải có chiết khấu.

1.4.13 Top 5 khu vực có doanh thu cao nhất (Doughnut)

region_top5 <- data %>%
  group_by(Region) %>%
  summarise(Total_Revenue = sum(Total_Price)) %>%
  arrange(desc(Total_Revenue)) %>%
  head(5)

p13 <- region_top5 %>%
  mutate(Percentage = Total_Revenue / sum(Total_Revenue) * 100) %>%
  ggplot(aes(x = 2, y = Percentage, fill = Region)) +
  geom_col() +
  coord_polar("y") +
  xlim(0.5, 2.5) +
  geom_text(aes(label = paste0(Region, "\n", round(Percentage, 1), "%")),
          position = position_stack(vjust = 0.5), size = 3) +
   scale_fill_brewer(palette = "Blues") +
  labs(title = "Top 5 khu vực doanh thu cao nhất") +
  theme_void() +
  theme(legend.position = "bottom")

print(p13)

🔹 Giải thích code:

coord_polar(“y”) → chuyển biểu đồ cột thành hình tròn (pie/doughnut).

xlim(0.5, 2.5) → tạo khoảng trống ở giữa để thành “doughnut”.

📊 Nhận xét:

Tỷ trọng cao: Top 5 khu vực này đóng góp một tỷ lệ cực kỳ cao trong tổng doanh thu của công ty (Mặc dù không có tổng phần trăm, nhưng mức đóng góp của từng khu vực đều xấp xỉ 20%, cho thấy Top 5 này gần như chiếm toàn bộ hoặc phần lớn tổng doanh thu).

1.4.14 Tỷ lệ tăng trưởng doanh thu theo quý

library(dplyr)
library(ggplot2)

growth_data_quarter <- data %>%
  mutate(
    Date = as.Date(Order_Date, format = "%d/%m/%Y"),
    YearQuarter = paste(format(Date, "%Y"), "Q", ceiling(as.numeric(format(Date, "%m"))/3), sep = "")
  ) %>%
  group_by(YearQuarter) %>%
  summarise(Quarterly_Revenue = sum(Total_Price), .groups = "drop") %>%
  arrange(YearQuarter) %>%
  mutate(Growth_Rate = (Quarterly_Revenue / lag(Quarterly_Revenue) - 1) * 100)

p14_quarter <- growth_data_quarter %>%
  ggplot(aes(x = YearQuarter, y = Growth_Rate, group = 1)) +
  geom_col(fill = ifelse(growth_data_quarter$Growth_Rate >= 0, "steelblue", "red"), alpha = 0.7) +
  geom_text(aes(label = sprintf("%.2f%%", Growth_Rate)), 
            vjust = ifelse(growth_data_quarter$Growth_Rate >= 0, -0.3, 1.3), 
            size = 3) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
  labs(title = "Tỷ lệ tăng trưởng doanh thu theo quý",
       x = "Quý-Năm", y = "Tỷ lệ tăng trưởng (%)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

print(p14_quarter)

🔹 Giải thích code:

mutate()→ Chuyển cột Order_Date sang dạng tháng-năm

group_by(YearMonth)→ Gom nhóm dữ liệu theo từng tháng-năm.

summarise()→ Tính tổng doanh thu mỗi tháng.

mutate(Growth_Rate = (Monthly_Revenue / lag(Monthly_Revenue) - 1) * 100) → Tính tỷ lệ tăng trưởng doanh thu so với tháng trước

Dòng fill = ifelse(growth_data$Growth_Rate >= 0, “steelblue”, “red”)→ Cột màu xanh khi tăng trưởng dương, màu đỏ khi tăng trưởng âm.

geom_hline(yintercept = 0, linetype = “dashed”) → Vẽ đường ngang tại mức 0%, giúp dễ phân biệt giữa tăng và giảm.

📊 Nhận xét:

Biến động lớn: Tỷ lệ tăng trưởng thay đổi rất mạnh giữa các tháng, dao động từ mức giảm khoảng -10% đến tăng hơn +12%. Điều này phản ánh lại sự biến động mạnh mẽ của doanh thu theo thời gian đã được phân tích trước đó.

Tăng trưởng không ổn định: Trong 3 năm, số tháng có tăng trưởng dương và tăng trưởng âm là tương đối xen kẽ và không ổn định.

1.4.15 Tương quan giữa các biến số (Correlation Heatmap)

numeric_data <- data %>%
  select(Unit_Price, Quantity, Discount, Total_Price)

correlation_matrix <- cor(numeric_data)

p15 <- as.data.frame(correlation_matrix) %>%
  mutate(Var1 = rownames(correlation_matrix)) %>%
  pivot_longer(cols = -Var1, names_to = "Var2", values_to = "Correlation") %>%
  ggplot(aes(x = Var1, y = Var2, fill = Correlation)) +
  geom_tile() +
  geom_text(aes(label = round(Correlation, 2)), color = "white", size = 4) +
  scale_fill_gradient2(low = "red", high = "blue", mid = "white", 
                      midpoint = 0, limits = c(-1, 1)) +
  labs(title = "Ma trận tương quan giữa các biến số",
       x = "", y = "") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

print(p15)

🔹 Giải thích code:

as.data.frame()→ chuyển ma trận sang dạng bảng (data frame).

mutate(Var1 = rownames(correlation_matrix)) → tạo cột mới Var1 lưu tên biến của từng hàng.

pivot_longer() → chuyển ma trận tương quan từ dạng rộng sang dạng dài (long format), để ggplot có thể vẽ được (mỗi ô = 1 cặp biến).

geom_tile() → tạo ô màu cho từng cặp biến theo giá trị tương quan.

geom_text() → ghi giá trị tương quan (làm tròn 2 chữ số) lên mỗi ô, chữ trắng để dễ nhìn.

scale_fill_gradient2()→ chia màu thành ba mức.

📊 Nhận xét:

Discount & Unit_Price có Tương quan Hoàn hảo (\(r=1.0\)): Mức chiết khấu áp dụng có mối quan hệ tuyến tính hoàn hảo với Đơn giá. Điều này cho thấy chính sách chiết khấu được xác định trực tiếp và đồng nhất dựa trên giá trị của sản phẩm.

Discount & Quantity có Tương quan Rất mạnh (\(r=0.82\)): Chiết khấu là một đòn bẩy cực kỳ hiệu quả để bán được Số lượng lớn sản phẩm. Khi chiết khấu tăng, số lượng mua trong giao dịch cũng tăng mạnh theo.

Unit_Price & Total_Price có Tương quan Mạnh (\(r=0.62\)): Các giao dịch có Đơn giá sản phẩm cao hơn thường dẫn đến Tổng giá trị giao dịch cao hơn . Quantity & Total_Price có Tương quan Yếu (\(r=0.31\)): Số lượng mua tăng không tác động mạnh đến Tổng giá trị giao dịch. Điều này gợi ý rằng việc tăng Số lượng thông qua Chiết khấu lớn đã làm giảm hiệu quả lợi nhuận, khiến Tổng giá không tăng tương ứng.

1.4.16 Tỷ lệ Doanh thu từ B2B và B2C theo Khu vực

p16 <- data %>%
  group_by(Region, Customer_Type) %>%
  summarise(Total_Revenue = sum(Total_Price), .groups = "drop") %>%
  group_by(Region) %>%
  mutate(Percentage = Total_Revenue / sum(Total_Revenue) * 100) %>%
  ggplot(aes(x = Region, y = Percentage, fill = Customer_Type)) +
  geom_col() +
  geom_text(aes(label = sprintf("%.1f%%", Percentage)),
            position = position_stack(vjust = 0.5),
            color = "white", size = 3.5) +
  coord_flip() +
  labs(title = "Tỷ lệ Doanh thu B2B/B2C theo Khu vực",
       x = "Khu vực", y = "Tỷ lệ (%)", fill = "Loại KH") +
  theme_minimal()

print(p16)

🔹 Giải thích code: group_by(Region, Customer_Type) → Gom nhóm dữ liệu theo khu vực và loại khách hàng

summarise(Total_Revenue = sum(Total_Price)) → Tính tổng doanh thu của mỗi nhóm (mỗi cặp Region–Customer_Type).

group_by(Region) → Gom nhóm lại theo Region để tính tỷ lệ % trong từng khu vực.

mutate(Percentage = Total_Revenue / sum(Total_Revenue) * 100) → Tính tỷ trọng doanh thu (%) của từng loại KH trong khu vực.

geom_col() → vẽ cột chồng (stacked bar) theo tỷ lệ %.

📊 Nhận xét:

Phụ thuộc nặng nề vào B2B: Khách hàng B2B (Business-to-Business) mang lại doanh thu vượt trội, đạt 105,150,854 đơn vị. Doanh thu này cao hơn 3.27 lần so với khách hàng B2C (Business-to-Consumer), chỉ đạt 32,189,768 đơn vị. B2B chiếm khoảng 76.6% tổng doanh thu.

Phân bổ B2B theo Khu vực: Biểu đồ tỷ lệ B2B/B2C theo khu vực (Biểu đồ 4) xác nhận sự thống trị này là đồng nhất trên tất cả các khu vực. Tỷ lệ đóng góp của B2B trong mỗi khu vực đều áp đảo B2C (phần màu cam/đỏ chiếm phần lớn các thanh).

1.4.17 Doanh thu theo Mùa

p17 <- data %>%
  mutate(
    Date = as.Date(Order_Date, format = "%d/%m/%Y"),
    Month = as.numeric(format(Date, "%m")),
    Season = case_when(
      Month %in% c(10, 11, 12) ~ "Mùa Đông",
      Month %in% c(1, 2, 3)  ~ "Mùa Xuân",
      Month %in% c(4, 5, 6)  ~ "Mùa Hè",
      Month %in% c(7, 8, 9) ~ "Mùa Thu"
    )
  ) %>%
  group_by(Season) %>%
  summarise(Total_Revenue = sum(Total_Price)) %>%
  ggplot(aes(x = Season, y = Total_Revenue, fill = Season)) +
  geom_col() +
  geom_text(aes(label = comma(round(Total_Revenue, 0))),
            position = position_stack(vjust = 0.5), 
            size = 4, angle = 90, color = "white") +
  labs(title = "Doanh thu theo mùa trong năm",
       x = "Mùa", y = "Tổng doanh thu") +
  scale_y_continuous(labels = comma) +
  theme_minimal()

print(p17)

🔹 Giải thích code:

Month = as.numeric(format(Date, “%m”)) → Trích ra tháng từ cột Date, chuyển thành số (1–12).

Season = case_when(…) → Tạo biến mới “Season” (mùa) dựa vào tháng:

group_by(Season) → Gom nhóm theo mùa

summarise() → Tính tổng doanh thu mỗi mùa.

ggplot(aes(x = Season, y = Total_Revenue, fill = Season)) → Mỗi mùa là một cột, màu khác nhau để dễ phân biệt.

📊 Nhận xét:

Doanh thu Đồng đều giữa các Mùa: Tổng doanh thu được phân bổ rất đồng đều giữa 4 mùa trong năm.

Mùa Hè (34,934,443) cao nhất, Mùa Xuân (34,129,781) thấp nhất. Sự khác biệt giữa mùa cao nhất và thấp nhất là rất nhỏ (chỉ khoảng 2.3%).

1.4.18 Doanh thu trung bình theo Tháng

p18 <- data %>%
  mutate(
    Order_Date = as.Date(Order_Date, format = "%d/%m/%Y"),
    Month = as.numeric(format(Order_Date, "%m"))
  ) %>%
  group_by(Month) %>%
  summarise(Avg_Revenue = mean(Total_Price, na.rm = TRUE)) %>%
  ggplot(aes(x = factor(Month), y = Avg_Revenue, group = 1)) +
  geom_line(color = "steelblue", size = 1) +
  geom_point(color = "steelblue", size = 2) +
  labs(title = " Doanh thu trung bình theo Tháng",
       x = "Tháng", y = "Doanh thu trung bình") +
  scale_y_continuous(labels = comma) +
  theme_minimal()

print(p18)

🔹 Giải thích code:

Month = as.numeric(format(Order_Date, “%m”)) → Tạo biến Month chứa số tháng (1–12).

group_by(Month) → Gom nhóm dữ liệu theo tháng.

summarise(Avg_Revenue = mean(Total_Price, na.rm = TRUE)) → Tính doanh thu trung bình mỗi tháng, bỏ qua giá trị bị thiếu (na.rm = TRUE).

geom_line(color = “steelblue”, size = 1) → Vẽ đường biểu diễn doanh thu trung bình, màu xanh thép, dày hơn mặc định.

geom_point(color = “steelblue”, size = 2) → Thêm các điểm tròn tại mỗi tháng để dễ nhìn.

📊 Nhận xét:

Đỉnh Giá trị: Doanh thu trung bình đạt đỉnh vào Tháng 12 (gần 136 đơn vị) và Tháng 2 (khoảng 132.5 đơn vị).

Đáy Giá trị: Doanh thu trung bình thấp nhất vào Tháng 4 (khoảng 127 đơn vị), cho thấy giá trị các đơn hàng vào thời điểm này là thấp nhất.

Kết luận: Các đơn hàng vào cuối năm không chỉ nhiều mà còn có giá trị trung bình cao hơn so với các tháng khác.

1.4.19 Doanh thu theo Nhóm sản phẩm và Loại khách hàng

p19 <- data %>%
  group_by(Category, Customer_Type) %>%
  summarise(Total_Revenue = sum(Total_Price)) %>%
  ggplot(aes(x = Category, y = Total_Revenue, fill = Customer_Type)) +
  geom_col(position = "dodge") +
  geom_text(aes(label = comma(round(Total_Revenue, 0))),
            position = position_dodge(width = 0.9),
            hjust = -0.1, size = 3.5, color = "black") +
  coord_flip() +
  labs(title = "Doanh thu theo Nhóm SP & Loại KH",
       x = "Nhóm sản phẩm", y = "Doanh thu", fill = "Loại KH") +
  scale_y_continuous(labels = comma, expand = expansion(mult = c(0, 0.15))) +
  theme_minimal()

print(p19)

🔹 Giải thích code:

group_by(Category, Customer_Type) → Gom nhóm theo nhóm sản phẩm (Category) và loại khách hàng (Customer_Type).

summarise(Total_Revenue = sum(Total_Price)) → Tính tổng doanh thu của từng cặp (nhóm sản phẩm, loại khách hàng).

geom_col(position = “dodge”) → Biểu đồ cột song song (grouped bars) — mỗi nhóm sản phẩm có nhiều cột ứng với các loại khách hàng khác nhau.

scale_y_continuous(labels = comma) → Hiển thị doanh thu có dấu phẩy ngăn cách hàng nghìn.

📊 Nhận xét:

Khách hàng B2B (Doanh thu: 105,150,854) áp đảo B2C (32,189,768)

Nhóm sản phẩm Alcoholic Beverages (Đồ uống có cồn) cũng thống trị về doanh thu (ước tính \(\approx 105,000,000\)).

Heatmap và biểu đồ phân bổ khẳng định mối liên hệ chặt chẽ: Doanh thu B2B chủ yếu đến từ việc bán Đồ uống có cồn (phần lớn là Champagne/Rượu mạnh), trong khi B2C đóng góp không đáng kể vào bất kỳ nhóm sản phẩm nào.

1.4.20 Doanh thu theo Khu vực và Mùa

p20 <- data %>%
  mutate(
    # Bước 1: chuyển ngày sang kiểu Date
    Order_Date = as.Date(Order_Date, format = "%d/%m/%Y"),

    # Bước 2: tách tháng
    Month = as.numeric(format(Order_Date, "%m")),

    # Bước 3: tạo cột Season
    Season = case_when(
      Month %in% c(10, 11, 12)  ~ "Mùa Đông",
      Month %in% c(1, 2, 3)   ~ "Mùa Xuân",
      Month %in% c(4, 5, 6)   ~ "Mùa Hè",
      Month %in% c(7, 8, 9) ~ "Mùa Thu"
    )
  ) %>%
  group_by(Region, Season) %>%
  summarise(Total_Revenue = sum(Total_Price, na.rm = TRUE)) %>%
  ggplot(aes(x = Region, y = Total_Revenue, fill = Season)) +
  geom_col(position = "dodge") +
  coord_flip() +
  labs(
    title = " Doanh thu theo Khu vực và Mùa ",
    x = "Khu vực",
    y = "Doanh thu"
  ) +
  scale_y_continuous(labels = comma) +
  theme_minimal()

print(p20)

🔹 Giải thích code:

Season = case_when(…) → Tạo cột mùa dựa trên tháng

group_by(Region, Season) → Gom nhóm theo khu vực và mùa trong năm.

summarise() → Tính tổng doanh thu của từng nhóm khu vực–mùa.

geom_col(position = “dodge”) → Vẽ các cột song song (đặt cạnh nhau) để dễ so sánh giữa các mùa

coord_flip() → Xoay biểu đồ nằm ngang, giúp đọc tên khu vực dễ hơn.

📊 Nhận xét:

Mùa Hè Dẫn đầu: Mùa Hè (màu xanh lá) là mùa mang lại doanh thu cao nhất ở hầu hết các khu vực, đặc biệt là Hamburg và Rheinland-Pfalz.

Mùa Đông Mạnh: Mùa Đông (màu đỏ cam) cũng là một mùa mạnh, thường là mùa có doanh thu cao thứ hai, đặc biệt ở các khu vực phía Nam.

Tác động của Mùa: Mặc dù tổng thể đồng đều, sự khác biệt theo mùa là rõ ràng ở cấp độ khu vực: Mùa Hè là mùa bán hàng mạnh mẽ nhất của công ty.

2 CHƯƠNG 2: PHÂN TÍCH TÌNH HÌNH TÀI CHÍNH NGÂN HÀNG STB (2015-2024)

2.1 GIỚI THIỆU VÀ XỬ LÝ DỮ LIỆU

# Load các thư viện cần thiết
library(tidyverse)
library(readxl)
library(kableExtra)
library(ggplot2)
library(ggthemes)
library(scales)
library(plotly)
library(corrplot)
library(PerformanceAnalytics)
library(gridExtra)
library(lubridate)
library(psych)
library(reshape2)
library(ggrepel)

2.1.1 Đọc dữ liệu

df <- read_excel("C:/Users/adminn/OneDrive - UFM/STB_Analys.xlsx", sheet = "Sheet1")

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

dim(df)
## [1] 10 20

2.1.3 Kiểm tra 10 dòng đầu tiên

cat("=== 10 DÒNG ĐẦU TIÊN CỦA DỮ LIỆU ===\n")
## === 10 DÒNG ĐẦU TIÊN CỦA DỮ LIỆU ===
head(df, 10)
## # A tibble: 10 × 20
##    ky_bao_cao tong_tai_san cho_vay_khach_hang tien_gui_cua_khach_hang
##    <chr>             <dbl>              <dbl>                   <dbl>
##  1 Năm 2024      727016711          473456903               582474928
##  2 Năm 2023      674374966          438411368               536873344
##  3 Năm 2022      588643085          404997291               499789702
##  4 Năm 2021      552748211          370470970               473197808
##  5 Năm 2020      492516029          334854576               427971850
##  6 Năm 2019      453581057          292058715               400844380
##  7 Năm 2018      406040598          253100111               349388922
##  8 Năm 2017      368468840          220197752               319859587
##  9 Năm 2016      332023043          196428077               291653101
## 10 Năm 2015      292032736          183660021               260994745
## # ℹ 16 more variables: chung_khoan_dau_tu <dbl>, von_dieu_le <dbl>,
## #   loi_nhuan_chua_phan_phoi <dbl>, cac_quy_du_tru <dbl>,
## #   tong_loi_nhuan_truoc_thue <dbl>, chi_phi_du_phong_rui_ro_tin_dung <dbl>,
## #   loi_nhuan_thuan_truoc_du_phong <dbl>, thu_nhap_lai_thuan <dbl>,
## #   lai_thuan_dich_vu <dbl>, tong_thu_nhap_hoat_dong <dbl>,
## #   tong_chi_phi_hoat_dong <dbl>, loi_nhuan_sau_thue <dbl>,
## #   tong_von_chu_so_huu <dbl>, chung_khoan_kinh_doanh <dbl>, …

🔹 Giải thích

Hàm head(df, 10) lấy 10 dòng đầu tiên của data frame data.

cat() in tiêu đề ra màn hình cho dễ đọc trong file R Markdown.

🔹 Ý nghĩa thống kê

Giúp xem cấu trúc dữ liệu thô: các tên cột, định dạng từng cột (số, chữ, ngày, ….

Phát hiện dòng bị lỗi hoặc thiếu dữ liệu (NA) ngay từ đầu.

2.1.4 Kiểm tra 10 dòng cuối

cat("=== 10 DÒNG CUỐI CÙNG CỦA DỮ LIỆU ===\n")
## === 10 DÒNG CUỐI CÙNG CỦA DỮ LIỆU ===
tail(df, 10)
## # A tibble: 10 × 20
##    ky_bao_cao tong_tai_san cho_vay_khach_hang tien_gui_cua_khach_hang
##    <chr>             <dbl>              <dbl>                   <dbl>
##  1 Năm 2024      727016711          473456903               582474928
##  2 Năm 2023      674374966          438411368               536873344
##  3 Năm 2022      588643085          404997291               499789702
##  4 Năm 2021      552748211          370470970               473197808
##  5 Năm 2020      492516029          334854576               427971850
##  6 Năm 2019      453581057          292058715               400844380
##  7 Năm 2018      406040598          253100111               349388922
##  8 Năm 2017      368468840          220197752               319859587
##  9 Năm 2016      332023043          196428077               291653101
## 10 Năm 2015      292032736          183660021               260994745
## # ℹ 16 more variables: chung_khoan_dau_tu <dbl>, von_dieu_le <dbl>,
## #   loi_nhuan_chua_phan_phoi <dbl>, cac_quy_du_tru <dbl>,
## #   tong_loi_nhuan_truoc_thue <dbl>, chi_phi_du_phong_rui_ro_tin_dung <dbl>,
## #   loi_nhuan_thuan_truoc_du_phong <dbl>, thu_nhap_lai_thuan <dbl>,
## #   lai_thuan_dich_vu <dbl>, tong_thu_nhap_hoat_dong <dbl>,
## #   tong_chi_phi_hoat_dong <dbl>, loi_nhuan_sau_thue <dbl>,
## #   tong_von_chu_so_huu <dbl>, chung_khoan_kinh_doanh <dbl>, …

🔹 Giải thích

tail(df, 10) lấy 10 dòng cuối cùng trong bảng dữ liệu.

🔹 Ý nghĩa thống kê

Kiểm tra phần cuối dữ liệu xem có dòng bị trống, lặp hoặc lỗi nhập liệu không.

2.1.5 Kiểm tra số quan sát và số biến

cat("Số quan sát (dòng):", nrow(df), "\n")
## Số quan sát (dòng): 10
cat("Số biến (cột):", ncol(df), "\n")
## Số biến (cột): 20

2.1.6 Kiểm tra số biến định lượng

cat("Các biến định lượng:", sum(sapply(df, is.numeric)), "\n")
## Các biến định lượng: 19

2.1.7 Kiểm tra số biến định tính

cat("Các biến định tính:", sum(sapply(df, is.character) | sapply(df, is.factor)),"\n" )
## Các biến định tính: 1

🔹 Giải thích

nrow(df) → đếm số hàng (số lượng quan sát/giao dịch).

ncol(df) → đếm số cột (số lượng biến/thuộc tính).

sapply(df, is.numeric) → kiểm tra cột nào là dạng số (numeric), kết quả trả về TRUE/FALSE cho từng cột.

sum(sapply(df, is.numeric)) → đếm tổng số biến định lượng.

sapply(df, is.character) | sapply(df, is.factor) → kiểm tra cột nào là dạng ký tự hoặc phân loại

sum(…) → đếm tổng số biến định tính.

🔹 Ý nghĩa thống kê

Giúp hiểu sơ bộ quy mô và cấu trúc dữ liệu

Có bao nhiêu dòng (quan sát)

Có bao nhiêu cột (biến)

Loại biến nào chiếm ưu thế (định lượng hay định tính)?

2.1.8 Tên các biến trong bộ dữ liệu

cat("Tên các biến của bộ dữ liệu gồm:\n")
## Tên các biến của bộ dữ liệu gồm:
cat(paste0(" - ", names(df)), sep = "\n")
##  - ky_bao_cao
##  - tong_tai_san
##  - cho_vay_khach_hang
##  - tien_gui_cua_khach_hang
##  - chung_khoan_dau_tu
##  - von_dieu_le
##  - loi_nhuan_chua_phan_phoi
##  - cac_quy_du_tru
##  - tong_loi_nhuan_truoc_thue
##  - chi_phi_du_phong_rui_ro_tin_dung
##  - loi_nhuan_thuan_truoc_du_phong
##  - thu_nhap_lai_thuan
##  - lai_thuan_dich_vu
##  - tong_thu_nhap_hoat_dong
##  - tong_chi_phi_hoat_dong
##  - loi_nhuan_sau_thue
##  - tong_von_chu_so_huu
##  - chung_khoan_kinh_doanh
##  - lai_co_ban_tren_co_phieu_vnd
##  - vay_TCTD_khac

2.1.9 Kiểm tra kiểu dữ liệu của các biến

cat("=== KIỂU DỮ LIỆU CỦA CÁC BIẾN ===\n")
## === KIỂU DỮ LIỆU CỦA CÁC BIẾN ===
str(df)
## tibble [10 × 20] (S3: tbl_df/tbl/data.frame)
##  $ ky_bao_cao                      : chr [1:10] "Năm 2024" "Năm 2023" "Năm 2022" "Năm 2021" ...
##  $ tong_tai_san                    : num [1:10] 7.27e+08 6.74e+08 5.89e+08 5.53e+08 4.93e+08 ...
##  $ cho_vay_khach_hang              : num [1:10] 4.73e+08 4.38e+08 4.05e+08 3.70e+08 3.35e+08 ...
##  $ tien_gui_cua_khach_hang         : num [1:10] 5.82e+08 5.37e+08 5.00e+08 4.73e+08 4.28e+08 ...
##  $ chung_khoan_dau_tu              : num [1:10] 81332610 71936877 61547075 71749610 75156127 ...
##  $ von_dieu_le                     : num [1:10] 18852157 18852157 18852157 18852157 18852157 ...
##  $ loi_nhuan_chua_phan_phoi        : num [1:10] 26064919 20316716 14939922 9423861 7303619 ...
##  $ cac_quy_du_tru                  : num [1:10] 5378109 4757251 4191077 3738749 3336508 ...
##  $ tong_loi_nhuan_truoc_thue       : num [1:10] 10255932 9296911 6665026 3871050 3339280 ...
##  $ chi_phi_du_phong_rui_ro_tin_dung: num [1:10] -1921365 -2730016 -4990584 -4152029 -3036974 ...
##  $ loi_nhuan_thuan_truoc_du_phong  : num [1:10] 12177297 12026927 11655610 8023079 6376254 ...
##  $ thu_nhap_lai_thuan              : num [1:10] 22512910 21243756 18116531 13293486 11526554 ...
##  $ lai_thuan_dich_vu               : num [1:10] 4908618 4544754 4606313 3863308 3744015 ...
##  $ tong_thu_nhap_hoat_dong         : num [1:10] 29569157 27561432 24717375 18986347 17270869 ...
##  $ tong_chi_phi_hoat_dong          : num [1:10] -17391860 -15534505 -13061765 -10963268 -10894615 ...
##  $ loi_nhuan_sau_thue              : num [1:10] 8214618 7452316 5334331 3018665 2681981 ...
##  $ tong_von_chu_so_huu             : num [1:10] 35213980 33967555 28791443 32607200 28956242 ...
##  $ chung_khoan_kinh_doanh          : num [1:10] 0 0 0 0 0 ...
##  $ lai_co_ban_tren_co_phieu_vnd    : num [1:10] 4135 3719 2593 1414 1248 ...
##  $ vay_TCTD_khac                   : num [1:10] 31905792 26241658 21052126 12016711 7880006 ...

🔹 Giải thích

Hàm str() hiển thị cấu trúc đối tượng, bao gồm:

Kiểu dữ liệu từng cột (numeric, character, factor, Date, …

Một vài giá trị mẫu của mỗi cột.

🔹 Ý nghĩa thống kê

Giúp xác định: Cột nào là biến định lượng (số, có thể tính trung bình, tổng, …)

Cột nào là biến định tính (phân loại: vùng, giới tính, loại khách hàng, …)

2.1.10 Thống kê mô tả tổng quan

cat("=== THỐNG KÊ MÔ TẢ TỔNG QUAN ===\n")
## === THỐNG KÊ MÔ TẢ TỔNG QUAN ===
summary(df)
##   ky_bao_cao         tong_tai_san       cho_vay_khach_hang 
##  Length:10          Min.   :292032736   Min.   :183660021  
##  Class :character   1st Qu.:377861780   1st Qu.:228423342  
##  Mode  :character   Median :473048543   Median :313456646  
##                     Mean   :488744528   Mean   :316763578  
##                     3rd Qu.:579669366   3rd Qu.:396365711  
##                     Max.   :727016711   Max.   :473456903  
##  tien_gui_cua_khach_hang chung_khoan_dau_tu  von_dieu_le      
##  Min.   :260994745       Min.   :39678056   Min.   :18852157  
##  1st Qu.:327241921       1st Qu.:66712258   1st Qu.:18852157  
##  Median :414408115       Median :72562728   Median :18852157  
##  Mean   :414304837       Mean   :69163399   Mean   :18852157  
##  3rd Qu.:493141728       3rd Qu.:75424848   3rd Qu.:18852157  
##  Max.   :582474928       Max.   :81332610   Max.   :18852157  
##  loi_nhuan_chua_phan_phoi cac_quy_du_tru    tong_loi_nhuan_truoc_thue
##  Min.   : 1264953         Min.   :2419833   Min.   :  155591         
##  1st Qu.: 2594855         1st Qu.:2592453   1st Qu.: 1680601         
##  Median : 6357592         Median :3150205   Median : 3278013         
##  Mean   : 9187365         Mean   :3448636   Mean   : 4141749         
##  3rd Qu.:13560907         3rd Qu.:4077995   3rd Qu.: 5966532         
##  Max.   :26064919         Max.   :5378109   Max.   :10255932         
##  chi_phi_du_phong_rui_ro_tin_dung loi_nhuan_thuan_truoc_du_phong
##  Min.   :-4990584                 Min.   :  851834              
##  1st Qu.:-2960235                 1st Qu.: 3310403              
##  Median :-2204452                 Median : 5872945              
##  Mean   :-2434482                 Mean   : 6576230              
##  3rd Qu.:-1674427                 3rd Qu.:10747477              
##  Max.   : -696243                 Max.   :12177297              
##  thu_nhap_lai_thuan lai_thuan_dich_vu tong_thu_nhap_hoat_dong
##  Min.   : 4020697   Min.   :1171263   Min.   : 6530157       
##  1st Qu.: 6839779   1st Qu.:2638409   1st Qu.: 9403198       
##  Median :10353621   Median :3533503   Median :15953104       
##  Mean   :11938156   Mean   :3289728   Mean   :16788161       
##  3rd Qu.:16910770   3rd Qu.:4374393   3rd Qu.:23284618       
##  Max.   :22512910   Max.   :4908618   Max.   :29569157       
##  tong_chi_phi_hoat_dong loi_nhuan_sau_thue tong_von_chu_so_huu
##  Min.   :-17391860      Min.   :  88609    Min.   :22080495   
##  1st Qu.:-12537141      1st Qu.:1333709    1st Qu.:23585311   
##  Median :-10080159      Median :2568423    Median :27766542   
##  Mean   :-10211931      Mean   :3286502    Mean   :27841915   
##  3rd Qu.: -6712127      3rd Qu.:4755415    3rd Qu.:31694460   
##  Max.   : -5154547      Max.   :8214618    Max.   :35213980   
##  chung_khoan_kinh_doanh lai_co_ban_tren_co_phieu_vnd vay_TCTD_khac     
##  Min.   :    0          Min.   :  49.0               Min.   : 2954073  
##  1st Qu.:    0          1st Qu.: 611.2               1st Qu.: 7445120  
##  Median :    0          Median :1188.5               Median :10063182  
##  Mean   :24848          Mean   :1606.6               Mean   :13363474  
##  3rd Qu.:47438          3rd Qu.:2298.2               3rd Qu.:18951346  
##  Max.   :95334          Max.   :4135.0               Max.   :31905792

🔹 Giải thích

summary() tự động tạo bảng thống kê mô tả cho mỗi cột:

Với biến số: hiển thị Min, 1st Qu., Median, Mean, 3rd Qu., Max

Với biến phân loại: đếm tần suất từng giá trị.

🔹 Ý nghĩa thống kê

Đây là phân tích mô tả (descriptive statistics) — bước đầu tiên trong mọi báo cáo thống kê.

Mean (trung bình) → giá trị đại diện chung.

Median (trung vị) → giá trị giữa, ít bị ảnh hưởng bởi ngoại lệ.

Min / Max → phạm vi dao động của dữ liệu

1st Qu. / 3rd Qu. → phân vị 25% và 75%, thể hiện độ phân tán.

2.2 XỬ LÍ VÀ MÃ HÓA DỮ LIỆU

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

cat("Số quan sát trùng lặp:", sum(duplicated(df)), "\n")
## Số quan sát trùng lặp: 0
cat("\n")

🔹 Giải thích:

Hàm duplicated(df) → tìm các dòng trùng lặp trong bộ dữ liệu.

Hàm sum() → đếm số dòng trùng đó.

Hàm cat() → in kết quả ra màn hình.

🔹 Ý nghĩa thống kê:

Giúp phát hiện và loại bỏ các quan sát trùng lặp, nhằm đảm bảo dữ liệu độc lập, chính xác, và tránh sai lệch trong phân tích thống kê.

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

cat("DỮ LIỆU THIẾU THEO TỪNG CỘT:\n")
## DỮ LIỆU THIẾU THEO TỪNG CỘT:
colSums(is.na(df))
##                       ky_bao_cao                     tong_tai_san 
##                                0                                0 
##               cho_vay_khach_hang          tien_gui_cua_khach_hang 
##                                0                                0 
##               chung_khoan_dau_tu                      von_dieu_le 
##                                0                                0 
##         loi_nhuan_chua_phan_phoi                   cac_quy_du_tru 
##                                0                                0 
##        tong_loi_nhuan_truoc_thue chi_phi_du_phong_rui_ro_tin_dung 
##                                0                                0 
##   loi_nhuan_thuan_truoc_du_phong               thu_nhap_lai_thuan 
##                                0                                0 
##                lai_thuan_dich_vu          tong_thu_nhap_hoat_dong 
##                                0                                0 
##           tong_chi_phi_hoat_dong               loi_nhuan_sau_thue 
##                                0                                0 
##              tong_von_chu_so_huu           chung_khoan_kinh_doanh 
##                                0                                0 
##     lai_co_ban_tren_co_phieu_vnd                    vay_TCTD_khac 
##                                0                                0

🔹 Giải thích:

is.na(df) will return a logic ma trận (logicmatrix) có cùng kích thước với df, trong đó mỗi giá trị là TRUE nếu phần tử đó bị thiếu (NA) hoặc FALSE không bị thiếu.

Hàm colSums()cộng tất cả giá trị TRUE trong từng cột (TRUE đượctính là 1), làmmà bạn sẽ biếtmỗi cột có tổngcộng bảo nhiêu giá trị NA.

🔹 Ý nghĩa thống kê:

Giúp phát hiện mức độ thiếu dữ liệu của từng biến, từ đó quyết định xử lý (loại bỏ hoặc điền giá trị) trước khi phân tích thống kê.

2.2.3 Chuẩn hóa tên cột và kiểu dữ liệu

colnames(df) <- c("ky_bao_cao", "tong_tai_san", "cho_vay_khach_hang", "tien_gui_cua_khach_hang", 
                  "chung_khoan_dau_tu", "von_dieu_le", "loi_nhuan_chua_phan_phoi", 
                  "cac_quy_du_tru", "tong_loi_nhuan_truoc_thue", "chi_phi_du_phong_rui_ro_tin_dung", 
                  "loi_nhuan_thuan_truoc_du_phong", "thu_nhap_lai_thuan", "lai_thuan_dich_vu", 
                  "tong_thu_nhap_hoat_dong", "tong_chi_phi_hoat_dong", "loi_nhuan_sau_thue", 
                  "tong_von_chu_so_huu", "chung_khoan_kinh_doanh", "lai_co_ban_tren_co_phieu_vnd", 
                  "vay_TCTD_khac")

2.2.4 Chuyển đổi kỳ báo cáo thành dạng năm

df$nam <- as.factor(df$ky_bao_cao)

2.2.5 Phân tổ tổng tài sản

df$tai_san_nhom <- cut(df$tong_tai_san,
                       breaks = quantile(df$tong_tai_san, probs = seq(0, 1, 1/3)),
                       include.lowest = TRUE,
                       labels = c("Nhỏ", "Vừa", "Lớn"))
table_taisan <- df[, c("ky_bao_cao", "tong_tai_san", "tai_san_nhom")]
table_taisan$tong_tai_san_f <- formatC(table_taisan$tong_tai_san, format = "d", big.mark = ".")
print(table_taisan[, c("ky_bao_cao", "tong_tai_san_f", "tai_san_nhom")])
## # A tibble: 10 × 3
##    ky_bao_cao tong_tai_san_f tai_san_nhom
##    <chr>      <chr>          <fct>       
##  1 Năm 2024   727.016.711    Lớn         
##  2 Năm 2023   674.374.966    Lớn         
##  3 Năm 2022   588.643.085    Lớn         
##  4 Năm 2021   552.748.211    Vừa         
##  5 Năm 2020   492.516.029    Vừa         
##  6 Năm 2019   453.581.057    Vừa         
##  7 Năm 2018   406.040.598    Nhỏ         
##  8 Năm 2017   368.468.840    Nhỏ         
##  9 Năm 2016   332.023.043    Nhỏ         
## 10 Năm 2015   292.032.736    Nhỏ

🔹 Giải thích:

df$tong_tai_san: cột tổng tài sản trong dataframe df.

quantile(df$tong_tai_san, probs = seq(0, 1, 1/3)):

seq(0, 1, 1/3) tạo dãy: 0, 1/3, 2/3, 1.

quantile() tính phân vị theo các mốc này → chia dữ liệu thành 3 phần bằng nhau theo giá trị tài sản.

cut(…, breaks = …, include.lowest = TRUE, labels = c(“Nhỏ”, “Vừa”, “Lớn”))

cut() chia dữ liệu thành 3 khoảng theo các giá trị phân vị vừa tính.

include.lowest = TRUE → giá trị nhỏ nhất cũng được đưa vào nhóm đầu tiên (“Nhỏ”).

2.2.6 Phân tổ LNST

df$loi_nhuan_nhom <- cut(df$loi_nhuan_sau_thue,
                         breaks = c(-Inf, 3000000, 8000000, Inf),
                         labels = c("Thấp", "Trung bình", "Cao"))
table_lnst <- df[, c("ky_bao_cao", "loi_nhuan_sau_thue", "loi_nhuan_nhom")]
table_lnst$loi_nhuan_sau_thue_f <- formatC(table_lnst$loi_nhuan_sau_thue, format = "d", big.mark = ".")
print(table_lnst[, c("ky_bao_cao", "loi_nhuan_sau_thue_f", "loi_nhuan_nhom")])
## # A tibble: 10 × 3
##    ky_bao_cao loi_nhuan_sau_thue_f loi_nhuan_nhom
##    <chr>      <chr>                <fct>         
##  1 Năm 2024   8.214.618            Cao           
##  2 Năm 2023   7.452.316            Trung bình    
##  3 Năm 2022   5.334.331            Trung bình    
##  4 Năm 2021   3.018.665            Trung bình    
##  5 Năm 2020   2.681.981            Thấp          
##  6 Năm 2019   2.454.864            Thấp          
##  7 Năm 2018   1.790.156            Thấp          
##  8 Năm 2017   1.181.560            Thấp          
##  9 Năm 2016   88.609               Thấp          
## 10 Năm 2015   647.919              Thấp

🔹 Giải thích:

cut() : chia biến liên tục (loi_nhuan_sau_thue) thành các khoảng (bins).

breaks = c(-Inf, 3000000, 8000000, Inf)

-Inf = âm vô cực (tức là mọi giá trị nhỏ hơn 3 triệu).

3000000 và 8000000 là mốc chia nhóm.

Inf = dương vô cực (mọi giá trị lớn hơn 8 triệu).

labels = c(“Thấp”, “Trung bình”, “Cao”)

2.2.7 Sắp xếp giảm dần theo tổng TS

df <- df[order(df$tong_tai_san, decreasing = TRUE), ]
df$tong_tai_san_f <- formatC(df$tong_tai_san, format = "d", big.mark = ".")
head(df[, c("ky_bao_cao", "tong_tai_san_f")], 5)
## # A tibble: 5 × 2
##   ky_bao_cao tong_tai_san_f
##   <chr>      <chr>         
## 1 Năm 2024   727.016.711   
## 2 Năm 2023   674.374.966   
## 3 Năm 2022   588.643.085   
## 4 Năm 2021   552.748.211   
## 5 Năm 2020   492.516.029

🔹 Giải thích:

order(df$tong_tai_san, decreasing = TRUE):

Hàm order() sắp xếp theo giá trị trong cột tong_tai_san.

decreasing = TRUE → sắp xếp giảm dần (tức là lớn nhất lên đầu).

df[…] → dùng kết quả đó để tái sắp xếp toàn bộ bảng dữ liệu df

2.2.8 Lọc năm có tổng tài sản bé nhất

min_val <- min(df$tong_tai_san, na.rm = TRUE)
df_min_taisan <- df[df$tong_tai_san == min_val, ]
df_min_taisan$tong_tai_san_f <- formatC(df_min_taisan$tong_tai_san, format = "d", big.mark = ".")
print(df_min_taisan[, c("ky_bao_cao", "tong_tai_san_f")])
## # A tibble: 1 × 2
##   ky_bao_cao tong_tai_san_f
##   <chr>      <chr>         
## 1 Năm 2015   292.032.736

🔹 Giải thích:

min() → tìm giá trị nhỏ nhất trong cột tong_tai_san . na.rm = TRUE → bỏ qua giá trị NA (thiếu dữ liệu) để tránh lỗi.

Kết quả: biến min_val chứa giá trị tài sản nhỏ nhất trong toàn bộ mẫu

Biểu thức df$tong_tai_san == min_val tạo điều kiện lọc, chỉ chọn dòng có tổng tài sản bằng giá trị nhỏ nhất vừa tìm.

Kết quả: df_min_taisan là bảng con chứa thông tin về kỳ (hoặc đối tượng) có tổng tài sản thấp nhất.

2.2.9 **Lọc năm có tổng tài sản lớn nhất)

max_val <- max(df$tong_tai_san, na.rm = TRUE)
df_max_taisan <- df[df$tong_tai_san == max_val, ]
df_max_taisan$tong_tai_san_f <- formatC(df_max_taisan$tong_tai_san, format = "d", big.mark = ".")
df_print <- df_max_taisan[, c("ky_bao_cao", "tong_tai_san_f")]
names(df_print) <- c("Kỳ báo cáo", "Tổng tài sản")
print(df_print)
## # A tibble: 1 × 2
##   `Kỳ báo cáo` `Tổng tài sản`
##   <chr>        <chr>         
## 1 Năm 2024     727.016.711

2.2.10 Tạo các chỉ số tài chính

# Tạo các chỉ số tài chính quan trọng
df <- df %>% mutate(
  # Tỷ lệ cho vay trên tiền gửi (Loan-to-Deposit Ratio)
  LTD_ratio = cho_vay_khach_hang / tien_gui_cua_khach_hang,
  
  # Tỷ lệ an toàn vốn (CAR)
  CAR = tong_von_chu_so_huu / tong_tai_san,
  
  # ROA (Return on Assets)
  ROA = loi_nhuan_sau_thue / tong_tai_san,
  
  # ROE (Return on Equity)
  ROE = loi_nhuan_sau_thue / tong_von_chu_so_huu,
  
  # Tỷ lệ chi phí hoạt động trên tổng thu nhập (Cost-to-Income Ratio)
  cost_to_income = abs(tong_chi_phi_hoat_dong) / tong_thu_nhap_hoat_dong,
  
  # Tăng trưởng tổng tài sản
  tang_truong_tai_san = (tong_tai_san - lag(tong_tai_san)) / lag(tong_tai_san),
  
  # Tăng trưởng lợi nhuận sau thuế
  tang_truong_loi_nhuan = (loi_nhuan_sau_thue - lag(loi_nhuan_sau_thue)) / lag(loi_nhuan_sau_thue),
  
  # Tỷ lệ thu nhập lãi thuần trên tổng tài sản
  thu_nhap_lai_thuan_ts = thu_nhap_lai_thuan / tong_tai_san,
  
  # Tỷ lệ dự phòng rủi ro tín dụng
  ty_le_du_phong = cac_quy_du_tru / cho_vay_khach_hang,
  
  # Hiệu quả sử dụng vốn
  hieu_qua_su_dung_von = loi_nhuan_sau_thue / tong_von_chu_so_huu
)

# Thay thế NA bằng 0 trong các cột tăng trưởng
df$tang_truong_tai_san[is.na(df$tang_truong_tai_san)] <- 0
df$tang_truong_loi_nhuan[is.na(df$tang_truong_loi_nhuan)] <- 0

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

2.3.1 Phân tích biến tổng tài sản

2.3.1.1 Thống kê mô tả

stat <- summary(df$tong_tai_san)
sd_val <- sd(df$tong_tai_san, na.rm=TRUE)

# Thêm dấu chấm ngăn cách cho các thống kê mô tả
stat_f <- formatC(stat, format = "d", big.mark = ".")
sd_f <- formatC(sd_val, format = "d", big.mark = ".")

# In ra kết quả có dấu phân cách
cat("Các chỉ số thống kê mô tả tổng tài sản:\n")
## Các chỉ số thống kê mô tả tổng tài sản:
print(stat_f)
##          Min.       1st Qu.        Median          Mean       3rd Qu. 
## "292.032.736" "377.861.779" "473.048.543" "488.744.527" "579.669.366" 
##          Max. 
## "727.016.711"
cat("Độ lệch chuẩn:", sd_f, "\n")
## Độ lệch chuẩn: 145.725.203

🔹 Giải thích:

summary(df$tong_tai_san) → tạo bảng tóm tắt 6 chỉ tiêu thống kê cơ bản

sd(df$tong_tai_san, na.rm=TRUE) → tính độ lệch chuẩn (Standard Deviation), đo mức dao động hoặc phân tán của tổng tài sản so với trung bình

Nhận xét: Tổng tài sản của các quan sát có mức trung bình khoảng 488,7 triệu, dao động khá lớn (độ lệch chuẩn ≈145,7 triệu). Giá trị thấp nhất là ≈292 triệu và cao nhất ≈727 triệu, cho thấy sự chênh lệch đáng kể giữa các đối tượng trong tập dữ liệu.

2.3.1.2 So sánh tổng tài sản giữa các nhóm

library(dplyr)
df$tai_san_nhom <- cut(df$tong_tai_san,
                       breaks = quantile(df$tong_tai_san, probs = seq(0, 1, 1/3), na.rm=TRUE),
                       include.lowest = TRUE,
                       labels = c("Nhỏ", "Vừa", "Lớn"))
ts_grouped <- df %>%
  group_by(tai_san_nhom) %>%
  summarise(
    Mean = mean(tong_tai_san, na.rm = TRUE),
    Median = median(tong_tai_san, na.rm = TRUE),
    Max = max(tong_tai_san, na.rm = TRUE),
    Min = min(tong_tai_san, na.rm = TRUE)
  )

# Thêm dấu chấm phân cách cho tất cả giá trị
ts_grouped$Mean <- formatC(ts_grouped$Mean, format = "d", big.mark = ".")
ts_grouped$Median <- formatC(ts_grouped$Median, format = "d", big.mark = ".")
ts_grouped$Max <- formatC(ts_grouped$Max, format = "d", big.mark = ".")
ts_grouped$Min <- formatC(ts_grouped$Min, format = "d", big.mark = ".")
print(ts_grouped)
## # A tibble: 3 × 5
##   tai_san_nhom Mean        Median      Max         Min        
##   <fct>        <chr>       <chr>       <chr>       <chr>      
## 1 Nhỏ          349.641.304 350.245.941 406.040.598 292.032.736
## 2 Vừa          499.615.099 492.516.029 552.748.211 453.581.057
## 3 Lớn          663.344.920 674.374.966 727.016.711 588.643.085

🔹 Giải thích:

quantile(df$tong_tai_san, probs = seq(0, 1, 1/3)) → chia dữ liệu theo phân vị 0%, 33,3%, 66,7%, 100%, tức là 3 phần bằng nhau (mỗi nhóm chứa khoảng 1/3 mẫu).

cut() → phân loại mỗi quan sát vào một nhóm tương ứng

include.lowest = TRUE → đảm bảo giá trị nhỏ nhất được tính vào nhóm đầu tiên.

group_by(tai_san_nhom) → gom dữ liệu theo nhóm quy mô (“Nhỏ”, “Vừa”, “Lớn”).

summarise() → tính 4 chỉ tiêu thống kê cơ bản cho từng nhóm → Giúp so sánh đặc điểm phân bố tài sản giữa các nhóm

Nhận xét: Tổng tài sản tăng dần theo quy mô nhóm. Nhóm “Nhỏ” có tài sản trung bình khoảng 349,6 triệu, nhóm “Vừa” đạt 499,6 triệu, và nhóm “Lớn” cao nhất với 663,3 triệu. Điều này cho thấy sự phân tầng rõ rệt về quy mô tài sản giữa các nhóm.

2.3.1.3 Tốc độ tăng trưởng qua từng năm

df$tang_truong_ts <- c(NA, diff(df$tong_tai_san) / head(df$tong_tai_san, -1) * 100)

# Làm tròn số cho gọn
df$tang_truong_ts_f <- round(df$tang_truong_ts, 2)

# In bảng gồm năm, tổng tài sản (dấu chấm), và tốc độ tăng trưởng %
df$tong_tai_san_f <- formatC(df$tong_tai_san, format = "d", big.mark = ".")
print(df[, c("ky_bao_cao", "tong_tai_san_f", "tang_truong_ts_f")])
## # A tibble: 10 × 3
##    ky_bao_cao tong_tai_san_f tang_truong_ts_f
##    <chr>      <chr>                     <dbl>
##  1 Năm 2024   727.016.711               NA   
##  2 Năm 2023   674.374.966               -7.24
##  3 Năm 2022   588.643.085              -12.7 
##  4 Năm 2021   552.748.211               -6.1 
##  5 Năm 2020   492.516.029              -10.9 
##  6 Năm 2019   453.581.057               -7.91
##  7 Năm 2018   406.040.598              -10.5 
##  8 Năm 2017   368.468.840               -9.25
##  9 Năm 2016   332.023.043               -9.89
## 10 Năm 2015   292.032.736              -12.0

🔹 Giải thích:

diff(df$tong_tai_san) → tính hiệu giữa các kỳ liên tiếp của biến tong_tai_san

head(df$tong_tai_san, -1) → lấy toàn bộ giá trị trừ kỳ cuối (để chia đúng cho giá trị kỳ trước).

diff(…) / head(…) * 100 → chuyển đổi sang tỷ lệ phần trăm tăng trưởng

Nhận xét: Tổng tài sản có xu hướng giảm liên tục qua các năm, với mức giảm trung bình khoảng 7–13% mỗi năm. Mặc dù năm 2024 đạt giá trị cao nhất (727 triệu), nhưng giai đoạn trước đó thể hiện sự suy giảm rõ rệt, cho thấy doanh nghiệp chưa duy trì được tăng trưởng ổn định về tài sản.

2.3.1.4 Liên hệ tương quan với biến cho vay khách hàng

cor(df$tong_tai_san, df$cho_vay_khach_hang, use="complete.obs")
## [1] 0.9940972

🔹 Giải thích:

cor(…) → hàm tính hệ số tương quan Pearson (mặc định).→ Dùng để đo mức độ và chiều hướng mối liên hệ tuyến tính giữa hai biến số định lượng.

df$tong_tai_san → biến thứ nhất: Tổng tài sản của doanh nghiệp.

df$cho_vay_khach_hang → biến thứ hai: Dư nợ cho vay khách hàng.

Kết quả: r=0.9940972 => Tương quan thuận cực kỳ mạnh giữa tổng tài sản và cho vay khách hàng.

2.3.2 Phân tích biến cho vay khách hàng

2.3.2.1 Thống kê mô tả

format_number <- function(x) {
  format(x, big.mark = ".", scientific = FALSE)
}
summary_vals <- summary(df$cho_vay_khach_hang)
summary_formatted <- lapply(summary_vals, format_number)
print(summary_formatted)
## $Min.
## [1] "183.660.021"
## 
## $`1st Qu.`
## [1] "228.423.342"
## 
## $Median
## [1] "313.456.646"
## 
## $Mean
## [1] "316.763.578"
## 
## $`3rd Qu.`
## [1] "396.365.711"
## 
## $Max.
## [1] "473.456.903"

Nhận xét:

Khoản cho vay khách hàng có giá trị trung bình khoảng 316,8 triệu, tương đối gần với trung vị 313,5 triệu, cho thấy phân bố khá cân đối. Giá trị dao động từ 183,7 triệu đến 396,4 triệu, phản ánh mức chênh lệch vừa phải giữa các khách hàng vay

Phân vị thứ nhất (Q1): 228,42 triệu → 25% khách hàng có giá trị cho vay ≤ mức này. Phân vị thứ ba (Q3): 396,37 triệu → 75% khách hàng có mức cho vay dưới giá trị này.

2.3.2.2 Kiểm tra tương quan với biến tổng tài sản

cor(df$cho_vay_khach_hang, df$tong_tai_san, use = "complete.obs")
## [1] 0.9940972

Kết quả: r=0.9940972 => Tương quan thuận cực kỳ mạnh giữa tổng tài sản và cho vay khách hàng.

2.3.2.3 Kiểm tra tương quan với biến tiền gửi khách hàng

ggplot(df, aes(x = tien_gui_cua_khach_hang, y = cho_vay_khach_hang)) +
  geom_point(color = "green", size = 2.5) +
  geom_smooth(method = "lm", color = "red") +
  labs(title = "Tương quan: Cho vay khách hàng vs Tiền gửi", x = "Tiền gửi khách hàng", y = "Cho vay khách hàng") +
  theme_light()

🔹 Nhận xét:

Biểu đồ thể hiện mối tương quan giữa biến Cho vay khách hàng và Tiền gửi khách hàng. Các điểm dữ liệu phân bố gần như hoàn toàn dọc theo đường hồi quy tuyến tính (màu đỏ), cho thấy hai biến có mối quan hệ cùng chiều rất mạnh.

Cụ thể, khi tiền gửi của khách hàng tăng lên, giá trị cho vay khách hàng cũng có xu hướng tăng tương ứng. Hệ số tương quan đạt khoảng 0,99, phản ánh mối liên kết gần như tuyến tính hoàn hảo giữa hai chỉ tiêu này. Điều này hàm ý rằng quy mô cho vay của ngân hàng có mối phụ thuộc chặt chẽ vào nguồn vốn huy động từ khách hàng.

2.3.2.4 Phân tích xu hướng cho vay khách hàng qua các năm

ggplot(df, aes(x = nam, y = cho_vay_khach_hang)) +
  geom_line(color = "blue", size = 1.1, group = 1) +
  geom_point(size = 2) +
  scale_y_continuous(labels = scales::comma) +
  labs(title = "Xu hướng dư nợ cho vay khách hàng theo thời gian", x = "Năm", y = "Cho vay khách hàng") +
  theme_minimal()

🔹Nhận xét:

Biểu đồ cho thấy dư nợ cho vay khách hàng có xu hướng tăng mạnh qua giai đoạn 2015–2024.

Cụ thể, dư nợ tăng đều hàng năm, phản ánh sự phát triển ổn định trong hoạt động tín dụng của ngân hàng . Đặc biệt, từ năm 2020 trở đi, tốc độ tăng trưởng có xu hướng cao hơn, cho thấy ngân hàng đã mở rộng hoạt động cho vay, đồng thời đáp ứng tốt nhu cầu vốn của thị trường.

Xu hướng này là tín hiệu tích cực về tăng trưởng quy mô tài sản sinh lời, tuy nhiên cần đi kèm với việc đảm bảo chất lượng tín dụng và quản lý rủi ro hiệu quả.

2.3.3 Phân tích biến tiền gửi của khách hàng

2.3.3.1 Thống kê mô tả

sum_vals <- summary(df$tien_gui_cua_khach_hang)

# Định dạng có dấu phân cách hàng nghìn (dùng dấu chấm chuẩn VN)
format_number <- function(x) {
  format(x, big.mark = ".", decimal.mark = ",", scientific = FALSE)
}

sapply(sum_vals, format_number)
##          Min.       1st Qu.        Median          Mean       3rd Qu. 
## "260.994.745" "327.241.921" "414.408.115" "414.304.837" "493.141.729" 
##          Max. 
## "582.474.928"

🔹Nhận xét:

Biến tiền gửi của khách hàng có giá trị nhỏ nhất là 260.994.745, giá trị phân vị thứ nhất (Q1) là 327.241.921, trung vị (Median) là 414.408.115, giá trị trung bình (Mean) là 414.304.837, phân vị thứ ba (Q3) là 493.141.729, và giá trị lớn nhất là 582.474.928.

Điều này cho thấy mức tiền gửi của khách hàng dao động trong khoảng từ khoảng 261 triệu đến 582 triệu, với trung bình và trung vị gần tương đương nhau, phản ánh phân bố khá cân đối và đồng đều giữa các khách hàng.

2.3.3.2 Tăng trưởng qua các năm

format_number <- function(x) {
  format(x, big.mark = ".", decimal.mark = ",", scientific = FALSE)
}

# Định dạng phần trăm
format_percent <- function(x) {
  if (is.na(x)) return(NA)
  paste0(format(round(x * 100, 2), decimal.mark = ",", nsmall = 2), " %")
}

df <- df %>% arrange(ky_bao_cao)
df$growth_tiengui <- c(NA, diff(df$tien_gui_cua_khach_hang) / head(df$tien_gui_cua_khach_hang, -1))

df$tien_gui_cua_khach_hang_fmt <- format_number(df$tien_gui_cua_khach_hang)
df$growth_tiengui_fmt <- sapply(df$growth_tiengui, format_percent)

print(df[, c("ky_bao_cao", "tien_gui_cua_khach_hang_fmt", "growth_tiengui_fmt")])
## # A tibble: 10 × 3
##    ky_bao_cao tien_gui_cua_khach_hang_fmt growth_tiengui_fmt
##    <chr>      <chr>                       <chr>             
##  1 Năm 2015   260.994.745                 <NA>              
##  2 Năm 2016   291.653.101                 11,75 %           
##  3 Năm 2017   319.859.587                 9,67 %            
##  4 Năm 2018   349.388.922                 9,23 %            
##  5 Năm 2019   400.844.380                 14,73 %           
##  6 Năm 2020   427.971.850                 6,77 %            
##  7 Năm 2021   473.197.808                 10,57 %           
##  8 Năm 2022   499.789.702                 5,62 %            
##  9 Năm 2023   536.873.344                 7,42 %            
## 10 Năm 2024   582.474.928                 8,49 %

Giải thích:

format_number(): định dạng số có dấu chấm ngăn cách hàng nghìn và dấu phẩy cho phần thập phân.

format_percent(): chuyển giá trị tỷ lệ sang dạng phần trăm, làm tròn 2 chữ số và thêm ký hiệu “%”. 🔹Nhận xét:

Tiền gửi của khách hàng tăng đều qua các năm, từ 260,9 triệu (2015) lên 582,5 triệu (2024).Tốc độ tăng trưởng dao động từ 5,6% đến 14,7%, cao nhất năm 2019, cho thấy xu hướng tích cực và ổn định trong huy động tiền gửi qua thời gian.

2.3.3.3 Tỷ trọng trên tổng tài sản

df$tytrong_tiengui_tren_tongtaisan <- df$tien_gui_cua_khach_hang /
df$tong_tai_san
ggplot(df, aes(x = nam, y = tytrong_tiengui_tren_tongtaisan)) +
  geom_col(fill = "orange") +
  geom_text(aes(label = round(tytrong_tiengui_tren_tongtaisan, 2)), vjust = -0.2, size = 3) +
  labs(title = "Tỷ trọng tiền gửi khách hàng / Tổng tài sản", x = "Năm", y = "Tỷ trọng") +
  theme_minimal()

🔹Nhận xét:

Tỷ trọng tiền gửi khách hàng trong tổng tài sản duy trì ở mức cao và ổn định, dao động quanh 80–85% trong giai đoạn 2015–2024.

Điều này cho thấy nguồn vốn huy động từ khách hàng vẫn là cấu phần chủ yếu trong tổng tài sản của ngân hàng, phản ánh chiến lược tập trung vào hoạt động huy động vốn truyền thống.

Giai đoạn 2015–2019, tỷ trọng duy trì ở mức ổn định cao (trên 0,8), thể hiện sự bền vững trong cơ cấu nguồn vốn.

Từ 2020–2023, có sự giảm nhẹ, cho thấy ngân hàng mở rộng các nguồn vốn khác hoặc tăng mạnh quy mô tài sản.

Năm 2024, tỷ trọng tăng nhẹ trở lại, cho thấy xu hướng phục hồi của tiền gửi khách hàng trong cơ cấu tài sản.

2.3.4 Phân tích biến lợi nhuận sau thuế

2.3.4.1 Thống kê mô tả

# Lấy thống kê mô tả cho biến
desc_vals <- summary(df$loi_nhuan_sau_thue)

# Hàm định dạng số có dấu chấm hàng nghìn, chuẩn Việt Nam
format_number <- function(x) {
  format(x, big.mark = ".", decimal.mark = ",", scientific = FALSE)
}

desc_vals_fmt <- sapply(desc_vals, format_number)
print(desc_vals_fmt)
##        Min.     1st Qu.      Median        Mean     3rd Qu.        Max. 
##    "88.609" "1.333.709" "2.568.423" "3.286.502" "4.755.415" "8.214.618"

🔹Nhận xét:

Lợi nhuận sau thuế tăng dần và phân bố khá lệch phải, thể hiện xu hướng tăng trưởng tích cực qua các năm.

Khoảng chênh giữa Min và Max lớn, cho thấy biến động mạnh về lợi nhuận, có thể do ảnh hưởng của các yếu tố kinh doanh và môi trường kinh tế từng năm.

Trung vị (2,57 triệu) nhỏ hơn trung bình (3,28 triệu) → chứng tỏ có một vài năm lợi nhuận rất cao kéo trung bình lên.

2.3.4.2 Tốc độ tăng trưởng LNST

df <- df %>% arrange(ky_bao_cao)

# Tính tốc độ tăng trưởng lợi nhuận sau thuế
df$growth_loi_nhuan <- c(NA, diff(df$loi_nhuan_sau_thue) / head(df$loi_nhuan_sau_thue, -1))
# Định dạng tăng trưởng thành phần trăm có phân cách chuẩn Việt Nam
format_percent <- function(x) {
  if (is.na(x)) return(NA)
  paste0(format(round(x * 100, 2), big.mark = ".", decimal.mark = ",", nsmall = 2), " %")
}
df$loi_nhuan_sau_thue_fmt <- format_number(df$loi_nhuan_sau_thue)
df$growth_loi_nhuan_fmt <- sapply(df$growth_loi_nhuan, format_percent)

# Xuất bảng với tăng trưởng đã định dạng
print(df[, c("ky_bao_cao", "loi_nhuan_sau_thue_fmt", "growth_loi_nhuan_fmt")])
## # A tibble: 10 × 3
##    ky_bao_cao loi_nhuan_sau_thue_fmt growth_loi_nhuan_fmt
##    <chr>      <chr>                  <chr>               
##  1 Năm 2015   "  647.919"            <NA>                
##  2 Năm 2016   "   88.609"            -86,32 %            
##  3 Năm 2017   "1.181.560"            1.233,45 %          
##  4 Năm 2018   "1.790.156"            51,51 %             
##  5 Năm 2019   "2.454.864"            37,13 %             
##  6 Năm 2020   "2.681.981"            9,25 %              
##  7 Năm 2021   "3.018.665"            12,55 %             
##  8 Năm 2022   "5.334.331"            76,71 %             
##  9 Năm 2023   "7.452.316"            39,70 %             
## 10 Năm 2024   "8.214.618"            10,23 %

🔹Nhận xét:

Lợi nhuận sau thuế tăng mạnh qua các năm, đặc biệt năm 2017 bứt phá (+1.233%) sau giai đoạn giảm sâu 2016.

Từ 2018–2024, tốc độ tăng duy trì ổn định và tích cực, cao nhất 2022 (76,7%), cho thấy hiệu quả hoạt động ngày càng được cải thiện rõ rệt.

2.3.4.3 ** Tương quan lợi nhuận sau thuế với tiền gửi khách hàng**

ggplot(df, aes(x = tien_gui_cua_khach_hang, y = loi_nhuan_sau_thue)) +
  geom_point() +
  geom_smooth(method = "lm") +
  labs(title = "Tương quan: Lợi nhuận sau thuế với Tiền gửi khách hàng", x = "Tiền gửi khách hàng", y = "Lợi nhuận sau thuế")

🔹Nhận xét:

Mối quan hệ: Có một mối quan hệ tuyến tính đồng biến (tích cực) mạnh giữa Tiền gửi của khách hàng và Lợi nhuận sau thuế.

Ý nghĩa: Khi tiền gửi của khách hàng tăng, lợi nhuận sau thuế có xu hướng tăng theo rõ rệt.

Mô hình: Đường hồi quy tuyến tính (màu xanh dương) phù hợp tốt với dữ liệu, cho thấy Tiền gửi là yếu tố dự báo quan trọng cho Lợi nhuận.

Độ tin cậy: Các điểm dữ liệu tập trung gần đường hồi quy, thể hiện mối tương quan mạnh và đáng tin cậy.

2.3.5 Phân tích biến tổng vốn chủ sở hữu

2.3.5.1 Thống kê mô tả

format_number <- function(x) {
  format(x, big.mark = ".", decimal.mark = ",", scientific = FALSE)
}
summary_vals <- summary(df$tong_von_chu_so_huu)
print(sapply(summary_vals, format_number))
##         Min.      1st Qu.       Median         Mean      3rd Qu.         Max. 
## "22.080.495" "23.585.311" "27.766.542" "27.841.915" "31.694.461" "35.213.980"

📊 Nhận xét

Giá trị nhỏ nhất (Min.): 22.080.495

Giá trị lớn nhất (Max.): 35.213.980

Giá trị trung vị (Median): 27.766.542 (Giá trị nằm giữa dãy dữ liệu)

Giá trị trung bình (Mean): 27.841.915 (Giá trị trung tâm)

Phân vị thứ nhất (1st Qu.): 23.585.311 (25% dữ liệu nhỏ hơn hoặc bằng giá trị này)

Phân vị thứ ba (3rd Qu.): 31.694.461 (75% dữ liệu nhỏ hơn hoặc bằng giá trị này)

2.3.5.2 Tăng trưởng vốn CSH qua các năm

format_number <- function(x) {
  format(x, big.mark = ".", decimal.mark = ",", scientific = FALSE)
}

# Định dạng phần trăm cho tăng trưởng
format_percent <- function(x) {
  if (is.na(x)) return(NA)
  paste0(format(round(x * 100, 2), decimal.mark = ",", nsmall = 2), " %")
}

# Tính tăng trưởng và định dạng
df_sorted <- df %>% arrange(ky_bao_cao)
df$growth_von_chu_so_huu <- c(NA, diff(df$tong_von_chu_so_huu) / head(df$tong_von_chu_so_huu, -1))
df$tong_von_chu_so_huu_fmt <- format_number(df$tong_von_chu_so_huu)
df$growth_von_chu_so_huu_fmt <- sapply(df$growth_von_chu_so_huu, format_percent)

knitr::kable(
  df[, c("ky_bao_cao", "tong_von_chu_so_huu_fmt", "growth_von_chu_so_huu_fmt")],
  col.names = c("Kỳ báo cáo", "Tổng VCSH (đã format)", "Tăng trưởng (%)"),
  align = c("c", "r", "r"),
  row.names = FALSE
)
Kỳ báo cáo Tổng VCSH (đã format) Tăng trưởng (%)
Năm 2015 22.080.495 NA
Năm 2016 22.191.934 0,50 %
Năm 2017 23.236.292 4,71 %
Năm 2018 24.632.367 6,01 %
Năm 2019 26.741.640 8,56 %
Năm 2020 28.956.242 8,28 %
Năm 2021 32.607.200 12,61 %
Năm 2022 28.791.443 -11,70 %
Năm 2023 33.967.555 17,98 %
Năm 2024 35.213.980 3,67 %

📊 Nhận xét về Tốc độ Tăng trưởng Tổng Vốn Chủ Sở Hữu

Vốn chủ sở hữu tăng đều qua các năm, phản ánh năng lực tài chính được củng cố.

Ngoại lệ năm 2022 giảm 11,7%, nhưng sau đó phục hồi mạnh năm 2023 (+18%) và tiếp tục tăng nhẹ năm 2024, cho thấy xu hướng tăng trưởng bền vững trở lại.

2.3.5.3 Xu hướng tổng vốn chủ sở hữu

ggplot(df, aes(x = nam, y = tong_von_chu_so_huu)) +
  geom_line(color = "blue") +
  geom_point(size = 2) +
  labs(title = "Xu hướng tổng vốn chủ sở hữu",
       x = "Năm",
       y = "Tổng vốn chủ sở hữu")

📈 Nhận xét Xu hướng Tổng Vốn Chủ Sở Hữu

Tổng vốn chủ sở hữu có xu hướng tăng trưởng dài hạn từ năm 2015 đến năm 2024.

Giai đoạn tăng ổn định (2015 - 2021): Vốn chủ sở hữu tăng trưởng liên tục và khá đều đặn.

Sụt giảm (Năm 2022): Ghi nhận một sự sụt giảm rõ rệt từ mức đỉnh năm 2021. Điểm dữ liệu năm 2022 nằm thấp hơn so với xu hướng tăng trưởng chung của các năm trước đó.

Phục hồi và Đạt đỉnh (Năm 2023 - 2024): Sau khi sụt giảm, vốn chủ sở hữu đã phục hồi mạnh mẽ vào năm 2023 và tiếp tục tăng, đạt mức cao nhất vào năm 2024

2.3.5.4 Tỷ trọng VCSH trên tổng tài sản

df$tytrong_vonchush_tren_tongts <- df$tong_von_chu_so_huu / df$tong_tai_san
ggplot(df, aes(x = nam, y = tytrong_vonchush_tren_tongts)) +
  geom_col(fill = "purple") +
  geom_text(aes(label = round(tytrong_vonchush_tren_tongts, 2)), vjust = -0.2, size = 3) +
  labs(title = "Tỷ trọng vốn chủ sở hữu / Tổng tài sản",
       x = "Năm",
       y = "Tỷ trọng")

📊 Nhận xét về Tỷ trọng Vốn Chủ Sở Hữu / Tổng Tài Sản

Tỷ trọng vốn chủ sở hữu giảm dần giai đoạn 2015–2021, sụt mạnh năm 2022 (~0,05) do vốn chủ sở hữu giảm hoặc tổng tài sản tăng nhanh.

Từ 2022–2024, tỷ trọng ổn định ở mức thấp, dù vốn chủ phục hồi, cho thấy tài sản (chủ yếu từ nợ) vẫn tăng nhanh hơn.

2.3.5.5 Tỷ suất sinh lời trên vốn chủ sở hữu (ROE)

df$ROE <- df$loi_nhuan_sau_thue / df$tong_von_chu_so_huu
df$ROE_fmt <- sapply(df$ROE, format_percent)

knitr::kable(
  df[, c("ky_bao_cao", "ROE_fmt")],
  col.names = c("Kỳ báo cáo", "ROE (%)"),
  align = c("c", "r"),
  row.names = FALSE
)
Kỳ báo cáo ROE (%)
Năm 2015 2,93 %
Năm 2016 0,40 %
Năm 2017 5,08 %
Năm 2018 7,27 %
Năm 2019 9,18 %
Năm 2020 9,26 %
Năm 2021 9,26 %
Năm 2022 18,53 %
Năm 2023 21,94 %
Năm 2024 23,33 %

Nhận xét: ROE tăng mạnh qua các năm, từ 2,9% (2015) lên 23,3% (2024).Sau giai đoạn tăng ổn định quanh 9% (2019–2021), chỉ số bứt phá mạnh từ 2022 trở đi, phản ánh hiệu quả sử dụng vốn chủ sở hữu ngày càng cao..

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

2.4.1 Biểu đồ 1:Tổng tài sản qua các năm

df$nam <- as.factor(df$ky_bao_cao)
p1 <- ggplot(df, aes(x = nam, y = tong_tai_san/1e6)) +
  geom_line(group = 1, color = "blue", size = 1.2, alpha = 0.8) +
  geom_point(color = "blue", size = 2.5) +
  geom_smooth(method = "lm", se = FALSE, color = "red", linetype = "dashed", aes(group = 1)) +
  geom_text(aes(label = round(tong_tai_san/1e6, 1)), vjust = -1, size = 3) +
  labs(title = "Tổng tài sản qua các năm", x = "Năm", y = "Tổng tài sản (triệu VND)") +
  theme_minimal()
print(p1)

🔹 Giải thích code

ggplot(df, aes(x = ky_bao_cao, y = tong_tai_san/1e6)) → trục X là kỳ báo cáo (năm), trục Y là tổng tài sản chuyển sang triệu VND (chia 1e6).

geom_line(…) + geom_point(…) → vẽ đường và điểm để thấy xu hướng.

geom_smooth(method = “lm”, se = FALSE, color = “red”, linetype = “dashed”) → vẽ đường hồi quy tuyến tính (trend).

geom_text(aes(label = round(tong_tai_san/1e6, 1)), vjust = -1) → in nhãn giá trị (làm tròn 1 chữ số).

labs(…) + theme_minimal() → tiêu đề, nhãn trục và theme.

🔹 Nhận xét

Tốc độ tăng trưởng: Tốc độ tăng trưởng dường như nhanh hơn ở những năm gần đây, đặc biệt là giai đoạn sau năm 2021, khi khoảng cách giữa các điểm dữ liệu theo chiều dọc lớn hơn.

Tính ổn định: Xu hướng tăng trưởng là rất ổn định, không có năm nào bị sụt giảm.

2.4.2 Biểu đồ 2: Cho vay khách hàng

p2 <- ggplot(df, aes(x = factor(ky_bao_cao), y = cho_vay_khach_hang/1e6)) +
  geom_col(fill = "steelblue", alpha = 0.8) +
  geom_text(aes(label = round(cho_vay_khach_hang/1e6, 1)), vjust = -0.5, size = 3) +
  geom_hline(yintercept = mean(df$cho_vay_khach_hang/1e6), 
             color = "red", linetype = "dashed", size = 1) +
  labs(title = "Cho vay khách hàng qua các năm", x = "Năm", y = "Cho vay (triệu VND)") +
  theme_minimal()
print(p2)

🔹 Giải thích code

aes(x = factor(ky_bao_cao), y = cho_vay_khach_hang/1e6) → cột theo năm, giá trị cho vay (triệu VND).

geom_col(fill = “steelblue”, alpha = 0.8) → cột màu xanh.

geom_text(…, vjust = -0.5) → gắn nhãn giá trị trên cột.

geom_hline(yintercept = mean(…), color = “red”, linetype = “dashed”) → vẽ đường trung bình cho vay để so sánh.

🔹 Nhận xét

Tăng trưởng liên tục: Hoạt động cho vay khách hàng tăng trưởng đều đặn qua tất cả các năm, từ 183.7 triệu VND (Năm 2015) lên đến 473.5 triệu VND (Năm 2024) . Vượt ngưỡng: Từ năm 2020 trở đi (334.9 triệu VND), mức cho vay đã vượt qua ngưỡng tham chiếu (đường đứt nét màu đỏ, khoảng 320 triệu VND), cho thấy sự mở rộng mạnh mẽ hoạt động tín dụng trong giai đoạn gần đây.

Tăng tốc: Tốc độ tăng trưởng dường như nhanh hơn trong những năm cuối (2020-2024), thể hiện sự gia tăng đáng kể trong quy mô danh mục cho vay.

2.4.3 Biểu đồ 3: Biểu đồ area - Tiền gửi khách hàng

p3 <- ggplot(df, aes(x = nam, y = tien_gui_cua_khach_hang/1e6)) +
  geom_area(fill = "lightgreen", alpha = 0.6) +
  geom_line(color = "darkgreen", size = 1, group = 1) +
  geom_point(color = "darkgreen", size = 2) +
  geom_text(aes(label = round(tien_gui_cua_khach_hang/1e6, 1)), vjust = -1, size = 3) +
  labs(title = "Tiền gửi khách hàng qua các năm", x = "Năm", y = "Tiền gửi (triệu VND)") +
  theme_minimal()
print(p3)

🔹 Giải thích code

geom_area(fill = “lightgreen”, alpha = 0.6) → vùng tích phân dưới đường (area) cho tiền gửi.

geom_line() + geom_point() → đường và điểm nhấn.

geom_text(… ) → in nhãn tiền gửi (triệu VND).

🔹 Nhận xét

Xu hướng chính: Tiền gửi khách hàng có xu hướng tăng trưởng liên tục và mạnh mẽ trong suốt giai đoạn từ năm 2015 (261 triệu VND) đến năm 2024 (582.5 triệu VND).

Tốc độ tăng trưởng: Tốc độ tăng trưởng nhìn chung là ổn định và có xu hướng tăng tốc trong giai đoạn gần đây (sau năm 2021).

Tính ổn định: Xu hướng tăng là rất nhất quán, không có năm nào bị sụt giảm.

2.4.4 Biểu đồ 4: Biểu đồ điểm - Lợi nhuận sau thuế

p4 <- ggplot(df, aes(x = ky_bao_cao, y = loi_nhuan_sau_thue/1e3)) +
  geom_point(color = "purple", size = 3, alpha = 0.7) +
  geom_segment(aes(xend = ky_bao_cao, yend = 0), color = "purple", alpha = 0.5) +
  geom_text(aes(label = round(loi_nhuan_sau_thue/1e3, 1)), vjust = -1, size = 3) +
  geom_smooth(method = "loess", se = FALSE, color = "orange") +
  labs(title = "Lợi nhuận sau thuế qua các năm", x = "Năm", y = "Lợi nhuận (nghìn VND)") +
  theme_minimal()
print(p4)

🔹 Giải thích code

geom_point(color = “purple”, size = 3) → điểm lợi nhuận mỗi năm (đơn vị nghìn VND do chia /1e3).

geom_segment(aes(xend = ky_bao_cao, yend = 0)) → vẽ đường thẳng từ mỗi điểm xuống trục 0 (so sánh trực quan).

geom_smooth(method = “loess”, se = FALSE, color = “orange”) → đường mượt LOESS thể hiện xu hướng phi tuyến.

geom_text(…) → nhãn giá trị.

🔹 Nhận xét

Tăng trưởng chung: Lợi nhuận sau thuế có xu hướng tăng trưởng cực kỳ mạnh mẽ và liên tục từ năm 2016 (mức thấp nhất là 88.6 nghìn VND) đến năm 2024 (mức cao nhất là 8214.6 nghìn VND).

Cải thiện ban đầu (2016 - 2021): Lợi nhuận tăng ổn định, nhưng tốc độ tăng trưởng ở mức trung bình.

Tăng trưởng bùng nổ (2022 - 2024): Giai đoạn này chứng kiến sự tăng trưởng đột phá, đặc biệt là từ năm 2021 (3018.7 nghìn VND) lên 2022 (5334.3 nghìn VND), và tiếp tục tăng rất mạnh vào năm 2023 và 2024. Độ dốc của biểu đồ tăng lên rõ rệt trong 3 năm cuối.

2.4.5 Biểu đồ 5: Biểu đồ bước - Tổng vốn chủ sở hữu

p5 <- ggplot(df, aes(x = ky_bao_cao, y = tong_von_chu_so_huu/1e6)) +
  geom_step(color = "brown", size = 1.2, direction = "hv") +
  geom_point(color = "brown", size = 2) +
  geom_ribbon(aes(ymin = 0, ymax = tong_von_chu_so_huu/1e6), 
              fill = "brown", alpha = 0.2) +
  geom_text(aes(label = round(tong_von_chu_so_huu/1e6, 1)), vjust = -1, size = 3) +
  labs(title = "Tổng vốn chủ sở hữu qua các năm", x = "Năm", y = "Vốn chủ sở hữu (triệu VND)") +
  theme_minimal()
print(p5)

🔹 Giải thích code

geom_step(direction = “hv”) → biểu diễn thay đổi theo bước (horizontal-vertical) cho vốn chủ sở hữu.

geom_ribbon(aes(ymin = 0, ymax = tong_von_chu_so_huu/1e6), fill = “brown”, alpha = 0.2) → vùng tô từ 0 lên giá trị vốn (visual emphasis).

geom_text(…) → gắn nhãn (triệu VND).

🔹 Nhận xét

Xu hướng chung: Tổng vốn chủ sở hữu có xu hướng tăng trưởng dài hạn từ 22.1 triệu VND (Năm 2015) lên 35.2 triệu VND (Năm 2024).

Tăng trưởng ổn định (2015 - 2021): Vốn chủ sở hữu tăng liên tục, đạt đỉnh cục bộ là 32.6 triệu VND vào năm 2021.

Sụt giảm đột ngột (Năm 2022): Ghi nhận một sự sụt giảm rõ rệt từ 32.6 (2021) xuống còn 28.8 triệu VND vào năm 2022. Đây là điểm bất thường trong xu hướng tăng.

Phục hồi mạnh mẽ (2023 - 2024): Vốn chủ sở hữu phục hồi nhanh chóng và vượt qua mức đỉnh cũ, đạt 34 triệu VND (2023) và mức cao nhất 35.2 triệu VND vào năm 2024.

2.4.6 Biểu đồ 6: Biểu đồ so sánh Tổng tài sản và Cho vay

p6 <- ggplot(df) +
  geom_line(aes(x = ky_bao_cao, y = tong_tai_san/1e6, color = "Tổng tài sản"), size = 1.2) +
  geom_line(aes(x = ky_bao_cao, y = cho_vay_khach_hang/1e6, color = "Cho vay KH"), size = 1.2) +
  geom_point(aes(x = ky_bao_cao, y = tong_tai_san/1e6), color = "blue", size = 2) +
  geom_point(aes(x = ky_bao_cao, y = cho_vay_khach_hang/1e6), color = "red", size = 2) +
  scale_color_manual(values = c("Tổng tài sản" = "blue", "Cho vay KH" = "red")) +
  labs(title = "So sánh Tổng tài sản và Cho vay KH", 
       x = "Năm", y = "Giá trị (triệu VND)", color = "Chỉ tiêu") +
  theme_minimal()
print(p6)

🔹 Giải thích code

Vẽ hai geom_line() cho tong_tai_san/1e6 và cho_vay_khach_hang/1e6, đặt màu khác nhau.

scale_color_manual(…) → gán tên/ màu cho legend.

geom_point() để nhấn các điểm.

🔹 Nhận xét

Xu hướng chung: Cả Tổng tài sản và Cho vay KH đều có xu hướng tăng trưởng liên tục và mạnh mẽ trong toàn bộ giai đoạn 2015-2024.

Mối quan hệ: Hai chỉ tiêu này có mối quan hệ đồng biến mạnh. Khi Tổng tài sản tăng, Cho vay KH cũng tăng theo.

Giai đoạn tăng trưởng mạnh: Cả hai chỉ tiêu đều cho thấy sự tăng tốc rõ rệt trong những năm gần đây, đặc biệt là sau năm 2021.

2.4.7 Biểu đồ 7: Biểu đồ tỷ lệ Cho vay/Tổng tài sản

df$ty_le_cho_vay <- df$cho_vay_khach_hang / df$tong_tai_san * 100

p7 <- ggplot(df, aes(x = ky_bao_cao, y = ty_le_cho_vay)) +
  geom_col(fill = "orange", alpha = 0.7) +
  geom_line(color = "darkorange", size = 1) +
  geom_point(color = "darkorange", size = 2) +
  geom_text(aes(label = paste0(round(ty_le_cho_vay, 1), "%")), vjust = -0.5, size = 3) +
  geom_hline(yintercept = mean(df$ty_le_cho_vay), color = "red", linetype = "dashed") +
  labs(title = "Tỷ lệ Cho vay/Tổng tài sản", x = "Năm", y = "Tỷ lệ (%)") +
  theme_minimal()
print(p7)

🔹 Giải thích code

df\(ty_le_cho_vay <- df\)cho_vay_khach_hang / df$tong_tai_san * 100 → tính tỉ lệ % cho vay trên tài sản.

geom_col() + geom_line() + geom_point() → cột + đường hiển thị tỷ lệ theo năm.

geom_hline(yintercept = mean(…), …) → đường trung bình tỉ lệ.

🔹Nhận xét

Xu hướng chung: Tỷ lệ này có xu hướng tăng dần qua thời gian, từ 62.9% (Năm 2015) lên 65.1% (Năm 2024).

Đạt đỉnh: Tỷ lệ đạt mức cao nhất là 68% vào năm 2020 và 68.8% vào năm 2022.

Ổn định ở mức cao: Từ năm 2018 trở đi, tỷ lệ này ổn định ở mức trên 62% và thường xuyên vượt qua hoặc tiệm cận đường tham chiếu (đường đứt nét màu đỏ, khoảng 64-65%).

2.4.8 Biểu đồ 8: Biểu đồ scatter plot - Mối quan hệ Tổng tài sản và Lợi nhuận

p8 <- ggplot(df, aes(x = tong_tai_san/1e6, y = loi_nhuan_sau_thue/1e3)) +
  geom_point(color = "darkgreen", size = 3, alpha = 0.7) +
  geom_smooth(method = "lm", se = TRUE, color = "red", fill = "pink") +
  geom_text(aes(label = ky_bao_cao), vjust = -1, size = 3) +
  geom_rug(color = "gray") +
  labs(title = "Mối quan hệ Tổng tài sản và Lợi nhuận sau thuế",
       x = "Tổng tài sản (triệu VND)", y = "Lợi nhuận sau thuế (nghìn VND)") +
  theme_minimal()
print(p8)

🔹 Giải thích code

aes(x = tong_tai_san/1e6, y = loi_nhuan_sau_thue/1e3) → scatter giữa tổng tài sản (triệu) và lợi nhuận (nghìn).

geom_smooth(method = “lm”, se = TRUE, color = “red”, fill = “pink”) → đường hồi quy + vùng confidence.

geom_text(aes(label = ky_bao_cao)) → gắn nhãn năm.

geom_rug() → hiển thị phân bố dọc/ ngang ở biên plot.

🔹Nhận xét

Mối quan hệ: Có một mối quan hệ tuyến tính đồng biến (tích cực) rất mạnh giữa Tổng tài sản và Lợi nhuận sau thuế.

Ý nghĩa: Khi Tổng tài sản tăng lên (quy mô công ty mở rộng), Lợi nhuận sau thuế cũng có xu hướng tăng theo rõ rệt.

Sự phù hợp của mô hình: Đường hồi quy tuyến tính (màu đỏ) nằm gần như xuyên qua tất cả các điểm dữ liệu, và vùng tin cậy (màu hồng nhạt) khá hẹp, cho thấy mô hình này phù hợp rất tốt với dữ liệu.

2.4.9 Biểu đồ 9: Biểu đồ heatmap tương quan

cor_data <- df %>%
  select(tong_tai_san, cho_vay_khach_hang, tien_gui_cua_khach_hang, 
         loi_nhuan_sau_thue, tong_von_chu_so_huu) %>%
  cor()
names_viet <- c(
  "Tổng tài sản",
  "Cho vay khách hàng",
  "Tiền gửi khách hàng",
  "Lợi nhuận sau thuế",
  "Tổng vốn chủ sở hữu"
)
colnames(cor_data) <- names_viet
rownames(cor_data) <- names_viet

library(reshape2)
cor_melt <- melt(cor_data)

p9 <- ggplot(cor_melt, aes(x = Var1, y = Var2, fill = value)) +
  geom_tile(color = "white") +
  geom_text(aes(label = round(value, 2)), color = "white", size = 4) +
  scale_fill_gradient2(low = "blue", high = "red", mid = "white", midpoint = 0) +
  labs(title = "Ma trận tương quan các chỉ tiêu", x = "", y = "") +
  theme_minimal()
print(p9)

🔹 Giải thích code

cor() trên các chỉ tiêu tài chính → ma trận tương quan.

melt(cor_data) → chuyển sang dạng dài để ggplot vẽ

geom_tile(color = “white”) + geom_text(…) → ô màu với giá trị tương quan; scale_fill_gradient2(…) chọn màu hai đầu.

🔹 Nhận xét

Ma trận này cho thấy mối quan hệ giữa các chỉ tiêu: Tổng tài sản, Cho vay khách hàng, Tiền gửi khách hàng, Lợi nhuận sau thuế, và Tổng vốn chủ sở hữu.

Tương quan rất mạnh và cùng chiều: Tất cả các cặp chỉ tiêu trong ma trận đều cho thấy hệ số tương quan rất cao (từ 0.9 trở lên).

Hầu hết các hệ số tương quan đều nằm trong khoảng 0.95 đến 1.00.

Màu sắc đỏ đậm thống trị toàn bộ ma trận cũng củng cố điều này.

2.4.10 Biểu đồ 10: Biểu đồ thể hiện tỷ lệ an toàn vốn (CAR)

df$CAR <- df$tong_von_chu_so_huu / df$tong_tai_san * 100

p10 <- ggplot(df, aes(x = ky_bao_cao, y = CAR)) +
  geom_col(fill = "lightsteelblue", alpha = 0.8) +
  geom_line(aes(group = 1), color = "darkblue", size = 1.2) +
  geom_point(color = "darkblue", size = 2.5) +
  geom_text(aes(label = paste0(round(CAR, 1), "%")), vjust = -0.5, size = 3) +
  geom_hline(yintercept = 8, color = "red", linetype = "dashed", size = 1) +
  labs(title = "Tỷ lệ an toàn vốn (CAR)", 
       x = "Năm", y = "CAR (%)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p10)

🔹 Giải thích code

df\(CAR <- df\)tong_von_chu_so_huu / df$tong_tai_san * 100 → CAR %.

geom_col() + geom_line() + geom_point() + geom_text() → hiển thị CAR theo năm với nhãn.

geom_hline(yintercept = 8, …) → tham chiếu ngưỡng CAR = 8% (ví dụ chuẩn Basel).

🔹Nhận xét Xu hướng Tỷ lệ An toàn Vốn (CAR)

Xu hướng Giảm chung: Tỷ lệ CAR có xu hướng giảm dần trong toàn bộ giai đoạn, từ mức 7.6% (Năm 2015) xuống còn 4.8% (Năm 2024).

Tiệm cận Ngưỡng tối thiểu:

Ngưỡng quy định (đường đứt nét màu đỏ) là 8%. Tỷ lệ CAR của công ty luôn thấp hơn ngưỡng quy định trong suốt 10 năm.

Tỷ lệ này đã giảm đáng kể trong những năm gần đây, đặc biệt là sau năm 2021 (5.9%) và duy trì ở mức thấp (khoảng 4.8% - 5%) trong giai đoạn 2022-2024.

2.4.11 Biểu đồ 11: Biểu đồ radar/chart - So sánh năm 2024 và 2015

radar_data <- df %>%
  filter(ky_bao_cao %in% c("Năm 2024", "Năm 2015")) %>%
  group_by(ky_bao_cao) %>%
  summarise(
    tong_tai_san = mean(tong_tai_san, na.rm = TRUE),
    cho_vay_khach_hang = mean(cho_vay_khach_hang, na.rm = TRUE),
    tien_gui_cua_khach_hang = mean(tien_gui_cua_khach_hang, na.rm = TRUE),
    loi_nhuan_sau_thue = mean(loi_nhuan_sau_thue, na.rm = TRUE),
    tong_von_chu_so_huu = mean(tong_von_chu_so_huu, na.rm = TRUE)
  ) %>%
  ungroup()

# 🔹 Chỉ scale các cột số
radar_data_scaled <- radar_data %>%
  mutate(across(where(is.numeric), scale)) %>%
  rename(Year = ky_bao_cao)

# 🔹 Dạng long cho ggplot
radar_data_long <- radar_data_scaled %>%
  pivot_longer(-Year, names_to = "Variable", values_to = "Value")

# 🔹 Biểu đồ radar
p11 <- ggplot(radar_data_long, aes(x = Variable, y = Value, color = Year, group = Year)) +
  geom_point(size = 3) +
  geom_polygon(alpha = 0.2, fill = NA) +
  geom_line(size = 1) +
  coord_polar() +
  labs(title = "So sánh chỉ tiêu năm 2024 và 2015", x = "", y = "") +
  theme_minimal()

print(p11)

🔹 Giải thích code

Lọc 2 năm, chọn các chỉ tiêu, scale() chuẩn hóa (z-score).

pivot_longer() đưa về dạng dài cho ggplot.

coord_polar() + geom_polygon() + geom_line() + geom_point() → vẽ chart radar/giọt.

🔹 Nhận xét

Tăng trưởng Quy mô Khổng lồ: Tất cả 5 chỉ tiêu được so sánh đều cho thấy mức tăng trưởng rất lớn từ Năm 2015 đến Năm 2024.

Đường biểu diễn của Năm 2024 (màu xanh lam, chỉ là một điểm trung tâm nhỏ) hoàn toàn bị áp đảo bởi đường biểu diễn của Năm 2015 (màu đỏ)

Đồng đều về Tăng trưởng: Mức tăng trưởng (hoặc mức độ thay đổi) giữa hai năm là đồng đều ở cả 5 chỉ tiêu: Tổng vốn chủ sở hữu, Cho vay khách hàng, Lợi nhuận sau thuế, Tiền gửi của khách hàng, và Tổng tài sản. Tất cả các điểm trên đường cong đều nằm ở một bán kính tương tự

2.4.12 Biểu đồ 12: Biểu đồ thể hiện cấu trúc tài sản nợ/vốn chủ sở hữu

df$ty_le_no_VCSH <- (df$tong_tai_san - df$tong_von_chu_so_huu) / df$tong_von_chu_so_huu

p12 <- ggplot(df, aes(x = ky_bao_cao, y = ty_le_no_VCSH)) +
  geom_col(fill = "coral", alpha = 0.7) +
  geom_line(aes(group = 1), color = "darkred", size = 1.2) +
  geom_point(color = "darkred", size = 2.5) +
  geom_text(aes(label = round(ty_le_no_VCSH, 1)), vjust = -0.5, size = 3) +
  geom_hline(yintercept = mean(df$ty_le_no_VCSH), 
             color = "blue", linetype = "dashed", size = 1) +
  labs(title = "Tỷ lệ Nợ/Vốn chủ sở hữu", 
       x = "Năm", y = "Tỷ lệ Nợ/VCSH") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p12)

🔹 Giải thích code

df\(ty_le_no_VCSH <- (df\)tong_tai_san - df\(tong_von_chu_so_huu) / df\)tong_von_chu_so_huu → tỷ lệ nợ trên vốn.

geom_col() + geom_line() + geom_point() + geom_text() hiển thị theo năm.

geom_hline(yintercept = mean(…), …) → đường trung bình.

🔹 Nhận xét

Xu hướng Tăng chung: Tỷ lệ Nợ/VCSH có xu hướng tăng liên tục trong suốt giai đoạn từ năm 2015 (12.2) đến năm 2024 (19.6).

Vượt ngưỡng (2019-2024): Tỷ lệ này đã vượt qua đường tham chiếu (đường đứt nét màu xanh dương, khoảng 16) từ năm 2019 trở đi. Tăng tốc (2022-2024):

Tỷ lệ tăng đột biến từ năm 2021 (15.9) lên 19.4 vào năm 2022.

Mức cao nhất đạt được là 19.6 vào năm 2024.

2.4.13 Biểu đồ 13: Biểu đồ thể hiện mối quan hệ rủi ro - lợi nhuận

p13 <- ggplot(df, aes(x = tong_tai_san/1e6, y = loi_nhuan_sau_thue/1e3)) +
  geom_point(aes(size = cho_vay_khach_hang/tong_tai_san * 100, 
                 color = tong_von_chu_so_huu/tong_tai_san * 100), 
             alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, color = "red", linetype = "dashed") +
  geom_label_repel(aes(label = substring(ky_bao_cao, 5)), 
                   size = 3, box.padding = 0.5) +
  scale_size_continuous(name = "Tỷ lệ cho vay (%)", range = c(3, 8)) +
  scale_color_gradient(name = "Tỷ lệ VCSH (%)", low = "blue", high = "red") +
  labs(title = "Mối quan hệ Rủi ro - Lợi nhuận",
       x = "Tổng tài sản (triệu VND)", 
       y = "Lợi nhuận sau thuế (nghìn VND)") +
  theme_minimal()
print(p13)

🔹 Giải thích code

geom_point(aes(size = cho_vay_khach_hang/tong_tai_san * 100, color = tong_von_chu_so_huu/tong_tai_san * 100)) → kích thước điểm theo tỷ lệ cho vay, màu theo tỷ lệ vốn CSH.

geom_smooth(method = “lm”, se = FALSE, color = “red”, linetype = “dashed”) → đường hồi quy.

geom_label_repel(aes(label = substring(ky_bao_cao, 5))) → nhãn năm rút gọn, tránh chồng.

🔹 Nhận xét

Tương quan mạnh: Có một mối quan hệ đồng biến tuyến tính rất mạnh giữa Tổng tài sản và Lợi nhuận sau thuế (tức là quy mô càng lớn, lợi nhuận càng cao) . Đường xu hướng (đứt nét đỏ) thể hiện rõ điều này.

Tăng trưởng bùng nổ: Sự tăng trưởng quy mô và lợi nhuận diễn ra rất nhanh trong giai đoạn 2022 - 2024, với các điểm dữ liệu nằm xa và cao hơn so với giai đoạn trước.

Màu sắc chuyển từ Đỏ (tỷ lệ VCSH% cao) sang Xanh/Tím (tỷ lệ VCSH% thấp) theo thời gian, đặc biệt là sau năm 2021.

Kích cỡ điểm (Tỷ lệ Cho vay %) không biến động quá lớn, duy trì ở mức cao và ổn định qua các năm, cho thấy Cho vay KH luôn là hoạt động kinh doanh cốt lõi và chiếm tỷ trọng lớn trong tài sản.

2.4.14 biểu đồ 14: Biểu đồ thể hiện phân tích tương quan động

correlation_analysis <- df %>%
  arrange(ky_bao_cao) %>%
  mutate(
    cor_cho_vay_loi_nhuan = rollapply(
      data = cbind(cho_vay_khach_hang, loi_nhuan_sau_thue),
      width = 3,
      FUN = function(x) cor(x[,1], x[,2]),
      by.column = FALSE,
      fill = NA
    )
  )

p14 <- ggplot(correlation_analysis, aes(x = ky_bao_cao, y = cor_cho_vay_loi_nhuan)) +
  geom_col(aes(fill = cor_cho_vay_loi_nhuan), alpha = 0.8) +
  geom_line(aes(group = 1), color = "purple", size = 1.2) +
  geom_point(color = "purple", size = 2.5) +
  geom_text(aes(label = round(cor_cho_vay_loi_nhuan, 2)), 
            vjust = -0.5, size = 3) +
  scale_fill_gradient2(low = "red", mid = "white", high = "blue", 
                      midpoint = 0, limits = c(-1, 1)) +
  geom_hline(yintercept = 0, color = "black", size = 0.5) +
  geom_hline(yintercept = c(-0.5, 0.5), color = "gray", linetype = "dashed") +
  labs(title = "Tương quan động giữa Cho vay và Lợi nhuận (3 năm)",
       x = "Năm", y = "Hệ số tương quan", fill = "Tương quan") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p14)

🔹 Giải thích code

arrange(ky_bao_cao) đảm bảo thứ tự thời gian.

rollapply(…, width = 3, FUN = function(x) cor(x[,1], x[,2]) …) → tính hệ số tương quan trượt (3 năm) giữa cho_vay_khach_hang và loi_nhuan_sau_thue.

Vẽ geom_col() + geom_line() + geom_point() và dùng scale_fill_gradient2() để color theo giá trị tương quan; thêm các đường tham chiếu (y=0, ±0.5).

🔹 Nhận xét

Mối tương quan cực mạnh: Hệ số tương quan giữa Cho vay và Lợi nhuận là rất cao và luôn dương (đồng biến) trong suốt giai đoạn 2015-2024. Tăng dần và Ổn định ở mức đỉnh:

Hệ số tăng từ 0.65 (tính đến năm 2015) lên mức 0.97 (tính đến năm 2017).

Từ năm 2017 trở đi, hệ số tương quan duy trì ở mức cực kỳ cao, chủ yếu nằm trong khoảng 0.91 đến 1.00 (được tô màu xanh đậm/tím).

Điểm cao nhất là 1.00 (được tính đến năm 2018 và 2022).

2.4.15 Biểu đồ 15: Biểu đồ thể hiện mật độ phân phối

p15 <- ggplot(df, aes(x = tong_tai_san/1e6)) +
  geom_histogram(aes(y = ..density..), fill = "lightgreen", alpha = 0.7, bins = 6) +
  geom_density(color = "darkgreen", size = 1.2) +
  geom_rug(color = "red") +
  geom_vline(aes(xintercept = mean(tong_tai_san/1e6)), color = "blue", linetype = "dashed", size = 1) +
  geom_vline(aes(xintercept = median(tong_tai_san/1e6)), color = "red", linetype = "dashed", size = 1) +
  labs(title = "Phân phối Tổng tài sản", x = "Tổng tài sản (triệu VND)", y = "Mật độ") +
  theme_minimal()
print(p15)

🔹 Giải thích code

geom_histogram(aes(y = ..density..), bins = 6) → histogram chuẩn hoá theo mật độ.

geom_density() → đường mật độ mượt.

geom_rug() → hiển thị từng quan sát ở đáy . geom_vline(…) cho mean và median.

🔹 Nhận xét

Hình dạng Phân phối: Phân phối của Tổng tài sản nhìn chung là tương đối đối xứng (hoặc hơi lệch nhẹ sang phải/trái, tùy vào định nghĩa chính xác của đường mật độ).

Giá trị Trung tâm: Cả giá trị trung bình (Mean) (đường màu xanh dương) và giá trị trung vị (Median) (đường màu đỏ) đều nằm rất gần nhau và tập trung xung quanh khoảng 480 - 500 triệu VND.

Việc Trung bình và Trung vị gần nhau củng cố nhận định về tính đối xứng của dữ liệu, cho thấy ít có giá trị ngoại lai (outliers) quá lớn hoặc quá nhỏ gây méo mó phân phối.

2.4.16 Biểu đồ 16: Biểu đồ thể hiện tích lũy

cumulative_data <- df %>%
  arrange(ky_bao_cao) %>%
  mutate(cum_tong_tai_san = cumsum(tong_tai_san)/1e6,
         cum_loi_nhuan = cumsum(loi_nhuan_sau_thue)/1e3)

p16 <- ggplot(cumulative_data, aes(x = ky_bao_cao)) +
  geom_line(aes(y = cum_tong_tai_san, color = "Tổng tài sản"), size = 1.2) +
  geom_line(aes(y = cum_loi_nhuan, color = "Lợi nhuận"), size = 1.2) +
  geom_point(aes(y = cum_tong_tai_san), color = "blue", size = 2) +
  geom_point(aes(y = cum_loi_nhuan), color = "red", size = 2) +
  geom_area(aes(y = cum_tong_tai_san), fill = "blue", alpha = 0.1) +
  scale_color_manual(values = c("Tổng tài sản" = "blue", "Lợi nhuận" = "red")) +
  labs(title = "Giá trị tích lũy qua các năm", x = "Năm", y = "Giá trị tích lũy", color = "Chỉ tiêu") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p16)

🔹 Giải thích code cum_tong_tai_san = cumsum(tong_tai_san)/1e6 và cum_loi_nhuan = cumsum(loi_nhuan_sau_thue)/1e3 → tích lũy theo thứ tự thời gian.

Vẽ hai đường tích lũy, điểm, và geom_area() cho tổng tài sản để nhấn.

🔹 Nhận xét Xu hướng Tăng chung: Cả Lợi nhuận tích lũy (màu đỏ) và Tổng tài sản tích lũy (màu xanh dương) đều có xu hướng tăng trưởng liên tục và mạnh mẽ qua các năm . Lợi nhuận Tích lũy (Màu đỏ): Tăng trưởng đột phá và có độ dốc lớn hơn nhiều so với Tổng tài sản tích lũy, đặc biệt là trong giai đoạn cuối (2022-2024). Điều này cho thấy công ty đã tạo ra tổng lợi nhuận rất lớn qua các năm, với sự tăng trưởng mạnh mẽ nhất vào giai đoạn gần đây.

Tổng Tài sản Tích lũy (Màu xanh dương): Tăng trưởng ổn định nhưng với tốc độ chậm hơn so với lợi nhuận tích lũy.

Chênh lệch: Khoảng cách giữa Lợi nhuận tích lũy và Tổng tài sản tích lũy ngày càng mở rộng theo thời gian.

2.4.17 Biểu đồ 17: Biểu đồ thể cơ cấu tài sản năm 2023

library(dplyr)
library(ggplot2)
library(RColorBrewer)

# Dữ liệu năm 2023 không có "Vay TCTD khác"
du_lieu_2023 <- data.frame(
  chi_tieu = c("Cho vay khách hàng", "Tiền gửi của khách hàng",
               "Chứng khoán đầu tư", "Tài sản khác"),
  gia_tri = c(438411368, 536873344, 71936877,
              674374966 - (438411368 + 536873344 + 71936877))
)

set3_colors <- brewer.pal(n = 4, name = "Set3")

du_lieu_2023 <- du_lieu_2023 %>%
  mutate(gia_tri = abs(gia_tri),
         phan_tram = gia_tri / sum(gia_tri) * 100,
         label = paste0(round(phan_tram, 1), "%"),
         ma_mau = set3_colors)

# Vẽ pie chart (chỉ hiện % trên lát cắt)
ggplot(du_lieu_2023, aes(x = "", y = phan_tram, fill = chi_tieu)) +
  geom_bar(stat = "identity", width = 1, color = "white") +
  coord_polar("y", start = 0) +
  geom_text(aes(label = label),
            position = position_stack(vjust = 0.5),
            size = 4, color = "black", fontface = "bold") +
  scale_fill_manual(values = setNames(set3_colors, du_lieu_2023$chi_tieu)) +
  labs(
    title = "BIỂU ĐỒ CƠ CẤU TÀI SẢN - NĂM 2023",
    fill = "Các khoản mục"
  ) +
  theme_void() +  
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold", size = 14),
    plot.subtitle = element_text(hjust = 0.5, size = 12),
    legend.position = "right"
  )

Giải thích code: - geom_bar(…, stat = “identity”) → tạo cột theo giá trị thực (dùng để xoay thành lát tròn).

  • coord_polar(“y”) → chuyển từ biểu đồ cột sang biểu đồ tròn.

-mcolor = “white” → viền = trắng ngăn cách các phần.

  • geom_text(aes(label = label): Hiển thị % của từng phần ngay bên trong lát cắt, căn giữa (vjust = 0.5).

  • scale_fill_manual() → dùng chính xác màu Set3 cho từng hạng mục.

  • labs() → đặt tiêu đề, chú thích và ghi chú tổng tài sản (định dạng có dấu phẩy ngăn cách).

Nhận xét:

  • Tiền gửi của khách hàng chiếm tỷ trọng lớn nhất (37.8%), cho thấy nguồn vốn chủ yếu của ngân hàng đến từ khoản mục này.

  • Cho vay khách hàng đứng thứ hai (30.9%), thể hiện vai trò trọng yếu của hoạt động cho vay trong tổng tài sản.

  • Tài sản khác cũng chiếm tỷ lệ đáng kể (26.3%), phản ánh quy mô các tài sản không nằm trong ba khoản mục chính còn lại.

  • Chứng khoán đầu tư chỉ chiếm một phần nhỏ (5.1%), cho thấy đầu tư vào chứng khoán không phải là mảng trọng tâm của cấu trúc tài sản.

2.4.18 Biểu đồ 18: Biểu đồ thể hiện biến động theo mùa

p18 <- ggplot(df, aes(x = factor(ky_bao_cao), group = 1)) +
  geom_line(aes(y = tong_tai_san/1e6, color = "Tổng tài sản"), size = 1.2) +
  geom_line(aes(y = cho_vay_khach_hang/1e6, color = "Cho vay"), size = 1.2) +
  geom_line(aes(y = tien_gui_cua_khach_hang/1e6, color = "Tiền gửi"), size = 1.2) +
  geom_point(aes(y = tong_tai_san/1e6), color = "blue", size = 2) +
  geom_point(aes(y = cho_vay_khach_hang/1e6), color = "red", size = 2) +
  geom_point(aes(y = tien_gui_cua_khach_hang/1e6), color = "green", size = 2) +
  scale_color_manual(values = c("Tổng tài sản" = "blue", "Cho vay" = "red", "Tiền gửi" = "green")) +
  labs(title = "Biến động các chỉ tiêu qua các năm", x = "Năm", y = "Giá trị (triệu VND)", color = "Chỉ tiêu") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
print(p18)

🔹 Giải thích code

Vẽ cùng lúc 3 geom_line() cho tong_tai_san/1e6, cho_vay_khach_hang/1e6, tien_gui_cua_khach_hang/1e6 với màu khác nhau bằng scale_color_manual(). geom_point() để nhấn từng đường.

🔹 Nhận xét Tăng trưởng Quy mô & Hoạt động Cốt lõi: Các chỉ tiêu cốt lõi như Tổng tài sản, Cho vay khách hàng, Tiền gửi khách hàng đều tăng trưởng liên tục và mạnh mẽ qua các năm. Biểu đồ Biến động các chỉ tiêu qua các năm cho thấy sự tăng trưởng đồng bộ của 3 chỉ tiêu này (Cho vay < Tiền gửi < Tổng tài sản).

Tổng vốn chủ sở hữu duy trì xu hướng tăng trưởng dài hạn, mặc dù bị sụt giảm tạm thời vào năm 2022 (-11,70%), nhưng đã phục hồi mạnh mẽ vào năm 2023-2024 (đạt mức tăng trưởng cao nhất 17,98% vào 2023).

2.4.19 Biểu đồ 19: Biểu đồ thể hiện phần trăm thay đổi so với năm gốc

base_year <- df %>% 
  filter(grepl("2015", ky_bao_cao)) %>% 
  pull(tong_tai_san) %>% 
  first()

df <- df %>%
  mutate(pct_change = (tong_tai_san - base_year) / base_year * 100)
p19 <- ggplot(df, aes(x = ky_bao_cao, y = pct_change)) +
  geom_col(fill = "lightcoral", alpha = 0.7) +
  geom_line(color = "red", size = 1.2, group = 1) +  # thêm group=1 để nối các điểm
  geom_point(color = "red", size = 2.5) +
  geom_text(aes(label = paste0(round(pct_change, 1), "%")), vjust = -0.5, size = 3) +
  geom_hline(yintercept = 0, color = "black", size = 0.5) +
  labs(title = "Phần trăm thay đổi Tổng tài sản so với năm 2015",
       x = "Năm", y = "Thay đổi (%)") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

print(p19)

🔹 Giải thích code

base_year <- df\(tong_tai_san[df\)ky_bao_cao == “Năm 2015”] → lấy giá trị gốc (năm 2015).

df\(pct_change <- (df\)tong_tai_san - base_year) / base_year * 100 → tính % thay đổi so với nền tảng.

Vẽ geom_col() + geom_line() + geom_point() + geom_text(); geom_hline(yintercept = 0) so sánh tăng/giảm.

Nhận xét

Tổng tài sản liên tiếp tăng qua từng năm, không hề có dấu hiệu giảm hoặc đi ngang trong suốt giai đoạn phân tích.

Xu hướng tăng mạnh từ sau năm 2020, cụ thể: năm 2021 đạt gần 90%, năm 2022 vượt 100%, các năm tiếp theo tăng vọt lên 130% và 149%.​

Mức tăng trưởng tuyệt đối vượt trội cho thấy doanh nghiệp/tổ chức có chiến lược mở rộng rõ rệt hoặc tận dụng tốt các cơ hội thị trường.

Không xuất hiện thời kỳ giảm sút tài sản; tốc độ tăng đều, phản ánh hoạt động kinh doanh/tài chính ổn định.

2.4.20 Biểu đồ 20: Biểu đồ thể hiện tương quan đa biến

p20 <- ggplot(df, aes(x = cho_vay_khach_hang/1e6, y = tien_gui_cua_khach_hang/1e6)) +
  geom_point(aes(size = loi_nhuan_sau_thue/1e3, color = tong_von_chu_so_huu/1e6), alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, color = "red") +
  geom_text(aes(label = substring(ky_bao_cao, 5)), vjust = -1, size = 3) +
  scale_size_continuous(name = "Lợi nhuận (nghìn)") +
  scale_color_gradient(name = "Vốn CSH (triệu)", low = "blue", high = "red") +
  labs(title = "Mối quan hệ đa biến giữa các chỉ tiêu",
       x = "Cho vay KH (triệu VND)", y = "Tiền gửi KH (triệu VND)") +
  theme_minimal()
print(p20)

🔹 Giải thích code

aes(x = cho_vay_khach_hang/1e6, y = tien_gui_cua_khach_hang/1e6) → scatter giữa cho vay và tiền gửi (triệu).

aes(size = loi_nhuan_sau_thue/1e3, color = tong_von_chu_so_huu/1e6) → kích thước đại diện cho lợi nhuận (nghìn), màu cho vốn CSH (triệu).

geom_smooth(method = “lm”, se = FALSE) → đường hồi quy chung.

geom_text(aes(label = substring(ky_bao_cao, 5))) → gắn nhãn năm rút gọn.

🔹 Nhận xét

Biểu đồ thể hiện mối quan hệ tuyến tính đồng biến rất mạnh giữa cho vay khách hàng và tiền gửi khách hàng, khi hai biến này tăng gần như song song theo thời gian.

Các điểm dữ liệu dịch chuyển rõ rệt từ góc dưới trái (2015) lên góc trên phải (2024), phản ánh quy mô hoạt động tín dụng và huy động vốn đều tăng trưởng liên tục.

Đồng thời, kích thước điểm (lợi nhuận) và màu sắc (vốn chủ sở hữu) cũng tăng dần, cho thấy doanh nghiệp không chỉ mở rộng quy mô mà còn nâng cao hiệu quả sinh lời và tích lũy vốn, thể hiện sức mạnh tài chính ngày càng vững chắc qua các năm.