Dưới đây là một chức năng mà bạn có thể chạy trong dplyr
để tìm số ngày trong một phạm vi nhất định bằng cách sử dụng chức năng between
(từ dplyr
). Đối với mỗi giá trị của Day
, mapply
chạy between
trên mỗi cặp Start
và End
ngày và chức năng sử dụng rowSums
trở TRUE
nếu Day
là giữa ít nhất một trong số họ. Tôi không chắc đó có phải là cách tiếp cận hiệu quả nhất hay không, nhưng nó cho kết quả gần như là một yếu tố cải thiện tốc độ.
test.overlap = function(vals) {
rowSums(mapply(function(a,b) between(vals, a, b),
spans_to_filter$Start, spans_to_filter$End)) > 0
}
main_data %>%
filter(test.overlap(Day))
Nếu bạn đang làm việc với các ngày (chứ không phải với ngày-times), nó có thể thậm chí hiệu quả hơn để tạo ra một vector của ngày và thử nghiệm cho các thành viên cụ thể (điều này có thể là một cách tiếp cận tốt hơn ngay cả với ngày -times):
filt.vals = as.vector(apply(spans_to_filter, 1, function(a) a["Start"]:a["End"]))
main_data %>%
filter(Day %in% filt.vals)
Bây giờ so sánh tốc độ thực hiện. Tôi rút ngắn mã của bạn để yêu cầu chỉ hoạt động lọc:
library(microbenchmark)
microbenchmark(
OP=main_data %>%
rowwise() %>%
filter(any(Day >= spans_to_filter$Start & Day <= spans_to_filter$End)),
eipi10 = main_data %>%
filter(test.overlap(Day)),
eipi10_2 = main_data %>%
filter(Day %in% filt.vals)
)
Unit: microseconds
expr min lq mean median uq max neval cld
OP 2496.019 2618.994 2875.0402 2701.8810 2954.774 4741.481 100 c
eipi10 658.941 686.933 782.8840 714.4440 770.679 2474.941 100 b
eipi10_2 579.338 601.355 655.1451 619.2595 672.535 1032.145 100 a
UPDATE: Dưới đây là một thử nghiệm với một khung dữ liệu lớn hơn nhiều và một vài ngày thêm khoảng để phù hợp (nhờ @Frank cho gợi ý này trong mình nhận xét đã bị xóa). Nó chỉ ra rằng tốc độ tăng là lớn hơn nhiều trong trường hợp này (khoảng một yếu tố là 200 cho phương pháp mapply/between
, và vẫn còn lớn hơn cho phương pháp thứ hai).
main_data = data.frame(Day=c(1:100000))
spans_to_filter =
data.frame(Span_number = c(1:9),
Start = c(2,7,1,15,12,23,90,9000,50000),
End = c(5,10,4,18,15,26,100,9100,50100))
microbenchmark(
OP=main_data %>%
rowwise() %>%
filter(any(Day >= spans_to_filter$Start & Day <= spans_to_filter$End)),
eipi10 = main_data %>%
filter(test.overlap(Day)),
eipi10_2 = {
filt.vals = unlist(apply(spans_to_filter, 1, function(a) a["Start"]:a["End"]))
main_data %>%
filter(Day %in% filt.vals)},
times=10
)
Unit: milliseconds
expr min lq mean median uq max neval cld
OP 5130.903866 5137.847177 5201.989501 5216.840039 5246.961077 5276.856648 10 b
eipi10 24.209111 25.434856 29.526571 26.455813 32.051920 48.277326 10 a
eipi10_2 2.505509 2.618668 4.037414 2.892234 6.222845 8.266612 10 a
Điều này trở nên nhanh hơn câu trả lời được chấp nhận khi bảng tra cứu tăng lên. – eddi
Các cải tiến đã được thực hiện gần đây ..nên nhanh hơn trên các bảng tra cứu nhỏ hơn. – Arun