1. Tổng quan

Đọc dữ liệu file csv

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(readr)
BK <- read_csv("D:/bike_sales_100k.csv")
## Rows: 100000 Columns: 11
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (5): Date, Bike_Model, Store_Location, Payment_Method, Customer_Gender
## dbl (6): Sale_ID, Customer_ID, Price, Quantity, Salesperson_ID, Customer_Age
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

2. Cấu trúc dữ liệu

2.1. Tên và kiểu dữ liệu của các biến

str(BK)
## spc_tbl_ [100,000 × 11] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ Sale_ID        : num [1:100000] 1 2 3 4 5 6 7 8 9 10 ...
##  $ Date           : chr [1:100000] "11-07-2022" "03-05-2024" "01-09-2022" "28-09-2022" ...
##  $ Customer_ID    : num [1:100000] 9390 3374 2689 3797 1633 ...
##  $ Bike_Model     : chr [1:100000] "Cruiser" "Hybrid Bike" "Folding Bike" "Mountain Bike" ...
##  $ Price          : num [1:100000] 318 3093 4248 1722 3941 ...
##  $ Quantity       : num [1:100000] 1 4 3 3 3 5 4 1 3 5 ...
##  $ Store_Location : chr [1:100000] "Philadelphia" "Chicago" "San Antonio" "San Antonio" ...
##  $ Salesperson_ID : num [1:100000] 589 390 338 352 580 829 916 291 906 562 ...
##  $ Payment_Method : chr [1:100000] "Apple Pay" "Apple Pay" "PayPal" "Apple Pay" ...
##  $ Customer_Age   : num [1:100000] 70 37 59 19 67 42 20 57 62 65 ...
##  $ Customer_Gender: chr [1:100000] "Female" "Male" "Female" "Male" ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   Sale_ID = col_double(),
##   ..   Date = col_character(),
##   ..   Customer_ID = col_double(),
##   ..   Bike_Model = col_character(),
##   ..   Price = col_double(),
##   ..   Quantity = col_double(),
##   ..   Store_Location = col_character(),
##   ..   Salesperson_ID = col_double(),
##   ..   Payment_Method = col_character(),
##   ..   Customer_Age = col_double(),
##   ..   Customer_Gender = col_character()
##   .. )
##  - attr(*, "problems")=<externalptr>
data_types_summary <- tibble(
  Ten_Cot = c("Sale_ID", "Date", "Customer_ID", "Bike_Model", "Price", 
              "Quantity", "Store_Location", "Salesperson_ID", "Payment_Method", 
              "Customer_Age", "Customer_Gender"),
  Loai_Du_lieu_trong_R = c("num", "chr", 
                          "num", "chr", 
                          "num", "num", 
                          "chr", "num)", 
                          "chr", "num", 
                          "chr"),
  Giai_thich = c("Mã số bán hàng.", "Ngày bán hàng (cần chuyển sang Date).", 
                 "Mã khách hàng.", "Tên hoặc loại xe đạp.", "Giá bán.", 
                 "Số lượng bán.", "Vị trí cửa hàng.", "Mã nhân viên bán hàng.", 
                 "Phương thức thanh toán.", "Tuổi của khách hàng.", 
                 "Giới tính của khách hàng.")
)
print(data_types_summary)
## # A tibble: 11 × 3
##    Ten_Cot         Loai_Du_lieu_trong_R Giai_thich                           
##    <chr>           <chr>                <chr>                                
##  1 Sale_ID         num                  Mã số bán hàng.                      
##  2 Date            chr                  Ngày bán hàng (cần chuyển sang Date).
##  3 Customer_ID     num                  Mã khách hàng.                       
##  4 Bike_Model      chr                  Tên hoặc loại xe đạp.                
##  5 Price           num                  Giá bán.                             
##  6 Quantity        num                  Số lượng bán.                        
##  7 Store_Location  chr                  Vị trí cửa hàng.                     
##  8 Salesperson_ID  num)                 Mã nhân viên bán hàng.               
##  9 Payment_Method  chr                  Phương thức thanh toán.              
## 10 Customer_Age    num                  Tuổi của khách hàng.                 
## 11 Customer_Gender chr                  Giới tính của khách hàng.
library(knitr)
kable(data_types_summary, 
      caption = "Bảng Tóm Tắt Loại Dữ liệu",
      col.names = c("Tên Cột", "Loại Dữ liệu trong R (R Type)", "Giải thích"))
