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 Kích thước bộ dữ liệu

# Đọc dữ liệu
data <- read.csv("C:/Users/adminn/Downloads/Sales_Orders_Data.csv", header = TRUE)
# 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

1.1.2 Kiểm tra vài dòng đầu tiên

cat("Xem vài dòng đầu:\n"); print(head(data))
## Xem vài dòng đầu:
##   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
##   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

1.1.3 Kiểm tra vài dòng cuối

cat("Xem vài dòng cuối:\n"); print(tail(data))
## Xem vài dòng cuối:
##          Order_ID Customer_ID Customer_Type      Product            Category
## 1048570 ORD349192       CUS25           B2C  Havana Club Alcoholic Beverages
## 1048571 ORD349192       CUS25           B2C      Bacardi Alcoholic Beverages
## 1048572 ORD349192       CUS25           B2C   Fritz-Kola         Soft Drinks
## 1048573 ORD349193     CUS2035           B2C Volvic Touch               Water
## 1048574 ORD349193     CUS2035           B2C       Vittel               Water
## 1048575 ORD349193     CUS2035           B2C        Fanta         Soft Drinks
##         Unit_Price Quantity Discount Total_Price         Region Order_Date
## 1048570      12.96        9        0      116.64  Niedersachsen 27/08/2022
## 1048571      13.84        3        0       41.52  Niedersachsen 27/08/2022
## 1048572       2.05        2        0        4.10  Niedersachsen 27/08/2022
## 1048573       1.46       11        0       16.06 Sachsen-Anhalt 05/11/2023
## 1048574       0.59        2        0        1.18 Sachsen-Anhalt 05/11/2023
## 1048575       1.23       15        0       18.45 Sachsen-Anhalt 05/11/2023

1.1.4 Kiểm tra số quan sát

cat("Số quan sát (dòng):", nrow(data), "\n")
## Số quan sát (dòng): 1048575

1.1.5 Kiểm tra số biến

cat("Số biến (cột):", ncol(data), "\n")
## Số biến (cột): 11

1.1.6 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.7 Cấu trúc dữ liệu

cat("=== CẤU TRÚC DỮ LIỆU ===\n")
## === CẤU TRÚC DỮ LIỆU ===
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" ...
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

1.1.8 Các biến định tính

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

1.1.9 Các biến định lượng

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

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

GIẢI THÍCH PHẦN 2:

Đoạn code R đầu tiên thực hiện các bước kiểm tra cơ bản để đánh giá chất lượng và quy mô của bộ dữ liệu. Kết quả từ các lệnh nrow, ncol, sum(duplicated(data)) và sapply(…) cho thấy:

  • Bộ dữ liệu rất lớn, bao gồm 1,048,575 giao dịch và 11 đặc điểm (cột).

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 các biến 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),
    Revenue_Before_Discount = Unit_Price * Quantity,
    Discount_Amount = Revenue_Before_Discount * Discount)

🔹 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 đó.

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á).

🔹 Ý nghĩa thống kê:

Đoạn code này giúp tạo thêm các biến về thời gian và doanh thu, từ đó dễ phân tích xu hướng bán hàng theo năm, quý, tháng, hoặc ngày, và đánh giá tác động của chiết khấu đến doanh thu.

1.2.5 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() → hoạt động giống câu lệnh if–else, 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.6 Mã hóa cột Oder_size

library(dplyr)

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

head(data,5)
##   Order_ID Customer_ID Customer_Type            Product    Category Unit_Price
## 1     ORD1     CUS1496           B2B         Vio Wasser       Water       1.66
## 2     ORD1     CUS1496           B2B              Evian       Water       1.56
## 3     ORD1     CUS1496           B2B             Sprite Soft Drinks       1.17
## 4     ORD1     CUS1496           B2B Rauch Multivitamin      Juices       3.22
## 5     ORD1     CUS1496           B2B       Gerolsteiner       Water       0.87
##   Quantity Discount Total_Price            Region Order_Date   Month Year
## 1       53     0.10       79.18 Baden-Württemberg 2023-08-23 2023-08 2023
## 2       90     0.10      126.36 Baden-Württemberg 2023-08-23 2023-08 2023
## 3       73     0.05       81.14 Baden-Württemberg 2023-08-23 2023-08 2023
## 4       59     0.10      170.98 Baden-Württemberg 2023-08-23 2023-08 2023
## 5       35     0.10       27.40 Baden-Württemberg 2023-08-23 2023-08 2023
##   Quarter Day_of_Week Revenue_Before_Discount Discount_Amount Is_High_Discount
## 1      Q3   Wednesday                   87.98          8.7980            FALSE
## 2      Q3   Wednesday                  140.40         14.0400            FALSE
## 3      Q3   Wednesday                   85.41          4.2705            FALSE
## 4      Q3   Wednesday                  189.98         18.9980            FALSE
## 5      Q3   Wednesday                   30.45          3.0450            FALSE
##   Discount_Category Order_Size
## 1   Medium Discount      Small
## 2   Medium Discount     Medium
## 3      Low Discount      Small
## 4   Medium Discount     Medium
## 5   Medium Discount      Small

