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
data <- read.csv("C:/Users/Welcome !/Downloads/Supermarket Transactions.csv")

a. Cấu trúc của 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 ...

b. Hiển thị một vài dòng đầu và cuối của dữ liệu

head(data)
##   X PurchaseDate CustomerID Gender MaritalStatus Homeowner Children
## 1 1   2007-12-18       7223      F             S         Y        2
## 2 2   2007-12-20       7841      M             M         Y        5
## 3 3   2007-12-21       8374      F             M         N        2
## 4 4   2007-12-21       9619      M             M         Y        3
## 5 5   2007-12-22       1900      F             S         Y        3
## 6 6   2007-12-22       6696      F             M         Y        3
##    AnnualIncome          City StateorProvince Country ProductFamily
## 1   $30K - $50K   Los Angeles              CA     USA          Food
## 2   $70K - $90K   Los Angeles              CA     USA          Food
## 3   $50K - $70K     Bremerton              WA     USA          Food
## 4   $30K - $50K      Portland              OR     USA          Food
## 5 $130K - $150K Beverly Hills              CA     USA         Drink
## 6   $10K - $30K Beverly Hills              CA     USA          Food
##   ProductDepartment      ProductCategory UnitsSold Revenue
## 1       Snack Foods          Snack Foods         5   27.38
## 2           Produce           Vegetables         5   14.90
## 3       Snack Foods          Snack Foods         3    5.52
## 4            Snacks                Candy         4    4.44
## 5         Beverages Carbonated Beverages         4   14.00
## 6              Deli          Side Dishes         3    4.37
tail(data)
##           X PurchaseDate CustomerID Gender MaritalStatus Homeowner Children
## 14054 14054   2009-12-29       2032      F             M         N        3
## 14055 14055   2009-12-29       9102      F             M         Y        2
## 14056 14056   2009-12-29       4822      F             M         Y        3
## 14057 14057   2009-12-31        250      M             S         Y        1
## 14058 14058   2009-12-31       6153      F             S         N        4
## 14059 14059   2009-12-31       3656      M             S         N        3
##       AnnualIncome        City StateorProvince Country  ProductFamily
## 14054  $10K - $30K      Yakima              WA     USA Non-Consumable
## 14055  $10K - $30K   Bremerton              WA     USA           Food
## 14056  $10K - $30K Walla Walla              WA     USA           Food
## 14057  $30K - $50K    Portland              OR     USA          Drink
## 14058  $50K - $70K     Spokane              WA     USA          Drink
## 14059  $50K - $70K    Portland              OR     USA Non-Consumable
##       ProductDepartment      ProductCategory UnitsSold Revenue
## 14054         Household       Paper Products         5   14.50
## 14055      Baking Goods         Baking Goods         3    9.64
## 14056      Frozen Foods           Vegetables         3    7.45
## 14057         Beverages Pure Juice Beverages         4    3.24
## 14058             Dairy                Dairy         2    4.00
## 14059         Household           Electrical         5   25.53

c. Kiểm tra dữ liệu bị thiếu (missing values)

any(is.na(data))
## [1] FALSE

Kết quả trả về FALSE nghĩa là không có bất kỳ giá trị thiếu (NA) nào trong toàn bộ dataframe

d. Chuyển đổi các biến cần thiết sang kiểu factor

data[] <- lapply(data, function(x) if (is.character(x)) as.factor(x) else x)

qual_data <- data[sapply(data, is.factor)]

Đoạn code trên dùng để tự động chuyển tất cả các cột có kiểu dữ liệu character trong dataframe data sang kiểu factor. Việc này rất quan trọng vì các biến dạng chữ thường biểu thị cho dữ liệu phân loại, và khi được chuyển thành factor, R sẽ hiểu đúng bản chất của chúng như các nhóm hoặc mức phân loại riêng biệt. Điều này giúp các mô hình thống kê và phân tích sau đó xử lý chính xác hơn các biến này, đồng thời hỗ trợ việc phân tích và trực quan hóa dữ liệu dễ dàng hơn.

Phần 2: Phân tích Mô tả Một biến Định tính (Univariate Descriptive Analysis)

2.1 Phân tích theo giới tính ( Gender)

# Tạo bảng tần suất cho biến Gender
freq_tableGender <- table(qual_data$Gender)

# Tính tỷ lệ phần trăm
percent_tableGender <- prop.table(freq_tableGender) * 100
## Tần suất các quan sát của biến Gender :
## 
##    F    M 
## 7170 6889
## Tỷ lệ phần trăm các quan sát của biến ProductDepartmentu:
## 
##  F  M 
## 51 49
# Biểu đồ cột
barplot(freq_tableGender,
        col = c("darkblue", "beige"),  # đổi thành 2 màu cho 2 cột
        main = "Biểu đồ cột thể hiệu giới tính của số người trong dữ liệu nghiên cứu",
        ylab = "Tần suất",
        xlab = "Giới Tính ")

legend("topright", 
       legend = c("Nữ  ", "Nam"),  # chú thích cho 2 cột
       fill = c("darkblue", "beige"))

Nhận xét :Trong tổng số người tham gia, nữ giới (F) chiếm 7170 người, trong khi nam giới (M) chiếm 6889 người. Mặc dù sự chênh lệch không quá lớn, nhưng số lượng nữ giới vẫn nhỉnh hơn nam giới trong tập dữ liệu này. Biểu đồ cho thấy sự phân bố giới tính tương đối cân đối, tuy nhiên nữ giới chiếm tỷ lệ cao hơn một chút.

2.2 Phân tích theo tình trạng hôn nhân (MaritalStatus)

# Tạo bảng tần suất
freq_table <- table(qual_data$MaritalStatus)