Bảng Tóm Tắt Loại Dữ liệu
Tên Cột Loại Dữ liệu trong R (R Type) Giải thích
Sale_ID num Mã số bán hàng.
Date chr Ngày bán hàng (cần chuyển sang Date).
Customer_ID num Mã khách hàng.
Bike_Model chr Tên hoặc loại xe đạp.
Price num Giá bán.
Quantity num Số lượng bán.
Store_Location chr Vị trí cửa hàng.
Salesperson_ID num) Mã nhân viên bán hàng.
Payment_Method chr Phương thức thanh toán.
Customer_Age num Tuổi của khách hàng.
Customer_Gender chr Giới tính của khách hàng.

2.2. Số dòng (quan sát) và số cột (biến)

dim(BK)
## [1] 100000     11

2.3. Kiểm tra số lượng giá trị bị thiếu theo từng cột

colSums(is.na(BK))
##         Sale_ID            Date     Customer_ID      Bike_Model           Price 
##               0               0               0               0               0 
##        Quantity  Store_Location  Salesperson_ID  Payment_Method    Customer_Age 
##               0               0               0               0               0 
## Customer_Gender 
##               0

2.4. Kiểm tra trùng lặp

Số hàng trùng lặp

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

Số quan sát trùng lặp trong cột Payment Method (Thống kê tần suất)

table(BK$Payment_Method)
## 
##   Apple Pay        Cash Credit Card  Debit Card  Google Pay      PayPal 
##       16751       16692       16653       16738       16613       16553

3. Phân tổ dữ liệu

3.1. Tạo thêm 1 biến theo tháng

BK1 <- BK %>%
  mutate(Month = as.numeric(format(as.Date(Date), "%m")))

3.2. Tạo quý từ tháng

BK2 <- BK1 %>%
  mutate(
    Quarter = case_when(
      Month %in% 1:3 ~ "Q1",
      Month %in% 4:6 ~ "Q2",
      Month %in% 7:9 ~ "Q3",
      Month %in% 10:12 ~ "Q4"
    ))

3.3. Phân loại theo nhóm tuổi

BK4 <- BK2 %>%
  mutate(
    # Tạo cột Age_Group
    Age_Group = case_when(
      # Nhóm Young: 18 đến 35 tuổi
      Customer_Age >= 18 & Customer_Age <= 35 ~ "Young",
      # Nhóm Middle-Aged: 36 đến 55 tuổi
      Customer_Age >= 36 & Customer_Age <= 55 ~ "Middle-Aged",
      # Nhóm Senior: 56 tuổi trở lên
      Customer_Age >= 56 ~ "Senior",
      # Xử lý các trường hợp còn lại (ví dụ: tuổi nhỏ hơn 18 hoặc NA)
      TRUE ~ "Other/Unknown" 
    )
  )

4. Phân tích các biến

4.1. Biến Price

BK %>%
  summarise(
    Gia_Tri_Lon_Nhat = max(Price, na.rm = TRUE),
    Gia_Tri_Nho_Nhat = min(Price, na.rm = TRUE),
    Gia_Tri_Trung_Binh = mean(Price, na.rm = TRUE),
    Gia_Tri_Trung_Vi = median(Price, na.rm = TRUE),
    Phuong_Sai         = var(Price, na.rm = TRUE)
  )
