0

I have a data.frame column with hourly values and want to count all negative values, if they are in a sequence of at least six consecutive negatives.

Example:

df <- data.frame(Values=c(-2, 2, 3, 4,-1,-1,-2,-3,
                          -1,-1,-1, 5, 4, 2,-4,-2,
                          -3,-4,-1, 3, 4, 4,-3,-1,
                          -2,-2,-3,-4))

The expected result would be 13, since the middle sequence of consecutive negatives contains only five negatives and is thus not counted.

Rich Scriven
  • 97,041
  • 11
  • 181
  • 245
brnwa
  • 25
  • 4
  • 1
    Have you tried anything yet? Where are you stuck? – TayTay Nov 02 '15 at 21:26
  • I searched for similar Questions here and found solutions like this one: http://stackoverflow.com/questions/19998836/r-count-consecutive-occurrences-of-values-in-a-single-column But I dont know if this also works for my Problem and if, how to adapt since I am not so experienced with R. – brnwa Nov 02 '15 at 21:29

3 Answers3

3

You could use the base function rle() along with sign(). The sign() function converts negatives and positives to -1 and 1, respectively. This makes a nice vector to pass to rle() to get the run-lengths. Then we can subset the run-lengths with the desired condition and take the sum.

with(rle(sign(df$Values)), sum(lengths[lengths >= 6 & values < 0]))
# [1] 13
Rich Scriven
  • 97,041
  • 11
  • 181
  • 245
2

Try:

library(cgwtools)
res <- seqle(which(df<0))
sum(res$lengths[res$lengths>=6])
[1] 13
DatamineR
  • 10,428
  • 3
  • 25
  • 45
  • This is a great answer. So much more concise than I would've imagined! – TayTay Nov 02 '15 at 21:45
  • 1
    Thanks Tgsmith! I always try to keep the code as concise as possible. To cite Churchill: "The best speeches are the shortest ones".I think this applies to code too :-) – DatamineR Nov 02 '15 at 21:52
0

you can always define your own function and call it.

NegativeValues <- function(x) {
   count <- 0
   innercount <- 0
   for (i in c(x, 0)) {
      if (i < 0) {
         innercount <- innercount + 1
      }
      else {
         if (innercount >= 6)
            count <- count + innercount
         innercount <- 0
      }      
   }
   return(count)
}

NegativeValues(df$Values)
gisi
  • 1