这是我作为data.frame的一部分的布尔样本:
atest <- c(FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
FALSE)
我想从每个FALSE返回一个从1开始的数字序列,然后增加1直到下一个FALSE.
得到的所需矢量是:
[1] 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1
Run Code Online (Sandbox Code Playgroud)
下面是实现此代码,但我敢肯定有一个更简单或更优雅的方式在R.做到这一点,我一直在努力学习如何R中更高效地编写代码的东西,而不是简单地完成工作.
result <- c()
x <- 1
for(i in 1:length(atest)){
if(atest[i] == FALSE){
result[i] <- 1
x <- 1
}
if(atest[i] != FALSE){
x <- x+1
result[i] <- x
}
}
Run Code Online (Sandbox Code Playgroud)
Jos*_*ich 19
这是一种方法,使用方便(但不是广为人知/使用)的基本功能:
> sequence(tabulate(cumsum(!atest)))
[1] 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1
Run Code Online (Sandbox Code Playgroud)
要打破它:
> # return/repeat integer for each FALSE
> cumsum(!atest)
[1] 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3
> # count the number of occurrences of each integer
> tabulate(cumsum(!atest))
[1] 10 10 1
> # create concatenated seq_len for each integer
> sequence(tabulate(cumsum(!atest)))
[1] 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1
Run Code Online (Sandbox Code Playgroud)
以下是使用其他熟悉功能的另一种方法:
seq_along(atest) - cummax(seq_along(atest) * !atest) + 1L
Run Code Online (Sandbox Code Playgroud)
因为它全部是矢量化的,所以它明显快于@Joshua的解决方案(如果速度有任何问题):
f0 <- function(x) sequence(tabulate(cumsum(!x)))
f1 <- function(x) {i <- seq_along(x); i - cummax(i * !x) + 1L}
x <- rep(atest, 10000)
library(microbenchmark)
microbenchmark(f0(x), f1(x))
# Unit: milliseconds
# expr min lq median uq max neval
# f0(x) 19.386581 21.853194 24.511783 26.703705 57.20482 100
# f1(x) 3.518581 3.976605 5.962534 7.763618 35.95388 100
identical(f0(x), f1(x))
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)