我不确定我可以在这里提出这个问题,请告诉我是否应该在其他地方这样做。
我有一个带有这种结构的1e6行的data.table:
V1 V2 V3
1: 03/09/2011 08:05:40 1145.0
2: 03/09/2011 08:06:01 1207.3
3: 03/09/2011 08:06:17 1198.8
4: 03/09/2011 08:06:20 1158.4
5: 03/09/2011 08:06:40 1112.2
6: 03/09/2011 08:06:59 1199.3
我正在使用以下代码将V1和V2变量转换为唯一的日期时间变量:
system.time(DT[,`:=`(index= as.POSIXct(paste(V1,V2),
format='%d/%m/%Y %H:%M:%S'),
V1=NULL,V2=NULL)])
user system elapsed
47.47 0.16 50.27
有没有什么方法可以改善这种转变的表现?
此处为dput(head(DT))
:
DT <- structure(list(V1 = c("03/09/2011", "03/09/2011", "03/09/2011",
"03/09/2011", "03/09/2011", "03/09/2011"), V2 = c("08:05:40",
"08:06:01", "08:06:17", "08:06:20", "08:06:40", "08:06:59"),
V3 = c(1145, 1207.3, 1198.8, 1158.4, 1112.2, 1199.3)), .Names = c("V1",
"V2", "V3"), class = c("data.table", "data.frame"), row.names = c(NA,
-6L), .internal.selfref = <pointer: 0x00000000002a0788>)
答案 0 :(得分:7)
这种方法似乎比OP快了大约40倍,它使用查找表并利用极快的数据表连接。此外,它利用了以下事实:虽然可能有1e6个日期和时间组合,但最多可以有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-sugar语法编写函数,并避免使用“$”进行子集化:
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)]
}
答案 1 :(得分:2)
如果您的数据中有许多时间戳会重复,您可以尝试添加,by=list(V1, V2)
,但必须有足够的重复次数才能支付拆分费用。
这里的瓶颈是糊状物和转换,这让我认为答案是否定的。 (除非您使用另一种转换为POSIX的方法)