Mô hình Hồi quy Logistic

1. OLS, GLM và Hồi quy Logistic

1.1. Hồi quy Bình phương cực tiểu thông thường (OLS - Ordinary Least Squares)

OLS là một trong những mô hình hồi quy cơ bản nhất, được sử dụng rộng rãi khi biến phụ thuộc là định lượng và có phân phối chuẩn.

  • Chỉ phù hợp cho biến phụ thuộc định lượng (liên tục).

  • Giả định: Phần dư của mô hình tuân theo phân phối chuẩn.

  • Mối quan hệ: Mô hình OLS giả định một mối quan hệ tuyến tính trực tiếp giữa biến phụ thuộc và các biến độc lập, được biểu diễn bằng công thức:

    \[Y = \beta_0 + \beta_1 X_1 + \ldots + \beta_k X_k + \epsilon\] Trong đó:

    • \(Y\): Biến phụ thuộc.
    • \(X_1, \ldots, X_k\): Các biến độc lập.
    • \(\beta_0\): Hệ số chặn (intercept).
    • \(\beta_1, \ldots, \beta_k\): Các hệ số hồi quy (coefficients) cho từng biến độc lập.
    • \(\epsilon\): Sai số ngẫu nhiên (error term), được giả định là tuân theo phân phối chuẩn với trung bình bằng 0 và phương sai không đổi.

1.2. Mô hình Tuyến tính Tổng quát (GLM - Generalized Linear Models)

GLM là tổng quát và mạnh mẽ hơn OLS, cho phép làm việc với nhiều loại biến phụ thuộc khác nhau, không chỉ giới hạn ở biến định lượng với phân phối chuẩn.

  • Khả năng xử lý: GLM có thể xử lý biến phụ thuộc định tính (phân loại) hoặc biến định lượng nhưng không theo phân phối chuẩn (ví dụ: dữ liệu đếm, dữ liệu tỷ lệ).

  • Cấu trúc của GLM: Một GLM bao gồm ba thành phần chính:

    1. Thành phần Ngẫu nhiên (Random Component):
      • Chỉ định phân phối xác suất của biến phụ thuộc \(Y\). Đây có thể là phân phối Bernoulli (cho kết quả nhị phân), phân phối Poisson (cho dữ liệu đếm), phân phối Gamma (cho dữ liệu liên tục dương và không đối xứng), v.v.
    2. Thành phần Hệ thống / Tuyến tính (Systematic / Linear Predictor):
      • Đây là phần tuyến tính của mô hình, tương tự như vế phải của phương trình OLS, biểu diễn mối quan hệ tuyến tính giữa các biến độc lập và một giá trị \(\eta\) (eta):

        \[\eta = \beta_0 + \beta_1 X_1 + \ldots + \beta_k X_k\] Trong đó \(\beta_0, \beta_1, \ldots, \beta_k\) là các hệ số tuyến tính cần ước lượng.

    3. Hàm Liên kết (Link Function - LF):
      • Là một hàm \(g(\cdot)\) biến đổi giá trị trung bình kỳ vọng của biến phụ thuộc, \(E(Y) = \mu\), sao cho nó có mối quan hệ tuyến tính với thành phần hệ thống \(\eta\):

        \[g(\mu) = \eta\]

      • Hàm liên kết cho phép chúng ta kết nối miền giá trị của biến phụ thuộc (ví dụ: xác suất từ 0 đến 1) với miền giá trị không giới hạn của phần tuyến tính.

1.3. Hồi quy Logistic

Hồi quy Logistic là một trường hợp đặc biệt và rất phổ biến của GLM.

  • Biến phụ thuộc: Được sử dụng khi biến phụ thuộc là định tính nhị phân (chỉ có hai cấp độ, ví dụ: 0 hoặc 1, “Có” hoặc “Không”, “Sống sót” hoặc “Tử vong”).

  • Phân phối ngẫu nhiên: Biến phụ thuộc tuân theo phân phối Bernoulli.

  • Hàm liên kết: Hồi quy Logistic sử dụng Hàm Logit làm hàm liên kết:

    \[g(p) = \ln\left(\frac{p}{1-p}\right)\] Trong đó \(p = P(Y=1|X)\) là xác suất của sự kiện “thành công” (biến phụ thuộc bằng 1) với điều kiện các biến độc lập \(X\).

  • Mô hình toán học: Khi kết hợp các thành phần của GLM, mô hình hồi quy Logistic được biểu diễn như sau:

    \[\ln\left(\frac{P(Y=1|X)}{1 - P(Y=1|X)}\right) = \beta_0 + \beta_1 X_1 + \ldots + \beta_k X_k\]

Hồi quy Logistic là công cụ mạnh mẽ để dự đoán xác suất xảy ra một sự kiện nhị phân, thay vì dự đoán trực tiếp kết quả 0 hoặc 1, giúp chúng ta hiểu rõ hơn về ảnh hưởng của các yếu tố đầu vào.

2. Hồi quy Logistic Nhị phân

2.1. Hồi quy Logistic

Trong hồi quy Logistic, chúng ta không trực tiếp dự đoán giá trị 0 hoặc 1, mà dự đoán xác suất của sự kiện (thường là sự kiện “thành công”, được mã hóa là 1). Xác suất này, \(P\), luôn nằm trong khoảng \([0,1]\).

Tuy nhiên, một mô hình tuyến tính (\(\beta_0 + \beta_1X\)) có thể cho ra giá trị bất kỳ từ \((-\infty, +\infty)\), không phù hợp để dự đoán trực tiếp xác suất. Do đó, chúng ta cần một hàm để “ép” giá trị tuyến tính vào khoảng \([0,1]\). Hàm đó chính là Hàm Logistic (hoặc Sigmoid).

2.3. Hàm Ngược của Logit (Logistic Function / Sigmoid Function)

Để chuyển đổi từ giá trị trên thang logit (kết quả của phần tuyến tính \(\beta_0+\beta_1X+\dots\)) trở lại xác suất \(P\), chúng ta sử dụng hàm ngược của Logit, còn gọi là Hàm Logistic hay Hàm Sigmoid:

\[ P(Y=1|X) = \frac{1}{1 + e^{-(\beta_0 + \beta_1X_1 + \dots + \beta_kX_k)}} = \frac{e^{\beta_0 + \beta_1X_1 + \dots + \beta_kX_k}}{1 + e^{\beta_0 + \beta_1X_1 + \dots + \beta_kX_k}} \]

Trong R, hàm plogis(x) chính là hàm sigmoid.

# Minh họa hàm sigmoid
# Tạo một dãy giá trị tuyến tính (logit)
linear_predictor_values <- seq(-5, 5, length.out = 100)

# Chuyển đổi sang xác suất bằng hàm plogis (sigmoid)
probabilities <- plogis(linear_predictor_values)

# Vẽ đồ thị
plot(linear_predictor_values, probabilities, type = "l", col = "blue", lwd = 2,
     xlab = "Giá trị trên thang Logit (Linear Predictor)",
     ylab = "Xác suất P(Y=1)",
     main = "Hàm Sigmoid (Hàm Ngược của Logit)")
grid()
Đồ thị minh họa hàm Sigmoid, chuyển đổi giá trị tuyến tính thành xác suất.

Đồ thị minh họa hàm Sigmoid, chuyển đổi giá trị tuyến tính thành xác suất.

2.4. Ước lượng Tham số bằng MLE

Các tham số \(\beta_0, \beta_1, \dots, \beta_k\) trong hồi quy Logistic được ước lượng bằng phương pháp Maximum Likelihood Estimation (MLE). Mục tiêu là tìm các giá trị \(\beta\) mà tối đa hóa hàm log-khả năng (log-likelihood) của mô hình.

Đối với hồi quy Logistic, biến phụ thuộc \(Y\) tuân theo phân phối Bernoulli. Hàm khối lượng xác suất của Bernoulli là \(f(y|p) = p^y(1-p)^{1-y}\). Hàm log-khả năng tổng quát sẽ là:

\[ \ln L(\beta|X,y) = \sum_{i=1}^{n} \left[y_i \ln(P_i) + (1-y_i)\ln(1-P_i)\right] \]

Trong đó \(P_i = \frac{1}{1 + e^{-(\beta_0 + \beta_1X_{i1} + \dots + \beta_kX_{ik})}}\).

Việc tối đa hóa hàm này thường được thực hiện bằng các thuật toán tối ưu hóa số học (ví dụ: Newton-Raphson), được tích hợp sẵn trong các hàm của R.

3. Thực hành Hồi quy Logistic trong R (với bộ dữ liệu Iris)

Sử dụng bộ dữ liệu iris. Vì hồi quy Logistic nhị phân yêu cầu biến phụ thuộc nhị phân, tạo một biến mới is_setosa (1 nếu là setosa, 0 nếu không phải).

# Tải bộ dữ liệu Iris
data(iris)

# Tạo biến phụ thuộc nhị phân: 1 nếu Species là "setosa", 0 nếu không phải
iris$is_setosa <- ifelse(iris$Species == "setosa", 1, 0)

# Kiểm tra phân bố của biến mới
table(iris$is_setosa)
## 
##   0   1 
## 100  50

3.1. Mô hình Hồi quy Logistic Đơn biến (Univariate)

Dự đoán is_setosa dựa trên một biến độc lập, ví dụ Sepal.Length.

# Chạy mô hình hồi quy logistic đơn biến
# family = binomial chỉ định phân phối Bernoulli cho biến phụ thuộc
# link = "logit" là hàm liên kết mặc định cho binomial, nhưng rõ ràng hơn khi chỉ rõ
model_logistic_univariate <- glm(is_setosa ~ Sepal.Length, 
                                 data = iris, 
                                 family = binomial(link = "logit"))

# Xem tóm tắt kết quả mô hình
summary(model_logistic_univariate)
## 
## Call:
## glm(formula = is_setosa ~ Sepal.Length, family = binomial(link = "logit"), 
##     data = iris)
## 
## Coefficients:
##              Estimate Std. Error z value Pr(>|z|)    
## (Intercept)   27.8285     4.8276   5.765 8.19e-09 ***
## Sepal.Length  -5.1757     0.8934  -5.793 6.90e-09 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 190.954  on 149  degrees of freedom
## Residual deviance:  71.836  on 148  degrees of freedom
## AIC: 75.836
## 
## Number of Fisher Scoring iterations: 7

Giải thích kết quả summary():

  • Call: Hàm được gọi để tạo mô hình.

  • Deviance Residuals: Đánh giá độ phù hợp của mô hình. Các giá trị nhỏ cho thấy mô hình khớp tốt.

  • Coefficients:

    • Estimate: Ước lượng các hệ số \(\beta\). Intercept\(\hat{\beta}_0\)Sepal.Length\(\hat{\beta}_1\).

    • Std. Error: Sai số chuẩn của các ước lượng.

    • z value: Giá trị thống kê kiểm định Wald (tỷ lệ Estimate / Std. Error).

    • Pr(>|z|): P-value tương ứng, cho biết ý nghĩa thống kê của từng hệ số. Một P-value nhỏ (thường < 0.05) cho thấy hệ số đó khác 0 một cách có ý nghĩa thống kê.

  • Null Deviance: Độ lệch của mô hình chỉ có hệ số chặn (intercept), không có biến độc lập.

  • Residual Deviance: Độ lệch của mô hình hiện tại (có các biến độc lập). Sự giảm đáng kể từ Null Deviance sang Residual Deviance cho thấy mô hình có các biến độc lập là tốt hơn đáng kể.

  • AIC (Akaike Information Criterion): Một tiêu chí để so sánh các mô hình; giá trị AIC thấp hơn thường được ưa thích hơn.

Diễn giải hệ số: Giá trị \(\hat{\beta}_1\) (ví dụ: Sepal.Length) trong hồi quy logistic đại diện cho sự thay đổi của log-odds khi biến độc lập tăng thêm 1 đơn vị. Có thể chuyển đổi thành Odds Ratio (OR) bằng cách lấy \(\exp(\hat{\beta}_1)\). Ví dụ, nếu \(\hat{\beta}_1 = -5.15\), thì \(OR = e^{-5.15} \approx 0.0058\). Điều này có nghĩa là, với mỗi cm tăng của Sepal.Length, tỷ lệ cơ hội (odds) để hoa là setosa giảm xuống còn 0.58% (hay giảm 99.42%), giữ các yếu tố khác không đổi.

3.2. Mô hình Hồi quy Logistic Đa biến (Multivariate)

Dự đoán is_setosa dựa trên nhiều biến độc lập.

# Chạy mô hình hồi quy logistic đa biến
model_logistic_multivariate <- glm(is_setosa ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width,
                                   data = iris, 
                                   family = binomial(link = "logit"))

summary(model_logistic_multivariate)
## 
## Call:
## glm(formula = is_setosa ~ Sepal.Length + Sepal.Width + Petal.Length + 
##     Petal.Width, family = binomial(link = "logit"), data = iris)
## 
## Coefficients:
##                Estimate Std. Error z value Pr(>|z|)
## (Intercept)     -16.946 457457.097       0        1
## Sepal.Length     11.759 130504.042       0        1
## Sepal.Width       7.842  59415.385       0        1
## Petal.Length    -20.088 107724.594       0        1
## Petal.Width     -21.608 154350.616       0        1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1.9095e+02  on 149  degrees of freedom
## Residual deviance: 3.2940e-09  on 145  degrees of freedom
## AIC: 10
## 
## Number of Fisher Scoring iterations: 25

Kết quả tương tự như mô hình đơn biến, nhưng có các hệ số cho từng biến độc lập, mỗi hệ số thể hiện sự thay đổi của log-odds khi biến đó tăng 1 đơn vị, giữ các biến độc lập khác không đổi.

3.3. Dự đoán Xác suất và Phân loại

Sử dụng mô hình để dự đoán xác suất và phân loại các quan sát.

# Dự đoán xác suất sử dụng mô hình đơn biến
# type = "response" trực tiếp trả về xác suất P(Y=1|X)
predicted_probs <- predict(model_logistic_univariate, newdata = iris, type = "response")

# Xem vài giá trị dự đoán đầu tiên
head(predicted_probs)
##         1         2         3         4         5         6 
## 0.8072845 0.9218391 0.9707656 0.9823690 0.8754500 0.4699741
# Chuyển xác suất thành dự đoán lớp (ví dụ: ngưỡng 0.5)
predicted_class <- ifelse(predicted_probs > 0.5, 1, 0)

# So sánh dự đoán với giá trị thực tế (ma trận nhầm lẫn - Confusion Matrix)
confusion_matrix <- table(Actual = iris$is_setosa, Predicted = predicted_class)
print("Ma trận nhầm lẫn:")
## [1] "Ma trận nhầm lẫn:"
print(confusion_matrix)
##       Predicted
## Actual  0  1
##      0 94  6
##      1 10 40
# Tính độ chính xác (Accuracy)
accuracy <- sum(diag(confusion_matrix)) / sum(confusion_matrix)
cat("\nAccuracy của mô hình đơn biến:", round(accuracy, 3), "\n")
## 
## Accuracy của mô hình đơn biến: 0.893

4. Mô hình Probit

Mô hình Probit cũng là một dạng hồi quy nhị phân thuộc GLM, tương tự như Logistic, nhưng sử dụng một hàm liên kết khác.

4.1. Hàm Liên kết Probit

Hàm liên kết của Probit là hàm phân vị nghịch đảo của phân phối chuẩn tắc (\(\Phi^{-1}\)), còn gọi là hàm quantiles chuẩn:

\[ g(p) = \Phi^{-1}(p) \]

Trong đó \(\Phi\) là hàm phân phối tích lũy (CDF) của phân phối chuẩn tắc (mean = 0, standard deviation = 1).

Do đó, mối quan hệ tuyến tính sẽ là:

\[ \Phi^{-1}(P(Y=1|X)) = \beta_0 + \beta_1X_1 + \dots + \beta_kX_k \]

Và để chuyển đổi ngược lại thành xác suất:

\[ P(Y=1|X) = \Phi(\beta_0 + \beta_1X_1 + \dots + \beta_kX_k) \]

Trong R, hàm pnorm(x)\(\Phi(x)\)qnorm(p)\(\Phi^{-1}(p)\).

4.2. So sánh Logistic và Probit

  • Logistic (Logit link): Dựa trên phân phối Logistic.

  • Probit (Probit link): Dựa trên phân phối Chuẩn.

Cả hai hàm Sigmoid (Logistic) và hàm CDF của phân phối chuẩn đều có hình dạng chữ “S”, rất giống nhau. Probit có “đuôi” nhẹ hơn (thay đổi chậm hơn ở các xác suất cực đoan gần 0 hoặc 1), trong khi Logistic có đuôi “nặng” hơn (thay đổi nhanh hơn). Trong nhiều ứng dụng thực tế, kết quả từ Logistic và Probit thường rất tương đồng.

4.3. Chạy Mô hình Probit

Chỉ cần thay đổi link = "probit" trong hàm glm().

# Chạy mô hình Probit đơn biến
model_probit_univariate <- glm(is_setosa ~ Sepal.Length, 
                               data = iris, 
                               family = binomial(link = "probit"))

summary(model_probit_univariate)
## 
## Call:
## glm(formula = is_setosa ~ Sepal.Length, family = binomial(link = "probit"), 
##     data = iris)
## 
## Coefficients:
##              Estimate Std. Error z value Pr(>|z|)    
## (Intercept)   15.7925     2.4921   6.337 2.34e-10 ***
## Sepal.Length  -2.9407     0.4618  -6.367 1.92e-10 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 190.954  on 149  degrees of freedom
## Residual deviance:  71.372  on 148  degrees of freedom
## AIC: 75.372
## 
## Number of Fisher Scoring iterations: 8

5. Hồi quy Logistic Đa thức (Multinomial Logistic Regression)

Khi biến phụ thuộc có nhiều hơn hai cấp độ và các cấp độ này không có thứ tự tự nhiên (nominal), chúng ta sử dụng hồi quy Logistic đa thức. Ví dụ, biến Species trong iris có ba cấp độ: “setosa”, “versicolor”, “virginica”.

  • Cách hoạt động: Mô hình đa thức thường hoạt động bằng cách xây dựng một loạt các mô hình logistic nhị phân, so sánh từng cấp độ với một cấp độ tham chiếu.

  • Trong R: Thường sử dụng hàm multinom() từ gói nnet.