# Tính tỷ lệ phần trăm
percent_table <- prop.table(freq_table) * 100
## Tần suất các quan sát của biến MaritalStatus :
## 
##    M    S 
## 6866 7193
## Tỷ lệ phần trăm các quan sát của biến MaritalStatus:
## 
##     M     S 
## 48.84 51.16
# Biểu đồ cột
colors <- c("skyblue", "darkblue", "darkblue")
barplot(freq_table,
        col = colors,
        main = "Biểu đồ cột thể hiện tình trạng hôn nhân trong khảo sát",
        ylab = "Tần suất",
        xlab = "Tình trạng hôn nhân")

legend("topright", legend = names(freq_table), fill = colors, cex = 0.8)

Nhận xét : Số lượng người độc thân (S) cao hơn so với số lượng người đã kết hôn (M).Cụ thể, tần suất người độc thân gần 7193, trong khi người đã kết hôn khoảng 6866 .Chênh lệch không lớn: mặc dù có sự khác biệt, nhưng khoảng cách tần suất giữa hai nhóm không quá lớn, cho thấy phân bố tình trạng hôn nhân trong dữ liệu nghiên cứu là khá cân đối giữa người đã kết hôn và độc thân.

2.3 Phân tích theo tình trạng sở hữu nhà (Homeowner)

# Tạo bảng tần suất cho biến Homeowner
freq_tableHomeowner <- table(qual_data$Homeowner)

# Tính tỷ lệ phần trăm
percent_tableHomeowner <- prop.table(freq_tableHomeowner) * 100
## Tần suất các quan sát của biến Homeowners :
## 
##    N    Y 
## 5615 8444
## Tỷ lệ phần trăm các quan sát của biến Homeowneru:
## 
##     N     Y 
## 39.94 60.06
# Biểu đồ cột
barplot(freq_tableHomeowner,
        col = c("brown", "beige"),  # đổi thành 2 màu cho 2 cột
        main = "Biểu đồ cột thể hiện số người sỡ hữu nhà trong dữ liệu nghiên cứu",
        ylab = "Tần suất",
        xlab = "Số người sỡ hữu nhà ")

legend("topright", 
       legend = c("Có nhà", "Không có nhà"),  # chú thích cho 2 cột
       fill = c("brown", "beige"))

Nhận xét :Dựa trên biểu đồ cột thể hiện số người sở hữu nhà trong dữ liệu nghiên cứu, có thể thấy rằng số lượng người có nhà (Y) chiếm tỷ lệ cao hơn rõ rệt so với số người không có nhà (N). Cụ thể, tần suất của nhóm có nhà vào khoảng 8444, trong khi nhóm không có nhà chỉ khoảng 5615. Điều này cho thấy trong mẫu dữ liệu nghiên cứu, đa số người tham gia có sở hữu nhà ở. Sự chênh lệch này khá rõ ràng và có thể phản ánh mức độ ổn định về mặt kinh tế – xã hội của nhóm người được khảo sát. Đây cũng có thể là một yếu tố quan trọng để phân tích sâu hơn khi xem xét mối liên hệ với các biến khác như tình trạng hôn nhân, thu nhập hoặc khả năng vay vốn.

2.4 Phân tích theo mức thu nhập hằng năm (AnnualIncome)

# Tạo bảng tần suất cho biến AnnualIncome
freq_tableAnnualIncome <- table(qual_data$AnnualIncome)

# Tính tỷ lệ phần trăm
percent_tableAnnualIncome <- prop.table(freq_tableAnnualIncome) * 100
## Tần suất các quan sát của biến AnnualIncome :
## 
##   $10K - $30K $110K - $130K $130K - $150K       $150K +   $30K - $50K 
##          3090           643           760           273          4601 
##   $50K - $70K   $70K - $90K  $90K - $110K 
##          2370          1709           613
## Tỷ lệ phần trăm các quan sát của biến AnnualIncomeu:
## 
##   $10K - $30K $110K - $130K $130K - $150K       $150K +   $30K - $50K 
##         21.98          4.57          5.41          1.94         32.73 
##   $50K - $70K   $70K - $90K  $90K - $110K 
##         16.86         12.16          4.36
# Biểu đồ cột với nhãn xoay dọc
barplot(freq_tableAnnualIncome,
        col = rainbow(length(freq_tableAnnualIncome)),
        main = "Biểu đồ cột thể hiện phân bố mức thu nhập hằng năm",
        ylab = "Tần suất",
        xlab = "",
        las = 2,                    # Xoay nhãn trục x theo chiều dọc
        cex.names = 0.8)            # Thu nhỏ chữ nếu quá dài

# Thêm chú thích
legend("topright",
       legend = names(freq_tableAnnualIncome),
       fill = rainbow(length(freq_tableAnnualIncome)))

Nhận xét : Biểu đồ phân bố tần suất thu nhập hàng năm cho thấy một cái nhìn rõ nét về cơ cấu thu nhập trong bộ dữ liệu nghiên cứu. Nổi bật nhất là nhóm thu nhập từ $30K – $50K, với 4.601 cá nhân, chiếm tỷ lệ cao nhất và thể hiện đây là mức thu nhập phổ biến nhất trong mẫu khảo sát. Điều này cho thấy phần lớn đối tượng nghiên cứu tập trung ở phân khúc thu nhập trung bình thấp. Kế đó, nhóm $10K – $30K cũng chiếm một phần đáng kể với 3.090 người, củng cố nhận định về sự tập trung của phần lớn cá nhân ở các nhóm thu nhập dưới mức trung bình. Ngược lại, các nhóm thu nhập cao hơn như $110K – $130K, $130K – $150K và đặc biệt là trên $150K chỉ ghi nhận tần suất rất thấp (lần lượt 643, 760 và 273 người). Sự chênh lệch rõ rệt này chỉ ra rằng, trong bộ dữ liệu, các mức thu nhập cao hơn là hiếm gặp và không đại diện cho phần lớn dân số nghiên cứu. Xu hướng chung của biểu đồ là sự phân bố lệch trái, với mật độ tần suất giảm dần khi mức thu nhập tăng lên, phản ánh đặc điểm thu nhập phổ biến thấp trong tập dữ liệu này.

