전류분석 시뮬레이션 current IOT data simul Rstudio muti core

 IOT 데이터는 일반적으로, 초당 데이터베이스를 받는다. 하지만, 아래와 같은 케이스는 분단위로 데이터 셋을 받아도 연간 한개 포인트에 52만개의 데이터 이다. 이것과 관련 해서 7일 단위 30일 단위 평균을 구할 때, 속도의 문제가 발생 한다.

속도의 문제가 발생 할때, 우리는 어떻게 처리 해야 하며, 그리고, 데이터가 발생 할시 트렌드 분석을 해야 하는데, 트렌드는 비선형 형태로 데이터가 나타난다. 비선형 형태로 데이터가 나타 날때, 어떻게 Base line 신호를 주어야 하는 기준치를 나타낼 것인지 새로운 문제가 될것이다.


그럼 이것을 어떠한 방식으로 풀어 내는지 확인 해보자 .

# library loading
library(dplyr)
library(ggplot2)
library(lubridate)
library(ggplot2)
library(lubridate)

데이터가 52만개를 계산 해야 하기 때문에, 멀티코어 코딩을 하기 위해서 코어의 갯수를 등록 하여야 한다. 만약에 코어 갯수가 2개 이하인 경우에는 멀티코어를 돌릴 수 없음을 알고 있어야 한다. 현재 상황은 코어 갯수 12개이며, Base 리소스는 있어야 하니, 10개 가지고 연산 할 것이다.

# 코어 갯수     
  register_core <- detectCores() - 2
  registerDoMC(cores = register_core)

아래는 random seed 값을 고정 하는 것이다. random seed를 고정 하지 않으면 ramdom 데이터 셋을 만들때마다 값이 바뀐다. 필요시 해야 한다.

# random 값 고정
 set.seed(1004)

분단위 데이터 셋을 만들려면, 하루에 1440개의 데이터 셋을 만들어야 한다. 그럴혀면 시작 데이터와 끝나는 데이터를 만든다. 이것은 R base libray에 탑재 되어 있으므로, 그냥 사용하면 된다.

# 시작일과 종료일을 정하기 
  start_date <- as.Date("2021-01-01")
  end_date <- as.Date("2021-12-31")
  
# 1년치 날짜  만들기   
  year_date <-  seq(from = start_date, to = end_date, by =1 )
  year_sensor_date  <- rep(year_date, each = 1440) #  1분 집계로 데이터 분리하기   

seq는 수열을 생성 하는 것으로 시작값과 종료값과 증분을 입력 하면 된다. 여기 예제는 1년치 365일치 데이터를 만들어야 하므로, 증분을 1로 하였다. 그리고, rep는 반복 하는 명령어 이므로, 1일당 1440분을 반복 한다.

# data 평균이 12이고 표준편차 2인 정규분포  
  current <- rnorm(length(year_sensor_date),12,2) 
 
# DataFrame기    
 df <- data.frame(일 = year_sensor_date, 전류값 = current)
 summary(current) 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    2.08   10.65   12.00   12.00   13.35   21.35

시뮬레이션 데이터를 정규분포로 만든다. 위 자료는 평균이 12이고 표준편차가 2인 정규분포를 만드는 것이다. 그러면, 정상적인 상태의 IOT 데이터가 만들어 진다. 설비의 설계가 문제가 없다면, 정규 분포 형태로 IOT 데이터의 흐름이 만들어 길것이다.

아래는 원데이터를 나타낸 것이다. 원단위로 데이터를 만들때, 일정 한 파형으로 분산이 만들어 질것이다. 데이터가 52만개 데이터를 그래프에서 표현 하므로 시간 많이 걸린다. 한 달치만 필터 걸어서 연산 하겠다.

 df %>% 
   filter(일>= "2021-01-01" &  일 <= "2021-01-31") %>% 
   ggplot(aes(x=일, y = 전류값, color = "red")) +
        geom_line()
IOT 원데이터

위와 같이 원데이터를 하면 편차가 많이 생기는 것을 볼수 있다. 그러나, 아래와 같이 일평균으로 데이터를 보면 적다는 것을 볼수 있다. 아래의 코드를 설명 하면, dplyr의 group_by() 함수와 summarise() 함수를 조합 해서 일단위 평균을 구한 것이다.