# Chạy mô hình hồi quy logistic đa thức
# Biến phụ thuộc là Species (có 3 cấp độ gốc)
# Cần gói 'nnet' để chạy hàm này
model_multinomial <- nnet::multinom(Species ~ Sepal.Length + Sepal.Width + Petal.Length + Petal.Width, 
                                    data = iris)
## # weights:  18 (10 variable)
## initial  value 164.791843 
## iter  10 value 16.177348
## iter  20 value 7.111438
## iter  30 value 6.182999
## iter  40 value 5.984028
## iter  50 value 5.961278
## iter  60 value 5.954900
## iter  70 value 5.951851
## iter  80 value 5.950343
## iter  90 value 5.949904
## iter 100 value 5.949867
## final  value 5.949867 
## stopped after 100 iterations
# Tóm tắt mô hình
# Các hệ số được hiển thị so với một nhóm tham chiếu (ở đây là "setosa")
summary(model_multinomial)
## Call:
## nnet::multinom(formula = Species ~ Sepal.Length + Sepal.Width + 
##     Petal.Length + Petal.Width, data = iris)
## 
## Coefficients:
##            (Intercept) Sepal.Length Sepal.Width Petal.Length Petal.Width
## versicolor    18.69037    -5.458424   -8.707401     14.24477   -3.097684
## virginica    -23.83628    -7.923634  -15.370769     23.65978   15.135301
## 
## Std. Errors:
##            (Intercept) Sepal.Length Sepal.Width Petal.Length Petal.Width
## versicolor    34.97116     89.89215    157.0415     60.19170    45.48852
## virginica     35.76649     89.91153    157.1196     60.46753    45.93406
## 
## Residual Deviance: 11.89973 
## AIC: 31.89973
# Dự đoán xác suất cho từng cấp độ
predictions_multi_prob <- predict(model_multinomial, newdata = iris, type = "probs")
head(predictions_multi_prob)
##      setosa   versicolor    virginica
## 1 1.0000000 1.526406e-09 2.716417e-36
## 2 0.9999996 3.536476e-07 2.883729e-32
## 3 1.0000000 4.443506e-08 6.103424e-34
## 4 0.9999968 3.163905e-06 7.117010e-31
## 5 1.0000000 1.102983e-09 1.289946e-36
## 6 1.0000000 3.521573e-10 1.344907e-35
# Dự đoán cấp độ có xác suất cao nhất
predicted_multi_class <- predict(model_multinomial, newdata = iris, type = "class")
head(predicted_multi_class)
## [1] setosa setosa setosa setosa setosa setosa
## Levels: setosa versicolor virginica
# Ma trận nhầm lẫn cho mô hình đa thức
confusion_matrix_multi <- table(Actual = iris$Species, Predicted = predicted_multi_class)
print("Ma trận nhầm lẫn (Đa thức):")
## [1] "Ma trận nhầm lẫn (Đa thức):"
print(confusion_matrix_multi)
##             Predicted
## Actual       setosa versicolor virginica
##   setosa         50          0         0
##   versicolor      0         49         1
##   virginica       0          1        49
# Tính độ chính xác
accuracy_multi <- sum(diag(confusion_matrix_multi)) / sum(confusion_matrix_multi)
cat("\nAccuracy của mô hình đa thức:", round(accuracy_multi, 3), "\n")
## 
## Accuracy của mô hình đa thức: 0.987

6. Maximum Likelihood Estimation (MLE) - Ước lượng Hợp lý Cực đại

Maximum Likelihood Estimation (MLE) là một phương pháp thống kê để ước lượng tham số của một mô hình phân phối xác suất dựa trên dữ liệu quan sát. Mục tiêu của MLE là tìm ra các giá trị tham số mà làm cho khả năng (likelihood) quan sát được dữ liệu hiện có là lớn nhất.

Mục đích: Ước lượng các tham số chưa biết của mô hình (ví dụ: trung bình, độ lệch chuẩn của phân phối chuẩn; xác suất p của phân phối Bernoulli) và tìm ra mô hình “phù hợp nhất” theo tiêu chí tối đa hóa khả năng xảy ra của dữ liệu.

Hàm Khả năng (Likelihood Function), ký hiệu là \(L(\theta)\), đo lường “khả năng” mà một bộ tham số \(\theta\) cụ thể sẽ tạo ra tập dữ liệu quan sát được \(x_1, x_2, \ldots, x_n\).

Nếu các quan sát \(x_1, \ldots, x_n\)độc lập và cùng phân phối (i.i.d) từ một phân phối có hàm mật độ xác suất (PDF) \(f(x | \theta)\) (hoặc hàm khối lượng xác suất PMF nếu dữ liệu rời rạc), thì hàm khả năng được định nghĩa là tích của các hàm mật độ/khối lượng xác suất của từng điểm dữ liệu:

\[L(\theta | x_1, \ldots, x_n) = \prod_{i=1}^n f(x_i | \theta)\]

  • \(\theta\): Véc-tơ các tham số của mô hình mà chúng ta muốn ước lượng (ví dụ: \(\theta = (\mu, \sigma)\) cho phân phối chuẩn, hoặc \(\theta = p\) cho phân phối Bernoulli).
  • \(x_i\): Điểm dữ liệu quan sát thứ \(i\).
  • \(f(x_i | \theta)\): Hàm mật độ xác suất (hoặc hàm khối lượng xác suất) của \(x_i\) với tham số \(\theta\).

Ví dụ: Với \(n\) lần tung đồng xu, có \(k\) lần mặt ngửa, \(f(x | p)\) là hàm khối lượng xác suất Bernoulli. Hàm khả năng sẽ là: \(L(p) = p^k (1-p)^{n-k}\).

Hàm Log-Khả năng (Log-Likelihood Function), thay vì tối đa hóa \(L(\theta)\) trực tiếp, chúng ta thường làm việc với logarit tự nhiên của hàm khả năng, gọi là hàm log-khả năng, ký hiệu \(\ln L(\theta)\) hoặc \(l(\theta)\).

Việc này có hai lý do chính:

  1. Tránh underflow số học: Khi nhân nhiều xác suất nhỏ, kết quả có thể quá nhỏ mà máy tính không thể biểu diễn chính xác. Logarit biến tích thành tổng.

  2. Đơn giản hóa việc tối ưu hóa: Việc tìm cực trị của một tổng thường dễ hơn nhiều so với tìm cực trị của một tích khi đạo hàm. Hàm logarit là hàm đồng biến, nên tối đa hóa \(\ln L(\theta)\) hoàn toàn tương đương với tối đa hóa \(L(\theta)\).

Công thức của hàm log-khả năng là:

\[\ln L(\theta | x_1, \ldots, x_n) = \sum_{i=1}^n \ln f(x_i | \theta)\]

Ví dụ (tiếp theo): Hàm log-khả năng cho ví dụ tung đồng xu sẽ là: \(\ln L(p) = k \ln(p) + (n-k) \ln(1-p)\).

Công thức Ước lượng MLE (Maximum Likelihood Estimator)

Mục tiêu của MLE là tìm giá trị của \(\theta\) (ký hiệu là \(\hat{\theta}_{MLE}\)) mà tối đa hóa hàm log-khả năng. Về mặt toán học, điều này được biểu diễn như sau:

\[\hat{\theta}_{MLE} = \arg\max_{\theta} \left[ \sum_{i=1}^n \ln f(x_i | \theta) \right]\]

Để tìm \(\hat{\theta}_{MLE}\), chúng ta thường thực hiện các bước:

  1. Lấy đạo hàm riêng của \(\ln L(\theta)\) theo mỗi tham số trong \(\theta\).

  2. Đặt các đạo hàm này bằng 0 (đây là các “phương trình điểm dừng” hay “score equations”).

  3. Giải hệ phương trình thu được để tìm giá trị của các tham số \(\hat{\theta}_{MLE}\).

Ví dụ (tiếp theo): Để tìm \(\hat{p}_{MLE}\) cho ví dụ tung đồng xu, ta lấy đạo hàm của \(\ln L(p)\) theo \(p\) và đặt bằng 0:

\[\frac{d}{dp} \ln L(p) = \frac{d}{dp} [k \ln(p) + (n-k) \ln(1-p)]\] \[= \frac{k}{p} - \frac{n-k}{1-p} = 0\]

Giải phương trình này, ta được:

\[\frac{k}{p} = \frac{n-k}{1-p}\] \[k(1-p) = p(n-k)\] \[k - kp = pn - kp\] \[k = pn\] \[\hat{p}_{MLE} = \frac{k}{n}\]

Ví dụ với R: có 100 lần tung đồng xu và thu được 60 lần mặt ngửa. Ước lượng xác suất p để đồng xu ra mặt ngửa.

# Dữ liệu
num_heads <- 60 # Số lần mặt ngửa
num_flips <- 100 # Tổng số lần tung

# Hàm log-khả năng cho phân phối nhị thức
# p_est là tham số p muốn ước lượng
log_likelihood_binomial <- function(p_est, k, n) {
  # Đảm bảo p_est nằm trong khoảng (0, 1) để tránh lỗi log(0)
  if (p_est <= 0 || p_est >= 1) {
    return(-Inf) # Trả về -Inf nếu p_est không hợp lệ
  }
  return(k * log(p_est) + (n - k) * log(1 - p_est))
}

# Tìm p_est tối đa hóa hàm log-khả năng bằng cách quét qua một dải giá trị
p_values <- seq(0.01, 0.99, by = 0.001)
likelihoods <- sapply(p_values, function(p) log_likelihood_binomial(p, num_heads, num_flips))

# Tìm p_est có likelihood lớn nhất
best_p_index <- which.max(likelihoods)
mle_p <- p_values[best_p_index]

cat("Ước lượng MLE cho xác suất mặt ngửa (p) là:", round(mle_p, 3), "\n")
## Ước lượng MLE cho xác suất mặt ngửa (p) là: 0.6
# Kết quả sẽ gần với 0.6, gần bằng k/n

Nhiệm vụ tuần 4

1. Giới thiệu bộ dữ liệu

Bộ dữ liệu train.csv là một phần của “Titanic: Machine Learning from Disaster” trên Kaggle. Nó chứa thông tin về một tập hợp hành khách trên tàu Titanic, bao gồm các đặc điểm cá nhân và quan trọng nhất là liệu họ có sống sót sau thảm họa hay không. Mục tiêu của phân tích này là khám phá các mối quan hệ giữa các biến số và biến mục tiêu Survived.

1.1 Đọc và làm quen dữ liệu

titanic <- read.csv("/Users/hotranhongnga/Downloads/UFM/HK2-2025/Phân tích dữ liệu định tính/R/Data nhiệm vụ 4/train.csv", stringsAsFactors = TRUE, header = TRUE, na.strings = c("", "NA") )

str(titanic)
## 'data.frame':    891 obs. of  12 variables:
##  $ PassengerId: int  1 2 3 4 5 6 7 8 9 10 ...
##  $ Survived   : int  0 1 1 1 0 0 0 0 1 1 ...
##  $ Pclass     : int  3 1 3 1 3 3 1 3 3 2 ...
##  $ Name       : Factor w/ 891 levels "Abbing, Mr. Anthony",..: 109 191 358 277 16 559 520 629 417 581 ...
##  $ Sex        : Factor w/ 2 levels "female","male": 2 1 1 1 2 2 2 2 1 1 ...
##  $ Age        : num  22 38 26 35 35 NA 54 2 27 14 ...
##  $ SibSp      : int  1 1 0 1 0 0 0 3 0 1 ...
##  $ Parch      : int  0 0 0 0 0 0 0 1 2 0 ...
##  $ Ticket     : Factor w/ 681 levels "110152","110413",..: 524 597 670 50 473 276 86 396 345 133 ...
##  $ Fare       : num  7.25 71.28 7.92 53.1 8.05 ...
##  $ Cabin      : Factor w/ 147 levels "A10","A14","A16",..: NA 82 NA 56 NA NA 130 NA NA NA ...
##  $ Embarked   : Factor w/ 3 levels "C","Q","S": 3 1 3 3 3 2 3 3 3 1 ...
head(titanic)
tail(titanic)

Phân loại biến:

names(titanic)
##  [1] "PassengerId" "Survived"    "Pclass"      "Name"        "Sex"        
##  [6] "Age"         "SibSp"       "Parch"       "Ticket"      "Fare"       
## [11] "Cabin"       "Embarked"
  • Biến định tính:

    • Survived: Biến nhị phân (0 = Chết, 1 = Sống sót). Đây là biến mục tiêu.

    • Pclass: Hạng vé (1 = Hạng 1, 2 = Hạng 2, 3 = Hạng 3). Biến định tính thứ bậc.

    • Sex: Giới tính (male = Nam, female = Nữ). Biến định tính nhị phân.

    • Embarked: Cảng lên tàu (C = Cherbourg, Q = Queenstown, S = Southampton). Biến định tính danh nghĩa.

    • Name: Tên hành khách. Mặc dù là chuỗi, nhưng mỗi tên là duy nhất; thường được sử dụng để trích xuất danh xưng (Title) - một biến định tính khác.

    • Cabin: Số cabin. Có nhiều giá trị thiếu và thường được xử lý thành biến định tính (có/không có cabin, hoặc tầng cabin).

    • Ticket: Số vé.

  • Biến định lượng (Numerical):

    • PassengerId: ID hành khách (thực tế là định danh).
    • Age: Tuổi.
    • SibSp: Số anh chị em/vợ chồng đi cùng.
    • Parch: Số cha mẹ/con cái đi cùng.
    • Fare: Giá vé.

1.2 Kiểm tra giá trị thiếu (NA) trong các biến định tính

# Kiểm tra số lượng giá trị NA cho TẤT CẢ các biến
na_all <- sapply(titanic, function(x) sum(is.na(x)))

# Chỉ hiển thị các biến có giá trị NA
na <- na_all[na_all > 0]
if (length(na) == 0) {
  cat("Không có giá trị NA nào trong dữ liệu.\n")
} else {
  cat("Số lượng giá trị NA trong các biến:\n")
  print(na)
}
## Số lượng giá trị NA trong các biến:
##      Age    Cabin Embarked 
##      177      687        2

Điều này cho thấy bảng dữ liệu titanic có giá trị NA. Cụ thể:

  • Age có 177 giá trị NA.
  • Cabin có 687 giá trị NA.
  • Embarked có 2 giá trị NA.

1.3 Tiền xử lý dữ liệu

Dựa trên kết quả kiểm tra NA và bản chất của các biến, thực hiện các bước tiền xử lý sau:

  • Chuyển đổi và gán nhãn cho các biến định tính: Đảm bảo các biến như Survived, Pclass, Sex, Embarked là kiểu factor với nhãn rõ ràng để dễ dàng phân tích và trực quan hóa.

  • Xử lý giá trị thiếu (NA):

    • Age (định lượng): Điền giá trị thiếu bằng giá trị trung vị (median) vì nó ít bị ảnh hưởng bởi các giá trị ngoại lai hơn so với giá trị trung bình.
    • Embarked (định tính): Điền giá trị thiếu bằng mode (giá trị xuất hiện nhiều nhất).
    • Cabin (định tính): Biến Cabin có quá nhiều giá trị thiếu (687 trên tổng số 891 dòng, chiếm khoảng 77%). Việc điền cụ thể các giá trị sẽ không hiệu quả. Thay vào đó,sẽ tạo một biến định tính nhị phân mới gọi là Has_Cabin để chỉ ra liệu hành khách có thông tin về cabin hay không (Yes/No). Điều này giúp biến đổi một biến có nhiều vấn đề thành một đặc trưng có ý nghĩa hơn.
# Chuyển đổi và gán nhãn cho các biến định tính chính
titanic_factor <- titanic %>%
  mutate(
    Survived = factor(Survived, levels = c(0, 1), labels = c("Perished", "Survived")),
    Pclass = factor(Pclass, levels = c(1, 2, 3), labels = c("1st Class", "2nd Class", "3rd Class")),
    Sex = factor(Sex, levels = c("male", "female"), labels = c("Male", "Female"))
  )

# Xử lý giá trị thiếu (NA)

# Xử lý Age: Điền bằng trung vị
median_age <- median(titanic_factor$Age, na.rm = TRUE)
titanic_factor$Age[is.na(titanic_factor$Age)] <- median_age

# Xử lý Embarked: Điền bằng mode
mode_embarked <- names(sort(table(titanic_factor$Embarked), decreasing = TRUE))[1]
titanic_factor$Embarked[is.na(titanic_factor$Embarked)] <- mode_embarked
titanic_factor$Embarked <- factor(titanic_factor$Embarked, levels = c("C", "Q", "S"), labels = c("Cherbourg", "Queenstown", "Southampton"))

# Xử lý Cabin: Tạo biến mới 'Has_Cabin'
titanic_factor <- titanic_factor %>% mutate( Has_Cabin = factor(ifelse(is.na(Cabin), "No", "Yes"), levels = c("No", "Yes")) )

sapply(titanic_factor, function(x) sum(is.na(x)))
## PassengerId    Survived      Pclass        Name         Sex         Age 
##           0           0           0           0           0           0 
##       SibSp       Parch      Ticket        Fare       Cabin    Embarked 
##           0           0           0           0         687           0 
##   Has_Cabin 
##           0
str(titanic_factor)
## 'data.frame':    891 obs. of  13 variables:
##  $ PassengerId: int  1 2 3 4 5 6 7 8 9 10 ...
##  $ Survived   : Factor w/ 2 levels "Perished","Survived": 1 2 2 2 1 1 1 1 2 2 ...
##  $ Pclass     : Factor w/ 3 levels "1st Class","2nd Class",..: 3 1 3 1 3 3 1 3 3 2 ...
##  $ Name       : Factor w/ 891 levels "Abbing, Mr. Anthony",..: 109 191 358 277 16 559 520 629 417 581 ...
##  $ Sex        : Factor w/ 2 levels "Male","Female": 1 2 2 2 1 1 1 1 2 2 ...
##  $ Age        : num  22 38 26 35 35 28 54 2 27 14 ...
##  $ SibSp      : int  1 1 0 1 0 0 0 3 0 1 ...
##  $ Parch      : int  0 0 0 0 0 0 0 1 2 0 ...
##  $ Ticket     : Factor w/ 681 levels "110152","110413",..: 524 597 670 50 473 276 86 396 345 133 ...
##  $ Fare       : num  7.25 71.28 7.92 53.1 8.05 ...
##  $ Cabin      : Factor w/ 147 levels "A10","A14","A16",..: NA 82 NA 56 NA NA 130 NA NA NA ...
##  $ Embarked   : Factor w/ 3 levels "Cherbourg","Queenstown",..: 3 1 3 3 3 2 3 3 3 1 ...
##  $ Has_Cabin  : Factor w/ 2 levels "No","Yes": 1 2 1 2 1 1 2 1 1 1 ...
head(titanic_factor)

