更高效的滚动连接向后而不是向前?

时间:2013-01-12 13:31:59

标签: r join data.table

data.table实现asof(也称为rollingLOCF)加入开箱即用。我发现了这个相关的问题:

Filling in missing (blanks) in a data table, per category - backwards and forwards

但该问题在数据中有NA。在我的情况下,我遵循那里的建议,以保持数据不规则,并使用roll=TRUE加入它。我想做的不是最后一次观察,而是要尽可能有效地进行下一次观察。

这是我尝试过的,首先使用time:=-time尝试欺骗它。我可以做得更好吗?我可以更快地完成吗?

llorJoin <- function(A,B){
    B <- copy(B);
    keys <- key(A);
    if( !identical(key(A), key(B)) | is.null(keys) ){
       stop("llorJoin::ERROR; A and B should have the same non-empty keys");
    }

    lastKey <- tail(keys,1L);
    myStr <- parse(text=paste0(lastKey,":=-as.numeric(",lastKey,")"));
    A <- A[,eval(myStr)]; setkeyv(A,keys);
    B <- B[,eval(myStr)]; setkeyv(B,keys);

    origin <- "1970-01-01 00:00.00 UTC";
    A <- B[A,roll=T];
    myStr2 <- parse(text=paste0(lastKey,":=as.POSIXct(-",lastKey,",origin=origin)"));
    A <- A[,eval(myStr2)]; setkeyv(A,keys);
    return(A);
}

library(data.table)
A <- data.table(time=as.POSIXct(c("10:01:01","10:01:02","10:01:04","10:01:05","10:01:02","10:01:01","10:01:01"),format="%H:%M:%S"),
                b=c("a","a","a","a","b","c","c"),
                d=c(1,1.9,2,1.8,5,4.1,4.2));
B <- data.table(time=as.POSIXct(c("10:01:01","10:01:03","10:01:00","10:01:01"),format="%H:%M:%S"),b=c("a","a","c","d"), e=c(1L,2L,3L,4L));
setkey(A,b,time)
setkey(B,b,time)

library(rbenchmark)
benchmark(llorJoin(A,B),B[A,roll=T],replications=10)
            test replications elapsed relative user.self sys.self user.child sys.child
1 llorJoin(A, B)           10   0.045        1     0.048        0          0         0
2 B[A, roll = T]           10   0.009        1     0.008        0          0         0

   b                time  e   d
1: a 2013-01-12 09:01:01  1 1.0
2: a 2013-01-12 09:01:02  2 1.9
3: a 2013-01-12 09:01:04 NA 2.0
4: a 2013-01-12 09:01:05 NA 1.8
5: b 2013-01-12 09:01:02 NA 5.0
6: c 2013-01-12 09:01:01 NA 4.1
7: c 2013-01-12 09:01:01 NA 4.2

因此,作为比较,加入初始数据的速度要快5倍。

1 个答案:

答案 0 :(得分:4)

很久以前,

roll参数可以执行 nocb 。更新此答案,以便#615可以关闭。

您也不需要再设置按键了。相反,您可以使用on=参数(在v1.9.6中实现)指定要加入的列。有了这两个功能,任务可以按如下方式完成:

require(data.table) # v1.9.6+
A[B, on=c("b", "time"), roll=-Inf]
#                   time b  e   d
# 1: 2015-10-11 10:01:01 a  1 1.0
# 2: 2015-10-11 10:01:02 a  2 1.9
# 3: 2015-10-11 10:01:04 a NA 2.0
# 4: 2015-10-11 10:01:05 a NA 1.8
# 5: 2015-10-11 10:01:02 b NA 5.0
# 6: 2015-10-11 10:01:01 c NA 4.1
# 7: 2015-10-11 10:01:01 c NA 4.2

就是这样。


如果不改变data.table,你就会以最快的方式接近。之前提交了以下功能请求:

FR#2300 Add backwards and firstback to roll=TRUE

我在这个问题上添加了一个链接。您可以在R-Forge上搜索功能请求列表。在这种情况下,像“roll”,“forward”和“backwards”这样的词语都能找到它。您可能需要4或5次尝试搜索尝试以确认错误或功能请求尚未提交。

我可能更快地实现该功能请求(内部只需要几行)而不是尝试,并为您提供最快的解决方法。