🔹 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:

< 100 → “Small”

< 500 → “Medium”

< 1000 → “Large”

Còn lại → “Very Large”

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.7 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'
  )

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>         <dbl>           <dbl>
##  1 B2B           Baden-Württemberg            7399      6296401.            282.
##  2 B2B           Bayern                       7453      6426283.            286.
##  3 B2B           Berlin                       7725      6880328.            298.
##  4 B2B           Brandenburg                  7403      6525847.            292.
##  5 B2B           Bremen                       7977      5761768.            241.
##  6 B2B           Hamburg                      8705      7480221.            287.
##  7 B2B           Hessen                       8337      7249384.            289.
##  8 B2B           Mecklenburg-Vorpomm…         8225      7227687.            295.
##  9 B2B           Niedersachsen                7248      6109817.            278.
## 10 B2B           Nordrhein-Westfalen          7523      6060823.            270.
## # ℹ 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:

Total_Orders: tổng số đơn hàng khác nhau (n_distinct(Order_ID))

Total_Revenue: tổng doanh thu (sum(Total_Price))

Avg_Order_Value: giá trị trung bình mỗi đơn hàng (mean(Total_Price))

.groups = ‘drop’ → bỏ nhóm sau khi tóm tắt, trả về bảng gọn hơn.

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í dụ: cá nhân, doanh nghiệp) 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.8 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'
  )

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>            <int>         <dbl>          <dbl>
##  1 Alcoholic Beverages 2021-01         170963      2973048.           17.4
##  2 Alcoholic Beverages 2021-02         156497      2683922.           17.8
##  3 Alcoholic Beverages 2021-03         168305      2812860.           17.7
##  4 Alcoholic Beverages 2021-04         170120      2815952.           17.6
##  5 Alcoholic Beverages 2021-05         167744      2865023.           17.5
##  6 Alcoholic Beverages 2021-06         172310      2910454.           17.4
##  7 Alcoholic Beverages 2021-07         171715      2841055.           17.3
##  8 Alcoholic Beverages 2021-08         170586      2948309.           17.5
##  9 Alcoholic Beverages 2021-09         162690      2784813.           17.3
## 10 Alcoholic Beverages 2021-10         170464      2906880.           17.7

🔹 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:

Total_Quantity: tổng số lượng sản phẩm bán ra trong tháng.

Total_Revenue: tổng doanh thu trong tháng.

Avg_Unit_Price: giá bán trung bình của sản phẩm.

.groups = ‘drop’ → bỏ cấu trúc nhóm sau khi tóm tắt, giúp bảng gọn hơn.

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.9 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'
  )

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>                     <int>         <dbl>           <dbl>
## 1 0%                       674968     32189768.            47.7
## 2 0-5%                     168122     28801144.           171. 
## 3 5-10%                    161028     57373493.           356. 
## 4 10-15%                    44457     18976217.           427.

🔹 Giải thích:

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

0%, 0–5%, 5–10%, 10–15%, >15%.

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

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

Number_of_Orders: tổng số đơn hàng.

Total_Revenue: tổng doanh thu.

Avg_Order_Value: giá trị trung bình mỗi đơn hàng.

.groups = ‘drop’ → loại bỏ cấu trúc nhóm khi xuất kết quả.

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.10 Phân tổ theo doanh thu và khu vực