Nhận xét về tiền xử lý dữ liệu:

Các biến định tính (Survived, Pclass, Sex, Embarked) đã được chuyển đổi sang kiểu factor và gán nhãn rõ ràng. Tất cả các giá trị thiếu trong Age, Embarked, và Cabin đã được xử lý.

  • Age đã được điền bằng trung vị.
  • Embarked đã được điền bằng mode.
  • Cabin đã được biến đổi thành một biến nhị phân Has_Cabin.

2. Phân tích mô tả biến định tính

2.1 Biến Survived (Khả năng sống sót)

Thống kê tần suất và tỷ lệ

# Bảng tần số
survived <- table(titanic_factor$Survived)

# Bảng tần suất
tylesurvived <- round(prop.table(survived) * 100, 2)

# Tạo bảng  
survivedtable <- data.frame(
  Survived = names(survived),
  Frequency = as.vector(survived),
  Percentage = paste0(tylesurvived, "%") ) 

# Hiển thị bảng
library(knitr)
kable(survivedtable, caption = "Bảng tần suất và tỷ lệ phần trăm khả năng sống sót")
Bảng tần suất và tỷ lệ phần trăm khả năng sống sót
Survived Frequency Percentage
Perished 549 61.62%
Survived 342 38.38%

Theo bảng trên, trong tổng số hành khách có thông tin về biến Survived:

  • Có 549 người không sống sót chiếm 61.62%.
  • Trong khi chỉ có 342 người sống sót chiếm 38.38%.

Tỷ lệ tử vong cao hơn đáng kể so với tỷ lệ sống sót. Kết quả này phản ánh rõ rằng trong tai nạn tàu Titanic, xác suất để một hành khách tử vong là vượt trội hơn so với sống sót. Nếu coi mỗi hành khách là một phép thử Bernoulli (sống sót hay không), thì tỷ lệ sống sót 38.38% cho thấy khả năng sống sót là khá thấp trong tổng thể.

Trực quan hóa bằng biểu đồ

ggplot(survivedtable, aes(x = Survived, y = Frequency, fill = Survived)) +
  geom_bar(stat = "identity", color = "black") +
  geom_text(aes(label = Percentage), vjust = -0.5, size = 4) +
  labs(title = "Tần suất sống sót trên tàu Titanic",
       x = "Trạng thái sống sót",
       y = "Số lượng hành khách") +
  theme_minimal() +
  scale_fill_brewer(palette = "Set1") +
  theme(legend.position = "none")

Từ bảng tần suất và biểu đồ cột, chúng ta thấy rằng phần lớn hành khách trên tàu Titanic đã không sống sót. Cụ thể, khoảng 61.62% hành khách đã tử vong, trong khi chỉ có khoảng 38.38% sống sót. Điều này cho thấy thảm họa Titanic thực sự là một sự kiện có tỷ lệ tử vong rất cao.

2.2 Biến Sex (Giới tính)

Thống kê tần suất và tỷ lệ

titanic_factor$Sex <- factor(titanic_factor$Sex, levels = c("Male", "Female"))

# Bảng tần số
sex <- table(titanic_factor$Sex)

# Bảng tần suất
tylesex <- round(prop.table(sex) * 100, 2)

# Tạo bảng  
sextable <- data.frame(
  Sex = names(sex),
  Frequency = as.vector(sex),
  Percentage = paste0(tylesex, "%") ) 

# Hiển thị bảng
library(knitr)
kable(sextable, caption = "Bảng tần suất và tỷ lệ phần trăm khả năng sống sót")
Bảng tần suất và tỷ lệ phần trăm khả năng sống sót
Sex Frequency Percentage
Male 577 64.76%
Female 314 35.24%

Trực quan hóa bằng biểu đồ

library(ggplot2)
ggplot(sextable, aes(x = Sex, y = Frequency, fill = Sex)) +
  geom_bar(stat = "identity", color = "black") + # stat = "identity" để sử dụng giá trị y (Frequency) trực tiếp
  geom_text(aes(label = Percentage), vjust = -0.5, size = 4) + # Hiển thị Percentage trên đầu cột
  labs(title = "Phân phối giới tính hành khách trên tàu Titanic",
       x = "Giới tính",
       y = "Số lượng hành khách") +
  theme_minimal() +
  scale_fill_brewer(palette = "Set2") + # Gán màu khác nhau cho mỗi giới tính từ bảng màu "Set1"
  theme(legend.position = "none") # Ẩn chú giải vì màu đã được gán trực tiếp trên cột

Từ bảng tần suất và biểu đồ, ta thấy rằng tỷ lệ hành khách nam cao hơn đáng kể so với nữ. Hành khách nam chiếm khoảng , trong khi hành khách nữ chỉ chiếm khoảng . Sự chênh lệch này có thể ảnh hưởng đến phân tích tỷ lệ sống sót, đặc biệt nếu có sự ưu tiên cứu hộ theo giới tính (phụ nữ và trẻ em trước) trong hoàn cảnh tai nạn.

3. Ước lượng khoảng và Kiểm định giả thuyết cho tỷ lệ

3.1 Ước lượng khoảng tin cậy cho tỷ lệ sống sót

# Số lượng người sống sót
n_survived <- sum(titanic_factor$Survived == "Survived")
# Tổng số hành khách
survived_total <- nrow(titanic_factor)
# Tính tỷ lệ mẫu
p <- n_survived / survived_total
# Tính khoảng tin cậy
ci_survived <- prop.test(n_survived, survived_total, conf.level = 0.95)
ci_survived
## 
##  1-sample proportions test with continuity correction
## 
## data:  n_survived out of survived_total, null probability 0.5
## X-squared = 47.627, df = 1, p-value = 5.154e-12
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.3519194 0.4167722
## sample estimates:
##         p 
## 0.3838384
cat("Tỷ lệ sống sót ước tính:", round(p * 100, 2), "%\n")
## Tỷ lệ sống sót ước tính: 38.38 %
cat("Khoảng tin cậy 95% cho tỷ lệ sống sót:\n")
## Khoảng tin cậy 95% cho tỷ lệ sống sót:
print(ci_survived$conf.int * 100)
## [1] 35.19194 41.67722
## attr(,"conf.level")
## [1] 0.95

Nhận xét: Khoảng tin cậy 95% cho tỷ lệ sống sót là từ 35.19% đến 41.68%. Điều này có nghĩa là với khoảng tin cậy 95% thì tỷ lệ sống sót thực sự của hành khách trên tàu Titanic nằm trong khoảng này.

3.2 Kiểm định giả thuyết cho tỷ lệ sống sót

Kiểm định giả thuyết rằng tỷ lệ sống sót có khác 50% hay không.

\(H_0\): Tỷ lệ sống sót là 50%. (\(H_0: p = 0.5\))

\(H_1\): Tỷ lệ sống sót khác 50%. (\(H_1: p \neq 0.5\)) Với Mức ý nghĩa \(\alpha = 0.05\).

ht_survived <- prop.test(n_survived, survived_total, p = 0.5, alternative = "two.sided", conf.level = 0.95)
print(ht_survived)
## 
##  1-sample proportions test with continuity correction
## 
## data:  n_survived out of survived_total, null probability 0.5
## X-squared = 47.627, df = 1, p-value = 5.154e-12
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.3519194 0.4167722
## sample estimates:
##         p 
## 0.3838384

Nhận xét: Với giá trị p-value 0 nhỏ hơn 0.05, chúng ta bác bỏ giả thuyết \(H_0\). Điều này có nghĩa là có bằng chứng thống kê mạnh mẽ cho thấy tỷ lệ sống sót trên tàu Titanic khác biệt đáng kể so với 50%. Thực tế, tỷ lệ sống sót thấp hơn nhiều.

4. Phân tích mối quan hệ ảnh hưởng giữa các biến định tính

4.1 Mối quan hệ giữa Survived và Sex

4.1.1 Bảng tần suất chéo và Trực quan hoá bằng biểu đồ

Bảng tần số chéo

# Bảng tần số chéo
table_sex_survived <- table(titanic_factor$Sex, titanic_factor$Survived)
print(table_sex_survived)
##         
##          Perished Survived
##   Male        468      109
##   Female       81      233
# Tỷ lệ theo hàng (tỷ lệ theo giới tính)
prop_table_sex_survived_row<- prop.table(table_sex_survived, margin = 1) * 100
print(round(prop_table_sex_survived_row, 2))
##         
##          Perished Survived
##   Male      81.11    18.89
##   Female    25.80    74.20

Biểu đồ

ggplot(titanic_factor, aes(x = Sex, fill = Survived)) +
  geom_bar(position = "fill", color = "black") + # position = "fill" để xem tỷ lệ
  labs(title = "Tỷ lệ Sống sót theo Giới tính",
       x = "Giới tính",
       y = "Tỷ lệ",
       fill = "Sống sót") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("Perished" = "pink", "Survived" = "lightgreen")) + # Màu sắc tùy chỉnh
  theme_minimal() +
  theme(legend.position = "right")

Nhận xét về mối quan hệ giữa Giới tính và Khả năng Sống sót

Phụ nữ có khả năng sống sót cao hơn đáng kể so với nam giới: Trong nhóm nữ giới, có 74.20% người sống sót (Survived), trong khi chỉ có 25.80% người không sống sót (Perished). Ngược lại, trong nhóm nam giới, tỷ lệ không sống sót là áp đảo với 81.11%, và chỉ có 18.89% nam giới sống sót. Sự chênh lệch này cho thấy chính sách “phụ nữ và trẻ em trước” (women and children first) dường như đã được ưu tiên thực hiện, hoặc phụ nữ có cơ hội tiếp cận thuyền cứu sinh tốt hơn.

Sự phân bổ số lượng tuyệt đối giữa các nhóm: Mặc dù có tỷ lệ sống sót cao, vẫn có 81 phụ nữ không sống sót. Số lượng nam giới không sống sót là rất lớn, lên tới 468 người, cho thấy phần lớn nam giới đã tử nạn. Trong khi đó, số lượng nữ giới sống sót là 233 người, cao hơn đáng kể so với 109 nam giới sống sót.”

Kết luận: Dữ liệu cho thấy giới tính là một yếu tố ảnh hưởng mạnh mẽ đến khả năng sống sót trên tàu Titanic, với phụ nữ có tỷ lệ sống sót vượt trội so với nam giới.

4.1.2 Kiểm định thống kê bằng Chi-bình phương (\({\chi^2}\))

Kiểm định xem mối quan hệ này có ý nghĩa thống kê hay không, kiểm định Chi-bình phương cho bảng tần suất chéo.

\(H_0\): Survived và Sex độc lập (không có mối quan hệ).

\(H_1\): Survived và Sex phụ thuộc (có mối quan hệ).

chitest_sex_survived <- chisq.test(table_sex_survived)
print(chitest_sex_survived)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  table_sex_survived
## X-squared = 260.72, df = 1, p-value < 2.2e-16

Nhận xét: Với giá trị p-value rất nhỏ <2e-16, chúng ta bác bỏ giả thuyết \(H_0\). Điều này có nghĩa là có bằng chứng thống kê mạnh mẽ cho thấy có mối quan hệ phụ thuộc có ý nghĩa giữa giới tính và khả năng sống sót.

4.1.3 Relative Risk (RR) và Odds Ratio (OR)

library(epitools)
addmargins(table_sex_survived)
##         
##          Perished Survived Sum
##   Male        468      109 577
##   Female       81      233 314
##   Sum         549      342 891
cat("\nRelative risk\n")
## 
## Relative risk
riskratio(table_sex_survived)
## $data
##         
##          Perished Survived Total
##   Male        468      109   577
##   Female       81      233   314
##   Total       549      342   891
## 
## $measure
##         risk ratio with 95% C.I.
##          estimate    lower    upper
##   Male   1.000000       NA       NA
##   Female 3.928037 3.276995 4.708422
## 
## $p.value
##         two-sided
##          midp.exact fisher.exact   chi.square
##   Male           NA           NA           NA
##   Female          0 6.463922e-60 3.711748e-59
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
cat("\nOdds Ratio\n")
## 
## Odds Ratio
oddsratio(table_sex_survived)
## $data
##         
##          Perished Survived Total
##   Male        468      109   577
##   Female       81      233   314
##   Total       549      342   891
## 
## $measure
##         odds ratio with 95% C.I.
##          estimate    lower    upper
##   Male    1.00000       NA       NA
##   Female 12.28921 8.894567 17.14789
## 
## $p.value
##         two-sided
##          midp.exact fisher.exact   chi.square
##   Male           NA           NA           NA
##   Female          0 6.463922e-60 3.711748e-59
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"

Nhận xét về RR và OR

  • Relative Risk (RR):
    Tỷ lệ sống sót của phụ nữ cao gấp khoảng 3.93 lần so với nam giới.
    Khoảng tin cậy 95% cho RR là từ 3.28 đến 4.71.
    Vì RR > 1 và khoảng tin cậy không chứa 1, điều này cho thấy sự khác biệt trong giới tính có ý nghĩa thống kê rõ ràng rằng nữ giới có tỷ lệ sống sót cao hơn.

  • Odds Ratio (OR):
    Tỷ lệ chênh sống sót của phụ nữ cao gấp khoảng 12.29 lần so với nam giới.
    Khoảng tin cậy 95% cho OR là từ 8.89 đến 17.15.
    OR cũng lớn hơn 1 đáng kể và khoảng tin cậy không chứa 1, khẳng định mối liên hệ mạnh mẽ giữa giới tính và khả năng sống sót.

Cả RR và OR đều cho thấy phụ nữ có khả năng sống sót cao hơn nam giới trong thảm họa Titanic. Đây là kết quả thống kê rõ ràng và phù hợp với bối cảnh xã hội và nguyên tắc cứu hộ tại thời điểm đó (“phụ nữ và trẻ em trước”).

4.2 Mối quan hệ giữa Survived và Pclass

4.2.1 Bảng tần suất chéo và Trực quan hoá bằng biểu đồ

Bảng tần suất chéo

# Bảng tần số chéo
table_pclass_survived <- table(titanic_factor$Pclass, titanic_factor$Survived)
print(table_pclass_survived)
##            
##             Perished Survived
##   1st Class       80      136
##   2nd Class       97       87
##   3rd Class      372      119
# Tỷ lệ theo hàng (tỷ lệ sống sót trong mỗi hạng vé)
prop_table_pclass_survived_row<- prop.table(table_pclass_survived, margin = 1) * 100
print(round(prop_table_pclass_survived_row, 2))
##            
##             Perished Survived
##   1st Class    37.04    62.96
##   2nd Class    52.72    47.28
##   3rd Class    75.76    24.24

Biểu đồ

ggplot(titanic_factor, aes(x = Pclass, fill = Survived)) +
  geom_bar(position = "fill", color = "black") + # position = "fill" để xem tỷ lệ
  labs(title = "Tỷ lệ Sống sót theo Hạng vé",
       x = "Hạng vé",
       y = "Tỷ lệ",
       fill = "Sống sót") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("Perished" = "orange", "Survived" = "darkgreen")) + # Màu sắc tùy chỉnh
  theme_minimal() +
  theme(legend.position = "right")

Nhận xét về mối quan hệ giữa Hạng vé và Khả năng Sống sót:

Có một xu hướng rõ ràng: hành khách ở hạng vé cao hơn (1st Class) có tỷ lệ sống sót cao hơn đáng kể so với hành khách ở hạng vé thấp hơn (3rd Class). Tỷ lệ sống sót của 1st Class là 62.96%, 2nd Class là 47.28%, và 3rd Class chỉ là 24.24%. Điều này cho thấy tầng lớp xã hội có thể đã đóng vai trò quan trọng trong việc phân bổ cơ hội sống sót.

4.2.2 Kiểm định thống kê bằng Chi-bình phương (\({\chi^2}\))

chitest_pclass_survived <- chisq.test(table_pclass_survived)
print(chitest_pclass_survived)
## 
##  Pearson's Chi-squared test
## 
## data:  table_pclass_survived
## X-squared = 102.89, df = 2, p-value < 2.2e-16

Nhận xét: Với p-value rất nhỏ <2e-16, chúng ta bác bỏ giả thuyết \(H_0\). Có bằng chứng thống kê mạnh mẽ cho thấy Pclass và Survived là phụ thuộc, tức là hạng vé có mối quan hệ có ý nghĩa với khả năng sống sót.

4.2.3 Relative Risk (RR) và Odds Ratio (OR) cho Survived và Pclass

So sánh các hạng vé thấp hơn với hạng vé 1 (1st Class) như là nhóm tham chiếu.

library(epitools)
addmargins(table_pclass_survived)
##            
##             Perished Survived Sum
##   1st Class       80      136 216
##   2nd Class       97       87 184
##   3rd Class      372      119 491
##   Sum            549      342 891
riskratio(table_pclass_survived)
## $data
##            
##             Perished Survived Total
##   1st Class       80      136   216
##   2nd Class       97       87   184
##   3rd Class      372      119   491
##   Total          549      342   891
## 
## $measure
##            risk ratio with 95% C.I.
##              estimate     lower     upper
##   1st Class 1.0000000        NA        NA
##   2nd Class 0.7509591 0.6249491 0.9023768
##   3rd Class 0.3849287 0.3193195 0.4640184
## 
## $p.value
##            two-sided
##             midp.exact fisher.exact   chi.square
##   1st Class         NA           NA           NA
##   2nd Class 0.00172126 1.777083e-03 1.650128e-03
##   3rd Class 0.00000000 1.786956e-22 5.209808e-23
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
oddsratio(table_pclass_survived)
## $data
##            
##             Perished Survived Total
##   1st Class       80      136   216
##   2nd Class       97       87   184
##   3rd Class      372      119   491
##   Total          549      342   891
## 
## $measure
##            odds ratio with 95% C.I.
##              estimate     lower     upper
##   1st Class 1.0000000        NA        NA
##   2nd Class 0.5287186 0.3533065 0.7880804
##   3rd Class 0.1888611 0.1332280 0.2658823
## 
## $p.value
##            two-sided
##             midp.exact fisher.exact   chi.square
##   1st Class         NA           NA           NA
##   2nd Class 0.00172126 1.777083e-03 1.650128e-03
##   3rd Class 0.00000000 1.786956e-22 5.209808e-23
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
  • Nhận xét Relative Risk cho Survived theo Pclass (so với 1st Class)

