Преобразование даты в число c, но с ограничением на количество дней в году - PullRequest
1 голос
/ 07 февраля 2020

Я хочу создать объект даты между 2008-01-01 и 2010-12-31 около 10K из них. Я написал код для этого, но я действительно хочу сохранить дни 1-366 в 2008 году, потому что 2008-02-29 (високосный год) я хочу, чтобы они перезапустились после 366, а затем стали 1 на 2009-01-01. Я могу сделать это как создать только для 2008, а затем 2009, а затем 2010, но это не будет удобно. Я читал о lubridate, но не мог понять это. Я также могу отфильтровать от 1 до 366, а затем 367-731, но это также не будет эффективным. Кто-нибудь знает лучший способ сделать это?

    set.seed(123)
    tim1=sample(365*3+1,10000,replace = TRUE)   ### that plus 1 from feb 29 in 2008
    dat1=as.Date(tim1,origin="2007-12-31")   # then 1 will be 2008-01-01

1 Ответ

1 голос
/ 07 февраля 2020

Вы можете создать вектор всех целевых дат и выборку из него. Для создания вектора существует seq.Date, метод seq для объектов класса "Date".

start <- as.Date("2008-01-01")
end <- as.Date("2010-12-31")
s <- seq(start, end, by = "days")

Вектор s включает все дни между start и end. Теперь сэмпл из него.

set.seed(123)
dat1 <- sample(s, 10000, TRUE)

Преобразуйте сэмпл в день года. См. help("strptime")

as.numeric(format(dat1, format = "%j"))

В конце удалите s, он больше не нужен.

rm(s)    # tidy up

Редактировать.

Следующие две функции выполняют то, о чем спрашивает вопрос, но двумя разными методами.
f1 - это приведенный выше код, заключенный в функцию, f2 использует ave/seq_along/match и немного сложнее. Тесты показывают, что функция f2 в два раза быстрее, чем f1

f1 <- function(start_date, end_date, n){
  start <- as.Date(start_date)
  end <- as.Date(end_date)
  s <- seq(start, end, by = "days")
  y <- sample(s, n, replace = TRUE)
  as.numeric(format(y, format = "%j"))
}

f2 <- function(start_date, end_date, n){
  start <- as.Date(start_date)
  end <- as.Date(end_date)
  s <- seq(start, end, by = "days")
  y <- sample(s, n, replace = TRUE)
  z <- ave(as.integer(s), lubridate::year(s), FUN = seq_along)
  z[match(y, s)]
}

set.seed(123)
x1 <- f1("2008-01-01", "2010-12-31", 100)
set.seed(123)
x2 <- f2("2008-01-01", "2010-12-31", 100)

all.equal(x1, x2)
#[1] TRUE

Теперь тесты.

library(microbenchmark)

mb <- microbenchmark(
  f1 = f1("2008-01-01", "2010-12-31", 1e4),
  f2 = f2("2008-01-01", "2010-12-31", 1e4),
  times = 50
)
print(mb, order = "median")

ggplot2::autoplot(mb)

enter image description here

...