본문 바로가기

정리/데이터 분석

[R] 극값 Local Maximum(Minimum) Point With R

728x90
극값 Local Maximum(Minimum) Point With R


R 을 이용한 변곡점, 극값을 찾아보면 몇몇 잘못된 포스팅이 보입니다. 국내나 국외 모두요. 

이를 정리하고자 본 포스팅을 계획했습니다.


본 포스팅은 다음의 정보를 담고 있습니다. 

[1] 변곡점, 극값의 정의 

[2] R에서 극값 찾기, ggplot2으로 극값 그리기



이를 위해 bitcoin 데이터를 활용하겠습니다.



[1] 변곡점, 극값의 정의 


변곡점과 극값의 정의는 여기서 확인이 가능합니다. 

변곡점 : https://en.wikipedia.org/wiki/Inflection_point 

극값 : https://en.wikipedia.org/wiki/Maxima_and_minima


결국 변곡점은 두번 미분 가능한 함수에 대해 위로 볼록에서 아래로 볼록으로 변하는 점. 또는 그 반대입니다.

f’‘=0 이며 근방에서 f’’의 부호가 바뀌면 그 점이 볼록입니다.

따.라.서. f’=0 인 점과는 무관 합니다! 그러나 포스팅에 잘못 표현된 곳이 적지 않습니다.

여담입니다만 실제로 고객이 변곡점을 단순히 변곡이 발생한 지점 변동이 있는 점로 해석하며 오용하기도 합니다.

이런 경우 고객이 표현을 고쳐주십사 하겠지만 데이터 분석가의 경우 용어 정의에서 재정의하여 수용하는 것이 업무를 이해하는데 도움이 됩니다.

극값은 local max-min point 이므로 미분과 무관한 값입니다. 오히려 연속성이 의미가 있죠.

미분 가능한 함수에서는 극값은 f` =0 인 점이 됩니다. 그러나 현실세계에서는 완벽한 함수는 없습니다.

어떤 데이터간의 관계가 하나의 함수로 정의될 수 없다는 말입니다.

따.라.서. 현실세계 데이터로변곡점 , 극값을 다루기 위해서는 샘플 points가지고 smoothing 작업으로 미분 가능한 것처럼 다뤄줘야 합니다.



다음은 현재 다루고자 하는 데이터의 그래프 입니다.

library(ggplot2, verbose=F,quietly=T, warn.conflicts=F)
source(paste0(getwd(),'/../../bitcoin/config/formarkdown_config.R'))
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
res<-callBTCWON(callConnection(), "2018-10-01",NA)
res[['candleDT']]<-1:nrow(res)  # index
ggplot(data=res)+ geom_point(aes(x=candleDT, y=openingPrice))

여기서 극값을 찾아야 하는데요. 극값을 찾아보도록 하겠습니다.




[2] R에서 극값 찾기. ggplot2으로 극값 그리기.


다음은 인터넷에있는 극값 찾는 방법입니다.

## 극값 찾기
localMaxima <- function(x) {
  # Use -Inf instead if x is numeric (non-integer)
  y <- diff(c(-.Machine$integer.max, x)) > 0L
  rle(y)$lengths
  y <- cumsum(rle(y)$lengths)
  y <- y[seq.int(1L, length(y), 2L)]
  if (x[[1]] == x[[2]]) {
    y <- y[-1]
  }
  y
}
mm_points<-localMaxima(res$openingPrice)
mm<-data.frame(mm_points=mm_points, values=res[mm_points,]$openingPrice)


ggplot(data=res,aes(x=candleDT, y=openingPrice))+ geom_point()+ 
  geom_point(data=mm, aes(x=mm_points, y=values), color="red")

# length(res[mm_points,]$openingPrice)
# length(mm_points)

이건 stackoverflow 에서 확인한 내용인데 이것을 극값으로 받아들이긴 쉽지 않네요. 좀 더 가다듬어야 할 것 같습니다.

이번엔 Local Ploynomial Regression Fitting 을 활용해봤습니다.

lo <- loess(data=res, formula=openingPrice~candleDT)
x<-res$candleDT
xl <- seq(min(x),max(x), (max(x) - min(x))/30000)
out = predict(lo,xl)
pre<-data.frame(x=xl,out=out)
# ggplot(data=pre,aes(x=xl, y=out))+ geom_line()
ggplot(data=res,aes(x=candleDT, y=openingPrice))+ geom_line()+ 
  geom_line(data=pre, aes(x=xl, y=out), color="red")

위 그래프를 보면 아시겠지만 fitting 선의 민감도가 낮아보입니다. 추세정도로만 활용 가능하겠군요.

loess 의 degree 와 span 을 수정하며 찾아보죠.

lo <- loess(data=res, formula=openingPrice~candleDT, degree=2, span=0.01)  #k-d tree limited by memory. ncmax= 27509
x<-res$candleDT
xl <- seq(min(x),max(x), (max(x) - min(x))/length(res$candleDT))
out = predict(lo,xl)
pre<-data.frame(x=xl,out=out)
# ggplot(data=pre,aes(x=xl, y=out))+ geom_line()
ggplot(data=res,aes(x=candleDT, y=openingPrice))+ geom_line()+ 
  geom_line(data=pre, aes(x=xl, y=out), color="red")

실험 결과, degree=2 span=0.01 이 적당한 것 같네요.

0.0005 로 내리니 k-d tree limited by memory. ncmax= 27509 에러가 뜨는군요. 이건 나중에 알아보겠습니다.

candleDT= 20000 근처에 극대값에 정확히 닿지는 않지만 그냥 이정도로 만족해야겠군요.


다음은 위의 loess 결과값에서  극값을 찾는 방식입니다. (인터넷에서 구해옴))

(하지만 여전히 문제는 있습니다.)

infl <- c(FALSE, diff(diff(out)>0)!=0)  # 직전 값과의 관계로 극값 뽑음.연속 TRUE 이다가 FALSE 나오는 지점, FALSE 나오다가 TRUE 나오는 지점 
ggplot(data=res,aes(x=candleDT, y=openingPrice))+ geom_line()+ 
  geom_point(data=res[which(infl==T),], aes(x=candleDT, y=openingPrice), color="red")

 

 제가 원하는 극값과 상당히 유사해졌군요. 

여전히 못찾는 부분에 대해서는 다시 고민해보고 잡도록 해보겠습니다.

변곡점은 다음 포스팅으로 ~.