Nếu bạn nào thích bài thơ Nhớ Rừng của Thế Lữ thì nên tìm hiểu về thuật toán Nhớ Rừng (MissForest) 😊!
Thuật toán MissForest là một phương pháp imputation (điền khuyết) dữ liệu bị thiếu, dựa trên thuật toán Random Forest (Rừng Ngẫu nhiên). Đây được coi là một trong những kỹ thuật điền khuyết hiệu quả và chính xác nhất, đặc biệt khi xử lý các tập dữ liệu phức tạp với nhiều kiểu biến (số và phân loại) và các mối quan hệ phi tuyến tính giữa các biến.
MissForest hoạt động như thế nào?
Ý tưởng cốt lõi của MissForest là sử dụng một mô hình Random Forest đã được huấn luyện để dự đoán các giá trị bị thiếu. Quá trình này diễn ra một cách lặp đi lặp lại cho đến khi các giá trị điền khuyết hội tụ.
Dưới đây là các bước chi tiết của thuật toán:
- Khởi tạo:
- Các giá trị bị thiếu (missing values) trong tập dữ liệu được điền tạm thời bằng một giá trị ban đầu. Thông thường, đối với biến số (numerical), người ta dùng giá trị trung bình (mean); đối với biến phân loại (categorical), người ta dùng giá trị xuất hiện nhiều nhất (mode).
- Lặp lại dự đoán:
- Sắp xếp các biến: Các biến (cột) trong tập dữ liệu sẽ được sắp xếp theo thứ tự tăng dần hoặc giảm dần dựa trên số lượng giá trị bị thiếu.
- Dự đoán từng biến: Bắt đầu với biến có ít giá trị bị thiếu nhất, thuật toán sẽ thực hiện các bước sau:
- Tách dữ liệu: Tập dữ liệu được chia thành hai phần:
- Tập huấn luyện (Training set): Gồm các hàng (quan sát) không có giá trị bị thiếu ở biến đang xét.
- Tập dự đoán (Prediction set): Gồm các hàng có giá trị bị thiếu ở biến đang xét.
- Huấn luyện mô hình: Một mô hình Random Forest được huấn luyện trên tập huấn luyện. Trong đó, biến đang xét là biến mục tiêu (target variable), và tất cả các biến còn lại là biến độc lập (features).
- Dự đoán và điền khuyết: Mô hình Random Forest vừa được huấn luyện sẽ được sử dụng để dự đoán các giá trị bị thiếu trên tập dự đoán. Các giá trị dự đoán này sẽ được điền vào bảng dữ liệu, thay thế cho các giá trị tạm thời trước đó.
- Tách dữ liệu: Tập dữ liệu được chia thành hai phần:
- Quá trình này được lặp lại cho tất cả các biến có giá trị bị thiếu.
- Điều kiện dừng:
- Toàn bộ chu trình ở bước 2 được lặp đi lặp lại nhiều lần.
- Thuật toán sẽ dừng lại khi sự khác biệt giữa tập dữ liệu đã điền khuyết ở vòng lặp hiện tại và vòng lặp trước đó không còn đáng kể nữa (hội tụ). Cụ thể, sự khác biệt này được tính toán riêng cho biến số và biến phân loại:
- Biến số: Sự khác biệt được tính bằng tổng bình phương sai lệch chuẩn hóa (normalized squared sum of differences).
- Biến phân loại: Sự khác biệt được tính bằng tỷ lệ số hàng mà giá trị phân loại bị thay đổi.
Khi thuật toán dừng lại, chúng ta sẽ có một tập dữ liệu hoàn chỉnh với các giá trị bị thiếu đã được điền bằng các giá trị dự đoán có độ chính xác cao.
Ưu và nhược điểm
🌳 Ưu điểm:
- Độ chính xác cao: Thường cho kết quả tốt hơn so với các phương pháp điền khuyết đơn giản như điền giá trị trung bình, trung vị hoặc các phương pháp hồi quy tuyến tính.
- Xử lý được nhiều kiểu dữ liệu: Có thể xử lý đồng thời cả biến số và biến phân loại trong cùng một tập dữ liệu mà không cần biến đổi phức tạp.
- Không cần chuẩn hóa dữ liệu: Random Forest không nhạy cảm với quy mô (scale) của các biến, do đó không yêu cầu chuẩn hóa dữ liệu.
- Có khả năng nắm bắt các mối quan hệ phức tạp: Hiệu quả trong việc xử lý các tương tác và mối quan hệ phi tuyến tính giữa các biến.
- Ít yêu cầu tinh chỉnh tham số: Hoạt động khá tốt với các tham số mặc định của Random Forest.
🌪️ Nhược điểm:
- Tốn tài nguyên tính toán: Vì phải huấn luyện nhiều mô hình Random Forest trong nhiều vòng lặp, MissForest có thể rất chậm và tốn bộ nhớ đối với các tập dữ liệu lớn (nhiều hàng và nhiều cột).
Khi nào nên sử dụng MissForest?
MissForest là một lựa chọn tuyệt vời khi:
- Tập dữ liệu của bạn có cả biến số và biến phân loại.
- Bạn nghi ngờ có các mối quan hệ phức tạp, phi tuyến tính giữa các biến.
- Độ chính xác của việc điền khuyết là ưu tiên hàng đầu.
- Tập dữ liệu không quá lớn về mặt kích thước (hàng triệu hàng hoặc hàng nghìn cột thì em nó chạy chậm còn hơn cả cụ rùa Hồ Gươm).
Ví dụ code R sử dụng gói missForest
Bạn có thể chạy thử code này trực tiếp trên Colab
- Cài đặt và tải gói
missForest
:
Đầu tiên, bạn cần cài đặt góimissForest
nếu chưa có. Sau đó, tải gói vào môi trường làm việc.
# Cài đặt gói missForest nếu chưa có
if (!requireNamespace("missForest", quietly = TRUE)) {
install.packages("missForest")
}
# Tải gói missForest
library(missForest)
- Tạo hoặc tải tập dữ liệu:
Để minh họa, tôi sẽ tạo một tập dữ liệu giả lập có giá trị bị thiếu. Bạn có thể thay bằng tập dữ liệu thực tế của mình.
# Tạo dữ liệu mẫu
set.seed(123) # Đặt seed để kết quả có thể tái lập
data <- data.frame(
A = c(1, 2, NA, 4, 5, NA),
B = c(NA, 3, 4, NA, 6, 7),
C = c("x", "y", NA, "x", "z", "y"),
D = c(10, NA, 12, 13, NA, 15)
)
# Xem dữ liệu
print("Dữ liệu gốc:")
print(data)
- Áp dụng MissForest để điền giá trị bị thiếu:
Sử dụng hàmmissForest()
để điền giá trị bị thiếu. Hàm này sẽ tự động xử lý cả dữ liệu số và phân loại.
# Chạy MissForest
result <- missForest(data, maxiter = 10, ntree = 100)
# Lấy dữ liệu đã được điền
imputed_data <- result$ximp
# Xem dữ liệu đã được điền
print("Dữ liệu sau khi điền giá trị bị thiếu:")
print(imputed_data)
Giải thích tham số:
maxiter
: Số vòng lặp tối đa (mặc định là 10).ntree
: Số lượng cây trong Random Forest (mặc định là 100).ximp
: Ma trận dữ liệu đã được điền giá trị bị thiếu.
Tuy nhiên, chúng ta phải nhớ factor biến, bằng không khi chúng ta chạy code trên sẽ bị lỗi sau: Error in missForest(data, maxiter = 10, ntree = 100): column C must be factor or numeric, is character
Do đó chúng ta phải có bước
# Chuyển cột C thành factor
data$C <- as.factor(data$C)
# Kiểm tra kiểu dữ liệu
str(data) # Xác nhận cột C đã là factor
Kiểm tra lỗi dự đoán (OOB error):
MissForest cung cấp lỗi ngoài túi (out-of-bag error) để đánh giá chất lượng điền giá trị.
# Xem lỗi OOB
print("Lỗi OOB:")
print(result$OOBerror)
Kết quả mẫu
Nếu bạn chạy code trên với dữ liệu mẫu, đầu ra sẽ trông như sau:
Dữ liệu gốc:
A B C D
1 1 NA x 10
2 2 3 y NA
3 NA 4 NA 12
4 4 NA x 13
5 5 6 z NA
6 NA 7 y 15
Dữ liệu sau khi điền (giá trị cụ thể phụ thuộc vào Random Forest):
A B C D
1 1.00 3.74 x 10.00
2 2.00 3.00 y 11.72
3 2.26 4.00 x 12.00
4 4.00 5.76 x 13.00
5 5.00 6.00 z 13.28
6 3.99 7.00 y 15.00
[1] "Lỗi OOB:"
NRMSE PFC
0.3384217 1.0000000
Lỗi OOB:
- Đối với biến số: Một giá trị nhỏ (ví dụ: 0.05) cho thấy dự đoán tốt.
- Đối với biến phân loại: Tỷ lệ lỗi phân loại (ví dụ: 0.1).
Lưu ý
- Dữ liệu thực tế: Thay
data
bằng tập dữ liệu của bạn (ví dụ: đọc từ file CSV bằngread.csv("file.csv")
). - Xử lý biến phân loại: MissForest tự động nhận diện biến phân loại nếu chúng được định dạng đúng (factor trong R).
- Hiệu suất: Với tập dữ liệu lớn, bạn có thể cần điều chỉnh
ntree
hoặcmaxiter
để cân bằng giữa tốc độ và độ chính xác. - Cài đặt thêm: Nếu bạn gặp lỗi, đảm bảo các gói phụ thuộc như
randomForest
đã được cài đặt.
Toàn bộ code:
# Cài đặt và tải gói missForest
if (!requireNamespace("missForest", quietly = TRUE)) {
install.packages("missForest")
}
library(missForest)
# Tạo dữ liệu mẫu
set.seed(123) # Đặt seed để kết quả có thể tái lập
data <- data.frame(
A = c(1, 2, NA, 4, 5, NA),
B = c(NA, 3, 4, NA, 6, 7),
C = c("x", "y", NA, "x", "z", "y"), # Cột C hiện là character
D = c(10, NA, 12, 13, NA, 15)
)
# Chuyển cột C thành factor
data$C <- as.factor(data$C)
# Kiểm tra kiểu dữ liệu
str(data) # Xác nhận cột C đã là factor
# Chạy MissForest
result <- missForest(data, maxiter = 10, ntree = 100)
# Lấy dữ liệu đã được điền
imputed_data <- result$ximp
# Xem dữ liệu đã được điền
print("Dữ liệu sau khi điền giá trị bị thiếu:")
print(imputed_data)
# Xem lỗi OOB
print("Lỗi OOB:")
print(result$OOBerror)
Chạy trên Colab