Вот функция, которую вы можете запустить в dplyr
, чтобы найти даты в пределах заданного диапазона с помощью функции between
(от dplyr
). Для каждого значения Day
, mapply
работает between
на каждой из пар Start
и End
даты и функция использует rowSums
для возврата TRUE
если Day
находится между, по меньшей мере, один из них. Я не уверен, что это самый эффективный подход, но это приводит к почти четвертому улучшению скорости.
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))
Если вы работаете с датами (а не с даты-времени), это может быть даже более эффективным, чтобы создать вектор конкретных дат и теста для членства (это может быть лучшим подходом, даже с датой -раз):
filt.vals = as.vector(apply(spans_to_filter, 1, function(a) a["Start"]:a["End"]))
main_data %>%
filter(Day %in% filt.vals)
Теперь сравните скорости выполнения. Я укоротить ваш код требует только операции фильтрации:
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: Ниже приведен тест с гораздо большим кадром данных и несколькими дополнительных диапазонами даты, чтобы соответствовать (спасибо @Frank предложившему это в его теперь удаленный комментарий). Оказывается, что в этом случае прирост скорости намного больше (примерно в 200 раз для метода mapply/between
и еще гораздо больше для второго метода).
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
Это становится быстрее, чем принятый ответ по мере роста таблицы поиска. – eddi
Усовершенствования были сделаны недавно ..должен быть быстрее и на небольших таблицах поиска. – Arun