Tỷ lệ sống sót của hành khách hạng hai (2nd Class) là khoảng 0.75 lần so với hạng nhất. Khoảng tin cậy 95% RR là từ 0.62 đến 0.9. Vì RR < 1 và khoảng tin cậy không chứa 1, điều này cho thấy hành khách hạng hai có tỷ lệ sống sót thấp hơn đáng kể so với hạng nhất.

Tỷ lệ sống sót của hành khách hạng ba (3rd Class) là khoảng 0.38 lần so với hạng nhất. Khoảng tin cậy 95% RR là từ 0.32 đến 0.46. Đây là một mức giảm rất lớn và có ý nghĩa thống kê, khẳng định hành khách hạng ba có tỷ lệ sống sót thấp hơn rất nhiều so với hạng nhất.

  • Nhận xét Odds Ratio cho Survived theo Pclass (so với 1st Class)

Tỷ lệ chênh sống sót của hành khách hạng hai (2nd Class) là khoảng 0.53 lần so với hạng nhất. Khoảng tin cậy 95% OR là từ 0.35 đến 0.79. Điều này cho thấy odds sống sót của hạng hai thấp hơn hạng nhất.

Tỷ lệ chênh sống sót của hành khách hạng ba (3rd Class) là khoảng 0.19 lần so với hạng nhất. Khoảng tin cậy 95% OR là từ 0.13 đến 0.27. Đây là một sự khác biệt rất lớn, khẳng định odds sống sót của hạng ba thấp hơn rất nhiều so với hạng nhất.

4.3 Mối quan hệ giữa Survived và Embarked

4.3.1 Bảng tần suất chéo và Trực quan hoá bằng biểu đồ

Bảng tần số chéo

# Bảng tần số chéo
table_embarked_survived <- table(titanic_factor$Embarked, titanic_factor$Survived)
print(table_embarked_survived)
##              
##               Perished Survived
##   Cherbourg         75       93
##   Queenstown        47       30
##   Southampton      427      219
# Tỷ lệ theo hàng (tỷ lệ sống sót ở mỗi cảng lên tàu)
prop_table_embarked_survived_row<- prop.table(table_embarked_survived, margin = 1) * 100
print(round(prop_table_embarked_survived_row, 2))
##              
##               Perished Survived
##   Cherbourg      44.64    55.36
##   Queenstown     61.04    38.96
##   Southampton    66.10    33.90

Trực quan hóa

ggplot(titanic_factor, aes(x = Embarked, fill = Survived)) +
  geom_bar(position = "fill", color = "black") +
  labs(title = "Tỷ lệ Sống sót theo Cảng lên tàu",
       x = "Cảng lên tàu",
       y = "Tỷ lệ",
       fill = "Sống sót") +
  scale_y_continuous(labels = scales::percent) +
  scale_fill_manual(values = c("Perished" = "violet", "Survived" = "lightblue")) +
  theme_minimal() +
  theme(legend.position = "right")

Nhận xét:

Có sự khác biệt về tỷ lệ sống sót giữa các cảng lên tàu. Hành khách lên tàu từ Cherbourg (C) có tỷ lệ sống sót cao nhất 55.36%, trong khi những người từ Southampton (S) có tỷ lệ thấp nhất 33.9%. Mối quan hệ này có thể gián tiếp, ví dụ, hành khách từ Cherbourg có thể có xu hướng mua vé hạng cao hơn.

4.3.2 Kiểm định thống kê bằng Chi-bình phương (\({\chi^2}\))

chitest_embarked <- chisq.test(table_embarked_survived)
print(chitest_embarked)
## 
##  Pearson's Chi-squared test
## 
## data:  table_embarked_survived
## X-squared = 25.964, df = 2, p-value = 2.301e-06

Nhận xét: Với p-value 2.3e-06 (nhỏ hơn 0.05), chúng ta bác bỏ giả thuyết \(H_0\). Có bằng chứng thống kê mạnh mẽ cho thấy Embarked và Survived là phụ thuộc, tức là cảng lên tàu có mối quan hệ có ý nghĩa với khả năng sống sót.

4.3.3 Relative Risk (RR) và Odds Ratio (OR) cho Survived và Embarked

Lấy cảng Cherbourg (C) làm nhóm tham chiếu vì nó có tỷ lệ sống sót cao nhất.

library(epitools)
addmargins(table_embarked_survived)
##              
##               Perished Survived Sum
##   Cherbourg         75       93 168
##   Queenstown        47       30  77
##   Southampton      427      219 646
##   Sum              549      342 891
riskratio(table_embarked_survived)
## $data
##              
##               Perished Survived Total
##   Cherbourg         75       93   168
##   Queenstown        47       30    77
##   Southampton      427      219   646
##   Total            549      342   891
## 
## $measure
##              risk ratio with 95% C.I.
##                estimate     lower     upper
##   Cherbourg   1.0000000        NA        NA
##   Queenstown  0.7038123 0.5157936 0.9603682
##   Southampton 0.6124039 0.5149589 0.7282882
## 
## $p.value
##              two-sided
##                 midp.exact fisher.exact   chi.square
##   Cherbourg             NA           NA           NA
##   Queenstown  1.796481e-02 1.954610e-02 1.718059e-02
##   Southampton 5.201648e-07 5.233446e-07 3.473864e-07
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
oddsratio(table_embarked_survived)
## $data
##              
##               Perished Survived Total
##   Cherbourg         75       93   168
##   Queenstown        47       30    77
##   Southampton      427      219   646
##   Total            549      342   891
## 
## $measure
##              odds ratio with 95% C.I.
##                estimate     lower     upper
##   Cherbourg   1.0000000        NA        NA
##   Queenstown  0.5169647 0.2955153 0.8934725
##   Southampton 0.4142557 0.2926246 0.5845844
## 
## $p.value
##              two-sided
##                 midp.exact fisher.exact   chi.square
##   Cherbourg             NA           NA           NA
##   Queenstown  1.796481e-02 1.954610e-02 1.718059e-02
##   Southampton 5.201648e-07 5.233446e-07 3.473864e-07
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"

Nhận xét về RR và OR cho Embarked:

  • Relative Risk (RR) cho Embarked

Tỷ lệ sống sót của hành khách lên tàu từ Queenstown (Q) là khoảng 0.7 lần so với Cherbourg. Khoảng tin cậy 95% RR là từ 0.52 đến 0.96. Giá trị này nhỏ hơn 1, cho thấy tỷ lệ sống sót từ Queenstown thấp hơn.

Tỷ lệ sống sót của hành khách lên tàu từ Southampton (S) là khoảng0.61 lần so với Cherbourg. Khoảng tin cậy 95% RR là từ 0.51 đến 0.73. Đây là một mức giảm đáng kể, cho thấy tỷ lệ sống sót từ Southampton thấp hơn nhiều so với Cherbourg.

  • Odds Ratio (OR) cho Embarked

Tỷ lệ chênh sống sót của hành khách lên tàu từ Queenstown (Q) là khoảng 0.52 lần so với Cherbourg. Khoảng tin cậy 95% OR là từ 0.3 đến 0.89. Điều này cho thấy odds sống sót từ Queenstown thấp hơn.

Tỷ lệ chênh sống sót của hành khách lên tàu từ Southampton (S) là khoảng 0.41, lần so với Cherbourg. Khoảng tin cậy 95% OR là từ 0.29 đến 0.58. Đây là một sự khác biệt đáng kể, khẳng định odds sống sót từ Southampton thấp hơn nhiều so với Cherbourg.

5. Tổng kết

Phân tích bộ dữ liệu train.csv của Titanic đã cho thấy một số mối quan hệ quan trọng giữa các biến định tính và khả năng sống sót:

  • Tỷ lệ sống sót chung: Chỉ có một phần nhỏ hành khách sống sót sau thảm họa, khẳng định mức độ nghiêm trọng của sự kiện.
  • Giới tính là yếu tố tác động mạnh mẽ nhất: Phụ nữ có tỷ lệ sống sót cao hơn đáng kể so với nam giới, phù hợp với các quy tắc cứu hộ “phụ nữ và trẻ em trước”. Cả Relative Risk và Odds Ratio đều cho thấy tác động rất lớn của giới tính lên khả năng sống sót.
  • Hạng vé cũng ảnh hưởng lớn: Hành khách ở hạng vé cao hơn (hạng 1) có cơ hội sống sót cao hơn nhiều so với những người ở hạng thấp hơn (hạng 3). Điều này có thể do vị trí cabin gần thuyền cứu sinh hơn hoặc sự ưu tiên trong quá trình sơ tán.
  • Cảng lên tàu có mối liên hệ: Có sự khác biệt về tỷ lệ sống sót giữa các cảng lên tàu. Mối quan hệ này có thể được giải thích thêm bằng cách phân tích các biến khác liên quan đến cảng lên tàu (có thể phân tích thêm hạng vé của hành khách từ mỗi cảng để thấy rõ hơn).
  • Các kiểm định Chi-bình phương đã xác nhận rằng tất cả các mối quan hệ được quan sát giữa Survived và Sex, Pclass, Embarked đều có ý nghĩa thống kê.

6. Mô hình Hồi quy Logistic và Probit

6.3 So sánh Mô hình Logistic và Probit

aic_logistic <- AIC(model_logistic)
aic_probit <- AIC(model_probit)

cat("AIC của mô hình Logistic:", round(aic_logistic, 2), "\n")
## AIC của mô hình Logistic: 798.01
cat("AIC của mô hình Probit:", round(aic_probit, 2), "\n")
## AIC của mô hình Probit: 799.85

Nhận xét về AIC:

Mô hình với AIC thấp hơn được ưu tiên. Ở đây, AIC của mô hình Logistic (798.01) và Probit (799.85) rất gần nhau. Điều này cho thấy cả hai mô hình đều có hiệu suất tương đương trong việc giải thích dữ liệu. Trong trường hợp này, việc lựa chọn mô hình nào có thể phụ thuộc vào mục đích sử dụng hoặc sự ưu tiên trong việc diễn giải (Odds Ratio của Logistic thường trực quan hơn).

Nhiệm vụ tuần 2,3

Phần 1: TÌM HIỂU VÀ CHUẨN BỊ DỮ LIỆU

1.1 Đọc và làm quen dữ liệu

# Đọc dữ liệu (stringsAsFactors = FALSE: không chuyển chuỗi thành factor, header = TRUE: dòng đầu tiên là tiêu đề cột)
data <- read.csv("NV1 - Supermarket Transactions.csv", stringsAsFactors = FALSE, header = TRUE)

# Xem cấu trúc tổng quát của dữ liệu: tên biến, kiểu dữ liệu
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 ...
# Xem một vài dòng đầu 
head(data)
# Xem vài dòng cuối 
tail(data)
# Liệt kê tên cột trong data
names(data)
##  [1] "X"                 "PurchaseDate"      "CustomerID"       
##  [4] "Gender"            "MaritalStatus"     "Homeowner"        
##  [7] "Children"          "AnnualIncome"      "City"             
## [10] "StateorProvince"   "Country"           "ProductFamily"    
## [13] "ProductDepartment" "ProductCategory"   "UnitsSold"        
## [16] "Revenue"

1.2 Kiểm tra giá trị thiếu (NA) trong các biến định tính

Cách xử lý giá trị thiếu:

  • Nếu có NA:

  • Nếu số lượng NA nhỏ → loại bỏ dòng chứa NA để tránh nhiễu.

  • Nếu số lượng NA lớn hoặc phân bố đều → thay thế bằng mode để giữ lại dữ liệu. Việc thay thế bằng mode sẽ giữ được cỡ mẫu, hạn chế mất dữ liệu, đồng thời vẫn phản ánh xu hướng chính của biến.

# Lọc biến định tính
dinhtinh <- c("Gender", "MaritalStatus", "Homeowner", "AnnualIncome", 
               "City", "StateorProvince", "Country",
               "ProductFamily", "ProductDepartment", "ProductCategory")

# Kiểm tra số lượng giá trị NA trong từng biến (sapply(...): áp dụng hàm cho từng cột và trả về vector, data[dinhtinh]: chọn các cột trong data theo tên/thứ tự có trong dinhtinh, function(x) ...: hàm ẩn danh áp dụng cho từng cột, is.na(x): kiểm tra giá trị NA trong cột, sum(is.na(x)): đếm số lượng NA trong cột)
nacounts <- sapply(data[dinhtinh], function(x) sum(is.na(x))) 
nacounts
##            Gender     MaritalStatus         Homeowner      AnnualIncome 
##                 0                 0                 0                 0 
##              City   StateorProvince           Country     ProductFamily 
##                 0                 0                 0                 0 
## ProductDepartment   ProductCategory 
##                 0                 0

Điều này cho thấy bảng dữ liệu dinhtinh không có giá trị NA.

1.3 Chuyển đổi biến sáng kiểu factor (nếu chưa phải)

Trong R, kiểu factor đại diện cho biến định tính (categorical), điều này cực kỳ quan trọng trong phân tích thống kê như:

  • Tính tần suất

  • Biểu đồ cột (bar chart)

  • Kiểm định Chi-square

  • Mô hình phân loại

# Chuyển tất cả biến định tính đã liệt kê thành kiểu factor (nếu chưa) (lapply(...): áp dụng hàm cho từng cột, trả về list, data[dinhtinh]: chọn các cột cần chuyển đổi, factor: hàm chuyển dữ liệu thành kiểu factor (biến phân loại))
data[dinhtinh] <- lapply(data[dinhtinh], factor)

# Kiểm tra lại để đảm bảo chuyển đổi thành công
str(data[dinhtinh])
## 'data.frame':    14059 obs. of  10 variables:
##  $ Gender           : Factor w/ 2 levels "F","M": 1 2 1 2 1 1 2 1 2 2 ...
##  $ MaritalStatus    : Factor w/ 2 levels "M","S": 2 1 1 1 2 1 2 1 1 2 ...
##  $ Homeowner        : Factor w/ 2 levels "N","Y": 2 2 1 2 2 2 2 2 2 1 ...
##  $ AnnualIncome     : Factor w/ 8 levels "$10K - $30K",..: 5 7 6 5 3 1 5 4 1 6 ...
##  $ City             : Factor w/ 23 levels "Acapulco","Bellingham",..: 8 8 4 12 3 3 13 23 2 15 ...
##  $ StateorProvince  : Factor w/ 10 levels "BC","CA","DF",..: 2 2 8 6 2 2 6 8 8 2 ...
##  $ Country          : Factor w/ 3 levels "Canada","Mexico",..: 3 3 3 3 3 3 3 3 3 3 ...
##  $ ProductFamily    : Factor w/ 3 levels "Drink","Food",..: 2 2 2 2 1 2 2 2 3 3 ...
##  $ ProductDepartment: Factor w/ 22 levels "Alcoholic Beverages",..: 20 18 20 21 4 11 13 6 15 14 ...
##  $ ProductCategory  : Factor w/ 45 levels "Baking Goods",..: 42 45 42 7 15 41 5 13 16 35 ...

Phần 2: PHÂN TÍCH MÔ TẢ MỘT BIẾN ĐỊNH TÍNH (Univariate Descriptive Analysis)

2.1. Gender

2.1.1. Thống kê tần suất và tỷ lệ phần trăm

# Bảng tần số
gender <- table(data$Gender)

# Bảng tần suất
tylegender <- round(prop.table(gender) * 100, 2)

# Tạo bảng trình bày rõ ràng 
gendertable <- data.frame(
  Gender = names(gender),
  Frequency = as.vector(gender),
  Percentage = paste0(tylegender, "%") # Hàm paste0() dùng để nối chuỗi ký tự (text) lại với nhau.hàm paste0() tự động bỏ khoảng trắng, còn paste() thì mặc định chèn khoảng trắng giữa các phần.
) 

# Hiển thị bảng
library(knitr)
kable(gendertable, caption = "Bảng tần suất và tỷ lệ phần trăm giới tính")
Bảng tần suất và tỷ lệ phần trăm giới tính
Gender Frequency Percentage
F 7170 51%
M 6889 49%

Bảng thống kê cho thấy biến Gender gồm có 2 hạng mục. Trong đó, Female: chiếm 51% với 7170 trường hợp. Và Male: chiếm 49% với 6889 trường hợp.

Nhìn chung, Female chiếm tỷ lệ cao hơn (51%) so với hạng mục còn lại, phản ánh sự mất cân đối nhất định trong phân bố giới tính của khách hàng.

2.1.2. Trực quan hoá bằng biểu đồ

library(ggplot2)
library(dplyr)

# Chuẩn bị dữ liệu để vẽ pie chart
genderplot <- gendertable %>% # %>%: toán tử pipe, truyền dữ liệu sang hàm tiếp theo
  mutate( # mutate(...): thêm cột mới vào data frame
    Label = paste0(Gender, ": ", Percentage, "")  # Gắn nhãn
  )

# Vẽ biểu đồ tròn bằng ggplot2
ggplot(genderplot, aes(x = "", y = Frequency, fill = Gender)) +
  geom_bar(stat = "identity", width = 1, color = "white") +
  coord_polar(theta = "y") +  # Chuyển bar chart thành pie chart
  theme_void() +              # Xoá trục, nền để tạo pie chart
  labs(title = "Biểu đồ tròn: Tỷ lệ giới tính") +
  geom_text(aes(label = Label), position = position_stack(vjust = 0.5)) +
  scale_fill_manual(values = c("lightblue", "pink")) +  # Tùy chọn màu
  theme(legend.title = element_blank())

Biểu đồ tròn trực quan hóa sự phân bố tỷ lệ giới tính trong tập dữ liệu. Từ biểu đồ, ta dễ dàng nhận thấy phần diện tích tương ứng với Female lớn hơn, củng cố kết luận từ bảng thống kê rằng đây là nhóm khách hàng chủ yếu.

2.2. MaritalStatus

2.2.1. Thống kê tần suất và tỷ lệ phần trăm

# Bảng tần số
maritalStatus <- table(data$MaritalStatus)

# Bảng tần suất
tylemaritalStatus <- round(prop.table(maritalStatus) * 100, 2)

# Tạo bảng trình bày rõ ràng
maritalStatustable <- data.frame(
  MaritalStatus = names(maritalStatus),
  Frequency = as.vector(maritalStatus),
  Percentage = paste0(tylemaritalStatus, "%")
)

