Làm sạch dữ liệu với R là quá trình dùng lệnh để đưa bộ dữ liệu thô về trạng thái sẵn sàng phân tích: đúng kiểu biến, giá trị thiếu được đánh dấu thống nhất, không còn bản ghi trùng và các biến đã được mã hóa theo một chuẩn. Khác với chỉnh tay trên Excel, mọi thao tác đều nằm trong script nên có thể kiểm tra và chạy lại.
Bài viết đi qua năm bước theo thứ tự nên làm, mỗi bước nêu dấu hiệu cần phát hiện và hàm R tương ứng. Ví dụ minh họa xuyên suốt là một khảo sát giả định về mức hài lòng của sinh viên với thư viện, gồm khoảng hai mươi câu Likert năm mức thu qua Google Forms.
Tóm tắt nhanh: năm bước gồm đọc dữ liệu và chuẩn hóa tên cột, kiểm tra kiểu biến, xử lý giá trị thiếu và trùng lặp, biến đổi biến, rồi đối chiếu kết quả.
Mỗi quyết định loại hay sửa dữ liệu đều cần được ghi vào nhật ký kèm lý do.
Chuẩn bị trước khi làm sạch dữ liệu với R
Trước khi gõ dòng lệnh đầu tiên, bạn cần hai thứ: bản sao dữ liệu gốc được cất riêng và bảng mã hóa biến (codebook). Bảng mã hóa cho biết mỗi cột ứng với câu hỏi nào, thang đo mấy mức, giá trị nào hợp lệ và câu nào cần đảo chiều. Thiếu tài liệu này, bạn sẽ phải đoán ý nghĩa của từng cột khi làm sạch.
Đọc tệp và chuẩn hóa tên cột
Google Forms xuất tên cột là nguyên văn câu hỏi, vừa dài vừa có dấu, rất bất tiện khi viết lệnh. Sau khi đọc bằng readr::read_csv(), bạn có thể dùng janitor::clean_names() để chuyển tên về dạng không dấu, viết thường. Tốt hơn nữa là đổi sang mã ngắn như HL1, HL2 bằng dplyr::rename(), dựa đúng theo bảng mã hóa đã lập.
Bước 1: Kiểm tra kiểu dữ liệu
Hàm glimpse() liệt kê từng cột kèm kiểu dữ liệu và vài giá trị đầu, là điểm xuất phát nhanh nhất. Hãy so từng dòng với bảng mã hóa: biến định lượng phải là kiểu số, biến phân loại nên là factor, ngày tháng phải là kiểu Date. Bất kỳ cột nào lệch kiểu đều cần được xử lý trước khi tính toán.
| Dấu hiệu khi xem glimpse | Nguyên nhân thường gặp | Cách xử lý trong R |
|---|---|---|
| Câu Likert có kiểu chr | Biểu mẫu lưu nhãn chữ như “Rất đồng ý” | Ánh xạ nhãn sang số bằng case_when() |
| Thu nhập có kiểu chr | Dấu chấm phân cách hàng nghìn | Chuyển bằng readr::parse_number() với locale phù hợp |
| Ngày khảo sát là văn bản | Định dạng ngày/tháng/năm kiểu Việt Nam | Chuyển bằng lubridate::dmy() |
| Mã phiếu mất số 0 ở đầu | Cột mã bị đọc thành số | Khai báo kiểu ký tự khi đọc tệp |
| Giới tính có nhiều cách viết | Nhập tự do, không dùng danh sách chọn | Chuẩn hóa chữ rồi chuyển sang factor |
Biến phân loại và thứ tự mức
Với biến như trình độ học vấn, thứ tự các mức có ý nghĩa khi vẽ biểu đồ và khi chọn nhóm tham chiếu trong hồi quy. Hãy dùng factor() với đối số levels liệt kê đúng thứ tự mong muốn, thay vì để R sắp theo bảng chữ cái. Gói forcats hỗ trợ gộp các nhóm quá nhỏ hoặc đổi nhãn hiển thị mà không làm sai giá trị gốc.
Bước 2: Xử lý giá trị thiếu và bản ghi trùng
Trong R, giá trị thiếu được biểu diễn bằng NA, nhưng dữ liệu tải về thường dùng nhiều ký hiệu khác như ô trống, số 99 hay chữ “không trả lời”. Việc đầu tiên là quy tất cả về NA, có thể khai báo ngay khi đọc tệp qua đối số na của read_csv(). Sau đó mới đếm và quyết định cách xử lý.
Đếm và mô tả giá trị thiếu
Kết hợp is.na() với colSums() cho biết số ô thiếu ở mỗi cột, còn rowSums() cho biết mỗi phiếu thiếu bao nhiêu câu. Gói naniar vẽ được bản đồ giá trị thiếu, giúp bạn thấy thiếu tập trung ở một nhóm câu hỏi hay rải rác ngẫu nhiên. Mẫu hình này ảnh hưởng trực tiếp đến lựa chọn xóa phiếu hay giữ lại.
Xóa, giữ hay thay thế?
Không có quy tắc chung áp dụng cho mọi đề tài, nhưng có một số hướng tham khảo:
- Phiếu bỏ trống phần lớn câu hỏi chính: thường loại khỏi phân tích, ghi rõ số phiếu và tiêu chí loại.
- Thiếu rải rác vài ô: có thể giữ phiếu và để các hàm tính toán bỏ qua NA, nêu rõ cách xử lý trong chương phương pháp.
- Thiếu có hệ thống ở một nhóm: cần cân nhắc kỹ, có thể dùng phương pháp quy nạp như gói mice sau khi trao đổi với giảng viên.
- Không bao giờ điền số tùy ý để làm đẹp dữ liệu, vì đó là ngụy tạo.
Phát hiện phiếu trùng
Phiếu trùng xuất hiện khi người trả lời bấm gửi hai lần hoặc khi gộp nhiều đợt thu. Hàm janitor::get_dupes() liệt kê các dòng giống nhau theo những cột bạn chỉ định, ví dụ email và toàn bộ câu trả lời. Sau khi xem xét, dùng distinct() để giữ một bản và ghi số phiếu đã loại vào nhật ký.
Bước 3: Biến đổi dữ liệu
Khi kiểu dữ liệu và giá trị thiếu đã ổn, bước biến đổi tạo ra các biến phục vụ trực tiếp cho câu hỏi nghiên cứu. Hàm mutate() là công cụ chính, kết hợp với across() khi cần áp dụng cùng một thao tác cho nhiều cột. Mọi biến mới nên có tên khác biến gốc để tiện đối chiếu về sau.
Đảo chiều câu hỏi nghịch
Với thang Likert năm mức, câu hỏi diễn đạt theo hướng phủ định được đảo bằng cách lấy 6 trừ giá trị gốc. Hãy xác định danh sách câu nghịch từ bảng mã hóa, không suy đoán sau khi xem kết quả độ tin cậy. Sau khi đảo, tính điểm trung bình thang đo bằng rowMeans() trên các cột cùng khái niệm.
Gộp nhóm và tạo biến phân loại
Biến liên tục như tuổi hay thu nhập đôi khi cần chia thành nhóm để mô tả mẫu. Hàm cut() hoặc case_when() cho phép đặt ngưỡng rõ ràng, nhưng ngưỡng phải có căn cứ lý thuyết hoặc theo cách phân loại chính thức. Chia nhóm chỉ để mô tả; khi phân tích, hãy ưu tiên giữ dạng liên tục để không mất thông tin.
Bước 4: Kiểm tra kết quả làm sạch
Bước cuối của việc làm sạch dữ liệu với R thường bị bỏ qua, nhưng chính nó giúp bạn tự tin khi bị hỏi. Hãy chạy lại summary() để chắc không còn giá trị ngoài miền hợp lệ, ví dụ câu Likert có giá trị 0 hoặc 7. Dùng count() để kiểm tra tần số các nhóm và so tổng số dòng với nhật ký.
Với bộ dữ liệu khảo sát trong ví dụ, các điều kiện nên được kiểm tra bằng lệnh gồm:
- Số dòng sau làm sạch bằng số dòng ban đầu trừ số phiếu đã loại trong nhật ký.
- Mọi câu Likert chỉ nhận giá trị từ 1 đến 5 hoặc NA.
- Mã phiếu là duy nhất, không còn giá trị lặp.
- Câu đã đảo chiều tương quan dương với các câu cùng thang đo.
Cách hiệu quả là viết từng điều kiện bằng stopifnot(): nếu dữ liệu vi phạm, script dừng ngay thay vì lặng lẽ cho ra kết quả sai. Cuối cùng, lưu dữ liệu sạch bằng saveRDS() để giữ nguyên kiểu factor và thứ tự mức, đồng thời xuất thêm bản .csv nếu cần chia sẻ.
Kinh nghiệm từ Luận Văn 360: lỗi khó phát hiện nhất chúng tôi thường gặp là đảo chiều câu nghịch hai lần, một lần trong script làm sạch và một lần trong script phân tích.
Kết quả là độ tin cậy giảm bất thường mà không rõ lý do. Hãy đảo chiều đúng một nơi, đặt tên biến mới có hậu tố riêng và ghi vào nhật ký.
Nếu bạn đã có script làm sạch nhưng chưa chắc các quyết định xử lý dữ liệu hợp lý, dịch vụ tư vấn phân tích dữ liệu bằng R của Luận Văn 360 có thể đọc lại mã và nhật ký. Bạn nhận góp ý để tự điều chỉnh, dữ liệu và kết luận vẫn hoàn toàn do bạn chịu trách nhiệm.
Lỗi thường gặp khi làm sạch dữ liệu
Sửa trực tiếp trên tệp gốc
Mở tệp gốc bằng Excel, xóa vài dòng rồi lưu đè khiến không ai, kể cả bạn, biết dữ liệu ban đầu ra sao. Hãy để tệp gốc ở thư mục chỉ đọc, như gợi ý trong bài tổ chức dự án phân tích dữ liệu bằng R.
Loại ngoại lai chỉ vì kết quả chưa đẹp
Giá trị cực đoan cần được kiểm tra xem có phải lỗi nhập hay không. Nếu là giá trị thật, việc loại bỏ phải dựa trên tiêu chí đặt trước và được báo cáo minh bạch, không phải vì hệ số chưa có ý nghĩa thống kê.
Không ghi nhật ký
Thiếu nhật ký, bạn khó giải thích vì sao cỡ mẫu giảm từ lúc thu đến lúc phân tích. Mỗi bước nên ghi số dòng trước, số dòng sau và lý do.
Kết luận
Làm sạch dữ liệu với R hiệu quả khi đi đúng thứ tự: chuẩn hóa tên cột, kiểm tra kiểu, xử lý giá trị thiếu và trùng, biến đổi biến, rồi tự kiểm tra bằng lệnh. Mọi bước đều nằm trong script và có nhật ký, nên bạn luôn giải trình được với giảng viên hay hội đồng. Cuốn R for Data Science là tài liệu miễn phí tốt để học sâu thêm các hàm của tidyverse.
Khi dữ liệu đã sạch, bước tiếp theo là đọc bài thống kê mô tả và trực quan hóa bằng R để mô tả mẫu nghiên cứu. Nếu cần người đồng hành rà soát quy trình, hãy tìm hiểu dịch vụ hỗ trợ phân tích dữ liệu bằng R của Luận Văn 360.