## # A tibble: 1 × 5
##   Gia_Tri_Lon_Nhat Gia_Tri_Nho_Nhat Gia_Tri_Trung_Binh Gia_Tri_Trung_Vi
##              <dbl>            <dbl>              <dbl>            <dbl>
## 1            5000.             200.              2598.            2599.
## # ℹ 1 more variable: Phuong_Sai <dbl>

4.2. Phân tích các giao dịch trong tháng

BK1 %>%
  group_by(Month) %>%
  summarise(
    Gia_Tri_Lon_Nhat = max(Price, na.rm = TRUE),
    Gia_Tri_Nho_Nhat = min(Price, na.rm = TRUE),
    Gia_Tri_Trung_Binh = mean(Price, na.rm = TRUE),
    Gia_Tri_Trung_Vi = median(Price, na.rm = TRUE),
    Phuong_Sai           = var(Price, na.rm = TRUE)
  )
## # A tibble: 12 × 6
##    Month Gia_Tri_Lon_Nhat Gia_Tri_Nho_Nhat Gia_Tri_Trung_Binh Gia_Tri_Trung_Vi
##    <dbl>            <dbl>            <dbl>              <dbl>            <dbl>
##  1     1            4999.             200.              2577.            2533.
##  2     2            4999.             200.              2589.            2602.
##  3     3            5000.             200.              2594.            2610.
##  4     4            5000.             201.              2625.            2668.
##  5     5            4999.             200.              2598.            2610.
##  6     6            4999.             200.              2597.            2588.
##  7     7            5000.             200.              2597.            2580.
##  8     8            5000.             200.              2586.            2562.
##  9     9            4999.             200.              2601.            2604.
## 10    10            4999.             201.              2593.            2599.
## 11    11            5000.             200.              2627.            2624.
## 12    12            5000.             200.              2598.            2599.
## # ℹ 1 more variable: Phuong_Sai <dbl>

4.3. Phân tích giá theo tháng

BK1 %>%
  group_by(Price, Month) %>%
  summarise(
    Giao_Dich_Trung_Binh = mean(Price, na.rm = TRUE),
    Giao_Dich_Trung_Vi   = median(Price, na.rm = TRUE),
    Phuong_Sai           = var(Price, na.rm = TRUE)
  ) %>%
  arrange(Month, Price)
## `summarise()` has grouped output by 'Price'. You can override using the
## `.groups` argument.
## # A tibble: 99,132 × 5
## # Groups:   Price [90,336]
##    Price Month Giao_Dich_Trung_Binh Giao_Dich_Trung_Vi Phuong_Sai
##    <dbl> <dbl>                <dbl>              <dbl>      <dbl>
##  1  200.     1                 200.               200.         NA
##  2  200.     1                 200.               200.         NA
##  3  201.     1                 201.               201.         NA
##  4  201.     1                 201.               201.         NA
##  5  201.     1                 201.               201.         NA
##  6  202.     1                 202.               202.         NA
##  7  202.     1                 202.               202.         NA
##  8  202.     1                 202.               202.         NA
##  9  203.     1                 203.               203.         NA
## 10  203.     1                 203.               203.         NA
## # ℹ 99,122 more rows

4.4. Phân tích các giao dịch trong quý

BK3 <- BK2 %>%
group_by(Quarter) %>%
  summarise(
    Tong_Giao_Dich     = sum(Price, na.rm = TRUE),
    Giao_Dich_Lon_Nhat = max(Price, na.rm = TRUE),
    Giao_Dich_Nho_Nhat = min(Price, na.rm = TRUE),
    Giao_Dich_Trung_Binh = mean(Price, na.rm = TRUE),
    Giao_Dich_Trung_Vi   = median(Price, na.rm = TRUE),
    Phuong_Sai            = var(Price, na.rm = TRUE),
    So_Luong_Giao_Dich    = n()
  ) %>%
  arrange(Quarter)
