2

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(). 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)

enter image description here

enter image description here

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???

user438383
  • 5,716
  • 8
  • 28
  • 43
gis.rajan
  • 517
  • 3
  • 20

3 Answers3

5

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)

enter image description here


*See e.g. Finding local maxima and minima

Community
  • 1
  • 1
Henrik
  • 65,555
  • 14
  • 143
  • 159
  • @ Henrik, I tried your code but its not working... Problem is in second part of the code `mins[sort(abs(mins - which.max(y)))[1:2]]`. `mins <- which(diff(sign(diff(c(Inf, x, Inf)))) == 2)` `mins` `# [1] 1 8 23` `mins[sort(abs(mins - which.max(x)))[1:2]]` `# [1] NA NA` – gis.rajan Feb 12 '17 at 02:02
  • I have done it another way... thanks for the code... I will check it and inform you... – gis.rajan Feb 14 '17 at 17:21
1

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
# ...........
loki
  • 9,816
  • 7
  • 56
  • 82
  • @ loki thanks for the reply.. but u got it wrongly... If u see the example image above... there are two peaks in one is at 4 and one is at 15. But I am only interested in the second Peak i.e. 15. for this Start will be at 8 and end will be 23. In your solution Start is at 4 which is first peak in my example, Peak is at 8 which is Start of second peak in my example and end is at 15 which is second peak in my example.. But I have got some idea from your example which I can use to solve my problem... – gis.rajan Feb 11 '17 at 16:04
1

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
gis.rajan
  • 517
  • 3
  • 20