# Hiển thị bảng
library(knitr)
kable(maritalStatustable, caption = "Bảng tần suất và tỷ lệ phần trăm tình trạng hôn nhân")
Bảng tần suất và tỷ lệ phần trăm tình trạng hôn nhân
MaritalStatus Frequency Percentage
M 6866 48.84%
S 7193 51.16%

Bảng thống kê cho thấy biến MaritalStatus gồm có 2 hạng mục. Trong đó, Married: chiếm 48.84% với 6866 trường hợp. Và Single: chiếm 51.16% với 7193 trường hợp.

Nhìn chung, Single chiếm tỷ lệ cao hơn (51.16%) so với hạng mục còn lại, phản ánh sự mất cân đối nhất định về tình trạng hôn nhân của khách hàng.

2.2.2. Trực quan hoá bằng biểu đồ

library(ggplot2)
library(dplyr)

# Chuẩn bị dữ liệu để vẽ pie chart
maritalStatusplot <- maritalStatustable %>%
  mutate(
    Label = paste0(MaritalStatus, ": ", Percentage, "")  # Gắn nhãn
  )

# Vẽ biểu đồ tròn bằng ggplot2
ggplot(maritalStatusplot, aes(x = "", y = Frequency, fill = MaritalStatus)) +
  geom_bar(stat = "identity", width = 1, color = "white") +
  coord_polar(theta = "y") +  # Chuyển bar chart thành pie chart
  theme_void() +              # Xoá trục, nền để tạo pie chart
  labs(title = "Biểu đồ tròn: Tỷ lệ tình trạng hôn nhân") +
  geom_text(aes(label = Label), position = position_stack(vjust = 0.5)) +
  scale_fill_manual(values = c("lightyellow", "violet")) +  # Tùy chọn màu
  theme(legend.title = element_blank())

Biểu đồ tròn trực quan hóa sự phân bố tỷ lệ tình trạng hôn nhân trong tập dữ liệu. Từ biểu đồ, ta dễ dàng nhận thấy phần diện tích tương ứng với Single lớn hơn, cho thấy sự phân bố không đều giữa hai trạng thái hôn nhận nhưng sự chênh lệch không quá lớn như giới tính.

2.3. Homeowner

2.3.1. Thống kê tần suất và tỷ lệ phần trăm

# Bảng tần số
homeowner <- table(data$Homeowner)

# Bảng tần suất
tylehomeowner <- round(prop.table(homeowner) * 100, 2)

# Tạo bảng trình bày rõ ràng
homeownertable <- data.frame(
  Homeowner = names(homeowner),
  Frequency = as.vector(homeowner),
  Percentage = paste0(tylehomeowner, "%")
)

# Hiển thị bảng
library(knitr)
kable(homeownertable, caption = "Bảng tần suất và tỷ lệ phần trăm về việc sở hữu nhà")
Bảng tần suất và tỷ lệ phần trăm về việc sở hữu nhà
Homeowner Frequency Percentage
N 5615 39.94%
Y 8444 60.06%

Biến Homeowner gồm 2 hạng mục: Y (Có nhà) chiếm 60.06% với 8444 khách hàng và N (Không có nhà) chiếm 39.94% với 5615 khách hàng.

Nhìn chung, nhóm Y chiếm tỷ lệ cao hơn 60.06%, cho thấy phần lớn khách hàng của siêu thị có nhà.

2.3.2. Trực quan hoá bằng biểu đồ

library(ggplot2)
library(dplyr)

# Chuẩn bị dữ liệu để vẽ pie chart
homeownerplot <- homeownertable %>%
  mutate(
    Label = paste0(Homeowner, ": ", Percentage, "")  # Gắn nhãn
  )

# Vẽ biểu đồ tròn bằng ggplot2
ggplot(homeownerplot, aes(x = "", y = Frequency, fill = Homeowner)) +
  geom_bar(stat = "identity", width = 1, color = "white") +
  coord_polar(theta = "y") +  # Chuyển bar chart thành pie chart
  theme_void() +              # Xoá trục, nền để tạo pie chart
  labs(title = "Biểu đồ tròn: Tỷ lệ sở hữu nhà") +
  geom_text(aes(label = Label), position = position_stack(vjust = 0.5)) +
  scale_fill_manual(values = c("green", "grey")) +  # Tùy chọn màu
  theme(legend.title = element_blank())

Biểu đồ tròn giúp trực quan hóa tỷ lệ sở hữu nhà. Phần lát cắt lớn hơn thuộc về nhóm Y, phù hợp với số liệu thống kê. Sự chênh lệch khá lớn so với giới tính và tình trạng hôn nhân. Vì biến này chỉ có 2 giá trị, biểu đồ tròn rất phù hợp để thể hiện sự khác biệt về tỷ lệ giữa các nhóm khách hàng.

2.4. AnnualIncome

2.4.1. Thống kê tần suất và tỷ lệ phần trăm

# Bảng tần suất
income <- table(data$AnnualIncome)

# Bảng tần suất
tyleincome <- round(prop.table(income) * 100, 2)

# Tạo bảng trình bày
incometable <- data.frame(
  AnnualIncome = names(income),
  Frequency = as.vector(income),
  Percentage = paste0(tyleincome, "%")
)

# Hiển thị bảng
library(knitr)
kable(incometable, caption = "Bảng tần suất và tỷ lệ phần trăm theo khoảng thu nhập")
Bảng tần suất và tỷ lệ phần trăm theo khoảng thu nhập
AnnualIncome Frequency Percentage
$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ến AnnualIncome được chia thành 8 khoảng khác nhau. Trong đó, nhóm thu nhập “$30K - $50K” có số lượng khách hàng cao nhất: 4601 người, tương đương 32.73%. Nhóm thu nhập có tỷ lệ thấp nhất là “$150k +”, chỉ chiếm 1.94%. Điều này cho thấy tập khách hàng chủ yếu nằm trong khoảng thu nhập thấp.

2.4.2. Trực quan hoá bằng biểu đồ

library(ggplot2)

# Chuyển về data.frame để ggplot dễ xử lý
incomeplotdf <- as.data.frame(income)
colnames(incomeplotdf) <- c("AnnualIncome", "Frequency")

# Vẽ biểu đồ cột
ggplot(incomeplotdf, aes(x = AnnualIncome, y = Frequency)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  labs(
    title = "Phân bố khách hàng theo khoảng thu nhập",
    x = "Khoảng thu nhập hằng năm",
    y = "Số lượng khách hàng"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Biểu đồ cột thể hiện rõ sự phân hóa theo thu nhập. Các cột có chiều cao không đồng đều, cho thấy sự mất cân đối giữa các khoảng thu nhập. Nhóm thu nhập “$30K - $50K” nổi bật hơn hẳn các nhóm còn lại, cho thấy đây có thể là nhóm khách hàng mục tiêu tiềm năng nhất của siêu thị.

2.5. City

2.5.1. Thống kê tần suất và tỷ lệ phần trăm

# Bảng tần suất
city <- table(data$City)

# Bảng tần suất
tylecity <- round(prop.table(city) * 100, 2)

# Tạo bảng trình bày
citytable <- data.frame(
  City = names(city),
  Frequency = as.vector(city),
  Percentage = paste0(tylecity, "%")
)

# Hiển thị bảng
library(knitr)
kable(citytable, caption = "Bảng tần suất và tỷ lệ phần trăm theo thành phố")
Bảng tần suất và tỷ lệ phần trăm theo thành phố
City Frequency Percentage
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.3%
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.5%
Victoria 176 1.25%
Walla Walla 160 1.14%
Yakima 376 2.67%

Biến City có 23 thành phố khác nhau. Trong đó, thành phố có số lượng giao dịch nhiều nhất là Salem, chiếm 9.86% với 1386 lượt). Nhiều thành phố chỉ chiếm tỷ lệ nhỏ dưới 5%. Điều này phản ánh sự tập trung khách hàng tại một số thành phố lớn, là thị trường trọng điểm cho doanh nghiệp.

2.5.2. Trực quan hoá bằng biểu đồ

# Đổi sang data frame cho ggplot2
cityplotdf <- as.data.frame(city)
colnames(cityplotdf) <- c("City", "Frequency")

# Vẽ biểu đồ cột
library(ggplot2)
ggplot(cityplotdf, aes(x = reorder(City, -Frequency), y = Frequency)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  labs(
    title = "Phân bố khách hàng theo thành phố",
    x = "Thành phố",
    y = "Số lượng khách hàng"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1))

Biểu đồ cột thể hiện rõ sự chênh lệch về số lượng khách hàng giữa các thành phố. Các cột có chiều cao không đồng đều và thấp dần, đặc biệt thành phố Salem có cột vượt trội, chứng tỏ đây là trung tâm mua sắm chính trong dữ liệu.

2.6. StateorProvince

2.6.1. Thống kê tần suất và tỷ lệ phần trăm

# Bảng tần suất
state <- table(data$StateorProvince)

# Bảng tần suất
tylestate <- round(prop.table(state) * 100, 2)

# Tạo bảng trình bày
statetable <- data.frame(
  StateorProvince = names(state),
  Frequency = as.vector(state),
  Percentage = paste0(tylestate, "%")
)

# Hiển thị bảng
library(knitr)
kable(statetable, caption = "Bảng tần suất và tỷ lệ phần trăm theo tỉnh/bang")
Bảng tần suất và tỷ lệ phần trăm theo tỉnh/bang
StateorProvince Frequency Percentage
BC 809 5.75%
CA 2733 19.44%
DF 815 5.8%
Guerrero 383 2.72%
Jalisco 75 0.53%
OR 2262 16.09%
Veracruz 464 3.3%
WA 4567 32.48%
Yucatan 654 4.65%
Zacatecas 1297 9.23%

Biến StateorProvince có 10 tỉnh/bang. Trong đó: WA có số lượng khách hàng lớn nhất, chiếm 32.48%. Một số bang khác chỉ đóng góp rất nhỏ vào tổng giao dịch. Kết quả này gợi ý về sự phân bổ khách hàng chưa đều giữa các khu vực, và doanh nghiệp có thể ưu tiên các tỉnh có lượng giao dịch lớn.

2.6.2. Trực quan hoá bằng biểu đồ

stateplotdf <- as.data.frame(state)
colnames(stateplotdf) <- c("StateorProvince", "Frequency")

ggplot(stateplotdf, aes(x = reorder(StateorProvince, -Frequency), y = Frequency)) +
  geom_bar(stat = "identity", fill = "darkgreen") +
  labs(
    title = "Phân bố khách hàng theo tỉnh/bang",
    x = "Tỉnh/Bang",
    y = "Số lượng khách hàng"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Biểu đồ cột cho thấy sự nổi bật của một vài tỉnh/ bang, với các cột cao hơn hẳn như WA, CA, OR. Điều này thể hiện tiềm năng thị trường tập trung tại một số khu vực nhất định, có thể do quy mô dân số, sức mua, hoặc phân phối của các chi nhánh siêu thị.

2.7. Country

2.7.1. Thống kê tần suất và tỷ lệ phần trăm

# Bảng tần số
country <- table(data$Country)

# Bảng tần suất
tylecountry <- round(prop.table(country) * 100, 2)

# Tạo bảng trình bày rõ ràng
countrytable <- data.frame(
  Country = names(country),
  Frequency = as.vector(country),
  Percentage = paste0(tylecountry, "%")
)

# Hiển thị bảng
library(knitr)
kable(countrytable, caption = "Bảng tần suất và tỷ lệ phần trăm theo quốc gia")
Bảng tần suất và tỷ lệ phần trăm theo quốc gia
Country Frequency Percentage
Canada 809 5.75%
Mexico 3688 26.23%
USA 9562 68.01%

Biến Country gồm 3 quốc gia. Trong đó, USA có tỷ lệ cao nhất là 68.01% với 9562 lượt giao dịch. Các quốc gia còn lại chiếm tỷ lệ nhỏ hơn, Mexico có tỷ lệ 26.23% với lượt giao dịch là 3688, thấp nhất là Canada. Điều này cho thấy phần lớn dữ liệu đến từ USA, đây có thể là thị trường chính của chuỗi siêu thị trong dữ liệu.

2.7.2. Trực quan hoá bằng biểu đồ

library(ggplot2)
library(dplyr)

# Chuẩn bị dữ liệu để vẽ pie chart
countryplot <- countrytable %>%
  mutate(
    Label = paste0(Country, ": ", Percentage, "")  # Gắn nhãn
  )

# Vẽ biểu đồ tròn bằng ggplot2
ggplot(countryplot, aes(x = "", y = Frequency, fill = Country)) +
  geom_bar(stat = "identity", width = 1, color = "white") +
  coord_polar(theta = "y") +  # Chuyển bar chart thành pie chart
  theme_void() +              # Xoá trục, nền để tạo pie chart
  labs(title = "Biểu đồ tròn: Tỷ lệ quốc gia") +
  geom_text(aes(label = Label), position = position_stack(vjust = 0.5)) +
  scale_fill_manual(values = c("orange", "lightgreen","pink")) +  # Tùy chọn màu
  theme(legend.title = element_blank())

Biểu đồ tròn thể hiện rõ sự áp đảo của USA, chiếm hơn nửa biểu đồ. Tiếp đến là Mexico tương đương một phần tư biểu đồ, còn lại Canada có tỷ lệ chiếm thấp nhất trong ba quốc gia.

2.8. ProductFamily

2.8.1. Thống kê tần suất và tỷ lệ phần trăm

pf <- table(data$ProductFamily)
tylepf <- round(prop.table(pf) * 100, 2)

pftable <- data.frame(
  ProductFamily = names(pf),
  Frequency = as.vector(pf),
  Percentage = paste0(tylepf, "%")
)

kable(pftable, caption = "Tần suất và tỷ lệ phần trăm theo nhóm sản phẩm")
Tần suất và tỷ lệ phần trăm theo nhóm sản phẩm
ProductFamily Frequency Percentage
Drink 1250 8.89%
Food 10153 72.22%
Non-Consumable 2656 18.89%

ProductFamily gồm 3 nhóm sản phẩm chính. Nhóm Food có số lượng giao dịch lớn nhất 72.22%, cho thấy đây là nhóm hàng được ưa chuộng nhất.Hai nhóm khác là Non-Cosmumable và Drink có tỷ lệ thấp hơn.

2.8.2. Trực quan hoá bằng biểu đồ

pfplotdf <- as.data.frame(pf)
colnames(pfplotdf) <- c("ProductFamily", "Frequency")

ggplot(pfplotdf, aes(x = reorder(ProductFamily, -Frequency), y = Frequency)) +
  geom_bar(stat = "identity", fill = "purple") +
  labs(
    title = "Phân bố khách hàng theo nhóm sản phẩm",
    x = "Nhóm sản phẩm",
    y = "Số lượng giao dịch"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 30, hjust = 1))

Biểu đồ cột giúp trực quan hóa rõ mức độ tiêu thụ từng nhóm sản phẩm. Cột tương ứng với Food cao vượt trội, nhấn mạnh tầm quan trọng của nhóm sản phẩm này trong kinh doanh hiện tại.

2.9. ProductDepartmen

2.9.1. Thống kê tần suất và tỷ lệ phần trăm

pd <- table(data$ProductDepartment)
tylepd <- round(prop.table(pd) * 100, 2)

pdtable <- data.frame(
  ProductDepartment = names(pd),
  Frequency = as.vector(pd),
  Percentage = paste0(tylepd, "%")
)

kable(pdtable, caption = "Tần suất và tỷ lệ phần trăm theo bộ phận sản phẩm")
Tần suất và tỷ lệ phần trăm theo bộ phận sản phẩm
ProductDepartment Frequency Percentage
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.1%
Meat 89 0.63%
Periodicals 202 1.44%
Produce 1994 14.18%
Seafood 102 0.73%
Snack Foods 1600 11.38%
Snacks 352 2.5%
Starchy Foods 277 1.97%

Biến ProductDepartment đại diện cho các bộ phận hàng hóa, có 22 hạng mục. Trong đó, bộ phận Produce chiếm tỷ trọng lớn 14.18% phản ánh nhu cầu tiêu dùng cao trong danh mục này.

2.9.2. Trực quan hoá bằng biểu đồ

pdplotdf <- as.data.frame(pd)
colnames(pdplotdf) <- c("ProductDepartment", "Frequency")

ggplot(pdplotdf, aes(x = reorder(ProductDepartment, -Frequency), y = Frequency)) +
  geom_bar(stat = "identity", fill = "lightblue") +
  labs(
    title = "Phân bố khách hàng theo bộ phận sản phẩm",
    x = "bộ phận sản phẩm",
    y = "Số lượng giao dịch"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 30, hjust = 1))

Biểu đồ cho thấy sự phân bố không đều giữa các bộ phận sản phẩm. Bộ phận Produce có cột cao hơn hẳn, là nơi tập trung chính của hoạt động mua bán, trong khi các bộ phận khác có lượng giao dịch thấp hơn đáng kể.

2.10. ProductCategory

2.10.1. Thống kê tần suất và tỷ lệ phần trăm

pc <- table(data$ProductCategory)
tylepc <- round(prop.table(pc) * 100, 2)

pctable <- data.frame(
  ProductCategory = names(pc),
  Frequency = as.vector(pc),
  Percentage = paste0(tylepc, "%")
)

kable(pctable, caption = "Tần suất và tỷ lệ phần trăm theo danh mục sản phẩm")
Tần suất và tỷ lệ phần trăm theo danh mục sản phẩm
ProductCategory Frequency Percentage
Baking Goods 484 3.44%
Bathroom Products 365 2.6%
Beer and Wine 356 2.53%
Bread 425 3.02%
Breakfast Foods 417 2.97%
Candles 45 0.32%
Candy 352 2.5%
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.1%
Cleaning Supplies 189 1.34%
Cold Remedies 93 0.66%
Dairy 903 6.42%
Decongestants 85 0.6%
Drinks 135 0.96%
Eggs 198 1.41%
Electrical 355 2.53%
Frozen Desserts 323 2.3%
Frozen Entrees 118 0.84%
Fruit 765 5.44%
Hardware 129 0.92%
Hot Beverages 226 1.61%
Hygiene 197 1.4%
Jams and Jellies 588 4.18%
Kitchen Products 217 1.54%
Magazines 202 1.44%
Meat 761 5.41%
Miscellaneous 42 0.3%
Packaged Vegetables 48 0.34%
Pain Relievers 192 1.37%
Paper Products 345 2.45%
Pizza 194 1.38%
Plastic Products 141 1%
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ến ProductCategory có 45 hạng mục. Trong đó, Vegetables có số lượng nhiều nhất là 1728 và chiếm 12.29%. Ngược lại, Canned Oysters có số lượng thấp nhất là 35 với tỷ lệ là 0.25%

