Sam Kh
Sam Kh

Reputation: 35

How Do I Find Consecutive Values

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

Answers (5)

Andrew
Andrew

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

Georgery
Georgery

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

arg0naut91
arg0naut91

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

Sotos
Sotos

Reputation: 51582

Here is another (less conventional) idea,

sum(tapply(x, cumsum(x != 1), FUN = length) == 4)
#[1] 2

Upvotes: 1

tmfmnk
tmfmnk

Reputation: 39858

One option could be:

sum(with(rle(x), lengths[as.logical(values)]) == 3)

[1] 2

Upvotes: 3

Related Questions