简体   繁体   中英

Finding start and end of a peak in time series in R

I am working on NDVI Time-Series Data which has 23 observations in a year. I am able to detect the peaks occurring between the 14 - 19 observation . Now I want to find the start and end of the Peak . I am able to find the start and end of peak by looking for sign change using diff function . But in some cases I am note able to find the end, as end of the peak is in next year. Solution is to repeat the values after 23 observation to make it cyclic and find the end.

Example given below will explain the problem in detail

x = c(250.7943,292.2904,340.459,368.811,363.4534,330.2302,291.6527,275.2815,299.9305,367.0331,461.2618,559.0772,639.6197,691.723,713.9833,709.5409,680.4415,626.1153,547.0395,450.4623,353.0839,277.257,241.597)

在此处输入图片说明

在此处输入图片说明

I am looking for sign change from the Peak in both direction and able to find the start of the peak at 8 observation but when I am looking for the end starting from Peak I am not able to find any change till 23. In this case I should get the end the peak at 23. As shown in table I have repeated the values manually in Excel to get the Sign change.

How this can be done in R???

One solution may be that putting a condition to check if sign change is not found till 23 observation then all 23 values will be padded at end of the vector and then look for the sign change.

Is there a simple approach to accomplish this???

Another possibility: (1) Pad your values with leading and lagging Inf to create dummy local minima* in the start and end of the time series. (2) Find indexes of all minima (including the dummies). (3) Find indexes of the two minima which are next to the maximum.

# pad values with Inf and get indexes of all local minima
i.mins  <- which(diff(sign(diff(c(Inf, x, Inf)))) == 2)

# index of max value
i.mx <- which.max(x)

# combine indexes of local minima and the max
i <- sort(c(i.mins, i.mx))

# select the two minima on either side of the max  
ix <- i[which(i == i.mx) + c(-1, 1)]
ix 
# [1]  8 23

plot(x, type = "b")
points(x = c(ix[1], i.mx, ix[2]),
       y = c(x[ix[1]], max(y), x[ix[2]]),
       col = c("blue", "red", "blue"), pch = 19, cex = 2)

在此处输入图片说明


*See eg Finding local maxima and minima

This is just to create a reproducible example:

y = data.frame(x = x, y = c(x[2:length(x)], NA))
y$diff <- y$y - y$x 

Then we start by generating a new column:

y$startEndPeak <- NA

Afterwards we loop over the data.frame holding all difference records. Thus we identify start/end points and peaks by comparing all differences with their previous conterpart:

for(i in 2:(nrow(y) - 1)){
  thisDif <- y$diff[i]
  prevDif <- y$diff[i-1]

  if (thisDif < 0 && prevDif > 0){
    y$startEndPeak[i] <- "start/end"
  }

  if (thisDif > 0 && prevDif < 0){
    y$startEndPeak[i] <- "peak"
  }

}
y

#         x        y     diff      startEndPeak
#   1  250.7943 292.2904  41.4961         <NA>
#   2  292.2904 340.4590  48.1686         <NA>
#   3  340.4590 368.8110  28.3520         <NA>
#   4  368.8110 363.4534  -5.3576    start/end
#   5  363.4534 330.2302 -33.2232         <NA>
#   6  330.2302 291.6527 -38.5775         <NA>
#   7  291.6527 275.2815 -16.3712         <NA>
#   8  275.2815 299.9305  24.6490         peak
#   9  299.9305 367.0331  67.1026         <NA>
#   10 367.0331 461.2618  94.2287         <NA>
#   11 461.2618 559.0772  97.8154         <NA>
#   12 559.0772 639.6197  80.5425         <NA>
#   13 639.6197 691.7230  52.1033         <NA>
#   14 691.7230 713.9833  22.2603         <NA>
#   15 713.9833 709.5409  -4.4424    start/end
#   16 709.5409 680.4415 -29.0994         <NA>
#   17 680.4415 626.1153 -54.3262         <NA>
#   18 626.1153 547.0395 -79.0758         <NA>
#   19 547.0395 450.4623 -96.5772         <NA>
#   20 450.4623 353.0839 -97.3784         <NA>
#   21 353.0839 277.2570 -75.8269         <NA>
#   22 277.2570 241.5970 -35.6600         <NA>
#   23 241.5970       NA       NA         <NA>

then we use vectors to place start and end points

y$startEndPeak[which(y$startEndPeak == "start/end")] <- c("start", "end")
y
#            x        y     diff startEndPeak
# ...........
#   3  340.4590 368.8110  28.3520         <NA>
#   4  368.8110 363.4534  -5.3576        start
# ...........
#   8  275.2815 299.9305  24.6490         peak
# ...........
#   15 713.9833 709.5409  -4.4424          end
# ...........

Usimg Loki's Approach I am able to partially solve my problem....

y = data.frame(x = x, y = c(x[2:length(x)], x[1]))

y$diff <- y$y - y$x
y$startEndPeak <- NA

for(i in 2:(nrow(y))){
  thisDif <- y$diff[i]
  prevDif <- y$diff[i-1]

  if (thisDif < 0 && prevDif > 0){
      y$startEndPeak[i] <- "peak"
     }


  if (thisDif > 0 && prevDif < 0){
      y$startEndPeak[i-1] <- "end"
      y$startEndPeak[i] <- "start"
   }
}

y
  #      x        y     diff startEndPeak
  # 250.7943 292.2904  41.4961         <NA>
  # 292.2904 340.4590  48.1686         <NA>
  # 340.4590 368.8110  28.3520         <NA>
  # 368.8110 363.4534  -5.3576         peak
  # 363.4534 330.2302 -33.2232         <NA>
  # 330.2302 291.6527 -38.5775         <NA>
  # 291.6527 275.2815 -16.3712          end
  # 275.2815 299.9305  24.6490        start
  # 299.9305 367.0331  67.1026         <NA>
  # 367.0331 461.2618  94.2287         <NA>
  # 461.2618 559.0772  97.8154         <NA>
  # 559.0772 639.6197  80.5425         <NA>
  # 639.6197 691.7230  52.1033         <NA>
  # 691.7230 713.9833  22.2603         <NA>
  # 713.9833 709.5409  -4.4424         peak
  # 709.5409 680.4415 -29.0994         <NA>
  # 680.4415 626.1153 -54.3262         <NA>
  # 626.1153 547.0395 -79.0758         <NA>
  # 547.0395 450.4623 -96.5772         <NA>
  # 450.4623 353.0839 -97.3784         <NA>
  # 353.0839 277.2570 -75.8269         <NA>
  # 277.2570 241.5970 -35.6600          end
  # 241.5970 250.7943   9.1973        start

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM