Этот подход, который, как представляется, работает на скорости ~ 40X быстрее, чем OP, использует таблицы поиска и использует преимущества чрезвычайно быстрых соединений таблиц данных. Кроме того, он использует тот факт, что, хотя может быть 1е6 комбинаций даты и времени, может быть не более 86400 уникальных времен и, возможно, еще меньше дат. Наконец, он полностью избегает использования paste(...)
.
library(data.table)
library(stringr)
# create a dataset with 1MM rows
set.seed(1)
x <- 1000*sample(1:1e5,1e6,replace=T)
dt <- data.table(id=1:1e6,
V1=format(as.POSIXct(x,origin="2011-01-01"),"%d/%m/%Y"),
V2=format(as.POSIXct(x,origin="2011-01-01"),"%H:%M:%S"),
V3=x)
DT <- dt
index.date <- function(dt) {
# Edit: this change processes only times from the dataset; slightly more efficient
V2 <- unique(dt$V2)
dt.time <- data.table(char.time=V2,
int.time=as.integer(substr(V2,7,8))+
60*(as.integer(substr(V2,4,5))+
60*as.integer(substr(V2,1,2))))
setkey(dt.time,char.time)
# all dates from dataset
dt.date <- data.table(char.date=unique(dt$V1), int.date=as.integer(as.POSIXct(unique(dt$V1),format="%d/%m/%Y")))
setkey(dt.date,char.date)
# join the dates
setkey(dt,V1)
dt <- dt[dt.date]
# join the times
setkey(dt,V2)
dt <- dt[dt.time, nomatch=0]
# numerical index
dt[,int.index:=int.date+int.time]
# POSIX date index
dt[,index:=as.POSIXct(int.index,origin='1970-01-01')]
# get back original order
setkey(dt,id)
return(dt)
}
# new approach
system.time(dt<-index.date(dt))
# user system elapsed
# 2.26 0.00 2.26
# original approach
DT <- dt
system.time(DT[,`:=`(index= as.POSIXct(paste(V1,V2),
format='%d/%m/%Y %H:%M:%S'),
V1=NULL,V2=NULL)])
# user system elapsed
# 84.33 0.06 84.52
Обратите внимание, что производительность зависит от количества уникальных дат. В тестовом случае было ~ 1200 уникальных дат.
РЕДАКТИРОВАНИЕ предложение написать функцию в более data.table сахара синтаксиса и избежать «$» для Подменю:
index.date <- function(dt,fmt="%d/%m/%Y") {
dt.time <- data.table(char.time = dt[,unique(V2)],key='char.time')
dt.time[,int.time :=as.integer(substr(char.time,7,8))+
60*(as.integer(substr(char.time,4,5))+
60*as.integer(substr(char.time,1,2)))]
# all dates from dataset
dt.date <- data.table(char.date = dt[,unique(V1)],key='char.date')
dt.date[,int.date:=as.integer(as.POSIXct(char.date,format=fmt))]
# join the dates
setkey(dt,V1)
dt <- dt[dt.date]
# join the times
setkey(dt,V2)
dt <- dt[dt.time, nomatch=0]
# numerical index
dt[,int.index:=int.date+int.time]
# POSIX date index
dt[,index:=as.POSIXct.numeric(int.index,origin='1970-01-01')]
# remove extra/temporary variables
dt[,`:=`(int.index=NULL,int.date=NULL,int.time=NULL)]
}
Если ваши даты GMT и больше, чем на 1 января, 1970 Вы можете попробовать ' быстрое время' упаковка. – aseidlitz
@aseidlitz Спасибо. Я забываю про «быстрое время». Я думаю, что это хороший застой. Но я не использую внутренне пакет data.table? – agstudy
Были некоторые дискуссии о добавлении поддержки fasttime в таблицу data.table, но насколько я вижу, это все еще открытый запрос в [R Forge] (https://r-forge.r-project.org/tracker/?func= detail & atid = 978 & aid = 2582 & group_id = 240) – aseidlitz