# Phân tổ doanh thu theo khu vực - Cơ bản
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))
print(phan_to_doanh_thu)
## # A tibble: 16 × 4
##    Region                 Tong_doanh_thu Doanh_thu_trung_binh So_don_hang
##    <fct>                           <dbl>                <dbl>       <int>
##  1 Hamburg                      9619253.                 137.       70310
##  2 Hessen                       9181452.                 145.       63475
##  3 Mecklenburg-Vorpommern       9120188.                 142.       64038
##  4 Saarland                     9020347.                 136.       66260
##  5 Rheinland-Pfalz              9011789.                 133.       67849
##  6 Berlin                       8879189.                 139.       64014
##  7 Thüringen                    8734228.                 134.       64979
##  8 Bayern                       8430479.                 130.       64643
##  9 Brandenburg                  8402955.                 136.       61977
## 10 Niedersachsen                8320694.                 123.       67657
## 11 Sachsen-Anhalt               8251296.                 128.       64333
## 12 Baden-Württemberg            8237277.                 128.       64249
## 13 Sachsen                      8213791.                 123.       66721
## 14 Schleswig-Holstein           8193415.                 124.       65841
## 15 Nordrhein-Westfalen          8139463.                 124.       65772
## 16 Bremen                       7584805.                 114.       66457

🔹 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)

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

🔹 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ệ. → Là bước nền tảng để hiểu dữ liệu trước khi đi vào phân tích xu hướng hoặc mô hình hóa thống kê.

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

cat("=== DOANH THU TRUNG BÌNH THEO LOẠI KHÁCH HÀNG ===\n")
## === DOANH THU TRUNG BÌNH 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))
print(customer_summary)
## # A tibble: 2 × 4
##   Customer_Type Mean_Revenue Total_Revenue So_Don_Hang
##   <fct>                <dbl>         <dbl>       <int>
## 1 B2B                  281.     105150854.      373607
## 2 B2C                   47.7     32189768.      674968

🔹 Giải thích:

  • group_by(Customer_Type) → gom nhóm dữ liệu theo từng loại khách hàng (ví dụ: cá nhân, doanh nghiệp, thành viên VIP,…).
  • summarise() → tính các chỉ tiêu thống kê cơ bản cho từng nhóm:
    • Mean_Revenue: doanh thu trung bình mỗi khách hàng.
    • Total_Revenue: tổng doanh thu của nhóm khách hàng đó.
    • So_Don_Hang: tổng số đơn hàng trong 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

cat("\n=== XU HƯỚNG DOANH THU THEO THÁNG ===\n")
## 
## === XU HƯỚNG DOANH THU THEO THÁNG ===
monthly_revenue <- data %>%
  group_by(Month) %>%
  summarise(Total_Revenue = sum(Total_Price, na.rm = TRUE))

ggplot(monthly_revenue, aes(x = Month, y = Total_Revenue, group = 1)) +
  geom_line(color = "blue", linewidth = 1.2) +
  geom_point(color = "red", size = 2) +
  scale_y_continuous(labels = comma) +
  labs(title = "Xu hướng doanh thu theo tháng",
       x = "Tháng", y = "Tổng doanh thu") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

🔹 Giải thích:

group_by(Customer_Type) → gom nhóm dữ liệu theo loại khách hàng (ví dụ: khách mới, khách thân thiết…).

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

Mean_Revenue: doanh thu trung bình của mỗi loại khách hàng.

Total_Revenue: tổng doanh thu đóng góp bởi từng nhóm khách hàng.

So_Don_Hang: số lượng đơn hàng của nhóm đó.

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 phối doanh thu

ggplot(data, aes(x = Total_Price)) +
  geom_histogram(bins = 50, fill = "steelblue", alpha = 0.7) +
  scale_x_continuous(labels = comma) +
  labs(title = "Phân phối doanh thu",
       subtitle = "Biểu đồ histogram thể hiện phân phối giá trị đơn hàng",
       x = "Doanh thu (Total_Price)", y = "Số lượng đơn hàng") +
  theme_minimal()

🔹 Giải thích:

ggplot(data, aes(x = Total_Price)) → khởi tạo biểu đồ ggplot với trục hoành là biến doanh thu (Total_Price).

geom_histogram(bins = 50, fill = “steelblue”, alpha = 0.7) → vẽ biểu đồ tần suất (histogram) với 50 cột, màu xanh dương và độ trong suốt 0.7 để dễ nhìn.

scale_x_continuous(labels = comma) → định dạng trục X theo dấu phẩy ngăn cách hàng nghìn (vd: 10,000 thay vì 10000).

labs() → đặt tiêu đề, phụ đề, tên trục X (Doanh thu) và trục Y (Số lượng đơn hàng).

theme_minimal() → áp dụng giao diện tối giản, giúp biểu đồ rõ ràng và chuyên nghiệp.

🔹 Ý nghĩa thống kê:

Biểu đồ histogram giúp quan sát trực quan phân phối doanh thu giữa các đơn hàng:

Nếu cột tập trung bên trái → nhiều đơn hàng giá trị thấp (phân phối lệch phải). → Đây là bước quan trọng để hiểu cấu trúc dữ liệu doanh thu, trước khi áp dụng các phân tích thống kê hay mô hình hóa nâng cao.

1.3.1.5 Phát hiện ngoại lệ

ggplot(data, aes(y = Total_Price)) +
  geom_boxplot(fill = "orange", alpha = 0.6) +
  scale_y_continuous(labels = comma) +
  labs(title = "Boxplot doanh thu", y = "Doanh thu (Total_Price)") +
  theme_minimal()

🔹 Giải thích:

ggplot(data, aes(y = Total_Price)) → chọn biến Total_Price làm trục tung (Y) để vẽ biểu đồ boxplot.

geom_boxplot(fill = “orange”, alpha = 0.6) → tạo biểu đồ hộp (boxplot), màu cam trong suốt 60%.

scale_y_continuous(labels = comma) → định dạng trục tung có dấu phẩy phân cách hàng nghìn (dễ đọc hơn).

labs(title = “Boxplot doanh thu”, y = “Doanh thu (Total_Price)”) → thêm tiêu đề và nhãn trục tung.

theme_minimal() → dùng giao diện tối giản, giúp biểu đồ rõ ràng và hiện đại.

🔹 Ý nghĩa thống kê:

Boxplot cho thấy phân bố, mức độ phân tán và các giá trị ngoại lai (outliers) của doanh thu.

Đường giữa hộp (median) biểu thị trung vị doanh thu – mức điển hình nhất.

Chiều dài hộp (IQR) thể hiện khoảng biến thiên của 50% dữ liệu giữa phân vị 25% và 75%.

Các chấm nằm ngoài hộp là đơn hàng có giá trị bất thường cao (outlier), thường chiếm tỷ lệ nhỏ nhưng ảnh hưởng lớn đến doanh thu tổng.

Kết hợp với histogram ở trên, có thể thấy đa số đơn hàng nhỏ, nhưng một số đơn hàng giá trị rất lớn kéo phân phối lệch phải.

1.3.1.6 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")

  ggplot(data, aes(x = Discount, y = Total_Price)) +
    geom_point(alpha = 0.4, color = "darkgreen") +
    geom_smooth(method = "lm", color = "red", se = FALSE) +
    labs(title = "Tương quan giữa mức chiết khấu và doanh thu",
         x = "Tỷ lệ chiết khấu", y = "Doanh thu (Total_Price)") +
    theme_minimal()
}
## 
## === 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.

Biểu đồ tán xạ giúp quan sát trực quan: dữ liệu phân bố rải rác hay có xu hướng tuyến tính rõ ràng.

1.3.1.7 Phân loại doanh thu (Revenue Segmentation)

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")))

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'
  )

cat("\n=== PHÂN LOẠI DOANH THU THEO NHÓM ===\n")
## 
## === PHÂN LOẠI DOANH THU THEO NHÓM ===
print(revenue_group_summary)
## # A tibble: 4 × 3
##   Revenue_Group So_Don_Hang Doanh_Thu_Trung_Binh
##   <fct>               <int>                <dbl>
## 1 Thấp               842596                 23.2
## 2 Trung bình         155134                202. 
## 3 Cao                 24442                699. 
## 4 Rất cao             26403               2626.

🔹 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:

0–100: Thấp

100–500: Trung bình

500–1000: Cao

1000: Rất cao

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:

So_Don_Hang = n() → đếm số đơn hàng thuộc mỗi nhóm.

Doanh_Thu_Trung_Binh = mean(Total_Price, na.rm = TRUE) → tính doanh thu trung bình của nhóm.

arrange() không có ở đây nhưng nếu thêm, có thể sắp xếp nhóm theo doanh thu hoặc số đơn hàng.

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

🔹 Ý 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.

Đây là bước phân tích mô tả quan trọng, giúp hiểu rõ cấu trúc doanh thu của toàn bộ dữ liệu..

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ả:

So_Don_Hang: tổng số đơn của mỗi loại khách.

Tong_Doanh_Thu: tổng doanh thu.

Doanh_Thu_Trung_Binh: giá trị trung bình mỗi đơn.

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

#Biểu đồ cột – số lượng đơn hàng
ggplot(customer_stats, aes(x = reorder(Customer_Type, -So_Don_Hang), y = So_Don_Hang, fill = Customer_Type)) +
  geom_col(show.legend = FALSE) +
  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(customer_stats, aes(x = reorder(Customer_Type, -So_Don_Hang), y = So_Don_Hang, fill = Customer_Type)) → 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.

theme_minimal() → giao diện biểu đồ gọn gàng, tối giản.

🔹 Ý 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.

#Biểu đồ tròn
ggplot(customer_stats, aes(x = "", y = Ty_Le_Don_Hang, fill = Customer_Type)) +
  geom_col(width = 1) +
  coord_polar(theta = "y") +
  labs(title = "Tỷ lệ loại khách hàng (%)") +
  theme_void()

🔹 Giải thích code:

ggplot(customer_stats, aes(x = ““, y = Ty_Le_Don_Hang, fill = Customer_Type)) → 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 đồ.

theme_void() → loại bỏ trục, lưới, nhãn để biểu đồ tròn gọn gàng.

🔹 Ý 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.

####So sánh doanhn thu phân phối theo loại khách hàng

ggplot(data, aes(x = Customer_Type, y = Total_Price, fill = Customer_Type)) +
  geom_boxplot(alpha = 0.6) +
  scale_y_continuous(labels = scales::comma) +
  labs(title = "Phân phối doanh thu theo loại khách hàng", x = "Loại khách hàng", y = "Doanh thu (Total_Price)") +
  theme_minimal()

🔹 Giải thích code:

ggplot(data, aes(x = Customer_Type, y = Total_Price, fill = Customer_Type)) → tạo biểu đồ, trục x là loại khách hàng, trục y là doanh thu từng đơn hàng, màu cột theo loại khách hàng.

geom_boxplot(alpha = 0.6) → vẽ biểu đồ hộp, alpha = 0.6 làm cột hơi trong suốt để dễ nhìn.

scale_y_continuous(labels = scales::comma) → hiển thị trục y với dấu phân cách hàng nghìn, dễ đọc số lớn.

labs(title = “Phân phối doanh thu theo loại khách hàng”, x = “Loại khách hàng”, y = “Doanh thu (Total_Price)”) → đặt tiêu đề và nhãn trục.

theme_minimal() → giao diện biểu đồ gọn gàng, tối giản.

🔹 Ý nghĩa thống kê:

Biểu đồ hộp thể hiện phân phối doanh thu từng đơn hàng theo loại khách hàng, bao gồm: trung vị, tứ phân vị và các giá trị ngoại lai (outlier).

Giúp nhận biết:

Nhóm khách hàng nào có doanh thu trung bình cao nhất.

Nhóm nào có sự biến thiên doanh thu lớn (có nhiều đơn hàng giá trị cao/thấp bất thường).

Đây là công cụ quan trọng để phân tích hành vi chi tiêu của khách hàng và ra quyết định marketing, khuyến mãi phù hợp.

1.3.2.3 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
# Biểu đồ so sánh doanh thu
ggplot(customer_summary, aes(x = Customer_Type, y = Total_Revenue, fill = Customer_Type)) +
  geom_bar(stat = "identity") +
  scale_y_continuous(labels = comma) +
  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(x = Customer_Type, y = Total_Revenue, fill = Customer_Type) → 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.

theme_minimal() → theme đơn giản, gọn gàng.

theme(legend.position = “none”) → ẩn chú giải màu (vì trục X đã thể hiện loại khách hàng).

🔹 Ý 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)

# Phân tích hiệu suất theo khu vực địa lý
region_summary <- data %>%
  group_by(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'
  ) %>%
  arrange(desc(Total_Revenue))                  # Sắp xếp theo doanh thu giảm dần

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 ===
print(region_summary)
## # A tibble: 16 × 4
##    Region                 Total_Orders Total_Revenue Avg_Order_Value
##    <fct>                         <int>         <dbl>           <dbl>
##  1 Hamburg                       23426      9619253.            137.
##  2 Hessen                        21071      9181452.            145.
##  3 Mecklenburg-Vorpommern        21414      9120188.            142.
##  4 Saarland                      22011      9020347.            136.
##  5 Rheinland-Pfalz               22668      9011789.            133.
##  6 Berlin                        21284      8879189.            139.
##  7 Thüringen                     21830      8734228.            134.
##  8 Bayern                        21476      8430479.            130.
##  9 Brandenburg                   20570      8402955.            136.
## 10 Niedersachsen                 22428      8320694.            123.
## 11 Sachsen-Anhalt                21416      8251296.            128.
## 12 Baden-Württemberg             21317      8237277.            128.
## 13 Sachsen                       22213      8213791.            123.
## 14 Schleswig-Holstein            21976      8193415.            124.
## 15 Nordrhein-Westfalen           21978      8139463.            124.
## 16 Bremen                        22115      7584805.            114.
# Biểu đồ doanh thu theo khu vực
ggplot(region_summary, aes(x = reorder(Region, Total_Revenue), y = Total_Revenue)) +
  geom_bar(stat = "identity", fill = "darkorange", alpha = 0.8) +
  coord_flip() +
  scale_y_continuous(labels = comma) +
  labs(title = "DOANH THU THEO KHU VỰC",
       subtitle = "Sắp xếp theo thứ tự doanh thu giảm dần",
       x = "Khu Vực", 
       y = "Tổng Doanh Thu") +
  theme_minimal()

GIẢI THÍCH 5.3:

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

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

1.4.1 Tổng quan hiệu suất bán hàng

# Tổng hợp các chỉ số kinh doanh quan trọng
overall_summary <- data %>%
  summarise(
    Total_Orders = n_distinct(Order_ID),        # Tổng số đơn hàng
    Total_Customers = n_distinct(Customer_ID),  # Tổng số khách hàng
    Total_Products = n_distinct(Product),       # Tổng số sản phẩm
    Total_Revenue = sum(Total_Price),           # Tổng doanh thu
    Avg_Order_Value = mean(Total_Price),        # Giá trị đơn hàng trung bình
    Total_Discount_Given = sum(Discount_Amount) # Tổng chiết khấu đã áp dụng
  )

cat("=== TỔNG QUAN HIỆU SUẤT KINH DOANH ===\n")
## === TỔNG QUAN HIỆU SUẤT KINH DOANH ===
print(overall_summary)
##   Total_Orders Total_Customers Total_Products Total_Revenue Avg_Order_Value
## 1       349193           10000             47     137340621        130.9783
##   Total_Discount_Given
## 1             11239427

GIẢI THÍCH 6.1:

  • Đoạn code này tính toán các chỉ số hiệu suất chính (KPIs) trên toàn bộ dữ liệu. Kết quả cung cấp một bức tranh tổng thể: có tổng cộng 349,193 đơn hàng từ 10,000 khách hàng khác nhau, tạo ra tổng doanh thu là 137,340,621. Đây là những con số cốt lõi để đánh giá quy mô hoạt động của doanh nghiệp.

1.4.2 Top 10 sản phẩm bán chạy nhất

# Xác định các sản phẩm có đóng góp doanh thu cao nhất
top_products <- data %>%
  group_by(Product, Category) %>%
  summarise(
    Total_Quantity = sum(Quantity),             # Tổng số lượng bán ra
    Total_Revenue = sum(Total_Price),           # Tổng doanh thu
    .groups = 'drop'
  ) %>%
  arrange(desc(Total_Revenue)) %>%              # Sắp xếp theo doanh thu giảm dần
  head(10)                                      # Lấy 10 sản phẩm hàng đầu

