在R中跟踪时间序列数据表中的更改
我有一个在R中跟踪时间序列数据表中的更改,r,performance,data.table,data-manipulation,R,Performance,Data.table,Data Manipulation,我有一个数据表如下 library(data.table) df = data.table( id = c(rep(1, 3), rep(2, 4), rep(3, 2)), time = c(seq(1, 3, 1), seq(1, 4, 1), seq(3, 4)), value1 = c(0, 0, 0, 0, 2, 0, 0, 0, 1), value2 = c(0, 1, 0, 1, 0, 0, 0, 0, 1) ) 哪种印刷品是这样的 id time
数据表
如下
library(data.table)
df = data.table(
id = c(rep(1, 3), rep(2, 4), rep(3, 2)),
time = c(seq(1, 3, 1), seq(1, 4, 1), seq(3, 4)),
value1 = c(0, 0, 0, 0, 2, 0, 0, 0, 1),
value2 = c(0, 1, 0, 1, 0, 0, 0, 0, 1)
)
哪种印刷品是这样的
id time value1 value2
1: 1 1 0 0
2: 1 2 0 1
3: 1 3 0 0
4: 2 1 0 1
5: 2 2 2 0
6: 2 3 0 0
7: 2 4 0 0
8: 3 3 0 0
9: 3 4 1 1
现在,我想创建两个新列,跟踪每个id
的值列中上次出现非零值的时间。我想要一个结果数据表,如下所示
id time value1 last_change1 value2 last_change2
1: 1 1 0 NA 0 NA
2: 1 2 0 NA 1 0
3: 1 3 0 NA 0 1
4: 2 1 0 NA 1 0
5: 2 2 2 0 0 1
6: 2 3 0 1 0 2
7: 2 4 0 2 0 3
8: 3 3 0 NA 0 NA
9: 3 4 1 0 1 0
有没有人有一个很好的解决方案,而且效果也很好
data.table
解决方案:现在可以使用尽可能多的非零值。感谢@Davidernburg指出。我必须说,这个例子应该考虑到这种情况
fun1 <- function(x) {
split(x,cumsum(x)) %>% lapply(function(x) {
if(any(x!=0)){ IND2<-(min(which(x!=0)):length(x));x<-NA;x[IND2]<-0:(length(IND2)-1);return(as.numeric(x))} else {x[]<-NA;return(as.numeric(x))}
}) %>% unlist %>% as.numeric
}
df[,`:=`(last_change1 = fun1(value1), last_change2 = fun1(value2)),by="id"]
一个选项是使用
zoo::na.locf
在value
列的相应行中为0
填入最后一个非零值的行号(特定于组)。最后,从当前行号中减去最后一个非零行号的行号
(按组,例如.I-.I[1]+1
)
编辑:根据@DavidArenburg
df[, c("last_change1", "last_change2") :=
lapply(.SD, function(x){.I - na.locf(ifelse(x == 0, NA_integer_, .I), na.rm = FALSE)}),
.SDcols = value1:value2, by=id]
#Modified df
df
# id time value1 value2 last_change1 last_change2
# 1: 1 1 0 0 NA NA
# 2: 1 2 0 1 NA 0
# 3: 1 3 0 0 NA 1
# 4: 2 1 0 1 NA 0
# 5: 2 2 2 0 0 1
# 6: 2 3 0 0 1 2
# 7: 2 4 0 0 2 3
# 8: 3 3 0 0 NA NA
# 9: 3 4 1 1 0 0
如果某个组中有多个非零值,这将不起作用。你能举个例子吗?我明天看一下。为整个数据集设置id=1
,看看你做了什么。我想你可以简化为函数(x).I-na.locf(ifelse(x==0,na\u integer,.I),na.rm=FALSE)
@DavidArenburg绝对是太棒了。我忽略了一个事实,.I[1]
最终将被取消。我会更新我的答案。
library(data.table)
library(zoo)
df[, c("last_change1", "last_change2") :=
lapply(.SD, function(x){as.integer((.I-.I[1]+1) - na.locf(as.integer(ifelse(x == 0, NA_integer_, .I-.I[1]+1)), na.rm = FALSE))}),
.SDcols = value1:value2, by=id]
df[, c("last_change1", "last_change2") :=
lapply(.SD, function(x){.I - na.locf(ifelse(x == 0, NA_integer_, .I), na.rm = FALSE)}),
.SDcols = value1:value2, by=id]
#Modified df
df
# id time value1 value2 last_change1 last_change2
# 1: 1 1 0 0 NA NA
# 2: 1 2 0 1 NA 0
# 3: 1 3 0 0 NA 1
# 4: 2 1 0 1 NA 0
# 5: 2 2 2 0 0 1
# 6: 2 3 0 0 1 2
# 7: 2 4 0 0 2 3
# 8: 3 3 0 0 NA NA
# 9: 3 4 1 1 0 0