Search code examples
rdplyrgroup-bynatemperature

Group rows of values above and below specific threshold in R


I have a data frame of furnace temperature logged over time. I would like to determine when the temperature begins increasing (furnace turns on) and when temperature starts decreasing (furnace turns off).

I want to group temperatures above and below a set number and find the min/max values in the group to determine when the furnace turns on/off. As shown in the shaded plot below, grouping data points within the shaded regions and finding the min/max will yield the date and time when the furnace turns on/off.

I'm stuck on the Group variable. How can I group only the numeric values in AboveBelow without including cells with NA? The groups also need to be different so only the min/max within those groups are calculated.

Sample data: Creates a column of temperature above 95 and below 70 with the rest as NA:

library(tidyverse)

date_seq <- seq(as.POSIXct("2020-01-05 12:00:00"), 
            as.POSIXct("2020-01-05 12:07:10"), 
            by=(10))

a <- data.frame(Date = strftime(date_seq, format="%Y-%m-%d"),
             Time = strftime(date_seq, format="%H:%M:%S"),
            Temp=c(65,64,65,67,72,77,85,92,97,100,101,100,98,91,86,79,71,68,67,66,65,65,65,64,65,
                       67,72,77,85,92,97,100,101,100,98,91,86,79,71,68,67,66,65,66))

a <- a %>% mutate(AboveBelow= ifelse(Temp>95 | Temp<70, Temp, NA))

Grouping data points within the shaded regions, and finding the min/max will yield the date and time when the furnace turns on/off

Sample result:

   Date       Time       Temp       AboveBelow Group OnOff
1  2020-01-05 12:00:00   65         65         1      
2  2020-01-05 12:00:10   64         64         1     On
3  2020-01-05 12:00:20   65         65         1      
4  2020-01-05 12:00:30   67         67         1      
5  2020-01-05 12:00:40   72         NA         NA      
6  2020-01-05 12:00:50   77         NA         NA      
7  2020-01-05 12:01:00   85         NA         NA      
8  2020-01-05 12:01:10   92         NA         NA      
9  2020-01-05 12:01:20   97         97         2      
10 2020-01-05 12:01:30  100        100         2      
11 2020-01-05 12:01:40  101        101         2     Off
12 2020-01-05 12:01:50  100        100         2      
13 2020-01-05 12:02:00   98         98         2      
14 2020-01-05 12:02:10   91         NA         NA      
15 2020-01-05 12:02:20   86         NA         NA      
16 2020-01-05 12:02:30   79         NA         NA      
17 2020-01-05 12:02:40   71         NA         NA      
18 2020-01-05 12:02:50   68         68         3      
19 2020-01-05 12:03:00   67         67         3      
20 2020-01-05 12:03:10   66         66         3      
21 2020-01-05 12:03:20   65         65         3      
22 2020-01-05 12:03:30   65         65         3      
23 2020-01-05 12:03:40   65         65         3      
24 2020-01-05 12:03:50   64         64         3     On
25 2020-01-05 12:04:00   65         65         3      
26 2020-01-05 12:04:10   67         67         3      
27 2020-01-05 12:04:20   72         NA         NA      
28 2020-01-05 12:04:30   77         NA         NA      
29 2020-01-05 12:04:40   85         NA         NA      
30 2020-01-05 12:04:50   92         NA         NA      
31 2020-01-05 12:05:00   97         97         4      
32 2020-01-05 12:05:10  100        100         4      
33 2020-01-05 12:05:20  101        101         4     Off
34 2020-01-05 12:05:30  100        100         4      
35 2020-01-05 12:05:40   98         98         4      
36 2020-01-05 12:05:50   91         NA         NA      
37 2020-01-05 12:06:00   86         NA         NA      
38 2020-01-05 12:06:10   79         NA         NA      
39 2020-01-05 12:06:20   71         NA         NA      
40 2020-01-05 12:06:30   68         68         5      
41 2020-01-05 12:06:40   67         67         5      
42 2020-01-05 12:06:50   66         66         5      
43 2020-01-05 12:07:00   65         65         5     On
44 2020-01-05 12:07:10   66         66         5

Solution

  • You can use rle to create Group and with the help of case_when create OnOff column.

    library(dplyr)
    
    a %>%
      group_by(Group = with(rle(!is.na(AboveBelow)), rep(cumsum(values), lengths))) %>%
      mutate(OnOff = case_when(AboveBelow < 70 & Temp == min(Temp) ~ 'On', 
                               AboveBelow > 95 & Temp == max(Temp) ~ 'Off', 
                               TRUE ~ ''), 
             Group = replace(Group, is.na(AboveBelow), NA)) 
    

    which returns :

    #         Date     Time Temp AboveBelow Group OnOff
    #1  2020-01-05 12:00:00   65         65     1      
    #2  2020-01-05 12:00:10   64         64     1    On
    #3  2020-01-05 12:00:20   65         65     1      
    #4  2020-01-05 12:00:30   67         67     1      
    #5  2020-01-05 12:00:40   72         NA    NA      
    #6  2020-01-05 12:00:50   77         NA    NA      
    #7  2020-01-05 12:01:00   85         NA    NA      
    #8  2020-01-05 12:01:10   92         NA    NA      
    #9  2020-01-05 12:01:20   97         97     2      
    #10 2020-01-05 12:01:30  100        100     2      
    #11 2020-01-05 12:01:40  101        101     2   Off
    #12 2020-01-05 12:01:50  100        100     2      
    #13 2020-01-05 12:02:00   98         98     2      
    #14 2020-01-05 12:02:10   91         NA    NA      
    #15 2020-01-05 12:02:20   86         NA    NA      
    #16 2020-01-05 12:02:30   79         NA    NA      
    #17 2020-01-05 12:02:40   71         NA    NA      
    #18 2020-01-05 12:02:50   68         68     3      
    #19 2020-01-05 12:03:00   67         67     3      
    #20 2020-01-05 12:03:10   66         66     3      
    #21 2020-01-05 12:03:20   65         65     3      
    #22 2020-01-05 12:03:30   65         65     3      
    #23 2020-01-05 12:03:40   65         65     3      
    #24 2020-01-05 12:03:50   64         64     3    On
    #25 2020-01-05 12:04:00   65         65     3      
    #26 2020-01-05 12:04:10   67         67     3      
    #27 2020-01-05 12:04:20   72         NA    NA      
    #28 2020-01-05 12:04:30   77         NA    NA      
    #29 2020-01-05 12:04:40   85         NA    NA      
    #30 2020-01-05 12:04:50   92         NA    NA      
    #31 2020-01-05 12:05:00   97         97     4      
    #32 2020-01-05 12:05:10  100        100     4      
    #33 2020-01-05 12:05:20  101        101     4   Off
    #34 2020-01-05 12:05:30  100        100     4      
    #35 2020-01-05 12:05:40   98         98     4      
    #36 2020-01-05 12:05:50   91         NA    NA      
    #37 2020-01-05 12:06:00   86         NA    NA      
    #38 2020-01-05 12:06:10   79         NA    NA      
    #39 2020-01-05 12:06:20   71         NA    NA      
    #40 2020-01-05 12:06:30   68         68     5      
    #41 2020-01-05 12:06:40   67         67     5      
    #42 2020-01-05 12:06:50   66         66     5      
    #43 2020-01-05 12:07:00   65         65     5    On
    #44 2020-01-05 12:07:10   66         66     5