Как повысить эффективность поиска самого последнего рабочего дня для всех дат в кадре данных R? - PullRequest
0 голосов
/ 04 апреля 2019

У меня есть датафрейм с несколькими миллионами строк. Один столбец является столбцом даты. Мне нужно добавить новый столбец, который имеет предыдущий рабочий день. У меня есть способ сделать это, но это очень медленно. По причинам, которые здесь не нужно объяснять, я должен выполнить это же преобразование 5 раз подряд.

Я попытался создать векторизованную функцию, которая выполняет те же действия, что и выше, а затем скомпилировал ее с помощью cmpfun, но, похоже, это не ускорило процесс. Буду очень признателен за любые мысли относительно 1) почему это происходит медленно и 2) как сделать это более эффективно.

library(timeDate)
library(dplyr)

# generate some random data
nrows <- 1000000
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(today())))

# subtract a day from today, check if it is a business day; if not, repeat a few times
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)
  )

1 Ответ

1 голос
/ 04 апреля 2019

Преобразование моего комментария в ответ:

В вашем примере у вас есть 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% ОП.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...