Bài Tập Buổi 02 — Khái niệm & Thống kê Mô tả Dữ liệu Định tính

Author

[Họ và tên] — [MSSV]

Published

May 19, 2026

BÀI TẬP BUỔI 02 — KHÁI NIỆM & THỐNG KÊ MÔ TẢ DỮ LIỆU ĐỊNH TÍNH

Yêu cầu chung

Bài tập yêu cầu sinh viên vận dụng R để phân loại, mã hóa và mô tả dữ liệu định tính trên một bộ dữ liệu thực tế trong lĩnh vực kinh tế–tài chính. Bối cảnh: một ngân hàng thương mại cần tổng hợp báo cáo về đặc điểm khách hàng vay vốn phục vụ quản trị rủi ro tín dụng.

Sinh viên sử dụng dataset sẵn có trong R (ví dụ: MASS::survey, datasets::UCBAdmissions) hoặc tải từ Kaggle, yêu cầu có ít nhất 3 biến định tính200+ quan sát.

⚠️ Quy định đường dẫn: Mọi lệnh đọc dữ liệu phải dùng đường dẫn tương đối từ vị trí file này. Ví dụ: read.csv("../../Data/filename.csv"). Không được dùng đường dẫn tuyệt đối.


Phần A — Thiết lập Quarto Project (CLO2)

1. Tạo file bài tập tại SinhVien/Exercises/exercise-session-02.qmd. Khai báo YAML header đầy đủ gồm: title, author (họ tên + MSSV), date: today, format: html với toc: true. (CLO2)

2. Thiết lập chunk toàn cục ngay sau YAML: (CLO2)

knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)

3. Nạp thư viện cần thiết trong chunk nhãn setup. Tối thiểu: tidyverse, ggplot2, scales. Nếu thêm thư viện khác, giải thích lý do trong comment. (CLO2)

4. Viết đoạn văn ngắn (không phải comment code) mô tả: tên dataset, nguồn gốc, số quan sát, số biến, lý do chọn dataset này cho phân tích định tính. (CLO5)


Phần B — Nạp & Khám phá Dữ liệu (CLO1, CLO2)

5. Đọc dữ liệu bằng đường dẫn tương đối: (CLO2)

df <- read.csv("../../Data/ten_file.csv")
# hoặc nếu dùng dataset nội bộ R:
# data("survey", package = "MASS")

6. Kiểm tra cấu trúc dữ liệu bằng str(df), head(df, 10), dplyr::glimpse(df) và giải thích sự khác biệt giữa ba hàm này. (CLO2)

7. Lập bảng liệt kê biến theo định dạng sau (viết trong prose): (CLO1)

Tên biến Kiểu trong R Thang đo thực tế Phân loại
Nominal / Ordinal / Định lượng

Bắt buộc có ít nhất 3 biến Nominal hoặc Ordinal.

8. Kiểm tra và xử lý missing values: (CLO2)

colSums(is.na(df))
df_clean <- df |> tidyr::drop_na()

Giải thích (≥ 50 từ): Tại sao phải xử lý missing values trước khi phân tích định tính?

9. Chuyển đổi kiểu biến cho ít nhất 2 biến định tính: (CLO1)

# Biến Nominal
df_clean$ten_bien_nominal <- as.factor(df_clean$ten_bien_nominal)

# Biến Ordinal (bắt buộc dùng ordered = TRUE)
df_clean$ten_bien_ordinal <- factor(
  df_clean$ten_bien_ordinal,
  levels = c("Thấp", "Trung bình", "Cao"),
  ordered = TRUE
)

Giải thích tại sao phải dùng ordered = TRUE cho biến Ordinal.

10. Tóm tắt thống kê summary(df_clean) và nhận xét phân phối của ít nhất 2 biến định tính: nhóm nào chiếm ưu thế, nhóm nào thiểu số. (CLO2)


Phần C — Phân tích Thống kê Chính (CLO1, CLO2, CLO5)

11. Tạo bảng tần số và tỷ lệ phần trăm cho biến định tính quan trọng nhất: (CLO2)