2.5 Phân tích theo thành phố (City)

# Tạo bảng tần suất cho biến City
freq_tableCity <- table(qual_data$City)

# Tính tỷ lệ phần trăm
percent_tableCity <- prop.table(freq_tableCity) * 100
## Tần suất các quan sát của biến City :
## 
##      Acapulco    Bellingham Beverly Hills     Bremerton       Camacho 
##           383           143           811           834           452 
##   Guadalajara       Hidalgo   Los Angeles        Merida   Mexico City 
##            75           845           926           654           194 
##       Orizaba      Portland         Salem    San Andres     San Diego 
##           464           876          1386           621           866 
## San Francisco       Seattle       Spokane        Tacoma     Vancouver 
##           130           922           875          1257           633 
##      Victoria   Walla Walla        Yakima 
##           176           160           376
## Tỷ lệ phần trăm các quan sát của biến Cityu:
## 
##      Acapulco    Bellingham Beverly Hills     Bremerton       Camacho 
##          2.72          1.02          5.77          5.93          3.22 
##   Guadalajara       Hidalgo   Los Angeles        Merida   Mexico City 
##          0.53          6.01          6.59          4.65          1.38 
##       Orizaba      Portland         Salem    San Andres     San Diego 
##          3.30          6.23          9.86          4.42          6.16 
## San Francisco       Seattle       Spokane        Tacoma     Vancouver 
##          0.92          6.56          6.22          8.94          4.50 
##      Victoria   Walla Walla        Yakima 
##          1.25          1.14          2.67
# Tên các thành phố và số lượng
cities <- names(freq_tableCity)
n <- length(freq_tableCity)

# Palette màu pastel tươi sáng, dễ nhìn, đủ phân biệt nhiều thành phố
colors <- c("#FF6F61", "#6B5B95", "#88B04B", "#F7CAC9", "#92A8D1", 
            "#955251", "#B565A7", "#009B77", "#DD4124", "#45B8AC")
colors <- rep(colors, length.out = n)

# Vẽ biểu đồ cột, ẩn tên mặc định trên trục X
bp <- barplot(freq_tableCity,
              col = colors,
              main = "Biểu đồ cột thể hiện tần suất phân bổ các thành phố",
              ylab = "Tần suất",
              xlab = "Các thành phố",
              names.arg = rep("", n),  # Ẩn tên mặc định
              ylim = c(0, max(freq_tableCity) * 1.3),
              las = 2)  # Chữ nghiêng đứng (dọc) để dễ đọc

# Thêm chữ tên thành phố ở dưới trục X, đẩy xuống thấp hơn trục, nghiêng 45 độ
text(x = bp, 
     y = par("usr")[3] - 0.05 * max(freq_tableCity),  # đẩy chữ xuống dưới trục
     labels = cities, 
     srt = 45,  # xoay nghiêng 45 độ
     adj = 1, 
     xpd = TRUE, 
     cex = 0.7)

# Thêm bảng chú thích (legend) ở góc trên bên phải, đẩy lên cao hơn 5%
legend("topright",
       legend = cities,
       fill = colors,
       border = "black",
       title = "Thành phố",
       cex = 0.7,
       ncol = 2,
       bty = "n",
       inset = c(0, 0.08))

Nhận xét Dựa vào biểu đồ cột thể hiện tần suất phân bố người dân theo thành phố trong bộ dữ liệu, ta có thể nhận xét như sau: Các thành phố được khảo sát có mức độ dân cư phân bố khá đa dạng, tuy nhiên có sự chênh lệch rõ rệt về số lượng người sinh sống giữa các thành phố. Trong đó, thành phố Salem là nơi có số người sinh sống cao nhất, với tần suất lên đến 1386, nổi bật hơn hẳn so với các thành phố còn lại. Tiếp theo là Tacoma (1257) và Los Angeles (926) cũng có số người sinh sống khá cao. Một số thành phố khác như Portland (876), San Diego (866), Seattle (922), và Hidalgo (845) cũng có mức tần suất tương đối cao, thể hiện đây là những nơi tập trung dân cư đáng kể trong bộ dữ liệu. Ngược lại, một số thành phố có tần suất rất thấp, điển hình như Guadalajara (75), San Francisco (130), và Bellingham (143). Điều này cho thấy số lượng người sinh sống ở các thành phố này trong bộ dữ liệu là rất hạn chế. Tóm lại, Salem là thành phố nổi bật nhất với số người sinh sống cao nhất, phản ánh vai trò có thể quan trọng về kinh tế hoặc xã hội của thành phố này trong phạm vi nghiên cứu.

2.6 Phân tích theo tỉnh/bang (StateorProvince)

# Tạo bảng tần suất cho biến StateorProvince
freq_tableStateorProvince <- table(qual_data$StateorProvince)

# Tính tỷ lệ phần trăm
percent_tableStateorProvince <- prop.table(freq_tableStateorProvince) * 100
## Tần suất các quan sát của biến StateorProvince :
## 
##      Acapulco    Bellingham Beverly Hills     Bremerton       Camacho 
##           383           143           811           834           452 
##   Guadalajara       Hidalgo   Los Angeles        Merida   Mexico City 
##            75           845           926           654           194 
##       Orizaba      Portland         Salem    San Andres     San Diego 
##           464           876          1386           621           866 
## San Francisco       Seattle       Spokane        Tacoma     Vancouver 
##           130           922           875          1257           633 
##      Victoria   Walla Walla        Yakima 
##           176           160           376
## Tỷ lệ phần trăm các quan sát của biếnStateorProvince:
## 
##      Acapulco    Bellingham Beverly Hills     Bremerton       Camacho 
##          2.72          1.02          5.77          5.93          3.22 
##   Guadalajara       Hidalgo   Los Angeles        Merida   Mexico City 
##          0.53          6.01          6.59          4.65          1.38 
##       Orizaba      Portland         Salem    San Andres     San Diego 
##          3.30          6.23          9.86          4.42          6.16 
## San Francisco       Seattle       Spokane        Tacoma     Vancouver 
##          0.92          6.56          6.22          8.94          4.50 
##      Victoria   Walla Walla        Yakima 
##          1.25          1.14          2.67
# Tên các tỉnh/tiểu bang và số lượng
states <- names(freq_tableStateorProvince)
n <- length(freq_tableStateorProvince)