2.10.2. Trực quan hoá bằng biểu đồ

library(ggplot2)

# Chuyển bảng tần suất sang data frame
pcdf <- as.data.frame(pc)
colnames(pcdf) <- c("ProductCategory", "Frequency")

# Sắp xếp và lấy top 10
top10pc <- pcdf |>
  dplyr::arrange(desc(Frequency)) |>
  dplyr::slice(1:10)

# Vẽ biểu đồ cột
ggplot(top10pc, aes(x = reorder(ProductCategory, Frequency), y = Frequency)) +
  geom_bar(stat = "identity", fill = "darkorange") +
  coord_flip() +
  labs(
    title = "Top 10 Danh mục sản phẩm phổ biến nhất",
    x = "Danh mục sản phẩm",
    y = "Tần suất giao dịch"
  ) +
  theme_minimal()

Biểu đồ thể hiện Top 10 danh mục sản phẩm có lượt mua cao nhất trong toàn bộ hệ thống. Danh mục Vegetables có tần suất cao nhất 1728, cho thấy đây là nhóm sản phẩm được ưa chuộng và tiêu thụ mạnh. Những danh mục phía sau như Snack Foods, Dairy cũng có lượng mua đáng kể và có thể là trọng tâm cho các chiến dịch tiếp thị.

Phần 3: ƯỚC LƯỢNG KHOẢNG VÀ KIỂM ĐỊNH GIẢ TUYẾT CHO TỶ LỆ (MỘT BIẾN)

3.1. Gender - Hạng mục: “F”

3.1.1. Ước lượng khoảng tin cậy 95%

# Tính số lượng nữ
xgender <- sum(data$Gender == "F")
ngender <- nrow(data) # nrow là tổng quan sát

Ta có tỷ lệ khách hàng nữ trong mẫu là khoảng 51%.

# Ước lượng khoảng tin cậy 95%
genderci <- prop.test(x = xgender, n = ngender, conf.level = 0.95)
genderci
## 
##  1-sample proportions test with continuity correction
## 
## data:  xgender out of ngender, null probability 0.5
## X-squared = 5.5765, df = 1, p-value = 0.0182
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.5016931 0.5182886
## sample estimates:
##         p 
## 0.5099936

Kết quả: Với khoảng tin cậy 95% cho tỷ lệ nữ trong tổng thể từ 50.17% đến 51.83%.

Với độ tin cậy 95%, chúng tôi ước lượng rằng tỷ lệ khách hàng nữ trong toàn bộ tập khách hàng nằm trong khoảng 50.17% đến 51.83%. Điều này có nghĩa là nếu thực hiện việc lấy mẫu nhiều lần tương tự như hiện tại, 95% số mẫu sẽ cho kết quả nằm trong khoảng này.

3.1.2. Kiểm định giả thuyết

Thực hiện kiểm định giả thuyết về tỷ lệ của hạng mục Nữ:

Giả thuyết Không (\({H}_0\)): Tỷ lệ Nữ = 0.5

Giả thuyết Thay thế (\({H}_1\)): Tỷ lệ Nữ ≠ 0.5

Mức ý nghĩa α=0.05.

# Kiểm định giả thuyết H0: tỷ lệ nữ = 0.5
genderhtest <- prop.test(x = xgender, n = ngender, p = 0.5, alternative = "two.sided")
genderhtest
## 
##  1-sample proportions test with continuity correction
## 
## data:  xgender out of ngender, null probability 0.5
## X-squared = 5.5765, df = 1, p-value = 0.0182
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.5016931 0.5182886
## sample estimates:
##         p 
## 0.5099936

Kết quả:

p-value = 0.0182

Giá trị thống kê Chi-bình phương: 5.576499

Bậc tự do (df): 1

Do p-value < 0.05, ta bác bỏ giả thuyết \({H}_0\). Như vậy, có bằng chứng thống kê ở mức ý nghĩa 5% cho thấy tỷ lệ nữ trong tổng thể khác 50%. Đây là một phát hiện có thể quan trọng trong việc xác định đối tượng khách hàng chính của doanh nghiệp.

3.2. Homeowner - Hạng mục: “Y”

3.2.1. Ước lượng khoảng tin cậy 95%

xhome <- sum(data$Homeowner == "Y")
nhome <- nrow(data)

homeci <- prop.test(x = xhome, n = nhome, conf.level = 0.95)
homeci
## 
##  1-sample proportions test with continuity correction
## 
## data:  xhome out of nhome, null probability 0.5
## X-squared = 568.86, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.5924537 0.6087145
## sample estimates:
##         p 
## 0.6006117

Tỷ lệ khách hàng có nhà trong mẫu là khoảng 60.06%.

Với khoảng tin cậy 95% cho tỷ lệ sở hữu nhà trong tổng thể từ 59.25% đến 60.87%.

Chúng tôi ước lượng rằng tỷ lệ khách hàng có sở hữu nhà nằm trong khoảng 59.25% đến 60.87%. Điều này cho thấy khả năng tài chính của phần lớn khách hàng có thể ở mức tương đối ổn định.

3.2.2. Kiểm định giả thuyết

Thực hiện kiểm định giả thuyết về tỷ lệ của hạng mục có nhà:

Giả thuyết Không (\({H}_0\)): Tỷ lệ có nhà = 0.6

Giả thuyết Thay thế (\({H}_1\)): Tỷ lệ có nhà ≠ 0.6

Mức ý nghĩa α=0.05.

homehtest <- prop.test(x = xhome, n = nhome, p = 0.6, alternative = "two.sided")
homehtest
## 
##  1-sample proportions test with continuity correction
## 
## data:  xhome out of nhome, null probability 0.6
## X-squared = 0.019445, df = 1, p-value = 0.8891
## alternative hypothesis: true p is not equal to 0.6
## 95 percent confidence interval:
##  0.5924537 0.6087145
## sample estimates:
##         p 
## 0.6006117

Kết quả: p-value = 0.8891

Với p-value = 0.8891, ta không bác bỏ giả thuyết \({H}_0\). Như vậy, có không đủ bằng chứng thống kê cho thấy tỷ lệ khách hàng sở hữu nhà không khác đáng kể 60%. Nếu khác, điều này cần được doanh nghiệp lưu ý khi lựa chọn sản phẩm hoặc chính sách tài chính phù hợp.

3.3. ProductFamily - Hạng mục: “Food”

3.3.1. Ước lượng khoảng tin cậy 95%

xfood <- sum(data$ProductFamily == "Food")
nfood <- nrow(data)

foodci <- prop.test(x = xfood, n = nfood, conf.level = 0.95)
foodci
## 
##  1-sample proportions test with continuity correction
## 
## data:  xfood out of nfood, null probability 0.5
## X-squared = 2774.9, df = 1, p-value < 2.2e-16
## alternative hypothesis: true p is not equal to 0.5
## 95 percent confidence interval:
##  0.7146709 0.7295489
## sample estimates:
##         p 
## 0.7221709

Kết quả:

Tỷ lệ Food quan sát được: 72.22%.

Khoảng tin cậy 95%: (71.47%; 72.95%)

Với 95% độ tin cậy, chúng tôi ước lượng rằng tỷ lệ giao dịch thuộc nhóm sản phẩm Food nằm trong khoảng 71.47% đến 72.95%. Điều này cho thấy Food là nhóm hàng chủ lực trong hệ thống siêu thị hiện tại.

3.3.2. Kiểm định giả thuyết

Thực hiện kiểm định giả thuyết về tỷ lệ của hạng mục có nhà:

Giả thuyết Không (\({H}_0\)): Tỷ lệ Food >= 0.7

Giả thuyết Thay thế (\({H}_1\)): Tỷ lệ Food < 0.7

Mức ý nghĩa α=0.05.

foodhtest <- prop.test(x = xfood, n = nfood, p = 0.7, alternative = "less")
foodhtest
## 
##  1-sample proportions test with continuity correction
## 
## data:  xfood out of nfood, null probability 0.7
## X-squared = 32.802, df = 1, p-value = 1
## alternative hypothesis: true p is less than 0.7
## 95 percent confidence interval:
##  0.0000000 0.7283768
## sample estimates:
##         p 
## 0.7221709

Kết quả: p-value = 1

Với giả thuyết \({H}_0\): tỷ lệ Food ≥ 70%, và p-value = 1, ta không bác bỏ giả thuyết \({H}_0\). Tức là có không đủ bằng chứng để kết luận rằng tỷ lệ sản phẩm Food thấp hơn 70%. Đây là thông tin quan trọng giúp điều chỉnh kỳ vọng doanh thu theo nhóm sản phẩm.

Phần 4: PHÂN TÍCH MỐI QUAN HỆ GIỮA HAI BIẾN ĐỊNH TÍNH (Bivariate Analysis)

4.1 Ôn lại kiến thức

4.1.1 Cấu trúc xác suất của bảng ngẫu nhiên

Bảng ngẫu nhiên (contingency table) là một bảng đếm tần số kết hợp giữa hai biến phân loại. Các ô trong bảng có thể được sinh ra từ các phân phối xác suất khác nhau, tùy thuộc vào bối cảnh thu thập dữ liệu.

Phân phối Poisson (Poisson Distribution)

Phân phối Poisson mô tả số lượng sự kiện xảy ra trong một khoảng thời gian hoặc không gian cố định, với giả định các sự kiện xảy ra độc lập và với tỉ lệ trung bình cố định.

Định nghĩa: Biến ngẫu nhiên 𝑋 có phân phối Poisson với tham số 𝜆> 0 nếu xác suất 𝑋 nhận giá trị 𝑘 là

\[P(X = k) = \frac{e^{-\lambda} \lambda^{k}}{k!}, \quad k = 0, 1, 2, \dots\]

Ý nghĩa tham số: 𝜆 là số sự kiện trung bình xảy ra trong khoảng quan sát.

Ứng dụng: Thường dùng để mô tả số lượng sự kiện hiếm gặp như số cuộc gọi điện thoại trong 1 giờ, số khách hàng đến cửa hàng trong 1 ngày, hay số lỗi phát sinh trên một sản phẩm.

Phân phối Đa thức (Multinomial Distribution)

Phân phối Đa thức là sự mở rộng của phân phối Nhị thức (Binomial), mô tả số lần các kết quả khác nhau xảy ra trong một chuỗi các phép thử độc lập, mỗi phép thử có nhiều hơn hai kết quả có thể.

Định nghĩa: Cho một phép thử với 𝑛 lần lặp lại độc lập, mỗi lần có 𝑘 kết quả có thể xảy ra với xác suất \(p_1, p_2, \dots, p_k\) (thỏa mãn \(\sum_{i=1}^k p_i = 1\)), thì vector biến ngẫu nhiên \((X_1, X_2, \dots, X_k)\)

là số lần kết quả thứ𝑖xảy ra, có phân phối Đa thức với xác suất:

\[P(X_1 = x_1, \dots, X_k = x_k) = \frac{n!}{x_1! x_2!\cdots x_k!} p_1^{x_1} p_2^{x_2} \cdots p_k^{x_k}\]

với điều kiện \(\sum_{i=1}^k x_i = n\).

Ứng dụng: Mô hình hóa bảng tần số trong các bảng phân loại có nhiều nhóm như kết quả khảo sát, phân bổ khách hàng theo loại sản phẩm, hoặc số lượng sản phẩm bán ra trong các danh mục khác nhau.

Tóm lại, cấu trúc xác suất của bảng ngẫu nhiên thường được xây dựng dựa trên phân phối Poisson khi quan tâm đến số lượng sự kiện xảy ra trên các ô bảng (đếm số lượng) hoặc phân phối Đa thức khi quan tâm đến phân phối tỉ lệ của các nhóm trong tổng số các phép thử.

4.1.2 Hiệu hai tỷ lệ

Hiệu hai tỷ lệ đo lường sự khác biệt về tỷ lệ xảy ra một sự kiện giữa hai nhóm phân loại (ví dụ: Nam và Nữ, Có và Không khuyến mãi, v.v.)

Công thức:

\[D = p_1 - p_2\]

Trong đó:

  • \(p_1\): Tỷ lệ xảy ra sự kiện ở nhóm 1
  • \(p_2\): Tỷ lệ xảy ra sự kiện ở nhóm 2
  • \(D\): Mức chênh lệch tỷ lệ giữa hai nhóm

Khoảng tin cậy cho hiệu tỷ lệ

Công thức ước lượng khoảng tin cậy 95% cho \(D\):

\[CI_{95\%} = D \pm Z_{1 - \alpha/2} \cdot SE\]

Trong đó:

\[SE = \sqrt{ \frac{p_1 (1 - p_1)}{n_1} + \frac{p_2 (1 - p_2)}{n_2} }\]

Diễn giải

  • Nếu khoảng tin cậy không chứa 0 → Có sự khác biệt có ý nghĩa thống kê giữa hai nhóm
  • Nếu CI chứa 0 → Không đủ bằng chứng để kết luận có sự khác biệt Ví dụ: Nếu hiệu tỷ lệ là 0.25 và CI là [0.15, 0.35], ta kết luận tỷ lệ sở hữu nhà ở nữ cao hơn đáng kể so với nam.

4.1.3 Ý nghĩa của Kiểm định Chi - Bình phương về tính độc lập

Kiểm định Chi-bình phương (Chi-square test of independence) là một phương pháp thống kê dùng để xác định xem hai biến định tính (phân loại) có quan hệ với nhau hay không hay nói cách khác, chúng có độc lập với nhau trong tổng thể hay không.

Giả thuyết kiểm định

  • H₀: Hai biến X và Y độc lập với nhau.
  • H₁: Hai biến X và Y có mối liên hệ, tức là không độc lập.

Công thức giá trị kiểm định

Phép kiểm định sử dụng phân phối Chi-bình phương (χ²) với công thức:

\[\chi^2 = \sum_{i,j}\frac{(n_{ij}-\hat{\mu}_{ij})^2}{\hat{\mu}_{ij}}\]

Trong đó:

  • \(n_{ij}\): là tần số quan sát tại ô hàng \(i\), cột \(j\) trong bảng chéo.
  • \(\hat{\mu}_{ij}\): là tần số kỳ vọng tại ô \(i,j\), được tính theo công thức:

\[\hat{\mu}_{ij} = \frac{n_{i+} \cdot n_{+j}}{n}\]

  • \(n_{i+}\): tổng hàng i
  • \(n_{+j}\): tổng cột j
  • \(n\): tổng tất cả các quan sát trong bảng

Bậc tự do (Degrees of Freedom)

\[df = (r - 1)(c - 1)\]

Trong đó:

  • \(r\): số hàng (số mức của biến thứ nhất)
  • \(c\): số cột (số mức của biến thứ hai)

Diễn giải kết quả

Sau khi chạy kiểm định trong R bằng hàm chisq.test(), kết quả trả về bao gồm:

  • Giá trị thống kê Chi-bình phương (X-squared)
  • Bậc tự do (df)
  • Giá trị p (p-value)

Ý nghĩa

  • Nếu p-value < 0.05 → Bác bỏ H₀ → Hai biến có mối liên hệ → Không độc lập
  • Nếu p-value ≥ 0.05 → Không bác bỏ H₀ → Chưa có bằng chứng thống kê đủ mạnh để khẳng định hai biến có quan hệ → Có thể độc lập

Lưu ý

  • Điều kiện áp dụng kiểm định Chi-bình phương: Tần số kỳ vọng trong ít nhất 80% số ô phải ≥ 5. Nếu không thỏa điều kiện, nên dùng kiểm định Fisher cho bảng 2x2.
  • Kiểm định Chi-bình phương không xác định chiều và mức độ của mối quan hệ, chỉ cho biết có hay không có liên hệ.

4.1.4 Relative Risk (Nguy cơ tương đối)

Relative Risk (RR) hay còn gọi là Nguy cơ tương đối là một thước đo dùng để so sánh xác suất xảy ra sự kiện giữa nhóm có phơi nhiễm (exposed)nhóm không phơi nhiễm (non-exposed). Thường được sử dụng trong nghiên cứu đoàn hệ (cohort studies).

Mục đích: Đo lường mức độ ảnh hưởng của một yếu tố (ví dụ: thói quen tiêu dùng, giới tính, tình trạng khuyến mãi…) đến khả năng xảy ra một sự kiện nào đó (ví dụ: mua hàng, bị bệnh, v.v.).

Công thức tính

Giả sử ta có bảng 2×2:

Sự kiện xảy ra (Yes) Không xảy ra (No) Tổng
Phơi nhiễm a b a + b
Không phơi nhiễm c d c + d

Công thức tính Relative Risk:

\[ RR = \frac{a / (a + b)}{c / (c + d)} \]

Trong đó:

  • \(a / (a + b)\): Xác suất xảy ra sự kiện ở nhóm phơi nhiễm
  • \(c / (c + d)\): Xác suất xảy ra sự kiện ở nhóm không phơi nhiễm

Diễn giải kết quả

  • RR = 1: Nguy cơ xảy ra sự kiện như nhau ở hai nhóm → Không có mối liên hệ
  • RR > 1: Nhóm phơi nhiễm có nguy cơ cao hơn → Có thể có mối liên hệ dương
  • RR < 1: Nhóm phơi nhiễm có nguy cơ thấp hơn → Có thể là yếu tố bảo vệ

Để đánh giá độ tin cậy của chỉ số Relative Risk (RR), ta cần tính khoảng tin cậy (Confidence Interval – CI), thường là khoảng tin cậy 95%.

Công thức khoảng tin cậy 95% cho RR

Khoảng tin cậy của RR dựa trên logarit tự nhiên của RR:

\[\ln(RR) \pm Z_{1 - \alpha/2} \cdot SE(\ln(RR))\]

Với:

  • \(Z_{1 - \alpha/2} = 1.96\) nếu mức tin cậy 95%
  • Sai số chuẩn:

\[SE(\ln(RR)) = \sqrt{ \frac{1}{a} - \frac{1}{a+b} + \frac{1}{c} - \frac{1}{c+d} }\]

Sau đó lấy mũ (exponential) để có khoảng tin cậy cho RR:

