Преобразование моего комментария в ответ:
В вашем примере у вас есть 1 миллион строк. Если бы в каждой строке была уникальная дата, ваш временной ряд охватил бы 2739 лет. Поскольку вы, похоже, работаете с данными NYSE, я считаю, что ваш фактический период времени намного короче, и, следовательно, большинство дат в ваших данных дублируются. Поэтому я предлагаю вам создать таблицу всех уникальных дат в ваших данных, запустить функцию делового дня и сопоставить результаты с исходными данными.
Вот подтверждение концепции:
library(timeDate)
library(dplyr)
# generate some random data
nrows <- 1000000
set.seed(888)
df <- tibble(row = sample(0:20, nrows, rep = TRUE),
date = sample(seq(as.Date('2014/01/01'), as.Date('2019/03/31'), by="day"), rep = TRUE, nrows)
)
# get the holidays from 2014 until now
holidays <- holidayNYSE(seq(2014, year(Sys.Date())))
df2 = data.table::copy(df)
# subtract a day from today, check if it is a business day; if not, repeat a few times
system.time({
df <- df %>%
mutate(
previous_biz_day = date - 1,
previous_biz_day = if_else(!isBizday(as.timeDate(previous_biz_day), holidays), previous_biz_day - 1, previous_biz_day),
previous_biz_day = if_else(!isBizday(as.timeDate(previous_biz_day), holidays), previous_biz_day - 1, previous_biz_day),
previous_biz_day = if_else(!isBizday(as.timeDate(previous_biz_day), holidays), previous_biz_day - 1, previous_biz_day)
)
})
# user system elapsed
# 19.828 0.906 20.789
##########
system.time({
df2 <- df2 %>%
distinct(date) %>%
mutate(
previous_biz_day = date - 1,
previous_biz_day = if_else(!isBizday(as.timeDate(previous_biz_day), holidays), previous_biz_day - 1, previous_biz_day),
previous_biz_day = if_else(!isBizday(as.timeDate(previous_biz_day), holidays), previous_biz_day - 1, previous_biz_day),
previous_biz_day = if_else(!isBizday(as.timeDate(previous_biz_day), holidays), previous_biz_day - 1, previous_biz_day)
) %>%
right_join(df2, by = "date")
})
# user system elapsed
# 0.148 0.004 0.152
########### compare results
all.equal(df, df2)
# [1] TRUE
Второй подход занял ~ 0,7% ОП.