Mình học R mà cứ nghĩ phải biết hết tidyverse mới làm được gì. Sai hoàn toàn. Phần lớn phân tích lâm sàng của mình từ trước đến nay chỉ dùng đúng 5 hàm từ gói dplyr: filter, select, mutate, group_by và summarize. Thêm arrange khi cần sắp xếp để kiểm tra. Đó là toàn bộ tidyverse bác sĩ cần trong 80% công việc thường ngày.
Bài này giả định bạn đã cài R và RStudio, và đã biết import dữ liệu. Nếu chưa, đọc quy trình R cho bài báo lâm sàng trước để nắm bức tranh tổng thể từ CSV đến bảng xuất báo.
filter: giữ lại hàng mình cần
filter() lọc hàng theo điều kiện, giống bộ lọc trong Excel nhưng tái lập được và không sửa file gốc.
library(dplyr)
# Lấy nhóm bệnh nhân dị tật hậu môn mức cao và trung gian
df_cao_tg <- df %>% filter(loai %in% c("cao", "trung_gian"))
# Lọc trẻ sơ sinh dưới 30 ngày tuổi
df_so_sinh <- df %>% filter(tuoi_ngay < 30)
# Kết hợp nhiều điều kiện
df_sub <- df %>% filter(loai == "cao", gioi == "nam", tuoi_ngay < 30)
Trong thực hành của mình, mỗi lần phân tích subgroup đều bắt đầu bằng một dòng filter. Không tạo bảng riêng, không copy sheet Excel mới, chỉ nối pipe.
select: rút cột cần làm việc
Dataset bệnh viện thường có 50 đến 100 cột. select() giữ lại những cột cần thiết, tránh nhầm cột khi viết code tiếp theo và làm nhẹ bảng khi xem qua.
df_phan_tich <- df %>%
select(id, tuoi_ngay, gioi, loai, bien_chung, thoi_gian_theo_doi)
Nếu muốn bỏ cột thay vì chọn, thêm dấu trừ:
df_sach <- df %>% select(-ghi_chu_thu_ky, -duong_dan_anh, -ma_noi_bo)
Mình dùng cách này trước khi chia sẻ dữ liệu với cộng sự, bỏ các cột nội bộ không liên quan đến phân tích.
mutate: tạo biến mới không cần script dài
mutate() thêm cột mới vào bảng hiện có mà không xóa cột cũ. Mình gộp tất cả bước tính toán vào một đoạn mutate thay vì gán từng dòng riêng.
df <- df %>%
mutate(
tuoi_thang = tuoi_ngay / 30.4,
nhom_tuoi = case_when(
tuoi_ngay < 30 ~ "So sinh",
tuoi_ngay < 365 ~ "Duoi 1 tuoi",
TRUE ~ "Tren 1 tuoi"
),
nhan_ket_qua = ifelse(bien_chung == 1, "Co bien chung", "Khong bien chung")
)
Ba việc trong một lần: chuyển đơn vị ngày sang tháng, tạo nhóm tuổi cho bảng so sánh, và tạo nhãn tiếng Việt cho biểu đồ. Nếu dữ liệu thay đổi, chạy lại một lần là xong.
group_by và summarize: thống kê theo nhóm tức thì
Đây là cặp mình dùng nhiều nhất ngay sau khi import dữ liệu. group_by() chia nhóm, summarize() tính chỉ số cho từng nhóm, kết quả ra bảng ngay lập tức.
df %>%
group_by(loai) %>%
summarize(
n = n(),
tuoi_trung_binh = mean(tuoi_ngay, na.rm = TRUE),
ti_le_bien_chung = mean(bien_chung, na.rm = TRUE),
theo_doi_trung_vi = median(thoi_gian_theo_doi, na.rm = TRUE)
)
Kết quả ra bảng so sánh tất cả nhóm trong vài giây. Đây là bước kiểm tra đầu tiên của mình sau khi load dữ liệu, trước cả khi chạy bất kỳ phép kiểm thống kê nào để xem phân phối và phát hiện vấn đề sớm.
Lưu ý nhỏ: sau group_by, nhớ thêm ungroup() nếu tiếp tục xử lý theo hàng thay vì theo nhóm. Quên bước này gây lỗi âm thầm khó tìm.
arrange: sắp xếp để phát hiện vấn đề sớm
arrange() sắp xếp hàng theo cột. Mình dùng sau mỗi bước mutate để xem kết quả tính toán có ổn không trước khi đi tiếp, và để phát hiện giá trị bất thường.
# Xem 10 bệnh nhân có thời gian theo dõi lâu nhất
df %>% arrange(desc(thoi_gian_theo_doi)) %>% head(10)
# Kiểm tra sau khi tính tuổi tháng
df %>% arrange(tuoi_thang) %>% head(20)
Đây là hàm tưởng đơn giản nhất nhưng giúp phát hiện nhiều lỗi nhập liệu nhất trong thực hành của mình.
Gộp 5 hàm thành một đoạn phân tích
Cả 5 hàm kết nối qua pipe. Ví dụ từ một phân tích subgroup thực tế:
ket_qua <- df %>%
filter(loai == "cao") %>%
select(id, tuoi_ngay, gioi, bien_chung, thoi_gian_theo_doi) %>%
mutate(tuoi_thang = round(tuoi_ngay / 30.4, 1)) %>%
group_by(gioi) %>%
summarize(
n = n(),
tuoi_tb = mean(tuoi_thang, na.rm = TRUE),
ti_le_bc = mean(bien_chung, na.rm = TRUE),
theo_doi_tb = mean(thoi_gian_theo_doi, na.rm = TRUE)
) %>%
arrange(desc(ti_le_bc))
Từ lọc nhóm đến bảng so sánh theo giới trong 13 dòng. Kết quả mình paste thẳng vào bảng paper.
Khi cần bảng mô tả mẫu có giá trị p và định dạng chuẩn journal, bước tiếp theo là dùng gtsummary trên dữ liệu đã lọc và làm sạch ở trên. Xem thêm ở bài lộ trình tự học R cho bác sĩ để thấy cả 5 hàm này nằm ở đâu trong quy trình đầy đủ.
Nếu bạn muốn học R có hệ thống, từ làm sạch dữ liệu đến regression và visualization cho paper lâm sàng, khóa R cho nghiên cứu y khoa đi theo đúng thứ tự này.