\[ CI_{95\%} = \left( e^{\ln(RR) - 1.96 \cdot SE},\; e^{\ln(RR) + 1.96 \cdot SE} \right) \]

Diễn giải kết quả

  • Nếu khoảng tin cậy không chứa 1, kết quả có ý nghĩa thống kê:

  • Nếu CI > 1 → Nhóm phơi nhiễm có nguy cơ cao hơn

  • Nếu CI < 1 → Nhóm phơi nhiễm có nguy cơ thấp hơn (tác dụng bảo vệ)

  • Nếu CI chứa 1 → Không thể kết luận có mối liên hệ rõ ràng về nguy cơ

Tính khoảng tin cậy cho RR trong R

  • Dùng gói epitools

install.packages(“epitools”) library(epitools) Tạo bảng 2x2: hàng = phơi nhiễm, cột = sự kiện: data <- matrix(c(60, 40, 30, 70), nrow = 2, byrow = TRUE) dimnames(data) <- list(Exposure = c(“Yes”, “No”), Outcome = c(“Buy”, “NotBuy”)) Tính RR và khoảng tin cậy: riskratio(data, rev = “columns”)

  • Dùng gói epiR

install.packages(“epiR”) library(epiR) data <- matrix(c(60, 40, 30, 70), nrow = 2, byrow = TRUE) epi.2by2(dat = data, method = “cohort.count”, conf.level = 0.95)

4.1.5 Odds Ratio - OR (Tỷ số chênh)

Odds là tỷ lệ giữa xác suất xảy ra sự kiện (p)không xảy ra sự kiện (1 - p):

\[\text{Odds} = \frac{p}{1 - p}\]

Odds Ratio (OR) là một thước đo được sử dụng phổ biến trong nghiên cứu y học, xã hội và hành vi tiêu dùng, giúp so sánh xác suất tương đối (odds) xảy ra sự kiện giữa hai nhóm. Odds Ratio (OR) là tỷ lệ giữa odds của hai nhóm:

\[OR = \frac{ \text{Odds trong nhóm 1} }{ \text{Odds trong nhóm 2} }\]

Cách tính OR từ bảng 2x2

Sự kiện xảy ra (Yes) Không xảy ra (No) Tổng
Nhóm 1 (phơi nhiễm) a b a + b
Nhóm 2 (không phơi nhiễm) c d c + d

Công thức:

\[OR = \frac{a / b}{c / d} = \frac{a \cdot d}{b \cdot c}\]

Diễn giải Odds Ratio

  • OR = 1: Không có mối liên hệ giữa hai biến
  • OR > 1: Nhóm 1 có odds xảy ra sự kiện cao hơn → mối liên hệ dương
  • OR < 1: Nhóm 1 có odds xảy ra sự kiện thấp hơn → mối liên hệ âm

Ví dụ:

  • OR = 2 nghĩa là odds xảy ra sự kiện ở nhóm 1 gấp 2 lần odds ở nhóm 2.
  • Không nên nhầm lẫn với RR, OR thường phóng đại mối liên hệ khi tần suất sự kiện cao.

Khi nào OR ≈ RR

  • Khi sự kiện là hiếm (tần suất thấp), OR gần như bằng RR.
  • Trong trường hợp phổ biến, OR có thể lớn hơn nhiều so với RR.

Tại sao OR quan trọng?

  • OR có tính đối xứng: Đảo chiều hàng – cột trong bảng 2x2 vẫn cho cùng kết quả.
  • OR được dùng trong mô hình logistic regression để diễn giải ảnh hưởng của biến độc lập đến xác suất xảy ra sự kiện.

Khoảng tin cậy cho Odds Ratio

Tính khoảng tin cậy 95% cho OR dựa trên log(OR):

\(SE(\ln(OR)) =\sqrt{ \frac{1}{a} + \frac{1}{b} + \frac{1}{c} + \frac{1}{d} }\)

\(CI_{95\%} = (e^{\ln(OR) - 1.96 \cdot SE}, \; e^{\ln(OR) + 1.96 \cdot SE})\)

  • Dùng DescTools::OddsRatio()

install.packages(“DescTools”) library(DescTools) a <- matrix(c(60, 40, 30, 70), nrow = 2, byrow = TRUE) OddsRatio(a, conf.level = 0.95)

  • Dùng epitools

install.packages(“epitools”) library(epitools) tb <- matrix(c(60, 40, 30, 70), nrow = 2, byrow = TRUE) oddsratio(tb, rev = “columns”)

Diễn giải kết quả - Nếu CI không chứa 1 → mối liên hệ có ý nghĩa thống kê - Nếu CI chứa 1 → chưa đủ bằng chứng để kết luận có mối liên hệ - Nếu OR > 1 và CI không chứa 1 → nhóm 1 có odds xảy ra sự kiện cao hơn đáng kể

4.2 Thực hành

4.2.1 Gender và ProductFamily

Bảng tần số

# Bảng tần số chéo
tabgenderpf <- table(data$Gender, data$ProductFamily)

# Tỷ lệ theo hàng (giới tính)
propgenderpf <- prop.table(tabgenderpf, margin = 1) 

# Hiển thị bảng
library(knitr)
kable(tabgenderpf, caption = "Bảng tần số chéo giữa Gender và ProductFamily")
Bảng tần số chéo giữa Gender và ProductFamily
Drink Food Non-Consumable
F 669 5149 1352
M 581 5004 1304

Số lượng khách hàng nữ mua hàng nhiều hơn nam ở tất cả các nhóm sản phẩm. Cả nam và nữ đều mua nhiều nhất nhóm Food, kế đến là Non-Consumable, sau cùng là Drink. Dù tổng số khách hàng nữ và nam gần tương đương, nữ chiếm ưu thế nhẹ về tổng số giao dịch, điều này có thể phản ánh xu hướng mua hàng thường xuyên hơn ở nữ.

Trực quan hoá bằng biểu đồ

library(ggplot2)
ggplot(data, aes(x = Gender, fill = ProductFamily)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent_format()) +
  labs(title = "Tỷ lệ nhóm sản phẩm theo giới tính", y = "Tỷ lệ", x = "Giới tính") +
  theme_minimal()

Nhận xét từ biểu đồ cột chồng:

Nhìn theo tỷ lệ, cơ cấu tiêu dùng giữa nam và nữ tương đối giống nhau. Tuy nhiên, tỷ lệ Food vẫn cao nhất ở cả hai giới, cho thấy đây là nhóm sản phẩm chủ đạo cho mọi đối tượng. Có vẻ như nữ chiếm tỷ lệ cao hơn một chút ở nhóm Drink, điều này có thể phản ánh nhu cầu khác biệt trong lựa chọn đồ uống.

Kiểm định Chi-bình phương

chisqgenderpf <- chisq.test(tabgenderpf)
chisqgenderpf
## 
##  Pearson's Chi-squared test
## 
## data:  tabgenderpf
## X-squared = 3.5185, df = 2, p-value = 0.1722

Giả thuyết:

\({H}_0\): Không có mối liên hệ giữa giới tính và nhóm sản phẩm

\({H}_1\): Có mối liên hệ giữa giới tính và nhóm sản phẩm

Kết quả kiểm định:

  • Giá trị Chi-squared: 3.52

  • Bậc tự do (df): 2

  • p-value = 0.1722

Kết luận:

Vì p-value > 0.05, ta không bác bỏ giả thuyết \({H}_0\). Như vậy, không có bằng chứng về mối liên hệ giữa giới tính và nhóm sản phẩm mà khách hàng lựa chọn. Nói cách khác, sự khác biệt nhỏ trong lựa chọn sản phẩm giữa nam và nữ trong bảng tần suất có thể là do ngẫu nhiên, và giới tính không ảnh hưởng đáng kể đến nhóm sản phẩm mà khách hàng lựa chọn, ít nhất là trong dữ liệu hiện tại.

Relative Risk

library(epitools)

# Bảng cho dòng sản phẩm "Drink"
# Lấy tổng số người nữ và nam
total_female <- sum(tabgenderpf["F", ])
total_male <- sum(tabgenderpf["M", ])
drink_table <- matrix(c(tabgenderpf["F", "Drink"], total_female - tabgenderpf["F", "Drink"], tabgenderpf["M", "Drink"], total_male - tabgenderpf["M", "Drink"]), nrow = 2, byrow = TRUE)
rownames(drink_table) <- c("Nữ", "Nam")
colnames(drink_table) <- c("Mua Drink", "Không Mua Drink")
message("Bảng cho Drink")
riskratio(drink_table)
## $data
##       Mua Drink Không Mua Drink Total
## Nữ          669            6501  7170
## Nam         581            6308  6889
## Total      1250           12809 14059
## 
## $measure
##                         NA
## risk ratio with 95% C.I. estimate     lower    upper
##                      Nữ  1.000000        NA       NA
##                      Nam 1.009891 0.9995229 1.020367
## 
## $p.value
##          NA
## two-sided midp.exact fisher.exact chi.square
##       Nữ          NA           NA         NA
##       Nam 0.06182901   0.06194737 0.06180684
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
# Bảng cho dòng sản phẩm "Food"
food_table <- matrix(c(tabgenderpf["F", "Food"], total_female - tabgenderpf["F", "Food"], tabgenderpf["M", "Food"], total_male - tabgenderpf["M", "Food"]), nrow = 2, byrow = TRUE)
rownames(food_table) <- c("Nữ", "Nam")
colnames(food_table) <- c("Mua Food", "Không Mua Food")
message("Bảng cho Food")
riskratio(food_table)
## $data
##       Mua Food Không Mua Food Total
## Nữ        5149           2021  7170
## Nam       5004           1885  6889
## Total    10153           3906 14059
## 
## $measure
##                         NA
## risk ratio with 95% C.I.  estimate     lower    upper
##                      Nữ  1.0000000        NA       NA
##                      Nam 0.9707514 0.9203271 1.023938
## 
## $p.value
##          NA
## two-sided midp.exact fisher.exact chi.square
##       Nữ          NA           NA         NA
##       Nam  0.2753749    0.2830759  0.2752955
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"
# Bảng cho dòng sản phẩm "Non-Consumable"
nonconsumable_table <- matrix(c(tabgenderpf["F", "Non-Consumable"], total_female - tabgenderpf["F", "Non-Consumable"], tabgenderpf["M", "Non-Consumable"], total_male - tabgenderpf["M", "Non-Consumable"]), nrow = 2, byrow = TRUE)
rownames(nonconsumable_table) <- c("Nữ", "Nam")
colnames(nonconsumable_table) <- c("Mua Non-Consumable", "Không Mua Non-Consumable")
message("Bảng cho Non-Consumable")
riskratio(nonconsumable_table)
## $data
##       Mua Non-Consumable Không Mua Non-Consumable Total
## Nữ                  1352                     5818  7170
## Nam                 1304                     5585  6889
## Total               2656                    11403 14059
## 
## $measure
##                         NA
## risk ratio with 95% C.I. estimate     lower    upper
##                      Nữ  1.000000        NA       NA
##                      Nam 0.999108 0.9832895 1.015181
## 
## $p.value
##          NA
## two-sided midp.exact fisher.exact chi.square
##       Nữ          NA           NA         NA
##       Nam  0.9126775    0.9142133  0.9127255
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "Unconditional MLE & normal approximation (Wald) CI"

Nhận xét về Relative Risk cho từng dòng sản phẩm

Sẽ phân tích kết quả của từng dòng sản phẩm (Drink, Food, Non-Consumable), với Nữ (Female) là nhóm tham chiếu (RR của Nữ so với Nữ là 1), và chúng ta sẽ xem xét RR của Nam (Male) so với Nữ.

  • Relative Risk cho “Drink”

Kết quả chính:

RR (Nam so với Nữ) = 1.009891

Khoảng tin cậy 95%: (0.9995229, 1.020367)

Giá trị p (Chi-squared): 0.06180684

Nhận xét:

Tỷ số nguy cơ là 1.01. Điều này có nghĩa là xác suất nam giới mua sản phẩm “Drink” cao hơn khoảng 1% so với nữ giới.

Khoảng tin cậy 95% (0.9995; 1.0204) gần chứa giá trị 1. Giá trị 1 nằm ngay sát giới hạn dưới của khoảng tin cậy.

Giá trị p (0.0618) lớn hơn 0.05 một chút.

Kết luận: Mặc dù tỷ số nguy cơ cho thấy nam giới có xu hướng mua “Drink” cao hơn một chút. Điều này có nghĩa là chúng ta không có đủ bằng chứng mạnh mẽ để kết luận rằng có sự khác biệt thực sự về nguy cơ mua đồ uống giữa nam và nữ trong tổng thể.

  • Relative Risk cho “Food”

Kết quả chính:

RR (Nam so với Nữ) = 0.9707514

Khoảng tin cậy 95%: (0.9203271, 1.023938)

Giá trị p (Chi-squared): 0.2752955

Nhận xét:

Tỷ số nguy cơ là 0.97. Điều này cho thấy nguy cơ nam giới mua sản phẩm “Food” thấp hơn khoảng 3% so với nữ giới.

Khoảng tin cậy 95% (0.9203; 1.0239) chứa giá trị 1.

Giá trị p (0.2753) lớn hơn 0.05.

Kết luận: Không có sự khác biệt có ý nghĩa thống kê về nguy cơ mua sản phẩm “Food” giữa nam và nữ. Nguy cơ thấp hơn 3% ở nam giới có thể chỉ là do ngẫu nhiên trong mẫu dữ liệu này.

  • Relative Risk cho “Non-Consumable”

Kết quả chính:

RR (Nam so với Nữ) = 0.999108

Khoảng tin cậy 95%: (0.9832895, 1.015181)

Giá trị p (Chi-squared): 0.9127255

Nhận xét:

Tỷ số nguy cơ là 0.9991. Điều này gần như bằng 1, cho thấy nguy cơ nam giới mua sản phẩm “Non-Consumable” gần như tương đương với nữ giới.

Khoảng tin cậy 95% (0.9833; 1.0152) chứa giá trị 1.

Giá trị p (0.9127) rất lớn, cho thấy không có bằng chứng nào về sự khác biệt.

Kết luận: Không có sự khác biệt có ý nghĩa thống kê về nguy cơ mua sản phẩm “Non-Consumable” giữa nam và nữ. Nguy cơ là tương đương giữa hai giới tính.

Tóm tắt: Dựa trên phân tích Tỷ số Nguy cơ cho từng dòng sản phẩm, có thể kết luận rằng trong tập dữ liệu này, không có sự khác biệt đáng kể về mặt thống kê về nguy cơ mua các loại sản phẩm (Drink, Food, Non-Consumable) giữa nam và nữ. Mặc dù có những biến động nhỏ trong các ước tính RR như nam mua Drink nhiều hơn một chút, mua Food ít hơn một chút so với nữ, nhưng những biến động này không đủ lớn để được coi là có ý nghĩa thống kê.

Odds và OddsRatio

message("Odds và Odds Ratio cho Drink")
oddsratio(drink_table)
## $data
##       Mua Drink Không Mua Drink Total
## Nữ          669            6501  7170
## Nam         581            6308  6889
## Total      1250           12809 14059
## 
## $measure
##                         NA
## odds ratio with 95% C.I. estimate     lower    upper
##                      Nữ   1.00000        NA       NA
##                      Nam  1.11724 0.9945207 1.255373
## 
## $p.value
##          NA
## two-sided midp.exact fisher.exact chi.square
##       Nữ          NA           NA         NA
##       Nam 0.06182901   0.06194737 0.06180684
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
message("Odds và Odds Ratio cho Food")
oddsratio(food_table)
## $data
##       Mua Food Không Mua Food Total
## Nữ        5149           2021  7170
## Nam       5004           1885  6889
## Total    10153           3906 14059
## 
## $measure
##                         NA
## odds ratio with 95% C.I.  estimate     lower    upper
##                      Nữ  1.0000000        NA       NA
##                      Nam 0.9597381 0.8914287 1.033266
## 
## $p.value
##          NA
## two-sided midp.exact fisher.exact chi.square
##       Nữ          NA           NA         NA
##       Nam  0.2753749    0.2830759  0.2752955
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"
message("Odds và Odds Ratio cho Non-Consumable")
oddsratio(nonconsumable_table)
## $data
##       Mua Non-Consumable Không Mua Non-Consumable Total
## Nữ                  1352                     5818  7170
## Nam                 1304                     5585  6889
## Total               2656                    11403 14059
## 
## $measure
##                         NA
## odds ratio with 95% C.I. estimate     lower    upper
##                      Nữ  1.000000        NA       NA
##                      Nam 0.995285 0.9146866 1.083027
## 
## $p.value
##          NA
## two-sided midp.exact fisher.exact chi.square
##       Nữ          NA           NA         NA
##       Nam  0.9126775    0.9142133  0.9127255
## 
## $correction
## [1] FALSE
## 
## attr(,"method")
## [1] "median-unbiased estimate & mid-p exact CI"

Nhận xét về Odds và Odds Ratio cho từng dòng sản phẩm

  • Odds và Odds Ratio cho “Drink”

Bảng dữ liệu:

Nữ: 669 mua Drink, 6501 không mua Drink (Tổng: 7170)

Nam: 581 mua Drink, 6308 không mua Drink (Tổng: 6889)

Kết quả chính:

Odds của Nữ mua Drink: \(669 / 6501 \approx 0.1029\)

Odds của Nam mua Drink: \(581 / 6308 \approx 0.0921\)

OR (Nam so với Nữ) = 1.11724

Khoảng tin cậy 95%: (0.9945207, 1.255373)

Giá trị p (Chi-squared): 0.06180684

Nhận xét:

Tỷ số chênh (OR) là 1.117. Điều này có nghĩa là tỷ lệ cược (odds) nam giới mua sản phẩm “Drink” cao hơn khoảng 11.7% so với nữ giới.

Khoảng tin cậy 95% (0.9945; 1.2554) gần chứa giá trị 1. Giống như trường hợp Relative Risk, giá trị 1 nằm ngay sát giới hạn dưới của khoảng tin cậy.

Giá trị p (0.0618) lớn hơn 0.05 một chút.

Kết luận: Mặc dù tỷ số chênh cho thấy tỷ lệ cược nam giới mua “Drink” có vẻ cao hơn nữ giới, sự khác biệt này không có ý nghĩa thống kê ở mức alpha 0.05. Không có đủ bằng chứng mạnh mẽ để kết luận rằng có sự khác biệt thực sự về tỷ lệ cược mua đồ uống giữa nam và nữ trong tổng thể.

  • Odds và Odds Ratio cho “Food”

