用 R 列中的下一个非零值替换 0

Replace 0s with next non-zero value in column R

别人给了我一个数据集,看起来有点像这样。

input = c(0,0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,2)

我需要做的是用下一个非零数字填充 0(它总是 1 或 2)。此外,下一个非零数字需要填充为下一个(最后一个值可以是任何值,因为无论如何我都会将其设置为 NA)。

所以函数应该return这个

> output =c(1,1,1,1,2,2,2,2,2,2,2,1,1,2,2,2,NA)
> cbind(input,output)
      input output
 [1,]     0      1
 [2,]     0      1
 [3,]     0      1
 [4,]     0      1
 [5,]     1      2
 [6,]     0      2
 [7,]     0      2
 [8,]     0      2
 [9,]     0      2
[10,]     0      2
[11,]     0      2
[12,]     2      1
[13,]     0      1
[14,]     1      2
[15,]     0      2
[16,]     0      2
[17,]     2     NA

谢谢!

-- 编辑部分 --

输出只需要是一个 array/vector(或者 R 中的任何合适的术语)。我将 2 绑定在一起的示例演示了 1 的偏移量以及填充。感谢大家的精彩回答

0 值设置为 NA 并使用 na.locf:

input[input==0] <- NA
na.locf(input, fromLast=TRUE)
## [1] 1 1 1 1 1 2 2 2 2 2 2 2 1 1 2 2 2

来自?na.locf

Generic function for replacing each NA with the most recent non-NA prior to it.

选择:

#find non-0s
x<-which(input!=0)
#replace 0s with subsequent nonzeros;
#  input[x] is the elements to replace
#  diff(c(0,x))-1 is the number of times to repeat
#    we need to pad x with a 0 to get initial 0s,
#    and we need to subtract 1 to ignore the nonzeros themselves
input[input==0]<-rep(input[x],diff(c(0,x))-1)
#replace nonzeros with the subsequent nonzeros
#  x[-1] removes the first element
#  we need to pad with NA as the final element
input[x]<-c(input[x[-1]],NA)

我又看了一遍,可能有点晦涩难懂;如果您想详细说明,请告诉我


编辑:

上面的方法对你的 input 非常有效,但如果有任何尾随的 0 就会失败。如果你的向量 v 上有尾随的 0s,这比较混乱但有效:

#as above
x<-which(v!=0)
#now, we need to integrate more NA replacement to this step
#  since we allow for 0s to finish v, also pad x with an end-of-vector marker
v[v==0]<-rep(c(v[x],NA),diff(c(0,x,length(v)+1))-1)
v[x]<-c(v[x[-1]],NA)

即使如此,它也比@MatthewLundberg 的建议(以牺牲可读性为代价)快得多(几乎是 4 倍)。然而,@PierreLafortune 的回答至高无上。仍然不确定它是如何工作的...

test<-sample(0:2,size=1e6,rep=T,prob=table2(input,prop=T))
microbenchmark(times=100L,matt(test),mike(test))

Unit: milliseconds
       expr       min        lq      mean    median        uq       max neval
 matt(test) 130.23987 130.70963 135.02442 131.23443 131.93079 183.73196   100
 mike(test)  36.27610  36.48493  36.66895  36.58639  36.73403  38.12300   100
 plaf(test)  22.18888  22.30271  23.08294  22.43586  22.65402  76.95877   100
output=input[!!input][cumsum(!!input)+1]
#[1]  1  1  1  1  2  2  2  2  2  2  2  1  1  2  2  2 NA

我们利用 R 如何将数字强制转换为逻辑值。 as.logical(0:2) 将 return FALSE TRUE TRUE。零变为 FALSE,其他数字被视为 TRUE。将否定感叹号放在 input 前面将其强制转换为合乎逻辑的。我本可以写成 as.logical(input),这只是节省几次击键的技巧。因此,我们使用该逻辑索引将非零值子集化为 input[!!input]。逻辑索引的累积总和 cumsum(!!input)+1 创建了一种在向其添加更改点时对更改点进行索引的快速方法。它有助于 运行 每个部分分开。