freq_table <- table(df_clean$ten_bien)
prop_table  <- round(prop.table(freq_table) * 100, 2)
print(freq_table); print(prop_table)

Nhận xét: Nhóm nào chiếm tỷ lệ cao nhất? Hàm ý kinh tế là gì?

12. Tính khoảng tin cậy 95% cho tỷ lệ của nhóm chiếm ưu thế: (CLO2)

n <- nrow(df_clean)
x <- freq_table["ten_nhom"]
prop.test(x = x, n = n, conf.level = 0.95)

Diễn giải: Khoảng tin cậy này có ý nghĩa gì với nhà quản lý?

13. Kiểm định giả thuyết: Tỷ lệ nhóm đó có bằng một giá trị tham chiếu lý thuyết không (tự chọn, ví dụ 30%)? (CLO2)

prop.test(x = x, n = n, p = 0.30, alternative = "two.sided")

Phát biểu đầy đủ: H₀, H₁, mức ý nghĩa α, p-value, và kết luận bằng ngôn ngữ kinh tế (không viết đơn giản “Bác bỏ H₀”).

14. Tạo bảng chéo giữa 2 biến định tính và tính tỷ lệ theo hàng: (CLO2)

cross_tab <- table(df_clean$bien_1, df_clean$bien_2)
prop.table(cross_tab, margin = 1)

Nhận xét sự khác biệt phân phối giữa các nhóm.

15. Vẽ Pareto chart tự xây dựng bằng ggplot2: (CLO2, CLO5)

pareto_data <- df_clean |>
  count(ten_bien, name = "tan_so") |>
  arrange(desc(tan_so)) |>
  mutate(
    pct     = tan_so / sum(tan_so) * 100,
    cum_pct = cumsum(pct)
  )

ggplot(pareto_data, aes(x = reorder(ten_bien, -tan_so))) +
  geom_col(aes(y = tan_so), fill = "#2563EB", alpha = 0.85) +
  geom_line(aes(y = cum_pct * max(tan_so) / 100, group = 1),
            color = "#DC2626", linewidth = 1) +
  geom_point(aes(y = cum_pct * max(tan_so) / 100),
             color = "#DC2626", size = 2.5) +
  scale_y_continuous(
    name      = "Tần số",
    sec.axis  = sec_axis(~ . * 100 / max(pareto_data$tan_so),
                         name = "Tỷ lệ tích lũy (%)")
  ) +
  labs(title   = "Biểu đồ Pareto — [Tên biến]",
       x       = "Nhóm",
       caption = "Nguồn: [Tên dataset]") +
  theme_minimal(base_size = 13)

16. Thực hiện Label Encoding và One-hot Encoding cho một biến Nominal: (CLO1)

# Label Encoding
df_clean$bien_label <- as.integer(as.factor(df_clean$ten_bien_nominal))

# One-hot Encoding
ohe_matrix <- model.matrix(~ ten_bien_nominal - 1, data = df_clean)
head(ohe_matrix)

Viết giải thích (≥ 80 từ): Tại sao Label Encoding gây sai lệch trong mô hình khi biến là Nominal?

17. Với biến Học vấn (Cấp 1 < Cấp 2 < Cấp 3 < Đại học), loại encoding nào phù hợp hơn và tại sao? Trình bày lý luận học thuật, không chỉ nêu đúng/sai. (CLO1, CLO5)


Phần D — Trực quan hóa & Báo cáo (CLO2, CLO5)

18. Vẽ Bar chart phân tầng (stacked) thể hiện phân phối một biến định tính theo nhóm của biến thứ hai: (CLO2)

ggplot(df_clean, aes(x = bien_1, fill = bien_2)) +
  geom_bar(position = "fill") +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_brewer(palette = "Set2") +
  labs(title   = "Phân phối [Biến 2] theo nhóm [Biến 1]",
       x       = "[Biến 1]",
       y       = "Tỷ lệ (%)",
       fill    = "[Biến 2]",
       caption = "Nguồn: [Tên dataset]") +
  theme_minimal(base_size = 13) +
  theme(legend.position = "bottom")