# 일단위 평균 구하기 
  df %>%  
    group_by(일) %>% 
    summarise(일전류 =  mean(전류값)) 
## # A tibble: 365 × 2
##    일         일전류
##    <date>      <dbl>
##  1 2021-01-01   11.9
##  2 2021-01-02   12.0
##  3 2021-01-03   12.0
##  4 2021-01-04   12.0
##  5 2021-01-05   12.0
##  6 2021-01-06   11.9
##  7 2021-01-07   12.1
##  8 2021-01-08   12.0
##  9 2021-01-09   12.0
## 10 2021-01-10   12.0
## # … with 355 more rows

일단위로 하였을때는 1,440개를 평균으로 계산 하였기 때문에, 평균의 편차가 적어 졌다. 그러면 우리가 원하는 평균일자와 기간을 구하여 연산하는 함수는 아래와 같다.

# 일단위로 데이터셋 구하기 
  days <- unique(df$일)      

  
# 30일 기준이 되는 데이터 셋 구하기        
  cal_date_fun <- function(i, x) {  
    start <- days[i] 
    end <- as.Date(start +  days(x))
    start <- as.Date(start)
    
    date_df <- data.frame(start, end)
    
    return(list(date_df)) 
  }         
  
# 30일 단위 평균 값 만들기  
  current_fun <- function(i) { 
    start <-date_df$start[i] 
    end <- date_df$end[i]
    
    cur_df <-   df %>% 
      filter(일 >= start) %>% 
      filter(일 <= end) %>% 
      summarise(평균 = mean(전류값)) %>% 
      mutate(일 = end)
    
    return(cur_df)
  }

함수는 어떠한 인수를 넣고 계산 한 다음에 결과 값을 리턴 하는데, 사용된다. 아래의 함수 중에서 cal_date_fun(i,x)는 계산 하고자하는 기간을 정하는 것이다. 만약에 30일 평균을 한다고 하면, 2021-01-31 부터 계산이 될 것이다.

# 일단위로 데이터셋 구하기 
  days <- unique(df$일)      

  
# 기준이 되는 데이터 셋 구하기        
  cal_date_fun <- function(i, x) {  
    start <- days[i] 
    end <- as.Date(start +  days(x))
    start <- as.Date(start)
    
    date_df <- data.frame(start, end)
    
    return(list(date_df)) 
  }         
  
# 일단 단위 평균 값 만들기  
  current_fun <- function(i) { 
    start <-date_df$start[i] 
    end <- date_df$end[i]
    
    cur_df <-   df %>% 
      filter(일 >= start) %>% 
      filter(일 <= end) %>% 
      summarise(평균 = mean(전류값)) %>% 
      mutate(일 = end)
    
    return(cur_df)
  }

위 함수를 이용하여, 7일 평균과 3일 평균을 가져올 것이다. 아래 함수에 파라메터를 넣고, 데이터를 돌린다. x는 30일일때, 계산 할 수 있는 구간을 만들고, 30일 평균 데이터를 돌리는 것이다.

# 파라메터 넣고 평균 데이터 가져오기   
#### x 가 30일 일때 데이터 셋 가져오기   
# x가 30일 때의 데이터 셋 가져오기 
  x <- 30   # 데이터 입력 파라메터 
  
# 최대로 구할 수 있는 데이터 만들기   
  y <- 1:(length(days) - x)
  
# mapply로 데이터 정리 하기  
  date_df <-   data.frame(do.call(rbind,mapply(cal_date_fun, y, x)))     
  
# 30일 평균 전류 가져오기 
  # system.time(
  # mylist <-  sapply(y, current_fun)  
  # )
  
# 멀티코어 코딩   
 system.time(
    mylist <- mclapply(y, current_fun, mc.cores = register_core)
 )
##  사용자  시스템 elapsed 
##   9.412   1.236   1.472

데이터가 많아 멀터코어(10core) 연산을 하였다. 만약에 아래와 같이 멀티코어 연산을 하지 않으면, 아래와 같이 속도가 조금 늦다. 데이터가 아주 많을 때에는 멀티코어 연산이 매우 유리 하다.

