Finding local maxima and minima in R

你说的曾经没有我的故事 提交于 2019-11-28 10:22:25

问题


I'm trying to create a function to find a "maxima" and "minima". I have the following data:

  y
  157
  144
   80
  106
  124
   46
  207
  188
  190
  208
  143
  170
  162
  178
  155
  163
  162
  149
  135
  160
  149
  147
  133
  146
  126
  120
  151
   74
  122
  145
  160
  155
  173
  126
  172
   93

I have tried this function to find "maxima"

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
}

maks <- localMaxima(x)

And funtion to find "minima"

localMinima <- 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
    }

    mins <- localMinima(x)

And the result is not 100% right

maks = 1  5  7 10 12 14 16 20 24 27 31 33 35
mins = 3  6  8 11 13 15 19 23 26 28 32 34 36

The result should

maks = 5  7 10 12 14 16 20 24 27 31 33 35
mins = 3  6  8 11 13 15 19 23 26 28 32 34

Finding local maxima and minima in R comes close, but doesn't quite fit.

How can I fix this?

Thanks you very much


回答1:


You could define two functions like the below which produce the vectors you need:

library(data.table)
#shift lags or leads a vector by a certain amount defined as the second argument
#the default is to lag a vector.
#The rationale behind the below code is that each local minimum's adjucent
#values will be greater than itself. The opposite is true for a local 
#maximum. I think this is what you are trying to achieve and one way to do 
#it is the following code
maximums <- function(x) which(x - shift(x, 1) > 0  & x - shift(x, 1, type='lead') > 0)
minimums <- function(x) which(x - shift(x, 1) < 0  & x - shift(x, 1, type='lead') < 0)

Output:

> maximums(y)
 [1]  5  7 10 12 14 16 20 24 27 31 33 35
> minimums(y)
 [1]  3  6  8 11 13 15 19 23 26 28 32 34



回答2:


this is a function i wrote a while back (and it's more general than you need). it finds peaks in sequential data x, where i define a peak as a local maxima with m points either side of it having lower value than it (so bigger m leads to more stringent criteria for peak finding):

 find_peaks <- function (x, m = 3){
     shape <- diff(sign(diff(x, na.pad = FALSE)))
     pks <- sapply(which(shape < 0), FUN = function(i){
        z <- i - m + 1
        z <- ifelse(z > 0, z, 1)
        w <- i + m + 1
        w <- ifelse(w < length(x), w, length(x))
        if(all(x[c(z : i, (i + 2) : w)] <= x[i + 1])) return(i + 1) else return(numeric(0))
    })
     pks <- unlist(pks)
     pks
}

so for your case m = 1:

 find_peaks(x, m = 1)
 #[1]  5  7 10 12 14 16 20 24 27 31 33 35

and for the minima:

 find_peaks(-x, m = 1)
 #[1]  3  6  8 11 13 15 19 23 26 28 32 34


来源:https://stackoverflow.com/questions/34205515/finding-local-maxima-and-minima-in-r

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!