在 R 中快速操作日期
Fast manipulation of Dates in R
我有大约 34000 个日期向量,我必须更改日期并移动月份。我已经尝试过使用循环并使用 mapply
函数,但速度非常慢。
这是我所拥有的示例:
library(lubridate)
list_dates = replicate(34000,seq(as.Date("2019-03-14"),length.out = 208,by = "months"),simplify = F)
new_day = round(runif(34000,1,30))
new_day[sample(1:34000,10000)] = NA
new_dates = mapply(FUN = function(dates,day_change){
day(dates) = ifelse(is.na(rep(day_change,length(dates))),day(dates),rep(day_change,length(dates)))
dates = as.Date(ifelse(is.na(rep(day_change,length(dates))),dates,dates%m-%months(1)),origin = "1970-01-01")
return(dates)
},dates = list_dates,day_change = as.list(new_day),SIMPLIFY = F)
变量 new_dates
应包含相应地移动到变量 new_day
的原始日期列表。 side 中的函数是这样工作的:
- 如果
new_day
与 NA 不同,它将把日期更改为新日期
- 如果
new_day
与 NA 不同,它将把日期的月份向后移动一位。
我愿意接受任何可以提高速度的解决方案,而不管使用的是什么包(如果它们在 CRAN 中)。
编辑
因此,根据评论,我减少了 2 个日期向量列表的示例,每个日期包含 2 个日期,并创建了新日期的手动向量:
list_dates = replicate(2,seq(as.Date("2019-03-14"),length.out = 2,by = "months"),simplify = F)
new_day = c(9,NA)
这是原始输入(变量list_dates):
[[1]]
[1] "2019-03-14" "2019-04-14"
[[2]]
[1] "2019-03-14" "2019-04-14"
并且 mapply
函数的预期输出是:
[[1]]
[1] "2019-02-09" "2019-03-09"
[[2]]
[1] "2019-03-14" "2019-04-14"
如您所见,日期的第一个向量已更改为第 9 天,并且每个日期都滞后一个月。第二个日期向量没有改变,因为 new_dates
是那个值的 NA
。
这是一个lubridate
解决方案
library(lubridate)
mapply(
function(x, y) { if (!is.na(y)) {
day(x) <- y;
month(x) <- month(x) - 1
}
return(x) },
list_dates, new_day, SIMPLIFY = F)
#[[1]]
#[1] "2019-02-09" "2019-03-09"
#
#[[2]]
#[1] "2019-03-14" "2019-04-14"
或使用purrr
library(purrr)
library(lubridate)
map2(list_dates, new_day, function(x, y) {
if (!is.na(y)) {
day(x) <- y
month(x) <- month(x) - 1
}
x })
除了 Maurits 的解决方案之外,如果您想进一步提高计算速度,您可能需要考虑使用 doParallel
的多核
library(data.table)
library(doParallel)
registerDoParallel(3)
df <- data.table(new_day,list_dates)
mlply(df,
function(new_day,list_dates){
list_dates <- list_dates[[1]]
if(!is.na(new_day)){
day(list_dates) <- new_day
list_dates <- list_dates %m-% months(1)
}
return(list_dates)
}, .parallel = T, .paropts = list(.packages='lubridate')
)
我有大约 34000 个日期向量,我必须更改日期并移动月份。我已经尝试过使用循环并使用 mapply
函数,但速度非常慢。
这是我所拥有的示例:
library(lubridate)
list_dates = replicate(34000,seq(as.Date("2019-03-14"),length.out = 208,by = "months"),simplify = F)
new_day = round(runif(34000,1,30))
new_day[sample(1:34000,10000)] = NA
new_dates = mapply(FUN = function(dates,day_change){
day(dates) = ifelse(is.na(rep(day_change,length(dates))),day(dates),rep(day_change,length(dates)))
dates = as.Date(ifelse(is.na(rep(day_change,length(dates))),dates,dates%m-%months(1)),origin = "1970-01-01")
return(dates)
},dates = list_dates,day_change = as.list(new_day),SIMPLIFY = F)
变量 new_dates
应包含相应地移动到变量 new_day
的原始日期列表。 side 中的函数是这样工作的:
- 如果
new_day
与 NA 不同,它将把日期更改为新日期 - 如果
new_day
与 NA 不同,它将把日期的月份向后移动一位。
我愿意接受任何可以提高速度的解决方案,而不管使用的是什么包(如果它们在 CRAN 中)。
编辑
因此,根据评论,我减少了 2 个日期向量列表的示例,每个日期包含 2 个日期,并创建了新日期的手动向量:
list_dates = replicate(2,seq(as.Date("2019-03-14"),length.out = 2,by = "months"),simplify = F)
new_day = c(9,NA)
这是原始输入(变量list_dates):
[[1]]
[1] "2019-03-14" "2019-04-14"
[[2]]
[1] "2019-03-14" "2019-04-14"
并且 mapply
函数的预期输出是:
[[1]]
[1] "2019-02-09" "2019-03-09"
[[2]]
[1] "2019-03-14" "2019-04-14"
如您所见,日期的第一个向量已更改为第 9 天,并且每个日期都滞后一个月。第二个日期向量没有改变,因为 new_dates
是那个值的 NA
。
这是一个lubridate
解决方案
library(lubridate)
mapply(
function(x, y) { if (!is.na(y)) {
day(x) <- y;
month(x) <- month(x) - 1
}
return(x) },
list_dates, new_day, SIMPLIFY = F)
#[[1]]
#[1] "2019-02-09" "2019-03-09"
#
#[[2]]
#[1] "2019-03-14" "2019-04-14"
或使用purrr
library(purrr)
library(lubridate)
map2(list_dates, new_day, function(x, y) {
if (!is.na(y)) {
day(x) <- y
month(x) <- month(x) - 1
}
x })
除了 Maurits 的解决方案之外,如果您想进一步提高计算速度,您可能需要考虑使用 doParallel
library(data.table)
library(doParallel)
registerDoParallel(3)
df <- data.table(new_day,list_dates)
mlply(df,
function(new_day,list_dates){
list_dates <- list_dates[[1]]
if(!is.na(new_day)){
day(list_dates) <- new_day
list_dates <- list_dates %m-% months(1)
}
return(list_dates)
}, .parallel = T, .paropts = list(.packages='lubridate')
)