19. Vẽ Pie chart cho biến có ≤ 5 nhóm. Nhận xét: khi nào Pie chart phù hợp, khi nào không nên dùng theo nguyên tắc trực quan hóa dữ liệu? (CLO2, CLO5)

pie_data <- df_clean |> count(ten_bien, name = "n")

ggplot(pie_data, aes(x = "", y = n, fill = ten_bien)) +
  geom_col(width = 1, color = "white") +
  coord_polar(theta = "y") +
  scale_fill_brewer(palette = "Pastel1") +
  labs(title = "Cơ cấu [Tên biến]", fill = "[Tên biến]") +
  theme_void(base_size = 13)

20. Viết đoạn diễn giải tổng hợp (≥ 150 từ, văn xuôi học thuật): (CLO5)

  • Đặc điểm phân phối của các biến định tính chính.
  • Nhóm chiếm ưu thế và hàm ý kinh tế–quản trị.
  • Biểu đồ nào thể hiện thông tin rõ nhất và tại sao.
  • Ít nhất 1 khuyến nghị cụ thể cho người ra quyết định.

Phần E — Prompt AI Nâng cao

Prompt 1 — Tình huống thực tế ngành Ngân hàng

"Tôi đang học phân loại dữ liệu định tính và thống kê mô tả bằng R trong môn
Phân tích Dữ liệu Định tính.

Hãy tạo một bài toán thực tế trong lĩnh vực Ngân hàng sử dụng bảng tần số,
biểu đồ Pareto và One-hot encoding. Bài toán gồm:
(1) Mô tả tình huống quản trị rủi ro tín dụng cụ thể.
(2) Dữ liệu giả định dạng bảng (ít nhất 5 biến, có Nominal và Ordinal).
(3) Câu hỏi phân tích cụ thể (phân nhóm khách hàng theo loại hình tín dụng).
(4) Code R đầy đủ để giải quyết từng câu hỏi."

[Sinh viên dán tóm tắt kết quả hội thoại — tối thiểu 100 từ, viết theo ngôn ngữ riêng, không copy nguyên văn AI]


Prompt 2 — Phản biện kỹ thuật & lỗi thường gặp

"Trong R, khi tôi chạy prop.test() để kiểm định tỷ lệ, tôi nhận được cảnh báo:
'Chi-squared approximation may be incorrect'.

Hãy giải thích:
(1) Nguyên nhân cảnh báo này là gì? Điều kiện nào bị vi phạm?
(2) Kết quả bị ảnh hưởng như thế nào về độ tin cậy?
(3) Phương pháp thay thế nào trong R phù hợp hơn khi cỡ mẫu nhỏ?
    (Gợi ý: binom.test() — Kiểm định chính xác)"

[Sinh viên dán tóm tắt kết quả hội thoại — tối thiểu 80 từ]


Phần F — AI-Grader: Tự chấm điểm

Sao chép toàn bộ code R và output chính, sau đó dùng prompt sau:

"Tôi vừa hoàn thành bài tập R về phân loại dữ liệu định tính, bảng tần số,
mã hóa biến và biểu đồ Pareto trong môn Phân tích Dữ liệu Định tính.

Đánh giá bài làm theo 4 tiêu chí (thang điểm 10):

1. Tính đúng đắn thống kê (CLO2): Hàm R dùng đúng phương pháp không?
   Kết quả bảng tần số, prop.test(), One-hot encoding có hợp lý không?

2. Chất lượng diễn giải (CLO5): Kết quả được giải thích bằng ngôn ngữ
   kinh tế–quản trị không, hay chỉ đọc con số?

3. Chuẩn đường dẫn Quarto (CLO2): Có dùng đường dẫn tương đối
   (../../Data/...) đúng chuẩn không?

4. Xử lý lỗi & điều kiện áp dụng (CLO1): Có kiểm tra missing values,
   chuyển đổi kiểu biến đúng cách, giải thích sự khác biệt
   Label Encoding vs One-hot Encoding không?

[Dán toàn bộ code R và output tại đây]"

[Sinh viên dán điểm tự chấm và nhận xét tóm tắt từ AI tại đây]