我有数据,其中连续的零运行被非零值的运行分隔。我想为“SOG”列中的零运行创建一个计数器。
对于 SOG 中的第一个 0 序列,将 Stops 列中的计数器设置为 1。对于第二次运行的零,将“Stops”设置为 2,依此类推。
SOG Stops
--- -----
4 0
4 0
0 1
0 1
0 1
3 0
4 0
5 0
0 2
0 2
1 0
2 0
0 3
0 3
0 3
我有数据,其中连续的零运行被非零值的运行分隔。我想为“SOG”列中的零运行创建一个计数器。
对于 SOG 中的第一个 0 序列,将 Stops 列中的计数器设置为 1。对于第二次运行的零,将“Stops”设置为 2,依此类推。
SOG Stops
--- -----
4 0
4 0
0 1
0 1
0 1
3 0
4 0
5 0
0 2
0 2
1 0
2 0
0 3
0 3
0 3
SOG <- c(4,4,0,0,0,3,4,5,0,0,1,2,0,0,0)
#run length encoding:
tmp <- rle(SOG)
#turn values into logicals
tmp$values <- tmp$values == 0
#cumulative sum of TRUE values
tmp$values[tmp$values] <- cumsum(tmp$values[tmp$values])
#inverse the run length encoding
inverse.rle(tmp)
#[1] 0 0 1 1 1 0 0 0 2 2 0 0 3 3 3
尝试
df$stops<- with(df, cumsum(c(0, diff(!SOG))>0)*!SOG)
df$stops
# [1] 0 0 1 1 1 0 0 0 2 2 0 0 3 3 3
使用dplyr
:
library(dplyr)
df <- df %>% mutate(Stops = ifelse(SOG == 0, yes = cumsum(c(0, diff(!SOG) > 0)), no = 0))
df$Stops
#[1] 0 1 1 1 0 0 0 2 2 0 0 3 3 3
编辑:对于我们这些仍然是初学者的人来说,这个问题的许多答案都使用了逻辑(即 TRUE、FALSE)。 !
在数字变量之前,例如SOG
测试值是否存在,如果是则0
赋值,否则。TRUE
FALSE
SOG
#[1] 4 0 0 0 3 4 5 0 0 1 2 0 0 0
!SOG
#[1] FALSE TRUE TRUE TRUE FALSE FALSE FALSE TRUE TRUE FALSE FALSE
#[12] TRUE TRUE TRUE
diff()
取值与之前的值之间的差。请注意,此列表中的元素比 in 少一个,SOG
因为第一个元素没有用于计算差异的滞后。当涉及到逻辑时,diff(!SOG)
产生1
for TRUE - FALSE = 1
、FALSE - TRUE = -1
和0
其他。
diff(SOG)
#[1] -4 0 0 3 1 1 -5 0 1 1 -2 0 0
diff(!SOG)
#[1] 1 0 0 -1 0 0 1 0 -1 0 1 0 0
所以cumsum(diff(!SOG) > 0)
只关注TRUE - FALSE
变化
cumsum(diff(!SOG) > 0)
#[1] 1 1 1 1 1 1 2 2 2 2 3 3 3
但由于差异列表短了一个元素,我们可以附加一个元素:
cumsum(c(0, diff(!SOG) > 0)) #Or cumsum( c(0, diff(!SOG)) > 0 )
#[1] 0 1 1 1 1 1 1 2 2 2 2 3 3 3
然后将该列表“乘以” !SOG
as in@akrun
的答案或使用该ifelse()
命令。如果是 的特定元素SOG == 0
,我们使用来自 的对应元素cumsum(c(0, diff(!SOG) > 0))
;如果不是0
,我们分配0
.
单线rle
将是-
df <- data.frame(SOG = c(4,4,0,0,0,3,4,5,0,0,1,2,0,0,0))
df <- transform(df, Stops = with(rle(SOG == 0), rep(cumsum(values) * values, lengths)))
df
# SOG Stops
#1 4 0
#2 4 0
#3 0 1
#4 0 1
#5 0 1
#6 3 0
#7 4 0
#8 5 0
#9 0 2
#10 0 2
#11 1 0
#12 2 0
#13 0 3
#14 0 3
#15 0 3