# 일반 sapply로 함수 리턴
 system.time(
    test_list <- sapply(y, current_fun)
 )
##  사용자  시스템 elapsed 
##   4.434   0.040   4.474

list 값을 데이터 프레임으로 가져오는 것이다.

# 데이터 셋 가져오기 
  cur_30_df <- data.frame(do.call(rbind,mylist))  %>% 
    rename(일평균30 = 평균)

아래는 7일일때, 함수의 파라메터를 넣고, 데이터를 돌리는 것이다.

### x 가 7일일때 데이터 셋 가져오기 
# x가 7일 때의 데이터 셋 가져오기 
  x <- 7   # 데이터 입력 파라메터 
  
# 최대로 구할 수 있는 데이터 만들기   
  y <- 1:(length(days) - x)
  
# mapply로 데이터 정리 하기  
  date_df <-   data.frame(do.call(rbind,mapply(cal_date_fun, y, x)))    
  
# 7일 평균 전류 가져오기 
 # mylist <-  sapply(y, current_fun)
  system.time(
    mylist <- mclapply(y, current_fun, mc.cores = register_core)
  )
##  사용자  시스템 elapsed 
##   6.864   0.760   1.193
# 7일 평균 전류 데이터 프레임 만들기   
 cur_7_df <- data.frame(do.call(rbind,mylist))  %>% 
    rename(일평균7 = 평균)  

IOT 데이터 셋을 일평균을 만든 다음에 ggplot2의 geom_smooth() 함수를 사용하면 loess하이퍼 파라메터를 이용하여, 평균 시계열 데이터로 평활화 한다.

##### 1일 평균 전류 가져오기  
# 1일 평균 전류 가져오기 
  cur_day_df <-  df %>% 
    group_by(일) %>% 
    summarise(일평균 = mean(전류값)) %>% 
    mutate(일 = as.Date(일))
  
# 1일 평균 데이터 hyper parameter 적용
  cur_day_df %>% 
    ggplot(aes(일, 일평균, color = "red")) +
    geom_line() + 
    geom_smooth()
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

ggplot2 데이터 평활화




일평균, 7일평균 30일 평균 데이터를 같이 그래프에 plot 시키려면, 앞에서 계산한, 1일 평균과 7일평균 30일 평균 데이터를 join(조인) 해야 한다.

# 데이터 조인 하기 
  current_set <- cur_day_df %>% 
    left_join(cur_7_df) %>% 
    left_join(cur_30_df) %>% 
    mutate(일평균7 = ifelse(is.na(일평균7), 0, 일평균7)) %>% 
    mutate(일평균30 = ifelse(is.na(일평균30), 0, 일평균30))
## Joining, by = "일"
## Joining, by = "일"

하지만, currnet_set 자료는 엑셀에서는 표현 하기 쉬우나, ggplot2에서는 tidyr에 탑재 된 gather() 함수를 이용해서 데이터 세로로 된것을 가로로 세운 다음 각 분류(1일, 7일,30일) 별로그룹화 하여 그림을 그린다.

# 그래프를 그리기 위한 gather 작업 하기 
  cur_plot <-  current_set %>%
    gather(key = "분류", value = "전류값", -c(일)) 

# ggplot2로 그래프 그리기       
  cur_plot %>%
    filter(일 >= "2021-02-01") %>% 
    group_by(분류) %>% 
    ggplot(aes(일, 전류값, group = 분류, color = 분류)) +
    geom_line()
일평균, 30일 평균, 7일 평균 데이터 셋 가져오기 


위와 같이 데이터셋을 1년치 그렸을 경우에는  어느 정도의 패턴이 나나타는데, 평균 일수가 많을 수록 분산의 범위가 좁다.   하지만,  이것을 가지고 절대 적인 기준으로 잡기에는 매우 어렵니다. 


댓글 없음:

댓글 쓰기

css cheat sheet 클래스 선택자, margin(마진), display , center 조정 간단한 구성 요소

 앞에서는 html의 간단한 sheet를 소개 하였습니다.   html은  주로 골격을 나타나는 것이라, 디자인을 하는데는 css로 하여야 합니다.  아래 코드와 같이 css 관련 하여 매우 간단하게 코딩 하겠습니다.  body 부분의 css 코딩  ...