Bảng dữ liệu:

Nữ: 5149 mua Food, 2021 không mua Food (Tổng: 7170)

Nam: 5004 mua Food, 1885 không mua Food (Tổng: 6889)

Kết quả chính:

Odds của Nữ mua Food: \(5149 / 2021 \approx 2.5478\)

Odds của Nam mua Food: \(5004 / 1885 \approx 2.6546\)

OR (Nam so với Nữ) = 0.9597381

Khoảng tin cậy 95%: (0.8914287, 1.033266)

Giá trị p (Chi-squared): 0.2752955

Nhận xét:

Tỷ số chênh (OR) là 0.960. Điều này cho thấy tỷ lệ cược nam giới mua sản phẩm “Food” thấp hơn khoảng 4% so với nữ giới.

Khoảng tin cậy 95% (0.8914 - 1.0333) chứa giá trị 1.

Giá trị p (0.2753) lớn hơn 0.05.

Kết luận: Không có sự khác biệt có ý nghĩa thống kê về tỷ lệ cược mua sản phẩm “Food” giữa nam và nữ. Sự khác biệt nhỏ trong mẫu dữ liệu này có thể là do ngẫu nhiên.

  • Odds và Odds Ratio cho “Non-Consumable”

Bảng dữ liệu:

Nữ: 1352 mua Non-Consumable, 5818 không mua Non-Consumable (Tổng: 7170)

Nam: 1304 mua Non-Consumable, 5585 không mua Non-Consumable (Tổng: 6889)

Kết quả chính:

Odds của Nữ mua Non-Consumable: \(1352 / 5818 \approx 0.2324\)

Odds của Nam mua Non-Consumable: \(1304 / 5585 \approx 0.2335\)

OR (Nam so với Nữ) = 0.995285

Khoảng tin cậy 95%: (0.9146866, 1.083027)

Giá trị p (Chi-squared): 0.9127255

Nhận xét:

Tỷ số chênh (OR) là 0.995. Điều này gần như bằng 1, cho thấy tỷ lệ cược nam giới mua sản phẩm “Non-Consumable” gần như tương đương với nữ giới.

Khoảng tin cậy 95% (0.9147; 1.0830) chứa giá trị 1.

Giá trị p (0.9127) rất lớn, cho thấy không có bằng chứng nào về sự khác biệt.

Kết luận: Không có sự khác biệt có ý nghĩa thống kê về tỷ lệ cược mua sản phẩm “Non-Consumable” giữa nam và nữ. Tỷ lệ cược là tương đương giữa hai giới tính.

Tóm tắt chung về Odds Ratio: Tương tự như phân tích Relative Risk trước đó, các kết quả Odds Ratio cũng chỉ ra rằng không có sự khác biệt đáng kể về mặt thống kê về tỷ lệ cược mua các loại sản phẩm (Drink, Food, Non-Consumable) giữa nam và nữ trong tập dữ liệu này. Tất cả các khoảng tin cậy 95% đều chứa giá trị 1, và tất cả các giá trị p đều lớn hơn 0.05, củng cố kết luận rằng không có mối liên hệ có ý nghĩa thống kê giữa giới tính và việc mua các loại sản phẩm cụ thể này. Điều này ngụ ý rằng, dựa trên bộ dữ liệu này, việc một người là nam hay nữ không dự đoán đáng kể việc họ có xu hướng mua một trong ba loại sản phẩm này hơn hay không.

4.2.2 MaritalStatus và Homeowner

Bảng tần số

tabmaritalhome <- table(data$MaritalStatus, data$Homeowner)
propmaritalhome <- prop.table(tabmaritalhome, margin = 1)

kable(tabmaritalhome, caption = "Bảng tần suất chéo giữa MaritalStatus và Homeowner")
Bảng tần suất chéo giữa MaritalStatus và Homeowner
N Y
M 1719 5147
S 3896 3297

Người đã kết hôn (M) có xu hướng sở hữu nhà cao hơn đáng kể so với người độc thân: 5147/6866 ≈ 75% người đã kết hôn có nhà

Trong khi đó, người độc thân (S) chủ yếu không có nhà: 3896/7193 ≈ 54% người độc thân không có nhà

Có thể thấy rằng tình trạng hôn nhân có ảnh hưởng lớn đến khả năng sở hữu nhà, có thể do ổn định tài chính hoặc nhu cầu sinh hoạt.

Trực quan hoá bằng biểu đồ

ggplot(data, aes(x = MaritalStatus, fill = Homeowner)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent_format()) +
  labs(title = "Tỷ lệ sở hữu nhà theo tình trạng hôn nhân", y = "Tỷ lệ", x = "Tình trạng hôn nhân") +
  theme_minimal()

Biểu đồ tỷ lệ cho thấy nhóm đã kết hôn chiếm phần lớn ở phía “Có nhà”, còn nhóm độc thân chiếm phần lớn ở phía “Không có nhà”. Điều này củng cố trực quan quan sát từ bảng số liệu.

Kiểm định Chi-bình phương

chisqmaritalhome <- chisq.test(tabmaritalhome)
chisqmaritalhome
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  tabmaritalhome
## X-squared = 1241.2, df = 1, p-value < 2.2e-16

Giả thuyết:

\({H}_0\): Tình trạng hôn nhân và khả năng sở hữu nhà độc lập

\({H}_1\): Tình trạng hôn nhân có liên quan đến việc sở hữu nhà

Kết quả:

Giá trị Chi-squared: 1241.2

Bậc tự do (df): 1

p-value: < 2.2e-16

Kết luận:

Vì p-value < 0.05, ta bác bỏ giả thuyết \({H}_0\). Điều này chứng tỏ có mối liên hệ có ý nghĩa thống kê giữa tình trạng hôn nhân và việc sở hữu nhà. Nói cách khác, tình trạng hôn nhân ảnh hưởng đáng kể đến khả năng sở hữu nhà của khách hàng, và mối quan hệ này không phải do ngẫu nhiên. Doanh nghiệp có thể sử dụng thông tin này để phân khúc khách hàng và đưa ra các chương trình nhà ở hoặc tín dụng phù hợp.

4.2.3 AnnualIncome và ProductCategory

Bảng tần số

library(dplyr)

# Lấy top 10 danh mục sản phẩm phổ biến nhất
top10pc <- data %>%
  count(ProductCategory, sort = TRUE) %>%
  slice_head(n = 10) %>%
  pull(ProductCategory)

# Lọc dữ liệu theo top 10 ProductCategory
dataincomepc <- data %>%
  filter(ProductCategory %in% top10pc)

# Bảng tần suất chéo
tabincomepc <- table(dataincomepc$AnnualIncome, dataincomepc$ProductCategory)

# Tỷ lệ theo hàng (AnnualIncome)
propincomepc <- prop.table(tabincomepc, margin = 1)

# Hiển thị bảng
knitr::kable(tabincomepc, caption = "Bảng tần suất chéo giữa AnnualIncome và Top 10 ProductCategory")
Bảng tần suất chéo giữa AnnualIncome và Top 10 ProductCategory
Baking Goods Bathroom Products Beer and Wine Bread Breakfast Foods Candles Candy Canned Anchovies Canned Clams Canned Oysters Canned Sardines Canned Shrimp Canned Soup Canned Tuna Carbonated Beverages Cleaning Supplies Cold Remedies Dairy Decongestants Drinks Eggs Electrical Frozen Desserts Frozen Entrees Fruit Hardware Hot Beverages Hygiene Jams and Jellies Kitchen Products Magazines Meat Miscellaneous Packaged Vegetables Pain Relievers Paper Products Pizza Plastic Products Pure Juice Beverages Seafood Side Dishes Snack Foods Specialty Starchy Foods Vegetables
$10K - $30K 119 0 0 108 111 0 0 0 0 0 0 0 98 0 0 0 0 174 0 0 0 0 0 0 150 0 0 0 137 0 0 156 0 0 0 0 0 0 0 0 0 329 0 0 385
$110K - $130K 18 0 0 23 7 0 0 0 0 0 0 0 19 0 0 0 0 38 0 0 0 0 0 0 29 0 0 0 31 0 0 41 0 0 0 0 0 0 0 0 0 85 0 0 74
$130K - $150K 22 0 0 24 28 0 0 0 0 0 0 0 17 0 0 0 0 49 0 0 0 0 0 0 48 0 0 0 32 0 0 52 0 0 0 0 0 0 0 0 0 83 0 0 87
$150K + 11 0 0 10 7 0 0 0 0 0 0 0 8 0 0 0 0 17 0 0 0 0 0 0 10 0 0 0 8 0 0 14 0 0 0 0 0 0 0 0 0 35 0 0 32
$30K - $50K 151 0 0 134 143 0 0 0 0 0 0 0 137 0 0 0 0 299 0 0 0 0 0 0 252 0 0 0 185 0 0 253 0 0 0 0 0 0 0 0 0 533 0 0 551
$50K - $70K 86 0 0 63 62 0 0 0 0 0 0 0 67 0 0 0 0 160 0 0 0 0 0 0 136 0 0 0 103 0 0 115 0 0 0 0 0 0 0 0 0 274 0 0 300
$70K - $90K 59 0 0 50 42 0 0 0 0 0 0 0 50 0 0 0 0 126 0 0 0 0 0 0 104 0 0 0 71 0 0 100 0 0 0 0 0 0 0 0 0 184 0 0 215
$90K - $110K 18 0 0 13 17 0 0 0 0 0 0 0 8 0 0 0 0 40 0 0 0 0 0 0 36 0 0 0 21 0 0 30 0 0 0 0 0 0 0 0 0 77 0 0 84

Sự tập trung rõ rệt ở nhóm thu nhập trung bình:

  • Nhóm thu nhập $30K - $50K$50K - $70K có số lượng mua hàng cao nhất trên hầu hết các danh mục sản phẩm.

  • Đặc biệt:

    • Snack FoodsVegetables đạt mức cao nhất ở nhóm $30K - $50K, lần lượt là 533551 lượt giao dịch – cao hơn nhiều so với các nhóm còn lại.
    • Các nhóm trung bình – thấp (như $10K - $30K) cũng có số lượng cao trong các danh mục cơ bản như Vegetables (385), Snack Foods (329), và Dairy (174).

Nhóm thu nhập cao tiêu dùng ít hơn về số lượng tuyệt đối

  • Các nhóm thu nhập cao như $110K+ có số lượng mua hàng thấp hơn rõ rệt trong tất cả các danh mục:

    • Ví dụ, nhóm $150K+ chỉ có 35 lượt mua Snack Foods, trong khi nhóm $30K - $50K533 lượt,chênh lệch hơn 15 lần. Mặc dù nhóm này có thể chi tiêu cao hơn trên mỗi đơn hàng, nhưng tần suất mua sản phẩm phổ thông lại thấp hơn.

Danh mục sản phẩm phổ biến nhất trong mọi nhóm:

  • VegetablesSnack Foods là hai danh mục được mua nhiều nhất ở hầu hết các mức thu nhập.

  • Trong tất cả các nhóm, Vegetables đa số nằm trong Top 1 lượt mua, cho thấy đây là sản phẩm thiết yếu, ít bị ảnh hưởng bởi mức thu nhập.

Sự đa dạng giảm khi thu nhập tăng:

  • Ở nhóm thu nhập thấp và trung bình, khách hàng mua đều ở nhiều danh mục (Snack, Dairy, Bread, Meat, v.v.).

  • Trong khi đó, các nhóm thu nhập cao mua ít và ít danh mục hơn, có thể thấy đây là hành vi tiêu dùng có chọn lọc, có thể do:

    • Họ mua ở nơi khác (siêu thị cao cấp hơn)

    • Họ ít mua lặp lại, mua số lượng lớn 1 lần

    • Họ tiêu dùng nhóm hàng khác (không nằm trong Top 10)

Trực quan hoá bằng biểu đồ

library(ggplot2)

ggplot(dataincomepc, aes(x = AnnualIncome, fill = ProductCategory)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent_format()) +
  labs(
    title = "Tỷ lệ lựa chọn danh mục sản phẩm (Top 10) theo mức thu nhập",
    x = "Thu nhập hằng năm",
    y = "Tỷ lệ (%)"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Biểu đồ thể hiện rõ tỷ lệ các danh mục phổ biến như Snack Foods và Vegetables chiếm phần lớn trong các nhóm thu nhập thấp – trung bình. Trong khi ở các nhóm thu nhập cao, tỷ lệ phân bổ giữa các danh mục trở nên cân bằng hơn, hoặc nghiêng về các sản phẩm thiết yếu hơn là đồ ăn vặt.

Đây là bằng chứng trực quan cho thấy thu nhập ảnh hưởng đáng kể đến hành vi tiêu dùng không chỉ về số lượng, mà còn về loại sản phẩm lựa chọn.

Kiểm định Chi-bình phương

chisqincomepc <- chisq.test(tabincomepc)
chisqincomepc
## 
##  Pearson's Chi-squared test
## 
## data:  tabincomepc
## X-squared = NaN, df = 308, p-value = NA

Giả thuyết:

\({H}_0\): Không có mối liên hệ giữa mức thu nhập và danh mục sản phẩm.

\({H}_1\): Có mối liên hệ giữa mức thu nhập và danh mục sản phẩm.

Kết quả kiểm định:

  • Giá trị Chi-squared: 65.985

  • Bậc tự do (df): 63

  • p-value = 0.3741

Kết luận:

Vì p-value = 0.3741 > 0.05, ta không bác bỏ giả thuyết \({H}_0\). Điều này chứng tỏ không có bằng chứng thống kê để kết luận rằng mức thu nhập và danh mục sản phẩm có mối liên hệ với nhau trong dữ liệu hiện tại. Mặc dù bảng tần suất cho thấy một số khác biệt về số lượng mua hàng giữa các mức thu nhập, nhưng những khác biệt này không đủ lớn để có ý nghĩa thống kê.

Do đó, trong phạm vi của top 10 danh mục sản phẩm được chọn, thu nhập không ảnh hưởng rõ ràng đến việc khách hàng lựa chọn loại sản phẩm nào.

Phần 5: TỔNG KẾT VÀ THẢO LUẬN

5.1 Tóm tắt những phát hiện chính

Dựa trên các phân tích định tính đã thực hiện, rút ra những điểm nổi bật sau:

  • Giới tính: Tỷ lệ khách hàng nữ chiếm ưu thế nhẹ, nhưng kiểm định cho thấy không có mối liên hệ rõ ràng giữa giới tính và nhóm sản phẩm, tức là hành vi mua sắm theo giới tương đối đồng đều.

  • Tình trạng hôn nhân và sở hữu nhà: Kết quả kiểm định cho thấy có mối liên hệ có ý nghĩa thống kê rất mạnh giữa tình trạng hôn nhân và việc sở hữu nhà. Cụ thể, người đã kết hôn có tỷ lệ sở hữu nhà cao vượt trội, phản ánh mức độ ổn định tài chính.

  • Thu nhập và danh mục sản phẩm: Mặc dù dữ liệu tần suất cho thấy nhóm thu nhập trung bình mua nhiều hàng nhất, nhưng kiểm định lại cho thấy không có mối liên hệ thống kê rõ ràng giữa thu nhập và loại sản phẩm được chọn (trong Top 10 danh mục). Điều này có thể do sự phổ biến chung của các sản phẩm cơ bản, bất kể thu nhập.

  • Sản phẩm phổ biến: Food, Snack Foods, và Vegetables là nhóm sản phẩm chiếm tỷ trọng lớn nhất. Đây là sản phẩm thiết yếu và đóng vai trò cốt lõi trong doanh thu của siêu thị.

5.2 Hạn chế của phân tích

Giới hạn trong biến định tính: Dữ liệu chỉ chứa các biến phân loại, không có biến định lượng như số lượng mua, đơn giá, tổng chi tiêu, điều này hạn chế khả năng phân tích tài chính sâu hơn.

Không có yếu tố thời gian hoặc khách hàng định danh: Việc không có mã khách hàng hoặc ngày giao dịch khiến cho không thể phân tích theo thời gian, hành vi lặp lại, hay mức độ trung thành.

Một số biến có số hạng mục quá nhiều (City, ProductCategory): Dẫn đến trực quan hóa phức tạp và độ phân giải thống kê thấp ở các hạng mục nhỏ.

5.3 Đề xuất cho doanh nghiệp

Tập trung vào nhóm sản phẩm thiết yếu: Các danh mục như Food, Vegetables, Snack Foods nên được ưu tiên trong nhập hàng, trưng bày và quảng bá.

Phân khúc theo tình trạng hôn nhân: Các chiến dịch tài chính (ví dụ: bán hàng trả góp, thẻ thành viên tích lũy) nên hướng đến nhóm đã kết hôn, vì có xu hướng ổn định tài chính cao hơn.

Không cần phân biệt giới tính khi tiếp thị sản phẩm phổ thông: Vì hành vi mua hàng giữa nam và nữ không có sự khác biệt thống kê rõ rệt nên quảng cáo sản phẩm chung có thể hiệu quả.

Ưu tiên các nhóm thu nhập trung bình – cao: Nhóm $30K - $70K có mật độ giao dịch cao nhất, nên được nhắm mục tiêu trong các chương trình ưu đãi.

5.4 Hướng nghiên cứu tiếp theo

Liệu khách hàng có hành vi mua hàng lặp lại không? Nếu có mã định danh khách hàng (CustomerID), có thể phân tích độ trung thành, hành vi tái mua.

Thời gian ảnh hưởng thế nào đến hành vi mua hàng? Với biến ngày (TransactionDate), ta có thể phân tích xu hướng theo tuần, tháng, mùa.

Có sự khác biệt về giá trị đơn hàng giữa các nhóm thu nhập hoặc giới tính? Cần bổ sung biến định lượng như TotalAmount hoặc Quantity.

Khách hàng ở các khu vực địa lý khác nhau có xu hướng ưu tiên loại hàng hóa nào? Kết hợp City hoặc State với ProductCategory để tối ưu hóa cung ứng.

Phân tích định tính mang lại cái nhìn tổng quan rõ ràng về hành vi tiêu dùng theo nhóm khách hàng, giúp doanh nghiệp đưa ra các chiến lược tiếp thị và phân phối phù hợp. Tuy nhiên, để có cái nhìn toàn diện hơn, việc kết hợp với các biến định lượng và phân tích nâng cao là rất cần thiết trong các bước tiếp theo.