Tôi có thói quen gộp các nhiệm vụ tương tự lại với nhau thành một dòng duy nhất. Ví dụ, nếu tôi cần phải lọc trên a
, b
và c
trong một bảng dữ liệu, tôi sẽ đặt chúng lại với nhau trong một []
với AND. Hôm qua, tôi nhận thấy rằng trong trường hợp cụ thể của mình, điều này cực kỳ chậm và đã thử nghiệm các bộ lọc xích thay thế. Tôi đã bao gồm một ví dụ dưới đây.
Đầu tiên, tôi chọn trình tạo số ngẫu nhiên, tải data.table và tạo một tập dữ liệu giả.
# Set RNG seed
set.seed(-1)
# Load libraries
library(data.table)
# Create data table
dt <- data.table(a = sample(1:1000, 1e7, replace = TRUE),
b = sample(1:1000, 1e7, replace = TRUE),
c = sample(1:1000, 1e7, replace = TRUE),
d = runif(1e7))
Tiếp theo, tôi xác định phương pháp của mình. Cách tiếp cận đầu tiên chuỗi các bộ lọc với nhau. AND thứ hai các bộ lọc với nhau.
# Chaining method
chain_filter <- function(){
dt[a %between% c(1, 10)
][b %between% c(100, 110)
][c %between% c(750, 760)]
}
# Anding method
and_filter <- function(){
dt[a %between% c(1, 10) & b %between% c(100, 110) & c %between% c(750, 760)]
}
Ở đây, tôi kiểm tra họ cho kết quả tương tự.
# Check both give same result
identical(chain_filter(), and_filter())
#> [1] TRUE
Cuối cùng, tôi điểm chuẩn chúng.
# Benchmark
microbenchmark::microbenchmark(chain_filter(), and_filter())
#> Unit: milliseconds
#> expr min lq mean median uq max
#> chain_filter() 25.17734 31.24489 39.44092 37.53919 43.51588 78.12492
#> and_filter() 92.66411 112.06136 130.92834 127.64009 149.17320 206.61777
#> neval cld
#> 100 a
#> 100 b
Được tạo vào ngày 2019-10-25 bởi gói reprex (v0.3.0)
Trong trường hợp này, chuỗi làm giảm thời gian chạy khoảng 70%. Tại sao điều này là trường hợp? Ý tôi là, những gì đang diễn ra dưới mui xe trong bảng dữ liệu? Tôi chưa thấy bất kỳ cảnh báo nào chống lại việc sử dụng &
, vì vậy tôi đã ngạc nhiên rằng sự khác biệt quá lớn. Trong cả hai trường hợp, họ đánh giá các điều kiện giống nhau, do đó không nên là một sự khác biệt. Trong trường hợp AND, &
là một toán tử nhanh và sau đó nó chỉ phải lọc bảng dữ liệu một lần (nghĩa là sử dụng vectơ logic kết quả từ AND), trái ngược với việc lọc ba lần trong trường hợp chuỗi.
Câu hỏi thưởng
Liệu nguyên tắc này giữ cho các hoạt động bảng dữ liệu nói chung? Là nhiệm vụ mô đun hóa luôn luôn là một chiến lược tốt hơn?
base
quan sát tương tự với các vectơ bằng cách thực hiện như sau: chain_vec <- function() { x <- which(a < .001); x[which(b[x] > .999)] }
và and_vec <- function() { which(a < .001 & b > .999) }
. (trong đó a
và b
là các vectơ có cùng độ dài từ runif
- Tôi đã sử dụng n = 1e7
cho các điểm cắt này).