Reputation: 35
Let´s assume I have this vector:
x <- c(1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0)
I want to find the amount of times we have ¨1¨ 3 consecutive times. For this I am using this code-
n.hot <- which(df, df$vector = 1,1,1)
What can I do to make it actually work? Thank you
Upvotes: 3
Views: 806
Reputation: 5138
If you want exactly three consecutive 1's or if you want at least three consecutive ones, here is a function using base R solution that utilizes cumsum()
(and diff()
. This just offsets the cumsum
vector to compare if there are n
consecutive ones. Right now it is designed to work with logical vectors or 0/1 vectors. And, if you have "at least"
as type it will select the first match, but it is easily adaptable to select the last if you wanted.
consecutive_n <- function(vector, n, type = c("equal", "at least")) {
length_vec <- length(vector)
cumsum_vec <- cumsum(vector)
difference <- cumsum_vec - c(rep(0, n), cumsum(vector)[-c((length_vec-n+1):length_vec)]) == n
type <- match.arg(type)
if(type == "equal") {
difference & c(0, diff(difference)) == 1
} else {
difference
}
}
consecutive_n(x, 3)
[1] FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
sum(consecutive_n(x, 3))
[1] 4
which(consecutive_n(x, 3))
[1] 5 10 14 21
sum(consecutive_n(x, 3, type = "at least"))
[1] 7
which(consecutive_n(x, 3, type = "at least"))
[1] 5 6 10 14 15 16 21
Data:
x <- c(1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0)
Upvotes: 0
Reputation: 8117
You can calculate the rolling sum and if it equals 3, you know it's what you want.
library(zoo)
x <- c(1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0)
threetogether <- rollsum(x, 3, fill = NA, align = "right")
threetogether == 3
Output:
[1] NA NA FALSE FALSE TRUE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE TRUE TRUE FALSE FALSE FALSE FALSE TRUE FALSE
Upvotes: 2
Reputation: 14764
In case 1 1 1 1
means for you that 1 1 1
actually appears twice, you could do:
sum(stats::filter(x, c(1, 1, 1), circular = TRUE, sides = 2) == 3)
[1] 7
Upvotes: 3
Reputation: 51582
Here is another (less conventional) idea,
sum(tapply(x, cumsum(x != 1), FUN = length) == 4)
#[1] 2
Upvotes: 1
Reputation: 39858
One option could be:
sum(with(rle(x), lengths[as.logical(values)]) == 3)
[1] 2
Upvotes: 3