Дата раунда до следующего дня недели в R - PullRequest
0 голосов
/ 26 апреля 2019

В настоящее время я борюсь с некоторыми преобразованиями дат в R. У меня есть большой набор данных финансовых данных со столбцом даты. Поскольку ценные бумаги не торгуются в выходные дни, мне нужно иметь только рабочие дни в моем наборе данных. Как можно округлить даты в этом столбце до предыдущего дня недели? Поэтому каждую субботу и воскресенье следует преобразовать в предыдущую пятницу. в приведенной ниже выдержке первое свидание - суббота, а второе - воскресенье. Теперь я хотел бы преобразовать их в 2007-03-02 и оставить остальные строки без изменений.

# A tibble: 6 x 5
Ticker Date       mean_PX_ASK mean_PX_BID Agency 
<chr>    <date>           <dbl>       <dbl> <chr>  
1 ABNANV 2007-03-03       102.        102.  Moody's
2 ABNANV 2007-03-04       102.        102.  Moody's
3 ABNANV 2007-03-12       102.        102.  Moody's
4 ABNANV 2007-03-12       102.        102.  Moody's
5 ABNANV 2008-09-17        88.9        88.4 Fitch  
6 ABNANV 2008-09-17        88.9        88.4 Fitch  

Рад любой помощи!

Ответы [ 4 ]

3 голосов
/ 26 апреля 2019

Это можно сделать в одной строке без пакетов или ifelse, если мы используем именованный вектор

df$Date <- with(df,  Date - setNames(rep(0:2, c(5, 1, 1)), 1:7)[format(Date, "%u")])
df
#  Ticker       Date mean_PX_ASK mean_PX_BID  Agency
#1 ABNANV 2007-03-02       102.0       102.0 Moody's
#2 ABNANV 2007-03-02       102.0       102.0 Moody's
#3 ABNANV 2007-03-12       102.0       102.0 Moody's
#4 ABNANV 2007-03-12       102.0       102.0 Moody's
#5 ABNANV 2008-09-17        88.9        88.4   Fitch
#6 ABNANV 2008-09-17        88.9        88.4   Fitch

Тесты

Использование большего набора данных

df1 <- df[rep(seq_len(nrow(df)), 1e7), ]

system.time({
df1 %>%
  mutate(Day = weekdays(Date), 
         Date = case_when(Day == "Saturday" ~ Date - 1, 
                          Day == "Sunday" ~ Date - 2, 
                          TRUE ~ Date)) %>%
   select(-Day)

})
# user  system elapsed 
# 41.468   6.881  49.588 
system.time({

with(df1,  Date - setNames(rep(0:2, c(5, 1, 1)), 1:7)[format(Date, "%u")])

})
# user  system elapsed 
# 27.456   2.785  30.490 

с microbenchmark,

library(microbenchmark)
microbenchmark(
   rs = df1 %>%
         mutate(Day = weekdays(Date), 
         Date = case_when(Day == "Saturday" ~ Date - 1, 
                          Day == "Sunday" ~ Date - 2, 
                          TRUE ~ Date)) %>%
   select(-Day),
ak = with(df1,  Date - setNames(rep(0:2, c(5, 1, 1)), 1:7)[format(Date, "%u")]), 
          times = 10L, unit = "relative")
#Unit: relative
# expr      min       lq     mean   median       uq      max neval cld
#   rs 1.401658 1.437164 1.446403 1.421731 1.512451 1.467511    10   b
#   ak 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000    10  a 

Данные

df <- structure(list(Ticker = c("ABNANV", "ABNANV", "ABNANV", "ABNANV", 
"ABNANV", "ABNANV"), Date = structure(c(13575, 13576, 13584, 
13584, 14139, 14139), class = "Date"), mean_PX_ASK = c(102, 102, 
102, 102, 88.9, 88.9), mean_PX_BID = c(102, 102, 102, 102, 88.4, 
88.4), Agency = c("Moody's", "Moody's", "Moody's", "Moody's", 
"Fitch", "Fitch")), row.names = c("1", "2", "3", "4", "5", "6"
), class = "data.frame")
3 голосов
/ 26 апреля 2019

Простым решением может быть использование case_when из dplyr, чтобы проверить, является ли weekday для этого дня "суббота" или "воскресенье", и вычесть дни соответственно.

library(dplyr)

df %>%
  mutate(Day = weekdays(Date), 
         Date = case_when(Day == "Saturday" ~ Date - 1, 
                          Day == "Sunday" ~ Date - 2, 
                          TRUE ~ Date)) %>%
   select(-Day)


#  Ticker       Date mean_PX_ASK mean_PX_BID  Agency
#1 ABNANV 2007-03-02       102.0       102.0 Moody's
#2 ABNANV 2007-03-02       102.0       102.0 Moody's
#3 ABNANV 2007-03-12       102.0       102.0 Moody's
#4 ABNANV 2007-03-12       102.0       102.0 Moody's
#5 ABNANV 2008-09-17        88.9        88.4   Fitch
#6 ABNANV 2008-09-17        88.9        88.4   Fitch

С bizdays нам нужно создать календарь, используя create.calendar и значение по умолчанию weekdays.Затем мы можем использовать adjust.previous, чтобы получить предыдущий рабочий день.

library(bizdays)
cal <- create.calendar("Actual", weekdays=c("saturday", "sunday"))
adjust.previous(df$Date, cal)

#[1] "2007-03-02" "2007-03-02" "2007-03-12" "2007-03-12" "2008-09-17" "2008-09-17"
1 голос
/ 26 апреля 2019

Использование wday от lubridate:

library(lubridate)
# Generate some data
dfdate <- seq.Date(from = as.Date("2019-04-26"), to = as.Date("2019-04-28"), by = "day")

dfdate
[1] "2019-04-26" "2019-04-27" "2019-04-28"

wday начинается в воскресенье, где wday = 1

# Change all values to a Friday
dfdate[wday(dfdate) == 7] <-  dfdate[wday(dfdate) == 7] - 1 # Saturdays to Fri
dfdate[wday(dfdate) == 1] <-  dfdate[wday(dfdate) == 1] - 2 # Sundays to Fri

dfdate
[1] "2019-04-26" "2019-04-26" "2019-04-26"
1 голос
/ 26 апреля 2019

В базе R вы можете использовать format.Date со строкой формата %u.

dates <- as.Date(c('2007-03-02', '2007-03-03', '2007-03-04'))
wd <- as.integer(format(dates, '%u'))
as.Date(ifelse(wd >= 6, dates + 5 - wd, dates), origin = '1970-01-01')
#[1] "2007-03-02" "2007-03-02" "2007-03-02"
...