# Palette màu pastel tươi sáng, đủ phân biệt nhiều tỉnh/tiểu bang
colors <- c("#FF6F61", "#6B5B95", "#88B04B", "#F7CAC9", "#92A8D1", 
            "#955251", "#B565A7", "#009B77", "#DD4124", "#45B8AC")
colors <- rep(colors, length.out = n)

# Vẽ biểu đồ cột, ẩn tên mặc định trên trục X
bp <- barplot(freq_tableStateorProvince,
              col = colors,
              main = "Biểu đồ cột thể hiện Phân phối tần suất theo tiểu bang ",
              ylab = "Tần suất",
              xlab = "Các tỉnh hay tiểu bang",
              names.arg = rep("", n),  # Ẩn tên mặc định
              ylim = c(0, max(freq_tableStateorProvince) * 1.3),
              las = 2)  # Chữ nghiêng đứng (dọc) để dễ đọc

# Thêm chữ tên tỉnh/tiểu bang ở dưới trục X, đẩy xuống thấp hơn trục, nghiêng 45 độ
text(x = bp, 
     y = par("usr")[3] - 0.05 * max(freq_tableStateorProvince),  # đẩy chữ xuống dưới trục
     labels = states, 
     srt = 45,  # xoay nghiêng 45 độ
     adj = 1, 
     xpd = TRUE, 
     cex = 0.7)

# Thêm bảng chú thích (legend) ở góc trên bên phải, đẩy lên cao 20%
legend("topright",
       legend = states,
       fill = colors,
       border = "black",
       title = "Tỉnh/TB",
       cex = 0.7,
       ncol = 2,
       bty = "n",
       inset = c(0, 0.001))  # Đẩy lên cao 20%

Nhận xét Nổi bật nhất là Salem, với tần suất cao vượt trội ở mức 1386, cho thấy đây là địa điểm có số lượng quan sát lớn nhất trong tập dữ liệu. Tiếp theo là Tacoma (1257) và Los Angeles (926), cùng với Seattle (922) và Portland (876), San Diego (866) và Spokane (875) cho thấy đây là những địa điểm có hoạt động hoặc sự hiện diện đáng kể. Ngược lại, một số địa điểm có tần suất rất thấp như Guadalajara (75), San Francisco (130), Bellingham (143), Walla Walla (160) và Victoria (176), cùng với Mexico City (194), phản ánh sự tập trung dữ liệu kém ở các khu vực này. Sự chênh lệch rõ rệt giữa các địa điểm có tần suất rất cao và rất thấp chỉ ra rằng dữ liệu không phân bố đồng đều, mà có xu hướng tập trung mạnh mẽ vào một số khu vực nhất định. Điều này gợi mở nhu cầu phân tích sâu hơn về các yếu tố địa lý, kinh tế-xã hội hoặc các đặc điểm riêng của từng địa điểm đã góp phần tạo nên sự phân bổ không đồng đều này.

2.7 Phân tích theo nhóm sản phẩm (ProductFamily)

# Tạo bảng tần suất cho biến ProductFamily
freq_tableProductFamily <- table(qual_data$ProductFamily)

# Tính tỷ lệ phần trăm
percent_tableProductFamily <- prop.table(freq_tableProductFamily) * 100
## Tần suất các quan sát của biến ProductFamily :
## 
##          Drink           Food Non-Consumable 
##           1250          10153           2656
## Tỷ lệ phần trăm các quan sát của biến ProductFamily:
## 
##          Drink           Food Non-Consumable 
##           8.89          72.22          18.89
products <- names(freq_tableProductFamily)
colors <- c("#FF7F50", "#6A5ACD", "#3CB371")  # 3 màu dễ phân biệt

bp <- barplot(freq_tableProductFamily,
              col = colors,
              main = "Biểu đồ tần suất theo nhóm sản phẩm",
              ylab = "Tần suất",
              xlab = "Nhóm sản phẩm",
              names.arg = products,
              ylim = c(0, max(freq_tableProductFamily)*1.2))

legend("topright",
       legend = products,
       fill = colors,
       border = "black",
       title = "Nhóm sản phẩm",
       cex = 0.8,
       bty = "n")

Nhận xét Biểu đồ tần suất các quan sát theo biến ProductFamily cho thấy sự phân bố không đồng đều giữa các nhóm sản phẩm. Nhóm Food chiếm ưu thế với 10.153 quan sát, chiếm phần lớn dữ liệu, trong khi nhóm Non-Consumable có 2.656 quan sát và nhóm Drink thấp nhất với 1.250 quan sát. Sự chênh lệch đáng kể này phản ánh mức độ phổ biến và tần suất xuất hiện khác nhau giữa các nhóm sản phẩm trong tập dữ liệu.Khuyến nghị rằng khi phân tích hoặc xây dựng mô hình dựa trên dữ liệu này, cần lưu ý đến sự mất cân bằng trong số lượng quan sát giữa các nhóm để tránh hiện tượng thiên lệch kết quả. Có thể áp dụng các phương pháp cân bằng dữ liệu như kỹ thuật lấy mẫu lại (resampling), hoặc sử dụng trọng số trong mô hình để đảm bảo tính đại diện cho các nhóm có số lượng quan sát thấp hơn. Ngoài ra, việc phân tích riêng biệt từng nhóm cũng có thể giúp khai thác sâu hơn các đặc điểm riêng biệt và đưa ra kết luận chính xác hơn về hành vi tiêu dùng hoặc đặc tính của từng nhóm sản phẩm.

