이번 포스팅에서는 장비별로 On, Off 상태 변화 간의 가동 시간(run time)을 구하고, 이렇게 구한 장비별 가동 시간의 평균을 집계해보겠습니다. 




먼저, 장비(device), 날짜/시간(time), status('ON', 'OFF') 의 3개 변수로 구성된 간단한 예제 DataFrame을 만들어보겠습니다. 



> #===========================

> # time difference by device

> #===========================

> device <- c('A', 'A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'C')

> time <- c('2018-07-01 10:20:23', '2018-07-01 10:30:55', '2018-07-01 11:11:01',

+           '2018-07-01 11:51:41', '2018-07-02 07:11:02', '2018-07-02 09:00:33',

+           '2018-07-02 09:20:24', '2018-07-02 12:12:21', '2018-07-02 14:01:09',

+           '2018-07-02 18:11:41', '2018-07-02 19:21:51', '2018-07-02 20:30:00')

> status <- c('ON', 'ON', 'ON', 'OFF', 'ON', 'ON', 'OFF', 'ON', 'OFF', 'ON', 'ON', 'OFF')

> df <- data.frame(device, time, status)


> df

   device                time status

1       A 2018-07-01 10:20:23     ON   <-- start

2       A 2018-07-01 10:30:55     ON

3       A 2018-07-01 11:11:01     ON

4       A 2018-07-01 11:51:41    OFF    <-- end


5       B 2018-07-02 07:11:02     ON    <-- start

6       B 2018-07-02 09:00:33     ON

7       B 2018-07-02 09:20:24    OFF    <-- end


8       C 2018-07-02 12:12:21     ON    <-- start

9       C 2018-07-02 14:01:09    OFF     <-- end

10      C 2018-07-02 18:11:41     ON    <-- start

11      C 2018-07-02 19:21:51     ON

12      C 2018-07-02 20:30:00    OFF     <-- end




다음으로 장비(device)와 날짜/시간(time)을 기준으로 정렬(sort)을 하겠습니다. 



> # sort df by device and time in ascending order

> df <- df[order(device, time),]

> df

   device                time status

1       A 2018-07-01 10:20:23     ON

2       A 2018-07-01 10:30:55     ON

3       A 2018-07-01 11:11:01     ON

4       A 2018-07-01 11:51:41    OFF

5       B 2018-07-02 07:11:02     ON

6       B 2018-07-02 09:00:33     ON

7       B 2018-07-02 09:20:24    OFF

8       C 2018-07-02 12:12:21     ON

9       C 2018-07-02 14:01:09    OFF

10      C 2018-07-02 18:11:41     ON

11      C 2018-07-02 19:21:51     ON

12      C 2018-07-02 20:30:00    OFF




각 장비(device) 별로 'ON' 이후에 다음 'OFF' 까지의 사이 중간에 끼어있는 'ON'은 필요가 없으므로 삭제를 해서 새로운 'df_2' 이름의 DataFrame을 만들어보겠습니다. 


[ 전처리 후의 Output Image ]


   device                time status

1       A 2018-07-01 10:20:23     ON   <-- start

2       A 2018-07-01 10:30:55     ON

3       A 2018-07-01 11:11:01     ON

4       A 2018-07-01 11:51:41    OFF    <-- end


5       B 2018-07-02 07:11:02     ON    <-- start

6       B 2018-07-02 09:00:33     ON

7       B 2018-07-02 09:20:24    OFF    <-- end


8       C 2018-07-02 12:12:21     ON    <-- start

9       C 2018-07-02 14:01:09    OFF     <-- end

10      C 2018-07-02 18:11:41     ON    <-- start

11      C 2018-07-02 19:21:51     ON

12      C 2018-07-02 20:30:00    OFF     <-- end

 





> # set of device

> device_set <- as.character(unique(df$device))

> # blank DataFrame to store the preprocessed dataset

> df_2 <- data.frame()

> for (i in 1:length(device_set)){

+   # split dataframe by device

+   device_i <- device_set[i]

+   df_i <- df[df$device == device_i, ]

+   

+   # add the first time of df_i to df2

+   df_2 <- rbind(df_2, df_i[1,])

+   

+   # add the time if the device is turned off or turned on again

+   for (j in 1:(nrow(df_i)-1)){

+     if((df_i$status[j] == 'ON' & df_i$status[j+1] == 'OFF') | 

+        (df_i$status[j] == 'OFF' & df_i$status[j+1] == 'ON')){

+       df_2 <- rbind(df_2, df_i[j+1,])

+     }

+   }

+ }

> df_2

   device                time status

1       A 2018-07-01 10:20:23     ON

4       A 2018-07-01 11:51:41    OFF

5       B 2018-07-02 07:11:02     ON

7       B 2018-07-02 09:20:24    OFF

8       C 2018-07-02 12:12:21     ON

9       C 2018-07-02 14:01:09    OFF

10      C 2018-07-02 18:11:41     ON

12      C 2018-07-02 20:30:00    OFF





lag() window function을 사용해서 장비, 날짜/시간, 상태를 한칸씩 밑으로 내리고(Lag), 장비 이름과 상태를 기준으로 필요한 행만 남기고 나머지는 삭제하겠습니다. 



> # lag window function

> library(dplyr)

> df_2_lag <- mutate(df_2, 

+                    device_lag = lag(device, 1), 

+                    time_lag = lag(time, 1), 

+                    status_lag = lag(status, 1))

> # filtering

> df_2_lag_filtered <- df_2_lag %>% 

 filter(device == device_lag & status == 'OFF')

> df_2_lag_filtered

  device                time status device_lag            time_lag status_lag

1      A 2018-07-01 11:51:41    OFF          A 2018-07-01 10:20:23         ON

2      B 2018-07-02 09:20:24    OFF          B 2018-07-02 07:11:02         ON

3      C 2018-07-02 14:01:09    OFF          C 2018-07-02 12:12:21         ON

4      C 2018-07-02 20:30:00    OFF          C 2018-07-02 18:11:41         ON




이제 장비(device)별로 'ON' 이후 다음번 'OFF' 까지의 가동 시간(run_time)을 difftime() 함수를 사용해서 구해보겠습니다. 이때 strptime() 함수를 사용해서 문자열 값을 '년/월/일/시간/분/초("%Y-%m-%d %H:%M:%S")' 형태로 만들어준 후에 difftime() 함수를 사용할 수 있습니다.  이렇 구한 가동시간은 '시간(hour)' 단위 값입니다. (분으로 환산하려면 곱하기 60, 초로 환산하려면 곱하기 60*60 을 해주면 됩니다) 



> # calculate the run_time

> df_2_lag_filtered$run_time <- as.numeric(difftime(strptime(df_2_lag_filtered$time, "%Y-%m-%d %H:%M:%S"),

+                                                   strptime(df_2_lag_filtered$time_lag, "%Y-%m-%d %H:%M:%S")))

> df_2_lag_filtered

  device                time status device_lag            time_lag status_lag run_time

1      A 2018-07-01 11:51:41    OFF          A 2018-07-01 10:20:23         ON 1.521667

2      B 2018-07-02 09:20:24    OFF          B 2018-07-02 07:11:02         ON 2.156111

3      C 2018-07-02 14:01:09    OFF          C 2018-07-02 12:12:21         ON 1.813333

4      C 2018-07-02 20:30:00    OFF          C 2018-07-02 18:11:41         ON 2.305278

 




마지막으로, 각 장비(device)별 가동시간(run_time)의 평균을 구해보겠습니다. 



> # average of run_time by device

> run_time_by_device <- df_2_lag_filtered %>% 

+   group_by(device) %>% 

+   summarise(run_time_avg = mean(run_time))

> run_time_by_device

# A tibble: 3 x 2

  device run_time_avg

  <fct>         <dbl>

1 A              1.52

2 B              2.16

3 C              2.06




많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요.



Posted by R Friend R_Friend

댓글을 달아 주세요

  1. 최고 2019.10.25 10:36  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 감사드립니다~

  2. 2019.11.06 15:47  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

  3. 2019.11.19 22:47  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

    • R Friend R_Friend 2019.11.19 23:01 신고  댓글주소  수정/삭제

      암명하세요 r린이님,

      교호작용항은 두 변수를 곱하는 방식으로 표현하시면 됩니다.

      가령, y~ be5a0 + beta1*x1 + beta2*x2 + beta3*x1*x2 (<== 교호작용항) 이런식으로요.

  4. 2019.11.19 23:13  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

  5. 2019.11.19 23:17  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

    • R Friend R_Friend 2019.11.19 23:22 신고  댓글주소  수정/삭제

      위의 댓글에 남겨주신 코드 중에

      %*% 를 * 로 수정해서 해보실래요?

      %*% 은 내적(dot product)을 할 때 사용하는 operator 여서 scalar (한개의 값, dot)을 반환합니다. (https://rfriend.tistory.com/145 )

      그냥 element-wise multiplication을 하시려면 * 만 사용하시면 됩니다.

      %*%를 사용해서 두 변수를 곱했기 때문에 값이 한개의 scalar값으로 반환되면서 벡터 길이가 다르다는 에러메시지가 난거 같습니다.

  6. 2019.11.19 23:30  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

  7. r린이 2019.11.19 23:41  댓글주소  수정/삭제  댓글쓰기

    감사합니다. 좋은 밤 되세요!