cat("=== TOP 10 SẢN PHẨM THEO DOANH THU ===\n")
## === TOP 10 SẢN PHẨM THEO DOANH THU ===
print(top_products)
## # A tibble: 10 × 4
##    Product         Category            Total_Quantity Total_Revenue
##    <chr>           <fct>                        <int>         <dbl>
##  1 Veuve Clicquot  Alcoholic Beverages         316620     24234519.
##  2 Moët & Chandon  Alcoholic Beverages         308477     20255705.
##  3 Johnnie Walker  Alcoholic Beverages         305202     11164523.
##  4 Jack Daniels    Alcoholic Beverages         310730     11163887.
##  5 Tanqueray       Alcoholic Beverages         304860      9924823.
##  6 Bacardi         Alcoholic Beverages         307767      6824726.
##  7 Havana Club     Alcoholic Beverages         309875      6753102.
##  8 Sauvignon Blanc Alcoholic Beverages         314981      2765448.
##  9 Riesling        Alcoholic Beverages         342425      2711547.
## 10 Cranberry Juice Juices                      862501      2693706.
# Biểu đồ top sản phẩm
ggplot(top_products, aes(x = reorder(Product, Total_Revenue), y = Total_Revenue)) +
  geom_bar(stat = "identity", fill = "purple", alpha = 0.8) +
  coord_flip() +
  scale_y_continuous(labels = comma) +
  labs(title = "TOP 10 SẢN PHẨM THEO DOANH THU",
       subtitle = "Các sản phẩm có đóng góp doanh thu cao nhất",
       x = "Sản Phẩm", 
       y = "Doanh Thu") +
  theme_minimal()

GIẢI THÍCH 6.2:

  • Code thực hiện nhóm dữ liệu theo sản phẩm, tính tổng doanh thu, sau đó sắp xếp giảm dần và lấy ra 10 sản phẩm dẫn đầu. Kết quả cho thấy 9 trên 10 sản phẩm có doanh thu cao nhất đều thuộc danh mục “Đồ uống có cồn” (Alcoholic Beverages). Đặc biệt, “Veuve Clicquot” và “Moët & Chandon” là hai sản phẩm chủ lực, mang lại doanh thu vượt trội so với phần còn lại.

1.4.3 Phân tích xu hướng theo thời gian

# Phân tích xu hướng doanh thu theo thời gian
monthly_trend <- data %>%
  group_by(Month) %>%
  summarise(
    Total_Revenue = sum(Total_Price),           # Tổng doanh thu theo tháng
    Total_Orders = n_distinct(Order_ID),        # Tổng số đơn hàng theo tháng
    Avg_Order_Value = mean(Total_Price),        # Giá trị đơn hàng trung bình
    .groups = 'drop'
  )

cat("=== XU HƯỚNG DOANH THU THEO THÁNG ===\n")
## === XU HƯỚNG DOANH THU THEO THÁNG ===
print(monthly_trend)
## # A tibble: 36 × 4
##    Month   Total_Revenue Total_Orders Avg_Order_Value
##    <chr>           <dbl>        <int>           <dbl>
##  1 2021-01      3815437.        10025            127.
##  2 2021-02      3430573.         8840            130.
##  3 2021-03      3649256.         9774            125.
##  4 2021-04      3652787.         9556            127.
##  5 2021-05      3718815.         9902            124.
##  6 2021-06      3729842.         9595            130.
##  7 2021-07      3689650.         9745            127.
##  8 2021-08      3797610.         9930            128.
##  9 2021-09      3589288.         9597            125.
## 10 2021-10      3749630.         9770            128.
## # ℹ 26 more rows
# Biểu đồ xu hướng
ggplot(monthly_trend, aes(x = Month, y = Total_Revenue, group = 1)) +
  geom_line(color = "red", size = 1.2) +
  geom_point(color = "red", size = 2) +
  scale_y_continuous(labels = comma) +
  labs(title = "XU HƯỚNG DOANH THU THEO THỜI GIAN",
       subtitle = "Biến động doanh thu qua các tháng",
       x = "Tháng", 
       y = "Doanh Thu") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

GIẢI THÍCH 6.3:

  • Biểu đồ đường thể hiện doanh thu hàng tháng từ năm 2021 đến 2023. Dữ liệu cho thấy doanh thu có sự biến động nhẹ qua các tháng nhưng nhìn chung không có xu hướng tăng trưởng hay suy giảm rõ rệt trong dài hạn. Doanh số duy trì ở một mức độ tương đối ổn định qua các năm.