Lets say I have a data table like this.
customer_id time_stamp value
1: 1 223 4
2: 1 252 1
3: 1 456 3
4: 2 455 5
5: 2 632 2
这样customer_id 和time_stamp 一起形成一个唯一的key。我想添加一些新列,指示“值”的前一个值和最后一个值。也就是说,我想要这样的输出。
customer_id time_stamp value value_PREV value_NEXT
1: 1 223 4 NA 1
2: 1 252 1 4 3
3: 1 456 3 1 NA
4: 2 455 5 NA 2
5: 2 632 2 5 NA
我希望这个速度很快,并且可以处理稀疏、不规则的时间。我认为 data.table 滚动连接会为我做这件事。然而,滚动连接似乎找到了最后一次或同一时间。因此,如果您在同一个表的两个副本上执行滚动连接(在将 _PREV 添加到副本的列名之后),这并不完全有效。您可以通过在副本的时间变量中添加一个很小的数字来伪造它,但这有点尴尬。
有没有办法简单地使用 rollin join 或其他一些 data.table 方法来做到这一点?我找到了一种有效的方法,但它仍然需要大约 40 行 R 代码。如果可以告诉滚动连接查找最后一次不包括同一时间,这似乎是单行的。或者也许还有其他一些巧妙的技巧。
这是示例数据。
data=data.table(customer_id=c(1,2,1,1,2),time_stamp=c(252,632,456,223,455),value=c(1,2,3,4,5))
data_sorted=data[order(customer_id,time_stamp)]
这是我写的代码。请注意,将 NA 放入 customer_id 不同的行会引发警告并且可能需要更改。我在下面将它们注释掉。有人对更换这两条线有什么建议吗?
add_prev_next_cbind<-function(data,ident="customer_id",timecol="time_stamp",prev_tag="PREV",
next_tag="NEXT",sep="_"){
o=order(data[[ident]],data[[timecol]])
uo=order(o)
data=data[o,]
Nrow=nrow(data)
Ncol=ncol(data)
#shift it, put any junk in the first row
data_prev=data[c(1,1:(Nrow-1)),]
#shift it, put any junk in the last row
data_next=data[c(2:(Nrow),Nrow),]
#flag the rows where the identity changes, these get NA
prev_diff=data[[ident]] != data_prev[[ident]]
prev_diff[1]=T
next_diff=data[[ident]] != data_next[[ident]]
next_diff[Nrow]=T
#change names
names=names(data)
names_prev=paste(names,prev_tag,sep=sep)
names_next=paste(names,next_tag,sep=sep)
setnames(data_prev,names,names_prev)
setnames(data_next,names,names_next)
#put NA in rows where prev and next are from a different ident
#replace the next two lines with something else
#data_prev[prev_diff,]<-NA
#data_next[next_diff,]<-NA
data_all=cbind(data,data_prev,data_next)
data_all=data_all[uo,]
return(data_all)
}