2.8 Phân tích theo bộ phận/phòng ban sản phẩm (ProductDepartment)

# Tạo bảng tần suất cho biến ProductDepartment
freq_tableProductDepartment <- table(qual_data$ProductDepartment)

# Tính tỷ lệ phần trăm
percent_tableProductDepartment <- prop.table(freq_tableProductDepartment) * 100
## Tần suất các quan sát của biến ProductDepartment :
## 
## Alcoholic Beverages         Baked Goods        Baking Goods           Beverages 
##                 356                 425                1072                 680 
##     Breakfast Foods        Canned Foods     Canned Products            Carousel 
##                 188                 977                 109                  59 
##            Checkout               Dairy                Deli                Eggs 
##                  82                 903                 699                 198 
##        Frozen Foods  Health and Hygiene           Household                Meat 
##                1382                 893                1420                  89 
##         Periodicals             Produce             Seafood         Snack Foods 
##                 202                1994                 102                1600 
##              Snacks       Starchy Foods 
##                 352                 277
## Tỷ lệ phần trăm các quan sát của biến ProductDepartmentu:
## 
## Alcoholic Beverages         Baked Goods        Baking Goods           Beverages 
##                2.53                3.02                7.63                4.84 
##     Breakfast Foods        Canned Foods     Canned Products            Carousel 
##                1.34                6.95                0.78                0.42 
##            Checkout               Dairy                Deli                Eggs 
##                0.58                6.42                4.97                1.41 
##        Frozen Foods  Health and Hygiene           Household                Meat 
##                9.83                6.35               10.10                0.63 
##         Periodicals             Produce             Seafood         Snack Foods 
##                1.44               14.18                0.73               11.38 
##              Snacks       Starchy Foods 
##                2.50                1.97
library(RColorBrewer)

departments <- names(freq_tableProductDepartment)
n <- length(freq_tableProductDepartment)

# Lấy bảng màu "Set3" (có tối đa 12 màu pastel khác biệt, thay đổi nếu nhiều hơn 12)
if (n <= 12) {
  colors <- brewer.pal(n, "Set3")
} else {
  # Nếu nhiều hơn 12, tạo màu ngẫu nhiên rõ ràng
  set.seed(123)
  colors <- grDevices::rainbow(n)
}

bp <- barplot(freq_tableProductDepartment,
              col = colors,
              main = "Biểu đồ cột Tần suất quan sát theo phòng ban sản phẩm",
              ylab = "Tần suất",
              xlab = "",
              names.arg = rep("", n),
              ylim = c(0, max(freq_tableProductDepartment)*1.3),
              las = 2)

text(x = bp,
     y = par("usr")[3] - 0.05 * max(freq_tableProductDepartment),
     labels = departments,
     srt = 45,
     adj = 1,
     xpd = TRUE,
     cex = 0.8)

legend("topright",
       legend = departments,
       fill = colors,
       border = "black",
       title = "ProductDepartment",
       cex = 0.5,
       bty = "n",
       inset = c(0, -0.01))


Nhận xét Biểu đồ cho thấy sự phân bố không đồng đều về tần suất các quan sát giữa các phòng ban sản phẩm. Trong đó, Produce (Rau quả) có số lượng quan sát cao nhất với 1.994 lần, tiếp theo là Snack Foods (Đồ ăn vặt) với 1.600 quan sát và Household (Đồ gia dụng) với 1.420 quan sát. Các nhóm như Frozen Foods và Baking Goods cũng có số lượng khá cao, lần lượt là 1.382 và 1.072.Ngược lại, một số phòng ban có tần suất thấp hơn đáng kể, tiêu biểu như Carousel chỉ có 59 quan sát, Meat (Thịt) với 89, và Checkout với 82. Những sự chênh lệch này cho thấy mức độ phổ biến và trọng tâm dữ liệu khác nhau giữa các loại sản phẩm, phản ánh xu hướng tiêu dùng hoặc cơ cấu hàng hóa trong hệ thống dữ liệu.Nhìn chung, dữ liệu tập trung nhiều vào các sản phẩm thiết yếu hoặc thường tiêu thụ như rau quả, đồ ăn vặt, và đồ gia dụng, trong khi các nhóm sản phẩm đặc thù hoặc ít phổ biến lại có số lượng quan sát thấp hơn.

2.9 Phân tích theo danh mục sản phẩm (ProductCategory)

# Tạo bảng tần suất cho biến ProductCategory
freq_tableProductCategory <- table(qual_data$ProductCategory)

