已经提出了类似的问题,我一直试图将各种答案(mobilePhone
,rle
等)拼凑起来,但这需要花费数小时的时间,而我仍然没有到那儿。
我的数据集的列只包含cumsum
/ TRUE
,例如:
FALSE
对于每组连续x <- c(FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE)
值,我想计算该集合中TRUE
的数量。可以忽略TRUE
值,即我想要输出上述数据,如下所示:
FALSE
答案 0 :(得分:5)
基础R中的一个简单的:
ave(x, cumsum(!x), FUN = cumsum)
#[1] 0 0 1 2 3 0 1 0 1 2 0
答案 1 :(得分:4)
sequence(rle(x)$lengths) * x
#[1] 0 0 1 2 3 0 1 0 1 2 0
或者,如果您可以考虑非base
(10^6
向量的速度提高约20倍)
library(data.table)
rowid(rleid(x))*x
# [1] 0 0 1 2 3 0 1 0 1 2 0
答案 2 :(得分:3)
可能有点难看,但在这里我们使用rle()
来查找TRUE值的运行。然后使用seq.int()
索引组(这也将使组成FALSE),但我们乘以该值,使FALSE索引变为0。
x <- c(FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE)
with(rle(x), unlist(Map(`*`, sapply(lengths, seq.int), values)))
# [1] 0 0 1 2 3 0 1 0 1 2 0
答案 3 :(得分:3)
爵士 考虑专门为运行计数,求和等创建的runner包。完全用C ++编写。
devtools::instal_github("gogonzo/runner")
library(runner)
x <- c(FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, FALSE)
streak_run(x)*x
# [1] 0 0 1 2 3 0 1 0 1 2 0
函数streak_run
计算连续出现的TRUE和FALSE,并乘以x
是这种情况下ifelse的更快更简单的版本。
还可以指定k
参数,该参数定义窗口大小。窗口大小可以是常量,也可以由相同长度的其他矢量指定。
答案 4 :(得分:2)
您可以使用Reduce
我们添加数字,但如果下一个数字为零,我们会再次开始添加。它用ifelse调整cumsum
函数。即。 Reduce(function(a,b),a+b,x,,T)
是cumsum(x)
函数。现在我们只引入ifelse
语句,以便下一个值为零时,将总和设置为零并再次开始添加。这是代码:
Reduce(function(a,b)ifelse(b==0,0,a)+b,x,accumulate = T)
[1] 0 0 1 2 3 0 1 0 1 2 0
您也可以使用<<-
并实施与上述相同的逻辑
c(b<-0,sapply(x,function(a)b<<-ifelse(a==0,b<-0,a)+b))[-1]#Remove the first b<-0 that I added
[1] 0 0 1 2 3 0 1 0 1 2 0
在第一个中,累计金额为a
,而在第二个累计金额为b
答案 5 :(得分:2)
总是有一些有趣的方法来使用cumsum
来做这种反击:
x[x] <- ave(x[x], cumsum(!x)[x], FUN=seq_along)
x
# [1] 0 0 1 2 3 0 1 0 1 2 0
答案 6 :(得分:1)
以下是使用split
和cumsum
的另一个选项:
unlist(sapply(split(x, cumsum(x == FALSE)), cumsum), use.names = F)
# [1] 0 0 1 2 3 0 1 0 1 2 0
以下是目前所有解决方案的microbenchmark
结果:
library(microbenchmark);
library(runner);
set.seed(2017);
x <- sample(c(TRUE, FALSE), 10^4, replace = T);
microbenchmark(
cumsum_thelatemail = ave(x[x], cumsum(!x)[x], FUN=seq_along),
reduce_Onyambu = Reduce(function(a,b)ifelse(b==0,0,a)+b,x,accumulate = T),
rle_MrFlick = with(rle(x), unlist(Map(`*`, sapply(lengths, seq.int), values))),
runner_Gonzo = streak_run(x)*x,
sequence_Henrik = sequence(rle(x)$lengths) * x,
split_Evers = unlist(sapply(split(x, cumsum(x == FALSE)), cumsum), use.names = F)
)
#Unit: microseconds
# expr min lq mean median uq
# cumsum_thelatemail 3569.336 3713.939 4196.6491 3802.570 4115.896
# reduce_Onyambu 40599.427 41884.466 45887.2020 43222.302 49277.158
# rle_MrFlick 9349.131 9907.766 11353.1854 10602.481 11213.147
# runner_Gonzo 275.912 293.085 316.6987 295.656 300.059
# sequence_Henrik 2696.624 2840.593 3177.7400 2956.738 3179.673
# split_Evers 4772.078 4954.352 5423.3227 5193.803 5528.410
# max neval
# 11360.39 100
# 103999.41 100
# 46731.03 100
# 538.49 100
# 11670.56 100
# 13607.49 100