Mô hình thống kê là công cụ mô tả các đặc điểm có hệ thống và ngẫu nhiên trong dữ liệu. Không như các mô hình vật lý, mô hình thống kê là một sự xấp xỉ – chúng ta không kỳ vọng mô hình là đúng hoàn toàn, nhưng mong rằng nó hữu ích trong việc hiểu và phân tích dữ liệu.
“All models are wrong, but some are useful.” – George Box
Mỗi mô hình thống kê gồm hai thành phần:
Tùy theo mục tiêu phân tích, mô hình thống kê có thể phục vụ:
Một mô hình quá đơn giản có thể không nắm bắt được cấu trúc thực của dữ liệu (underfitting), trong khi mô hình quá phức tạp có thể phản ánh cả nhiễu (overfitting).
Nguyên tắc chọn mô hình: Đơn giản nhất có thể, nhưng không đơn giản quá mức.
Trực quan hóa dữ liệu là bước đầu tiên và bắt buộc trong phân tích:
Ví dụ:
Bộ dữ liệu đo dung tích thở ra (FEV) của trẻ em, với các biến:
FEV: thể tích khí thở ra trong một giây (lít)
Chiều cao (Ht, cm)
Giới tính (F hoặc M)
Tình trạng hút thuốc (có hoặc không)
Biểu đồ sử dụng: plot(), boxplot(),
interaction.plot()
Trong R, biến phân loại được định nghĩa qua factor() và
cần mã hóa đúng để sử dụng trong mô hình:
Smoke với các mức "yes" và
"no" sẽ được ánh xạ thành biến giả (dummy variable).relevel().Hồi quy tuyến tính là một trong những mô hình thống kê nền tảng, được sử dụng để mô tả mối quan hệ tuyến tính giữa một biến phản hồi liên tục \(y\) và một hoặc nhiều biến giải thích \(x_1, x_2, ..., x_p\).
Đây là một trường hợp đặc biệt của GLM, với:
Ứng dụng thực tiễn:
Dạng tổng quát (scalar): \[ y_i = \beta_0 + \beta_1 x_{1i} + \cdots + \beta_p x_{pi} + \varepsilon_i, \quad \varepsilon_i \sim N(0, \sigma^2) \]
Dạng ma trận: \[ \mathbf{y} = X\boldsymbol{\beta} + \boldsymbol{\varepsilon} \]
Trong đó:
Phương pháp: Bình phương tối thiểu (Least Squares)
\[ \hat{\boldsymbol{\beta}} = (X^T X)^{-1} X^T \mathbf{y} \]
Ước lượng phương sai sai số: \[ \hat{\sigma}^2 = \frac{\text{RSS}}{n - p'}, \quad \text{RSS} = \sum_{i=1}^n (y_i - \hat{y}_i)^2 \]
Khi các quan sát có phương sai khác nhau (heteroscedasticity), mô hình WLS cho phép gán trọng số phù hợp:
\[ \hat{\boldsymbol{\beta}} = (X^T W X)^{-1} X^T W \mathbf{y} \]
Trong đó \(W = \text{diag}(w_1, ..., w_n)\) là ma trận trọng số, thường được xác định ngược với phương sai của từng quan sát.
Mục đích: Kiểm định xem mô hình phức tạp hơn (nhiều biến hơn) có cải thiện đáng kể so với mô hình đơn giản.
Kiểm định F:
\[ F = \frac{(\text{RSS}_A - \text{RSS}_B)/(p'_B - p'_A)}{\text{RSS}_B/(n - p'_B)} \]
Hoặc theo hệ số xác định \(R^2\):
\[ F = \frac{R^2 / (p' - 1)}{(1 - R^2)/(n - p')} \]
Khi giả định phương sai không hằng hoặc phân phối sai số bị lệch, ta có thể biến đổi biến phản hồi:
Ví dụ với log biến phụ thuộc:
Nếu mô hình hoá \(\log(y)\), ta có:
\[ \eta = \log(\mu) \Rightarrow \mu = \exp(\eta) \]
Khi đó, một đơn vị tăng trong \(x\) làm \(\mu\) thay đổi theo hệ số \(\exp(\beta_j)\).
Exponential Dispersion Models (EDMs) là một lớp phân phối xác suất bao gồm nhiều phân phối quen thuộc:
EDMs là nền tảng phân phối cho GLMs, cho phép:
Một phân phối thuộc EDM có dạng:
\[ f(y; \theta, \phi) = a(y, \phi) \exp\left\{ \frac{y\theta - \kappa(\theta)}{\phi} \right\} \]
Trong đó:
| Phân phối | Hàm phương sai \(V(\mu)\) | Hàm liên kết chính tắc |
|---|---|---|
| Normal | \(1\) | Identity: \(g(\mu) = \mu\) |
| Poisson | \(\mu\) | Log: \(\log(\mu)\) |
| Binomial | \(\mu(1 - \mu)\) | Logit: \(\log\left(\frac{\mu}{1 - \mu}\right)\) |
| Gamma | \(\mu^2\) | Inverse / Log |
| Inverse Gaussian | \(\mu^3\) | \(1 / \mu^2\), Log |
Ngoài ra, một lớp phân phối tổng quát thuộc EDMs là Tweedie distribution, với hàm phương sai có dạng:
\[ V(\mu) = \mu^\xi \]
Ứng dụng phổ biến: mô hình hóa dữ liệu bảo hiểm, chi phí y tế, v.v.
Loại dữ liệu: Dữ liệu nhị phân hoặc tỷ lệ thành công
trong số lần thử cố định
Ví dụ: số hạt giống nảy mầm trong số 100 hạt.
Phân phối: Nhị thức (binomial)
\[ \phi = 1, \quad V(\mu) = \mu(1 - \mu) \]
Hàm liên kết chính tắc:
\[ g(\mu) = \log\left(\frac{\mu}{1 - \mu}\right) \]
Mục đích:
Dự đoán xác suất thành công hoặc phân tích ảnh hưởng của biến giải thích
đến xác suất xảy ra sự kiện.
Ví dụ:
Tỷ lệ hạt giống nảy mầm, tỷ lệ bệnh nhân khỏi bệnh, xác suất bỏ phiếu
cho một ứng viên.
Lưu ý:
Nếu có hiện tượng quá phân tán (overdispersion), nên dùng
quasi-binomial hoặc beta-binomial.
Loại dữ liệu: Số lần xảy ra sự kiện trong thời gian/khoảng không gian
Phân phối: Poisson
\[ \phi = 1, \quad V(\mu) = \mu \]
Hàm liên kết chính tắc:
\[ g(\mu) = \log(\mu) \]
Mục đích:
Mô hình hóa số lượng sự kiện: số ca bệnh, số hành vi, số cuộc gọi,
v.v.
Lưu ý:
Ứng dụng mở rộng:
Loại dữ liệu: Dữ liệu đếm có phương sai lớn hơn trung bình
Phân phối: Negative Binomial
\[ V(\mu) = \mu + \frac{\mu^2}{k}, \quad k > 0 \]
Mục đích:
Giải quyết hiện tượng quá phân tán bằng cách thêm biến ngẫu nhiên cấp
hai vào cường độ xảy ra sự kiện.
Ước lượng:
Dùng Maximum Likelihood Estimation để ước lượng \(\beta\) và \(k\)
Ví dụ:
Dữ liệu số vết đốm trên lá (pock data)
Loại dữ liệu: Đếm, nhưng không cần phân phối xác suất cụ thể
Đặc điểm:
\[ V(\mu) = \mu, \quad \phi \ne 1 \]
Mục đích:
Giữ công thức Poisson nhưng cho phép phương sai lớn hơn trung bình
Lưu ý:
Không thể tính AIC vì không có hàm khả năng cụ thể.
Loại dữ liệu: Liên tục > 0, ví dụ: chi phí, thời gian, lượng mưa
Phân phối: Gamma
\[ V(\mu) = \mu^2 \]
Hàm liên kết thường dùng: Log, Identity, Inverse
Ứng dụng:
Thời gian chờ, chi phí bảo hiểm, độ thấm nước
Mục đích:
Mô hình hóa mối quan hệ phi tuyến giữa biến giải thích và log(μ)
Phân phối: Inverse Gaussian
\[ V(\mu) = \mu^3 \]
Ứng dụng:
Dữ liệu thời gian di chuyển, thời gian đạt ngưỡng trong các tiến trình
ngẫu nhiên
So sánh với Gamma:
Thích hợp hơn khi dữ liệu có đuôi dài hoặc lệch phải rất mạnh.
Lớp phân phối: Tweedie
\[ V(\mu) = \mu^\xi, \quad 1 < \xi < 2 \]
Hàm liên kết phổ biến: Log
Ứng dụng:
Chi phí bảo hiểm – dữ liệu nhiều giá trị 0 nhưng cũng có giá trị dương
lớn
Lưu ý:
Phải ước lượng chỉ số \(\xi\) từ dữ
liệu
Tùy vào giá trị \(\xi\):
Standardized residuals (phần dư chuẩn hóa):
\[ r_i = \frac{y_i - \hat{\mu}_i}{\sqrt{\hat{V}(\hat{\mu}_i)}} \]
Deviance residuals:
\[ r_i = \text{sign}(y_i - \hat{\mu}_i) \cdot \sqrt{d(y_i, \hat{\mu}_i)} \]
Pearson residuals:
\[ r_i = \frac{y_i - \hat{\mu}_i}{\sqrt{V(\hat{\mu}_i)}} \]
Quantile residuals: Phần dư biến đổi sao cho nếu mô hình đúng thì \(r_i \sim N(0,1)\). Đặc biệt hữu ích với dữ liệu rời rạc như Binomial, Poisson.
Leverage (Đòn bẩy):
Tính từ ma trận “hat”: \[
H = X (X^T X)^{-1} X^T, \quad h_i = H_{ii}
\]
Cook’s Distance:
Đo mức thay đổi khi loại bỏ quan sát: \[
D_i = \frac{(\hat{\mu} - \hat{\mu}_{(i)})^T (\hat{\mu} -
\hat{\mu}_{(i)})}{p' s^2}
\]
DFBETAS: Ảnh hưởng của từng quan sát đến từng hệ số \(\beta_j\)
DFFITS: Ảnh hưởng của quan sát đến giá trị fitted \(\hat{y}_i\)
Khi so sánh các mô hình tuyến tính tổng quát (GLM), ta thường sử dụng AIC và BIC – hai tiêu chí đánh đổi giữa độ phù hợp của mô hình và độ phức tạp (số lượng tham số).
AIC – Akaike Information Criterion:
\[ \text{AIC} = -2 \ell(\hat{\beta}) + 2k \]
BIC – Bayesian Information Criterion:
\[ \text{BIC} = -2 \ell(\hat{\beta}) + k \log n \] Trong đó:
\(\ell(\hat{\beta})\): log-likelihood của mô hình
\(k\): số tham số trong mô hình
\(n\): số lượng quan sát
Mô hình nào có AIC hoặc BIC nhỏ hơn sẽ được ưu tiên lựa chọn.
Mặc dù cả AIC và BIC đều hướng tới việc lựa chọn mô hình cân bằng giữa độ phù hợp và độ phức tạp, nhưng hai tiêu chí này khác nhau ở mức độ phạt dành cho số lượng tham số trong mô hình. Cụ thể:
AIC áp dụng mức phạt tuyến tính theo số tham số: \(2k\)
BIC áp dụng mức phạt lôgarit phụ thuộc vào kích thước mẫu: \(k \log(n)\)
Do đó, khi kích thước mẫu \(n\) tăng, hệ số \(\log(n)\) trong công thức BIC cũng trở nên lớn hơn, khiến BIC trừng phạt mô hình phức tạp nghiêm khắc hơn so với AIC. Điều này giúp BIC có xu hướng chọn các mô hình đơn giản hơn, tránh hiện tượng overfitting.
Dựa trên khoảng cách giữa ước lượng và giả thuyết null:
\[ W = \frac{(\hat{\beta}_j - \beta_{0j})^2}{\text{Var}(\hat{\beta}_j)} \sim \chi^2_1 \]
summary(glm(...))So sánh log-likelihood giữa mô hình đầy đủ và mô hình bị ràng buộc:
\[ L = 2 \left[ \ell(\hat{\beta}) - \ell(\beta^*) \right] \sim \chi^2_q \]
anova(model1, model2, test = "Chisq")Dựa trên gradient của log-likelihood tại giá trị giả thuyết:
\[ S = U(\zeta^*)^T \cdot I^{-1}(\zeta^*) \cdot U(\zeta^*) \]
| Kiểm định | Ưu điểm | Nhược điểm |
|---|---|---|
| Wald | Tính toán trực tiếp từ mô hình đã fit (summary(glm)) | Ít chính xác với hệ số lớn hoặc phân phối lệch |
| Likelihood Ratio Test (LRT) | Chính xác với mô hình lồng nhau | Phải fit cả hai mô hình |
| Score Test | Không cần fit mô hình đầy đủ | Phức tạp hơn để tính trong R |
Ngôn ngữ R được sử dụng xuyên suốt trong sách để:
| Hàm / Lệnh R | Mục đích |
|---|---|
lm() |
Fit mô hình hồi quy tuyến tính |
glm() |
Fit mô hình GLM với phân phối và hàm liên kết tùy chọn |
summary() |
Hiển thị bảng kết quả với ước lượng, SE, z-value, p-value |
anova() |
So sánh các mô hình, đặc biệt với test = "Chisq" cho
LRT |
plot() |
Vẽ biểu đồ chẩn đoán mô hình (residuals, Cook’s distance, Q-Q plot) |
predict() |
Dự đoán giá trị fitted hoặc mới, có thể kèm khoảng tin cậy |
fitted() |
Trích xuất giá trị fitted từ mô hình |
residuals() |
Trích xuất phần dư theo loại (Pearson, deviance, …), ví dụ:
residuals(model, type = "deviance") |
cooks.distance() |
Tính khoảng cách Cook để phát hiện điểm ảnh hưởng |
influence.measures() |
Tổng hợp các chỉ số ảnh hưởng |
AIC(), BIC() |
So sánh mô hình bằng tiêu chí thông tin |
library(readr)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following object is masked from 'package:kableExtra':
##
## group_rows
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(skimr)
library(psych)
library(csv)
library(DT)
library(ggplot2)
##
## Attaching package: 'ggplot2'
## The following objects are masked from 'package:psych':
##
## %+%, alpha
library(forcats)
library(knitr)
library(tibble)
Vì bộ dữ liệu được lưu dưới định dạng CSV, ta tiến
hành đọc dữ liệu thông qua hàm read.csv() trong R. Kết quả
được lưu vào đối tượng data để sử dụng cho các phân tích
tiếp theo.
data <- read.csv("F:/PTDLDT/Supermarket Transactions.csv", header = T)
datatable(data)
## Warning in instance$preRenderHook(instance): It seems your data is too big for
## client-side DataTables. You may consider server-side processing:
## https://rstudio.github.io/DT/server.html
Tập dữ liệu ghi lại các thông tin liên quan đến giao dịch mua hàng tại siêu thị, bao gồm thông tin khách hàng, địa lý, và sản phẩm. Dữ liệu phù hợp cho các mục tiêu như:
Phân tích thói quen tiêu dùng
Nhận diện phân khúc thị trường
Hỗ trợ quyết định kinh doanh theo địa phương hoặc nhóm sản phẩm
Trước khi tiến hành phân tích, ta cần tìm hiểu cụ thể các biến có trong bộ dữ liệu, bao gồm tên biến, kiểu dữ liệu và ý nghĩa nội dung. Việc hiểu rõ các biến giúp xác định chính xác phương pháp xử lý phù hợp cho từng loại biến (định tính hay định lượng).
Tên của các biến trong bộ dữ liệu có thể được liệt kê thông qua lệnh
names() như sau:
names(data)
## [1] "X" "PurchaseDate" "CustomerID"
## [4] "Gender" "MaritalStatus" "Homeowner"
## [7] "Children" "AnnualIncome" "City"
## [10] "StateorProvince" "Country" "ProductFamily"
## [13] "ProductDepartment" "ProductCategory" "UnitsSold"
## [16] "Revenue"
Dưới đây là bảng mô tả chi tiết từng biến:
variable_description <- data.frame(
Bien = c("Unnamed: 0", "PurchaseDate", "CustomerID", "Gender", "MaritalStatus", "Homeowner",
"Children", "AnnualIncome", "City", "StateorProvince", "Country", "ProductFamily",
"ProductDepartment", "ProductCategory", "UnitsSold", "Revenue"),
Mo_ta = c("Chỉ số dòng (có thể không cần thiết)",
"Ngày thực hiện giao dịch",
"ID khách hàng",
"Giới tính: F - Nữ, M - Nam",
"Tình trạng hôn nhân: S - Độc thân, M - Đã kết hôn",
"Sở hữu nhà: Y - Có, N - Không",
"Số con trong gia đình",
"Thu nhập hằng năm (phân nhóm)",
"Thành phố cư trú",
"Bang hoặc tỉnh",
"Quốc gia",
"Nhóm sản phẩm chính",
"Bộ phận sản phẩm",
"Danh mục sản phẩm cụ thể",
"Số lượng sản phẩm bán ra",
"Doanh thu giao dịch (USD)"),
stringsAsFactors = FALSE
)
kbl(variable_description, col.names = c("Biến", "Mô tả"), booktabs = TRUE) %>%
kable_styling(latex_options = c("striped", "hold_position"))
| Biến | Mô tả |
|---|---|
| Unnamed: 0 | Chỉ số dòng (có thể không cần thiết) |
| PurchaseDate | Ngày thực hiện giao dịch |
| CustomerID | ID khách hàng |
| Gender | Giới tính: F - Nữ, M - Nam |
| MaritalStatus | Tình trạng hôn nhân: S - Độc thân, M - Đã kết hôn |
| Homeowner | Sở hữu nhà: Y - Có, N - Không |
| Children | Số con trong gia đình |
| AnnualIncome | Thu nhập hằng năm (phân nhóm) |
| City | Thành phố cư trú |
| StateorProvince | Bang hoặc tỉnh |
| Country | Quốc gia |
| ProductFamily | Nhóm sản phẩm chính |
| ProductDepartment | Bộ phận sản phẩm |
| ProductCategory | Danh mục sản phẩm cụ thể |
| UnitsSold | Số lượng sản phẩm bán ra |
| Revenue | Doanh thu giao dịch (USD) |
Để có cái nhìn tổng quan về dữ liệu, ta sử dụng các hàm
dim() và str() nhằm kiểm tra kích thước bảng
dữ liệu cũng như kiểu dữ liệu của từng biến.
dim(data)
## [1] 14059 16
Kết quả cho thấy bộ dữ liệu có 14,059 dòng (giao dịch) và 16 biến (thuộc tính).
str(data)
## 'data.frame': 14059 obs. of 16 variables:
## $ X : int 1 2 3 4 5 6 7 8 9 10 ...
## $ PurchaseDate : chr "2007-12-18" "2007-12-20" "2007-12-21" "2007-12-21" ...
## $ CustomerID : int 7223 7841 8374 9619 1900 6696 9673 354 1293 7938 ...
## $ Gender : chr "F" "M" "F" "M" ...
## $ MaritalStatus : chr "S" "M" "M" "M" ...
## $ Homeowner : chr "Y" "Y" "N" "Y" ...
## $ Children : int 2 5 2 3 3 3 2 2 3 1 ...
## $ AnnualIncome : chr "$30K - $50K" "$70K - $90K" "$50K - $70K" "$30K - $50K" ...
## $ City : chr "Los Angeles" "Los Angeles" "Bremerton" "Portland" ...
## $ StateorProvince : chr "CA" "CA" "WA" "OR" ...
## $ Country : chr "USA" "USA" "USA" "USA" ...
## $ ProductFamily : chr "Food" "Food" "Food" "Food" ...
## $ ProductDepartment: chr "Snack Foods" "Produce" "Snack Foods" "Snacks" ...
## $ ProductCategory : chr "Snack Foods" "Vegetables" "Snack Foods" "Candy" ...
## $ UnitsSold : int 5 5 3 4 4 3 4 6 1 2 ...
## $ Revenue : num 27.38 14.9 5.52 4.44 14 ...
Nhận xét
Phần lớn các biến định tính như Gender,
MaritalStatus, Homeowner, City,
Country,… hiện đang ở dạng character. Để phục
vụ phân tích thống kê và trực quan hóa, nên chuyển các biến này sang
kiểu factor.
Các biến định lượng như UnitsSold và
Revenue có kiểu numeric – đây là định dạng phù
hợp để thực hiện các phép tính như trung bình, độ lệch chuẩn,…
Biến PurchaseDate đang được lưu dưới dạng chuỗi
(character). Nếu cần thực hiện phân tích theo thời gian,
biến này nên được chuyển sang kiểu Date để xử lý chính xác
hơn.
Ngoài ra, biến X có thể chỉ là chỉ số thứ tự quan
sát, không mang ý nghĩa phân tích nên có thể loại bỏ nếu không cần
thiết.
Dữ liệu bao gồm cả các biến định lượng (như số lượng
bán ra, doanh thu) và định tính (như giới tính, tình
trạng hôn nhân, khu vực,…).
Do đó, ta sẽ thực hiện thống kê mô tả riêng biệt cho từng nhóm biến nhằm
đảm bảo lựa chọn đúng công cụ và phương pháp phân tích phù hợp với loại
dữ liệu tương ứng.
Trong phần này, ta xem xét ba biến định lượng chính là Children, UnitsSold và Revenue – đại diện cho số con trong gia đình, số sản phẩm bán được và doanh thu của mỗi giao dịch.
# Tạo bảng thống kê
quant_stats <- psych::describe(select(data, Children, UnitsSold, Revenue)) %>%
select(mean, median, min, max, sd, skew, kurtosis) %>%
round(2) %>%
rownames_to_column(var = "Biến")
# Đổi tên cột cho rõ ràng
colnames(quant_stats) <- c(
"Biến", "Trung bình", "Trung vị", "Min", "Max",
"Độ lệch chuẩn", "Skew", "Kurtosis"
)
# Hiển thị bảng đẹp hơn
kable(quant_stats, format = "html", align = "c", booktabs = TRUE,
caption = "Bảng thống kê mô tả các biến định lượng") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
full_width = F, position = "center", font_size = 13)
| Biến | Trung bình | Trung vị | Min | Max | Độ lệch chuẩn | Skew | Kurtosis |
|---|---|---|---|---|---|---|---|
| Children | 2.53 | 3.00 | 0.00 | 5.0 | 1.49 | -0.02 | -1.03 |
| UnitsSold | 4.08 | 4.00 | 1.00 | 8.0 | 1.17 | 0.01 | -0.44 |
| Revenue | 13.00 | 11.25 | 0.53 | 56.7 | 8.22 | 1.13 | 1.39 |
Nhận xét:
Children: Số con trung bình mỗi hộ gia đình là 2.53, với độ lệch chuẩn 1.49 và giá trị nằm trong khoảng từ 0 đến 5. Skew và kurtosis đều gần 0 → cho thấy phân phối khá đối xứng và dẹt, đặc trưng của dữ liệu rời rạc.
UnitsSold: Trung bình mỗi giao dịch bán được 4 sản phẩm, với trung vị cũng là 4.00 → chỉ ra phân phối cân đối và ổn định. Độ lệch và độ nhọn phân phối nhỏ (≈ 0) xác nhận đặc tính gần chuẩn.
Revenue: Doanh thu trung bình mỗi giao dịch đạt 13 USD, nhưng có phương sai lớn (sd = 8.22) và phân phối lệch phải rõ rệt (skew = 1.13). Điều này cho thấy đa số các giao dịch có doanh thu thấp, và chỉ một số ít mang lại giá trị cao bất thường (kurtosis > 1).
Các biến định tính sẽ được lần lượt trình bày với bảng tần số và tỷ lệ. Đây là nhóm các biến dạng chuỗi hoặc định danh, không thể áp dụng phép toán.
Bảng tần số và tỷ lệ %:
gender_table <- table(data$Gender)
gender_prop <- prop.table(gender_table)
gender_df <- data.frame(
Giới_tính = names(gender_table),
`Số lượng` = as.vector(gender_table),
`Tỷ lệ (%)` = round(100 * as.vector(gender_prop), 2),
check.names = FALSE
)
kable(gender_df, align = "c", col.names = c("Giới tính", "Số lượng", "Tỷ lệ (%)")) %>%
kableExtra::kable_styling(full_width = FALSE, position = "center", bootstrap_options = c("striped", "hover")) %>%
row_spec(0, bold = TRUE) %>%
column_spec(1:3, width = "4cm")
| Giới tính | Số lượng | Tỷ lệ (%) |
|---|---|---|
| F | 7170 | 51 |
| M | 6889 | 49 |
Biểu đồ:
data %>%
ggplot(aes(x = Gender)) +
geom_bar(fill = "#2E86C1") +
labs(title = "Phân bố giới tính", x = "Giới tính", y = "Số lượng") +
theme_minimal()
Nhận xét: Tỷ lệ khách hàng nam và nữ gần như cân bằng,
cho thấy phân bố giới tính trong dữ liệu là đồng đều. Điều này tạo điều
kiện thuận lợi để siêu thị triển khai các chiến lược marketing mang tính
toàn diện, hướng đến cả hai nhóm đối tượng mà không cần phân biệt rõ rệt
theo giới.
Bảng tần số và tỷ lệ %:
tbl2 <- table(data$MaritalStatus)
prop2 <- prop.table(tbl2)
df2 <- data.frame(
Muc = names(tbl2),
`Số lượng` = as.vector(tbl2),
`Tỷ lệ (%)` = round(100 * as.vector(prop2), 2),
check.names = FALSE
)
library(kableExtra)
kable(df2, align = "c", col.names = c("Tình trạng hôn nhân", "Số lượng", "Tỷ lệ (%)")) %>%
kable_styling(full_width = FALSE, position = "center", bootstrap_options = c("striped", "hover")) %>%
row_spec(0, bold = TRUE) %>%
column_spec(1:3, width = "4cm")
| Tình trạng hôn nhân | Số lượng | Tỷ lệ (%) |
|---|---|---|
| M | 6866 | 48.84 |
| S | 7193 | 51.16 |
Biểu đồ:
data %>%
ggplot(aes(x = MaritalStatus)) +
geom_bar(fill = "#CA6F1E") +
labs(title = "Phân bố tình trạng hôn nhân", x = "Tình trạng", y = "Số lượng") +
theme_minimal()
Nhận xét: Tỷ lệ khách hàng độc thân chiếm ưu thế nhẹ so
với nhóm đã kết hôn, cho thấy đây là một phân khúc tiềm năng – đại diện
cho nhóm khách hàng có xu hướng tự chủ về tài chính và nhu cầu chi tiêu
linh hoạt hơn. Điều này mở ra cơ hội cho các chiến lược sản phẩm và
khuyến mãi nhắm đến cá nhân hơn là hộ gia đình.
Bảng tần số và tỷ lệ%:
tbl3 <- table(data$Homeowner)
prop3 <- prop.table(tbl3)
df3 <- data.frame(
Muc = names(tbl3),
`Số lượng` = as.vector(tbl3),
`Tỷ lệ (%)` = round(100 * as.vector(prop3), 2),
check.names = FALSE
)
kable(df3, align = "c", col.names = c("Sở hữu nhà", "Số lượng", "Tỷ lệ (%)")) %>%
kable_styling(full_width = FALSE, position = "center", bootstrap_options = c("striped", "hover")) %>%
row_spec(0, bold = TRUE) %>%
column_spec(1:3, width = "4cm")
| Sở hữu nhà | Số lượng | Tỷ lệ (%) |
|---|---|---|
| N | 5615 | 39.94 |
| Y | 8444 | 60.06 |
Biểu đồ:
data %>%
ggplot(aes(x = Homeowner)) +
geom_bar(fill = "#28B463") +
labs(title = "Trạng thái sở hữu nhà", x = "Sở hữu nhà", y = "Số lượng") +
theme_minimal()
Nhận xét: Khoảng 60% khách hàng trong dữ liệu là người sở hữu nhà, cho thấy phần lớn khách hàng thuộc nhóm có nền tảng tài chính ổn định. Điều này có thể gợi ý rằng họ có xu hướng chi tiêu cao hơn hoặc sẵn sàng đầu tư vào các sản phẩm/dịch vụ có giá trị lớn hơn so với nhóm chưa sở hữu nhà. Đây là một yếu tố quan trọng để cân nhắc trong các chiến lược định giá và phân khúc thị trường.
Bảng tần số và tỷ lệ%:
data$AnnualIncome <- trimws(gsub("\\$", "", data$AnnualIncome))
income_table <- table(data$AnnualIncome)
income_prop <- prop.table(income_table)
income_df <- data.frame(
Muc = names(income_table),
Soluong = as.vector(income_table),
Tile = round(100 * as.vector(income_prop), 2)
)
kable(income_df, col.names = c("Mức thu nhập", "Số lượng", "Tỷ lệ (%)"), align = "c") %>%
kable_styling(full_width = FALSE, position = "center", bootstrap_options = c("striped", "hover")) %>%
row_spec(0, bold = TRUE) %>%
column_spec(1:3, width = "4cm")
| Mức thu nhập | Số lượng | Tỷ lệ (%) |
|---|---|---|
| 10K - 30K | 3090 | 21.98 |
| 110K - 130K | 643 | 4.57 |
| 130K - 150K | 760 | 5.41 |
| 150K + | 273 | 1.94 |
| 30K - 50K | 4601 | 32.73 |
| 50K - 70K | 2370 | 16.86 |
| 70K - 90K | 1709 | 12.16 |
| 90K - 110K | 613 | 4.36 |
Biểu đồ:
data %>%
ggplot(aes(x = fct_infreq(AnnualIncome))) +
geom_bar(fill = "#7D3C98") +
labs(title = "Phân bố thu nhập hàng năm", x = "Mức thu nhập", y = "Số lượng") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Nhận xét: Phần lớn khách hàng (gần 50%) tập trung trong nhóm thu nhập trung bình từ 30K đến 70K, cho thấy đây là phân khúc chủ đạo và có tiềm năng chi tiêu ổn định. Điều này gợi ý rằng siêu thị nên tập trung phát triển các dòng sản phẩm phổ thông, có mức giá hợp lý, cùng với chương trình khuyến mãi và ưu đãi phù hợp với khả năng chi tiêu của nhóm này. Bên cạnh đó, đây cũng là nhóm có thể dễ dàng chuyển đổi thành khách hàng thân thiết thông qua chính sách chăm sóc và tích điểm mua sắm hiệu quả.
Bảng tần số và tỷ lệ%:
city_table <- table(data$City)
city_prop <- prop.table(city_table)
city_df <- data.frame(
City = names(city_table),
Soluong = as.vector(city_table),
Tile = round(100 * as.vector(city_prop), 2)
)
kable(city_df, col.names = c("Thành phố", "Số lượng", "Tỷ lệ (%)"), align = "c") %>%
kable_styling(full_width = FALSE, position = "center", bootstrap_options = c("striped", "hover")) %>%
row_spec(0, bold = TRUE) %>%
column_spec(1:3, width = "4cm")
| Thành phố | Số lượng | Tỷ lệ (%) |
|---|---|---|
| Acapulco | 383 | 2.72 |
| Bellingham | 143 | 1.02 |
| Beverly Hills | 811 | 5.77 |
| Bremerton | 834 | 5.93 |
| Camacho | 452 | 3.22 |
| Guadalajara | 75 | 0.53 |
| Hidalgo | 845 | 6.01 |
| Los Angeles | 926 | 6.59 |
| Merida | 654 | 4.65 |
| Mexico City | 194 | 1.38 |
| Orizaba | 464 | 3.30 |
| Portland | 876 | 6.23 |
| Salem | 1386 | 9.86 |
| San Andres | 621 | 4.42 |
| San Diego | 866 | 6.16 |
| San Francisco | 130 | 0.92 |
| Seattle | 922 | 6.56 |
| Spokane | 875 | 6.22 |
| Tacoma | 1257 | 8.94 |
| Vancouver | 633 | 4.50 |
| Victoria | 176 | 1.25 |
| Walla Walla | 160 | 1.14 |
| Yakima | 376 | 2.67 |
Biểu đồ:
data %>%
ggplot(aes(x = fct_infreq(City))) +
geom_bar(fill = "#F39C12") +
labs(title = "Phân bố theo thành phố", x = "Thành phố", y = "Số lượng") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Nhận xét: Dữ liệu cho thấy Salem (9.86%), Tacoma (8.94%), Los Angeles (6.59%), Seattle (6.56%), và Portland (6.23%) là những thành phố có mật độ giao dịch cao nhất, cho thấy đây là các khu vực thị trường trọng điểm mà siêu thị nên ưu tiên đầu tư về quảng bá, phân phối và chăm sóc khách hàng.
Ngoài ra, các thành phố như Bremerton, Spokane, San Diego và Hidalgo cũng chiếm tỷ trọng khá lớn (trên 5%), đóng vai trò bổ trợ quan trọng trong chiến lược mở rộng thị trường.
Ngược lại, các thành phố như Guadalajara, Victoria, San Francisco chỉ chiếm tỷ lệ dưới 1.5%, nên có thể được xem là khu vực tiềm năng dài hạn hoặc dùng để thử nghiệm các chiến dịch nhỏ trước khi mở rộng quy mô.
Bảng tần số và tỷ lệ%:
state_table <- table(data$StateorProvince)
state_prop <- prop.table(state_table)
state_df <- data.frame(
State = names(state_table),
Soluong = as.vector(state_table),
Tile = round(100 * as.vector(state_prop), 2)
)
kable(state_df, col.names = c("Bang/Tỉnh", "Số lượng", "Tỷ lệ (%)"), align = "c") %>%
kable_styling(full_width = FALSE, position = "center", bootstrap_options = c("striped", "hover")) %>%
row_spec(0, bold = TRUE) %>%
column_spec(1:3, width = "4cm")
| Bang/Tỉnh | Số lượng | Tỷ lệ (%) |
|---|---|---|
| BC | 809 | 5.75 |
| CA | 2733 | 19.44 |
| DF | 815 | 5.80 |
| Guerrero | 383 | 2.72 |
| Jalisco | 75 | 0.53 |
| OR | 2262 | 16.09 |
| Veracruz | 464 | 3.30 |
| WA | 4567 | 32.48 |
| Yucatan | 654 | 4.65 |
| Zacatecas | 1297 | 9.23 |
Biểu đồ:
data %>%
ggplot(aes(x = fct_infreq(StateorProvince))) +
geom_bar(fill = "#5DADE2") +
labs(title = "Phân bố theo bang/tỉnh", x = "Bang/Tỉnh", y = "Số lượng") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Nhận xét: Ba bang Washington (WA - 32.48%), California (CA - 19.44%) và Oregon (OR - 16.09%) chiếm tổng cộng gần 70% số lượng khách hàng, khẳng định đây là khu vực trọng tâm trong chiến lược thị trường.
→ Các hoạt động như phân tích hành vi tiêu dùng, tối ưu hóa danh mục sản phẩm, và triển khai chiến dịch tiếp thị nên ưu tiên tập trung vào nhóm bang này để đạt hiệu quả cao nhất.
Bên cạnh đó, Zacatecas (9.23%) và DF (5.80%) cũng thể hiện là những thị trường đáng chú ý với quy mô trung bình, phù hợp cho việc mở rộng dịch vụ hoặc thử nghiệm chính sách mới. Các bang có tỷ trọng thấp hơn như Guerrero, Veracruz, Yucatan hay Jalisco có thể được xem là thị trường vệ tinh, tiềm năng để phát triển dài hạn hoặc triển khai các chiến dịch khu vực nhỏ, có chọn lọc.
Bảng tần số và tỷ lệ%:
country_table <- table(data$Country)
country_prop <- prop.table(country_table)
country_df <- data.frame(
Country = names(country_table),
Soluong = as.vector(country_table),
Tile = round(100 * as.vector(country_prop), 2)
)
kable(country_df, col.names = c("Quốc gia", "Số lượng", "Tỷ lệ (%)"), align = "c") %>%
kable_styling(full_width = FALSE, position = "center", bootstrap_options = c("striped", "hover")) %>%
row_spec(0, bold = TRUE) %>%
column_spec(1:3, width = "4cm")
| Quốc gia | Số lượng | Tỷ lệ (%) |
|---|---|---|
| Canada | 809 | 5.75 |
| Mexico | 3688 | 26.23 |
| USA | 9562 | 68.01 |
Biểu đồ:
data %>%
ggplot(aes(x = Country)) +
geom_bar(fill = "#E74C3C") +
labs(title = "Phân bố theo quốc gia", x = "Quốc gia", y = "Số lượng") +
theme_minimal()
Nhận xét: Hoa Kỳ (USA) chiếm tỷ lệ áp đảo với 68.01% số khách hàng, khẳng định đây là thị trường cốt lõi cần được ưu tiên đầu tư về hạ tầng, dịch vụ và chiến lược tiếp thị.
Mexico đứng thứ hai với 26.23%, là một thị trường tiềm năng với quy mô đủ lớn để triển khai chiến dịch bản địa hóa, như điều chỉnh ngôn ngữ, giá cả, ưu đãi và sản phẩm phù hợp văn hóa.
Canada tuy chỉ chiếm 5.75%, nhưng vẫn là một thị trường vệ tinh đáng chú ý, phù hợp để duy trì hiện diện thương hiệu và thử nghiệm sản phẩm/dịch vụ mới trước khi mở rộng sâu hơn.
→ Chiến lược phân khúc địa lý rõ ràng sẽ giúp doanh nghiệp tối ưu hóa nguồn lực và nâng cao hiệu quả tiếp cận từng thị trường.
Bảng tần số và tỷ lệ%:
tbl <- table(data$ProductFamily)
prop <- prop.table(tbl)
df <- data.frame(
Muc = names(tbl),
`Số lượng` = as.vector(tbl),
`Tỷ lệ (%)` = round(100 * as.vector(prop), 2),
check.names = FALSE
)
kable(df, align = "c", col.names = c("Nhóm sản phẩm", "Số lượng", "Tỷ lệ (%)")) %>%
kable_styling(full_width = FALSE, position = "center", bootstrap_options = c("striped", "hover")) %>%
row_spec(0, bold = TRUE) %>%
column_spec(1:3, width = "4cm")
| Nhóm sản phẩm | Số lượng | Tỷ lệ (%) |
|---|---|---|
| Drink | 1250 | 8.89 |
| Food | 10153 | 72.22 |
| Non-Consumable | 2656 | 18.89 |
Biểu đồ:
data %>%
ggplot(aes(x = ProductFamily)) +
geom_bar(fill = "#1F618D") +
labs(title = "Phân bố nhóm sản phẩm", x = "Nhóm sản phẩm", y = "Số lượng") +
theme_minimal()
Nhận xét: Nhóm sản phẩm Food chiếm tỷ trọng áp đảo với hơn 72% tổng số giao dịch, khẳng định đây là mảng kinh doanh cốt lõi của siêu thị và cần được ưu tiên trong chiến lược sản phẩm, trưng bày và khuyến mãi. Trong khi đó, các nhóm Non-Consumable (18.89%) và Drink (8.89%) tuy chiếm tỷ lệ thấp hơn nhưng vẫn thể hiện tiềm năng phát triển, đặc biệt thông qua các chiến dịch bán chéo hoặc kết hợp combo để tăng giá trị đơn hàng và mở rộng hành vi tiêu dùng của khách.
Bảng tần số và tỷ lệ%:
tbl <- table(data$ProductDepartment)
prop <- prop.table(tbl)
df <- data.frame(
Muc = names(tbl),
`Số lượng` = as.vector(tbl),
`Tỷ lệ (%)` = round(100 * as.vector(prop), 2),
check.names = FALSE
)
kable(df, align = "c", col.names = c("Bộ phận", "Số lượng", "Tỷ lệ (%)")) %>%
kable_styling(full_width = FALSE, position = "center", bootstrap_options = c("striped", "hover")) %>%
row_spec(0, bold = TRUE) %>%
column_spec(1:3, width = "4cm")
| Bộ phận | Số lượng | Tỷ lệ (%) |
|---|---|---|
| Alcoholic Beverages | 356 | 2.53 |
| Baked Goods | 425 | 3.02 |
| Baking Goods | 1072 | 7.63 |
| Beverages | 680 | 4.84 |
| Breakfast Foods | 188 | 1.34 |
| Canned Foods | 977 | 6.95 |
| Canned Products | 109 | 0.78 |
| Carousel | 59 | 0.42 |
| Checkout | 82 | 0.58 |
| Dairy | 903 | 6.42 |
| Deli | 699 | 4.97 |
| Eggs | 198 | 1.41 |
| Frozen Foods | 1382 | 9.83 |
| Health and Hygiene | 893 | 6.35 |
| Household | 1420 | 10.10 |
| Meat | 89 | 0.63 |
| Periodicals | 202 | 1.44 |
| Produce | 1994 | 14.18 |
| Seafood | 102 | 0.73 |
| Snack Foods | 1600 | 11.38 |
| Snacks | 352 | 2.50 |
| Starchy Foods | 277 | 1.97 |
Biểu đồ:
data %>%
ggplot(aes(x = fct_infreq(ProductDepartment))) +
geom_bar(fill = "#D35400") +
labs(title = "Phòng ban sản phẩm", x = "Phòng ban", y = "Số lượng") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Nhận xét: Rau quả (Produce), Snack Foods và Household là ba bộ phận sản phẩm chiếm tỷ trọng lớn nhất trong tổng doanh số, lần lượt đạt 14,18%, 11,38% và 10,10%. Điều này cho thấy sức mua mạnh mẽ và sự quan tâm lớn của khách hàng đối với những nhóm hàng này. Do vậy, việc tập trung đầu tư vào trưng bày bắt mắt, triển khai các chương trình khuyến mãi hấp dẫn và phát triển đa dạng sản phẩm trong các nhóm này sẽ là chiến lược then chốt giúp tăng trưởng doanh thu và củng cố vị thế cạnh tranh trên thị trường.
Bảng tần số và tỷ lệ%:
tbl <- table(data$ProductCategory)
prop <- prop.table(tbl)
df <- data.frame(
Muc = names(tbl),
`Số lượng` = as.vector(tbl),
`Tỷ lệ (%)` = round(100 * as.vector(prop), 2),
check.names = FALSE
)
kable(df, align = "c", col.names = c("Danh mục", "Số lượng", "Tỷ lệ (%)")) %>%
kable_styling(full_width = FALSE, position = "center", bootstrap_options = c("striped", "hover")) %>%
row_spec(0, bold = TRUE) %>%
column_spec(1:3, width = "4cm")
| Danh mục | Số lượng | Tỷ lệ (%) |
|---|---|---|
| Baking Goods | 484 | 3.44 |
| Bathroom Products | 365 | 2.60 |
| Beer and Wine | 356 | 2.53 |
| Bread | 425 | 3.02 |
| Breakfast Foods | 417 | 2.97 |
| Candles | 45 | 0.32 |
| Candy | 352 | 2.50 |
| Canned Anchovies | 44 | 0.31 |
| Canned Clams | 53 | 0.38 |
| Canned Oysters | 35 | 0.25 |
| Canned Sardines | 40 | 0.28 |
| Canned Shrimp | 38 | 0.27 |
| Canned Soup | 404 | 2.87 |
| Canned Tuna | 87 | 0.62 |
| Carbonated Beverages | 154 | 1.10 |
| Cleaning Supplies | 189 | 1.34 |
| Cold Remedies | 93 | 0.66 |
| Dairy | 903 | 6.42 |
| Decongestants | 85 | 0.60 |
| Drinks | 135 | 0.96 |
| Eggs | 198 | 1.41 |
| Electrical | 355 | 2.53 |
| Frozen Desserts | 323 | 2.30 |
| Frozen Entrees | 118 | 0.84 |
| Fruit | 765 | 5.44 |
| Hardware | 129 | 0.92 |
| Hot Beverages | 226 | 1.61 |
| Hygiene | 197 | 1.40 |
| Jams and Jellies | 588 | 4.18 |
| Kitchen Products | 217 | 1.54 |
| Magazines | 202 | 1.44 |
| Meat | 761 | 5.41 |
| Miscellaneous | 42 | 0.30 |
| Packaged Vegetables | 48 | 0.34 |
| Pain Relievers | 192 | 1.37 |
| Paper Products | 345 | 2.45 |
| Pizza | 194 | 1.38 |
| Plastic Products | 141 | 1.00 |
| Pure Juice Beverages | 165 | 1.17 |
| Seafood | 102 | 0.73 |
| Side Dishes | 153 | 1.09 |
| Snack Foods | 1600 | 11.38 |
| Specialty | 289 | 2.06 |
| Starchy Foods | 277 | 1.97 |
| Vegetables | 1728 | 12.29 |
Biểu đồ:
data %>%
ggplot(aes(x = fct_infreq(ProductCategory))) +
geom_bar(fill = "#45B39D") +
labs(title = "Danh mục sản phẩm cụ thể", x = "Danh mục", y = "Số lượng") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
Nhận xét: Danh mục Vegetables và Snack Foods đứng đầu về số lượng giao dịch, lần lượt chiếm 12,29% và 11,38% tổng số. Điều này minh chứng cho sự ưu tiên rõ ràng của khách hàng đối với các sản phẩm thực phẩm tươi sống và đồ ăn nhanh tiện lợi trong thói quen mua sắm hàng ngày. Vì vậy, doanh nghiệp nên tiếp tục củng cố và phát triển mạnh mẽ hai nhóm hàng này thông qua việc nâng cao chất lượng, đa dạng hóa sản phẩm và xây dựng các chương trình khuyến mãi sáng tạo nhằm giữ vững lòng trung thành của khách hàng và tăng trưởng bền vững.