# Tính tỷ lệ phần trăm
percent_tableProductCategory <- prop.table(freq_tableProductCategory) * 100
## Tần suất các quan sát của biến City :
## 
##         Baking Goods    Bathroom Products        Beer and Wine 
##                  484                  365                  356 
##                Bread      Breakfast Foods              Candles 
##                  425                  417                   45 
##                Candy     Canned Anchovies         Canned Clams 
##                  352                   44                   53 
##       Canned Oysters      Canned Sardines        Canned Shrimp 
##                   35                   40                   38 
##          Canned Soup          Canned Tuna Carbonated Beverages 
##                  404                   87                  154 
##    Cleaning Supplies        Cold Remedies                Dairy 
##                  189                   93                  903 
##        Decongestants               Drinks                 Eggs 
##                   85                  135                  198 
##           Electrical      Frozen Desserts       Frozen Entrees 
##                  355                  323                  118 
##                Fruit             Hardware        Hot Beverages 
##                  765                  129                  226 
##              Hygiene     Jams and Jellies     Kitchen Products 
##                  197                  588                  217 
##            Magazines                 Meat        Miscellaneous 
##                  202                  761                   42 
##  Packaged Vegetables       Pain Relievers       Paper Products 
##                   48                  192                  345 
##                Pizza     Plastic Products Pure Juice Beverages 
##                  194                  141                  165 
##              Seafood          Side Dishes          Snack Foods 
##                  102                  153                 1600 
##            Specialty        Starchy Foods           Vegetables 
##                  289                  277                 1728
## Tỷ lệ phần trăm các quan sát của biến ProductDepartmentu:
## 
##         Baking Goods    Bathroom Products        Beer and Wine 
##                 3.44                 2.60                 2.53 
##                Bread      Breakfast Foods              Candles 
##                 3.02                 2.97                 0.32 
##                Candy     Canned Anchovies         Canned Clams 
##                 2.50                 0.31                 0.38 
##       Canned Oysters      Canned Sardines        Canned Shrimp 
##                 0.25                 0.28                 0.27 
##          Canned Soup          Canned Tuna Carbonated Beverages 
##                 2.87                 0.62                 1.10 
##    Cleaning Supplies        Cold Remedies                Dairy 
##                 1.34                 0.66                 6.42 
##        Decongestants               Drinks                 Eggs 
##                 0.60                 0.96                 1.41 
##           Electrical      Frozen Desserts       Frozen Entrees 
##                 2.53                 2.30                 0.84 
##                Fruit             Hardware        Hot Beverages 
##                 5.44                 0.92                 1.61 
##              Hygiene     Jams and Jellies     Kitchen Products 
##                 1.40                 4.18                 1.54 
##            Magazines                 Meat        Miscellaneous 
##                 1.44                 5.41                 0.30 
##  Packaged Vegetables       Pain Relievers       Paper Products 
##                 0.34                 1.37                 2.45 
##                Pizza     Plastic Products Pure Juice Beverages 
##                 1.38                 1.00                 1.17 
##              Seafood          Side Dishes          Snack Foods 
##                 0.73                 1.09                11.38 
##            Specialty        Starchy Foods           Vegetables 
##                 2.06                 1.97                12.29
# Sắp xếp tần suất giảm dần
sorted_freq <- sort(freq_tableProductCategory, decreasing = TRUE)

# Màu sắc đẹp
library(RColorBrewer)
n <- length(sorted_freq)
colors <- colorRampPalette(brewer.pal(9, "Set3"))(n)

# Vẽ biểu đồ thanh ngang
par(mar = c(5, 10, 4, 2))  # Điều chỉnh lề
bar_heights <- barplot(sorted_freq,
                       horiz = TRUE,
                       las = 1,
                       col = colors,
                       main = "Tần suất các loại ProductCategory",
                       xlab = "Tần suất",
                       cex.names = 0.7)

# Chia thành 2 nhóm cho chú thích
half_n <- ceiling(n / 2)
legend_labels1 <- names(sorted_freq)[1:half_n]
legend_labels2 <- names(sorted_freq)[(half_n + 1):n]
legend_colors1 <- colors[1:half_n]
legend_colors2 <- colors[(half_n + 1):n]

# Thêm chú thích gần nhau (vị trí tương đối)
legend(x = "topright",
       inset = c(-0.25, 0),  # đẩy sang trái
       legend = legend_labels1,
       fill = legend_colors1,
       cex = 0.6,
       bty = "n")

legend(x = "topright",
       inset = c(-0.05, 0),  # đẩy sát bên phải
       legend = legend_labels2,
       fill = legend_colors2,
       cex = 0.6,
       bty = "n")

Nhận xét Biến ProductCategory thể hiện sự đa dạng của các nhóm hàng hóa được phân loại theo đặc điểm tiêu dùng. Dữ liệu cho thấy nhóm có tần suất cao nhất là Vegetables với 1.728 lượt quan sát, tiếp theo là Snack Foods (1.600) và Fruit (765), cho thấy đây là những loại sản phẩm được tiêu thụ phổ biến nhất. Ngược lại, các nhóm như Candles (45), Miscellaneous (42), và Canned Oysters (35) có tần suất thấp, phản ánh mức độ tiêu dùng không thường xuyên hoặc ít phổ biến hơn. Các sản phẩm như Dairy (903), Jams and Jellies (588), và Baking Goods (484) cũng nằm trong nhóm có tần suất tương đối cao, cho thấy vai trò quan trọng trong tiêu dùng hàng ngày. Nhìn chung, dữ liệu phản ánh sự ưu tiên của người tiêu dùng đối với các nhóm thực phẩm tươi sống, thực phẩm ăn nhanh và một số mặt hàng thiết yếu trong sinh hoạt.

Phần 3: Ước lượng Khoảng và Kiểm định Giả thuyết cho Tỷ lệ (Một biến)

3.1. Biến Gender

a. Xác định Hạng mục Quan tâm:

Biến định tính: Gender

Hạng mục quan tâm: “F” (Nữ)

Sử dụng prop.test() để ước lượng khoảng tin cậy 95% cho tỷ lệ nữ trong tổng thể:

gender_table <- table(data$Gender)
n_gender <- sum(gender_table)
x_gender <- gender_table["F"]

