我正在尝试按序列对测量进行分组,填写runNumber列,如下所示。每次timetep重新启动时,都必须为该序列分配一个新的runNumber。 示例数据:
timestep robotid runNumber
1 0 1 1
2 0 2 1
3 1 1 1
4 2 2 1
5 0 1 2
6 1 1 2
7 1 2 2
第一次尝试适用于小型数据集,但实际数据需要很长时间。
mydata$runNumber <- 1
runcounter <- 1
for(counter in 2:nrow(mydata)){
if(mydata[counter-1, c("timestep")] > mydata[counter, c("timestep")]){
runcounter <- runcounter + 1
}
mydata[counter, c("runNumber")] <- runcounter
}
有没有更有效的方法来实现这一目标?提前致谢。
答案 0 :(得分:4)
数据:强>
df1 <- read.table(text = ' timestep robotid runNumber
1 0 1 1
2 1 1 1
3 2 2 1
4 0 1 2
5 1 1 2', header = TRUE)
df1$runNumber <- NULL # remove runNumber column
<强>代码:强>
如果时间步重新开始由值0
指示,那么我们可以检查它,然后从中获取逻辑向量的累积和。
within(df1, runNumber <- cumsum(timestep == 0))
# timestep robotid runNumber
# 1 0 1 1
# 2 1 1 1
# 3 2 2 1
# 4 0 1 2
# 5 1 1 2
使用data.table会更快。试试这个:
library('data.table')
setDT(df1)[, runNumber := cumsum(timestep == 0)]
df1
编辑:根据问题中发布的新数据
数据:强>
df1 <- read.table(text='timestep robotid runNumber
1 0 1 1
2 0 2 1
3 1 1 1
4 2 2 1
5 0 1 2
6 1 1 2
7 1 2 2')
df1$runNumber <- NULL
<强>代码:强>
library('data.table')
setDT(df1)[, runNumber := {
x <- rle(timestep == 0) # find run length for values = 0
y <- cumsum(x$lengths)[!x$values] # extract the indices
rep(seq_len(length(y)), c( y[1], diff(y))) # create group ids
} ]
df1
# timestep robotid runNumber
# 1: 0 1 1
# 2: 0 2 1
# 3: 1 1 1
# 4: 2 2 1
# 5: 0 1 2
# 6: 1 1 2
# 7: 1 2 2
答案 1 :(得分:0)
tidyr
包具有方便的fill
功能。假设每次重启时间步长== 0。
df<-read.table(header=TRUE, text="timestep robotid
0 1
1 1
2 2
0 1
1 1")
#find the number of starts
nstarts<-length(df$timestep[df$timestep==0])
#set each restart to the sequence
df$runNumber[df$timestep==0]<-1:nstarts
#fill the rows
library(tidyr)
fill(df, runNumber)