Lần đầu mình mở SPSS chạy descriptive cho một paper, mỗi bảng output phải copy thủ công vào Word. Mỗi figure phải save dạng emf rồi paste, lệch font, sửa lại nhãn. Một paper retrospective tốn 2 ngày chỉ để làm tables và figures.
Sau khi chuyển sang R, cùng pipeline đó còn ~3 giờ. Không phải vì R "nhanh hơn" theo nghĩa tính toán. Mà vì 5 thao tác descriptive bác sĩ làm hằng ngày trong SPSS có thể gen ra table và figure publication-ready bằng một đoạn code, chạy lại trong 3 giây mỗi khi data update.
Bài này map 5 thao tác phổ biến nhất từ SPSS sang R. Code copy-paste được. Bạn chỉ sửa tên cột thành tên cột data của bạn.
1. Bảng 1 (descriptive theo nhóm)
SPSS workflow: Analyze → Descriptive → Frequencies / Descriptives, chạy từng cột, copy output vào Word, sửa định dạng. Hoặc Crosstabs nếu chia theo nhóm. 30-45 phút cho 1 Bảng 1 đầy đủ.
R workflow:
library(gtsummary)
data %>%
tbl_summary(by = outcome,
statistic = list(all_continuous() ~ "{median} ({p25}, {p75})",
all_categorical() ~ "{n} ({p}%)")) %>%
add_p()
Output: Bảng 1 chia theo outcome có/không, mỗi biến tự chọn median + IQR (cho continuous) hoặc n (%) (cho categorical), thêm cột p-value cuối. Format Q1-ready.
Tôi dùng đúng đoạn này cho Bảng 1 trong một paper retrospective. Reviewer không hỏi gì về format Bảng 1.
2. So sánh 2 nhóm (t-test hoặc Mann-Whitney)
SPSS workflow: Analyze → Compare Means → Independent t-test, hoặc Nonparametric Tests → Legacy Dialogs → 2 Independent Samples cho Mann-Whitney. Chọn biến, click qua dialog, copy output.
R workflow:
t.test(age ~ outcome, data = data)
wilcox.test(age ~ outcome, data = data)
Một dòng cho t-test, một dòng cho Mann-Whitney. Output có mean, CI, p-value. Đủ để viết "age was lower in group A vs B (median 4.0 vs 6.5, p = 0.012)".
Lưu ý: trước khi chạy t-test, check phân bố. R có sẵn:
shapiro.test(data$age[data$outcome == "yes"])
shapiro.test(data$age[data$outcome == "no"])
Nếu cả hai p > 0.05, dùng t-test. Nếu không, dùng Wilcoxon. Hai dòng quyết định.
3. So sánh nhiều nhóm (ANOVA hoặc Kruskal-Wallis)
SPSS workflow: Analyze → Compare Means → One-Way ANOVA, hoặc Nonparametric Tests → K Independent Samples cho Kruskal-Wallis.
R workflow:
aov_result <- aov(age ~ stage, data = data)
summary(aov_result)
TukeyHSD(aov_result)
Hoặc nếu non-parametric:
kruskal.test(age ~ stage, data = data)
ANOVA Tukey post-hoc một dòng TukeyHSD() ra luôn p-value cho từng cặp nhóm. SPSS bắt bạn tick "Post Hoc" trong dialog rồi chọn Tukey/Bonferroni qua dropdown. R gọn hơn 1 click.
4. Logistic regression
SPSS workflow: Analyze → Regression → Binary Logistic, chọn dependent + covariates, tick "CI for exp(B)", chạy. Output có odds ratio, CI, p-value nhưng phải scroll qua nhiều bảng.
R workflow:
model <- glm(outcome ~ age + sex + stage + comorbidity,
data = data, family = binomial)
summary(model)
Để gen bảng OR + CI + p publication-ready trong 1 lệnh:
library(gtsummary)
tbl_regression(model, exponentiate = TRUE)
Output: Bảng OR (95% CI) + p-value cho từng biến. Format đẹp, paste thẳng vào Word hoặc export PNG.
Tôi dùng combo glm cộng tbl_regression cho bảng regression trong một paper. Khi reviewer yêu cầu add một covariate (ví dụ BMI), mình chỉnh một ký tự trong code, chạy lại, table mới sẵn sàng. Nếu là SPSS, phải click toàn bộ dialog lại từ đầu.
5. Plot publication-ready
SPSS workflow: Graphs → Chart Builder, kéo thả, sửa axis, sửa color, export. Mỗi figure 15-30 phút.
R workflow (ggplot):
Boxplot age theo nhóm:
library(ggplot2)
ggplot(data, aes(x = outcome, y = age, fill = outcome)) +
geom_boxplot() +
labs(x = "Outcome", y = "Age (years)") +
theme_classic()
Kaplan-Meier survival:
library(survival)
library(survminer)
fit <- survfit(Surv(time, event) ~ stage, data = data)
ggsurvplot(fit, pval = TRUE, risk.table = TRUE)
Forest plot cho meta-analysis:
library(metafor)
forest(rma_result)
Tất cả publication-ready ở mức 300 dpi. Một meta-analysis có thể gen forest plot bằng vài dòng metafor — figure đạt chuẩn Q1, gần như không cần chỉnh tay.
Workflow tiết kiệm thực
Đo theo một paper đoàn hệ hồi cứu cỡ trung bình:
| Task | SPSS | R |
|---|---|---|
| Bảng 1 chia nhóm | 45 phút | 5 phút |
| 4 t-test + 4 chi-square | 20 phút | 2 phút |
| Logistic regression Table 3 | 30 phút | 5 phút |
| 6 figures | 90 phút | 30 phút |
| Tổng | 3 giờ 5 phút | 42 phút |
Tiết kiệm rõ nhất ở re-run. Mỗi lần bộ dữ liệu được bổ sung thêm ca mới, SPSS phải click lại từ đầu. R chạy lại một lệnh source("analysis.R"), table và figure update ngay.
Khi nào đoạn này không có ý nghĩa
Nếu bạn viết 1 paper retrospective một năm, không update data sau IRB lock, không cần figure custom, đừng tốn 30-40 giờ học R. Tôi đã viết kỹ trong bài so sánh khi nào SPSS đủ và khi nào nên đổi sang R. Đọc trước.
Nếu bạn đang chạy cohort prospective với data update hằng tháng, hoặc bắt đầu viết SR/MA, 5 thao tác trên tiết kiệm hàng chục giờ mỗi paper. Đó là lúc đầu tư R có ROI rõ ràng.
Học 5 thao tác này có hệ thống: khoá R-stats trên tuyentranmd.com thiết kế 8 tuần đi từ load data đến gen Bảng 1 cộng forest plot publication-ready. Mỗi bài kèm data lâm sàng VN, code template paste-được, không phải example tutorial generic.