# Ước lượng tỷ lệ và khoảng tin cậy 95%
prop.test(x_gender, n_gender, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_gender out of n_gender, 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

H0: tỷ lệ nữ trong tổng thể = 0.5

H1: tỷ lệ nữ ≠ 0.5

prop.test(x_gender, n_gender, p = 0.5, alternative = "two.sided")
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_gender out of n_gender, 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 luận:

Nếu p-value < 0.05: Bác bỏ H0, tức tỷ lệ nữ khác 0.5

Nếu p-value ≥ 0.05: Không đủ bằng chứng bác bỏ H0

p-value = 0.0182 < 0.05 (mức ý nghĩa 5%)

Vậy ta bác bỏ H0, cho thấy tỷ lệ nữ trong tổng thể khác 50% (cụ thể là cao hơn một chút theo kết quả mẫu).

3.2. Biến Homeowner

Biến Homeowner là biến định tính, thể hiện trạng thái có sở hữu nhà (Y) hoặc không (N).

Hạng mục quan tâm: “Y” (Có sở hữu nhà)

Sử dụng prop.test() để ước lượng khoảng tin cậy 95% cho tỷ lệ người sở hữu nhà trong tổng thể:

home_table <- table(data$Homeowner)
n_home <- sum(home_table)
x_home <- home_table["Y"]

# Ước lượng tỷ lệ và khoảng tin cậy 95%
prop.test(x_home, n_home, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_home out of n_home, 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

Khoảng tin cậy 95% là một khoảng giá trị, dựa trên mẫu, cho biết ta có thể tự tin 95% rằng tỷ lệ người sở hữu nhà thực tế trong tổng thể nằm trong khoảng này.

c. Kiểm định Giả thuyết:

H0: tỷ lệ người sở hữu nhà trong tổng thể = 0.6 H1: tỷ lệ người sở hữu nhà ≠ 0.6

prop.test(x_home, n_home, p = 0.6, alternative = "two.sided")
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_home out of n_home, 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 luận:

Nếu p-value < 0.05: Bác bỏ H0, tức tỷ lệ người sở hữu nhà khác 0.6 Nếu p-value ≥ 0.05: Không đủ bằng chứng bác bỏ H0

p-value = 0.8891 Không đủ bằng chứng bác bỏ H0.Tỷ lệ người sở hữu nhà trong mẫu là khoảng 60.06%.

Khoảng tin cậy 95% cho tỷ lệ này là từ 59.25% đến 60.87%, nghĩa là ta khá chắc chắn tỷ lệ thật trong tổng thể nằm trong khoảng này.

Khi kiểm định giả thuyết tỷ lệ người sở hữu nhà bằng 50%, ta bác bỏ giả thuyết này (p-value rất nhỏ), nghĩa là tỷ lệ người sở hữu nhà thực sự khác xa 50% — nhiều hơn.

Khi kiểm định giả thuyết tỷ lệ người sở hữu nhà bằng 60%, ta không bác bỏ giả thuyết này (p-value lớn), nghĩa là 60% là một tỷ lệ hợp lý và phù hợp với dữ liệu.

3.3. Biến ProductFamily

Sử dụng prop.test() để ước lượng khoảng tin cậy 95% cho tỷ lệ sản phẩm thuộc nhóm “Food” trong tổng thể:

product_table <- table(data$ProductFamily)
n_product <- sum(product_table)
x_food <- product_table["Food"]

# Ước lượng tỷ lệ và khoảng tin cậy 95%
prop.test(x_food, n_product, conf.level = 0.95)
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_food out of n_product, 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

H0: tỷ lệ sản phẩm “Food” trong tổng thể = 0.7 H1: tỷ lệ sản phẩm “Food” > 0.7

prop.test(x_food, n_product, p = 0.7, alternative = "greater")
## 
##  1-sample proportions test with continuity correction
## 
## data:  x_food out of n_product, null probability 0.7
## X-squared = 32.802, df = 1, p-value = 5.101e-09
## alternative hypothesis: true p is greater than 0.7
## 95 percent confidence interval:
##  0.7158789 1.0000000
## sample estimates:
##         p 
## 0.7221709

Kết luận:

Nếu p-value < 0.05: Bác bỏ H0, tức tỷ lệ sản phẩm “Food” lớn hơn 0.7 Nếu p-value ≥ 0.05: Không đủ bằng chứng bác bỏ

Vì p-value=5.101e-09 nhỏ hơn mức ý nghĩa 0.05, ta có đủ bằng chứng để bác bỏ giả thuyết H0.

Với mức ý nghĩa 5%, ta bác bỏ giả thuyết rằng tỷ lệ sản phẩm “Food” trong tổng thể bằng 70%. Kết quả cho thấy tỷ lệ sản phẩm “Food” lớn hơn 70% trong tổng thể.

Phần 4: Phân tích Mối quan hệ giữa Hai biến Định tính (Bivariate Analysis)

Cặp 1: Gender vs ProductFamily

# Tạo bảng tần số
table_gender_pf <- table(data$Gender, data$ProductFamily)

# Tính tỷ lệ phần trăm 
prop_gender_pf <- prop.table(table_gender_pf, 1) * 100
prop_gender_pf <- round(prop_gender_pf, 2)
## [1] "Bảng tần số:"
##    
##     Drink Food Non-Consumable
##   F   669 5149           1352
##   M   581 5004           1304
## [1] "Tỷ lệ phần trăm(%):"
##    
##     Drink  Food Non-Consumable
##   F  9.33 71.81          18.86
##   M  8.43 72.64          18.93
# Vẽ biểu đồ cột chồng có thêm số liệu trên cột
library(ggplot2)

# Chuyển bảng sang dạng data frame để vẽ
df_plot <- as.data.frame(table_gender_pf)
colnames(df_plot) <- c("Gender", "ProductFamily", "Frequency")

ggplot(df_plot, aes(x = Gender, y = Frequency, fill = ProductFamily)) +
  geom_bar(stat = "identity", position = "stack") +
  geom_text(aes(label = Frequency), 
            position = position_stack(vjust = 0.5), 
            size = 3, color = "black") +
  labs(title = "Biểu đồ cột chồng: Gender vs ProductFamily",
       x = "Gender", y = "Tần suất") +
  theme_minimal()

# Thực hiện kiểm định Chi-bình phương
chisq_test <- chisq.test(table_gender_pf)

# In kết quả kiểm định
cat("Kết quả kiểm định Chi-bình phương:\n")
## Kết quả kiểm định Chi-bình phương:
cat("Chi-squared =", chisq_test$statistic, "\n")
## Chi-squared = 3.51849
cat("df =", chisq_test$parameter, "\n")
## df = 2
cat("p-value =", chisq_test$p.value, "\n")
## p-value = 0.1721748
# Kết luận
if (chisq_test$p.value < 0.05) {
  cat("=> Có mối quan hệ ý nghĩa thống kê giữa Gender và ProductFamily.\n")
} else {
  cat("=> Không có mối quan hệ ý nghĩa thống kê giữa Gender và ProductFamily.\n")
}
## => Không có mối quan hệ ý nghĩa thống kê giữa Gender và ProductFamily.

Cặp 2: MaritalStatus vs Homeowner

# Tạo bảng tần số
table_ms_home <- table(data$MaritalStatus, data$Homeowner)

# Tính tỷ lệ phần trăm
prop_ms_home <- prop.table(table_ms_home, 1) * 100
prop_ms_home <- round(prop_ms_home, 2)
## [1] "Bảng tần số: MaritalStatus vs Homeowner"
##    
##        N    Y
##   M 1719 5147
##   S 3896 3297
## [1] "Tỷ lệ phần trăm(%):"
##    
##         N     Y
##   M 25.04 74.96
##   S 54.16 45.84
# Vẽ biểu đồ cột chồng có nhãn
library(ggplot2)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
# Dữ liệu chuẩn bị để vẽ
df_plot2 <- as.data.frame(table_ms_home)
colnames(df_plot2) <- c("MaritalStatus", "Homeowner", "Frequency")

# Tính vị trí nhãn
df_plot2 <- df_plot2 %>%
  group_by(MaritalStatus) %>%
  mutate(pos = cumsum(Frequency) - Frequency / 2)

ggplot(df_plot2, aes(x = MaritalStatus, y = Frequency, fill = Homeowner)) +
  geom_bar(stat = "identity", position = "stack") +
  geom_text(aes(label = Frequency, y = pos), size = 3, color = "black") +
  labs(title = "Biểu đồ cột chồng: MaritalStatus vs Homeowner",
       x = "Marital Status", y = "Tần suất") +
  theme_minimal()

# Kiểm định Chi-bình phương
chisq_test2 <- chisq.test(table_ms_home)

# In kết quả
cat("Kết quả kiểm định Chi-bình phương (MaritalStatus vs Homeowner):\n")
## Kết quả kiểm định Chi-bình phương (MaritalStatus vs Homeowner):
cat("Chi-squared =", chisq_test2$statistic, "\n")
## Chi-squared = 1241.218
cat("df =", chisq_test2$parameter, "\n")
## df = 1
cat("p-value =", chisq_test2$p.value, "\n")
## p-value = 6.724506e-272
if (chisq_test2$p.value < 0.05) {
  cat("=> Có mối quan hệ ý nghĩa thống kê giữa MaritalStatus và Homeowner.\n")
} else {
  cat("=> Không có mối quan hệ ý nghĩa thống kê giữa MaritalStatus và Homeowner.\n")
}
## => Có mối quan hệ ý nghĩa thống kê giữa MaritalStatus và Homeowner.

Cặp 3: AnnualIncome vs Gender

# Tạo bảng tần số
table_income_gender <- table(data$AnnualIncome, data$Gender)

# Tính tỷ lệ phần trăm 
prop_income_gender <- prop.table(table_income_gender, 1) * 100
prop_income_gender <- round(prop_income_gender, 2)
print("Bảng tần suất chéo: AnnualIncome vs Gender")
## [1] "Bảng tần suất chéo: AnnualIncome vs Gender"
print(table_income_gender)
##                
##                    F    M
##   $10K - $30K   1587 1503
##   $110K - $130K  307  336
##   $130K - $150K  390  370
##   $150K +        140  133
##   $30K - $50K   2243 2358
##   $50K - $70K   1224 1146
##   $70K - $90K    959  750
##   $90K - $110K   320  293
print("Tỷ lệ phần trăm theo hàng (%):")
## [1] "Tỷ lệ phần trăm theo hàng (%):"
print(prop_income_gender)
##                
##                     F     M
##   $10K - $30K   51.36 48.64
##   $110K - $130K 47.74 52.26
##   $130K - $150K 51.32 48.68
##   $150K +       51.28 48.72
##   $30K - $50K   48.75 51.25
##   $50K - $70K   51.65 48.35
##   $70K - $90K   56.11 43.89
##   $90K - $110K  52.20 47.80
library(dplyr)
library(ggplot2)

# Chuẩn bị dữ liệu
df_plot_income_gender <- as.data.frame(table_income_gender)
colnames(df_plot_income_gender) <- c("AnnualIncome", "Gender", "Frequency")

df_plot_income_gender <- df_plot_income_gender %>%
  group_by(AnnualIncome) %>%
  mutate(pos = cumsum(Frequency) - Frequency / 2)

# Vẽ biểu đồ
ggplot(df_plot_income_gender, aes(x = AnnualIncome, y = Frequency, fill = Gender)) +
  geom_bar(stat = "identity", position = "stack") +
  geom_text(aes(label = Frequency, y = pos), size = 3, color = "black") +
  labs(title = "Biểu đồ cột chồng: AnnualIncome vs Gender",
       x = "Annual Income", y = "Tần suất") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

chisq_test_income_gender <- chisq.test(table_income_gender)

cat("Kết quả kiểm định Chi-bình phương (AnnualIncome vs Gender):\n")
## Kết quả kiểm định Chi-bình phương (AnnualIncome vs Gender):
cat("Chi-squared =", chisq_test_income_gender$statistic, "\n")
## Chi-squared = 30.88325
cat("df =", chisq_test_income_gender$parameter, "\n")
## df = 7
cat("p-value =", chisq_test_income_gender$p.value, "\n")
## p-value = 6.533308e-05
if (chisq_test_income_gender$p.value < 0.05) {
  cat("=> Có mối quan hệ ý nghĩa thống kê giữa AnnualIncome và Gender.\n")
} else {
  cat("=> Không có mối quan hệ ý nghĩa thống kê giữa AnnualIncome và Gender.\n")
}
## => Có mối quan hệ ý nghĩa thống kê giữa AnnualIncome và Gender.