print(BK3, n = Inf)
## # A tibble: 4 × 8
##   Quarter Tong_Giao_Dich Giao_Dich_Lon_Nhat Giao_Dich_Nho_Nhat
##   <chr>            <dbl>              <dbl>              <dbl>
## 1 Q1           67234561.              5000.               200.
## 2 Q2           68775426.              5000.               200.
## 3 Q3           68184828.              5000.               200.
## 4 Q4           55623419.              5000.               200.
## # ℹ 4 more variables: Giao_Dich_Trung_Binh <dbl>, Giao_Dich_Trung_Vi <dbl>,
## #   Phuong_Sai <dbl>, So_Luong_Giao_Dich <int>

4.5. Theo quý và Price

BK2 %>%
  group_by(Quarter, Price) %>%
  summarise(
    Tong_Giao_Dich     = sum(Price, na.rm = TRUE),
    Giao_Dich_Trung_Binh = mean(Price, na.rm = TRUE),
    Giao_Dich_Trung_Vi   = median(Price, na.rm = TRUE),
    Phuong_Sai            = var(Price, na.rm = TRUE),
    So_Luong_Giao_Dich    = n()
  ) %>%
  arrange(Quarter, Price)
## `summarise()` has grouped output by 'Quarter'. You can override using the
## `.groups` argument.
## # A tibble: 97,465 × 7
## # Groups:   Quarter [4]
##    Quarter Price Tong_Giao_Dich Giao_Dich_Trung_Binh Giao_Dich_Trung_Vi
##    <chr>   <dbl>          <dbl>                <dbl>              <dbl>
##  1 Q1       200.           200.                 200.               200.
##  2 Q1       200.           200.                 200.               200.
##  3 Q1       200.           400.                 200.               200.
##  4 Q1       200.           200.                 200.               200.
##  5 Q1       200.           200.                 200.               200.
##  6 Q1       201.           201.                 201.               201.
##  7 Q1       201.           201.                 201.               201.
##  8 Q1       201.           201.                 201.               201.
##  9 Q1       201.           201.                 201.               201.
## 10 Q1       201.           201.                 201.               201.
## # ℹ 97,455 more rows
## # ℹ 2 more variables: Phuong_Sai <dbl>, So_Luong_Giao_Dich <int>

4.6. Phân tích Tỷ lệ Khách hàng theo Giới tính

library(ggplot2)
library(dplyr) # Cần thiết cho %>% và count(), mutate()

# Đảm bảo bạn đã định nghĩa BK2 (data frame gốc)
# Tùy thuộc vào code gốc của bạn, nếu BK2 là tên data frame đã làm sạch, thì OK.

BK5 <- BK2 %>%
  count(Customer_Gender) %>%
  mutate(percentage = n / sum(n))

# Sửa lỗi: Thay gender_counts bằng BK5
ggplot(BK5, aes(x = "", y = n, fill = Customer_Gender)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y", start = 0) + # Chuyển sang biểu đồ tròn
  labs(
    title = "Tỷ lệ Khách hàng theo Giới tính",
    fill = "Giới tính"
  ) +
  theme_void() + # Loại bỏ các yếu tố trục và lưới
  geom_text(aes(label = scales::percent(percentage)),
            position = position_stack(vjust = 0.5),
            color = "black")

4.7. Phân tích Số lượng Bán theo Vị trí Cửa hàng

BK6 <- BK2 %>%
  group_by(Store_Location) %>%
  summarise(Total_Quantity = sum(Quantity, na.rm = TRUE)) %>%
  ungroup() %>%
  arrange(desc(Total_Quantity))

# Tạo biểu đồ cột
ggplot(BK6, aes(x = reorder(Store_Location, -Total_Quantity), y = Total_Quantity)) +
  geom_bar(stat = "identity", fill = "lightgreen", color = "darkgreen") +
  labs(
    title = "Tổng Số lượng Xe Bán ra theo Vị trí Cửa hàng",
    x = "Vị trí Cửa hàng (Store Location)",
    y = "Tổng Số lượng (Quantity)"
  ) +
  theme_classic()