0
votes

Following this answer, I'm trying to find the local minima of a function. Here is what I'm doing:

require(ggplot2)
require(zoo)

x <- seq(0, 25, by=0.1)
y <- sin(x)

my.df <- data.frame(x, y)

xz <- as.zoo(y)
rxz <- zoo::rollapply(xz, width = 20, align = "center", function(x) which.min(x)==2)

indexes <- index(rxz)[coredata(rxz)]
indexes

ggplot(my.df, aes(x, y)) + geom_line() + geom_vline(xintercept = my.df$x[indexes])

Plotting the results gives:

enter image description here

I guess the x offset is due to the width I use, but can't figure out why this happens, as rollapply supposed to use a centred rolling window.

1
Tangent: you're using require wrong: it never stops following code when the package is not available, which is almost never what is intended. Either use require and check the return value, or use library. Refs: stackoverflow.com/a/51263513r2evans
Thanks for the tip! Generally, I don't use require in my functions because they are within a package that imports the necessary dependencies with roxygen. I only use it to provide working snippets. I'll use library from now on :)Ben

1 Answers

3
votes

Two suggestions:

  1. Based on @IceCreamToucan's comment, your use of ==2 might be more appropriate as 10 or 11, due to your width of 20.

  2. To mitigate the problem of determine which of 10 or 11 is more appropriate (since you have an even-width kernel), I suggest an odd-width kernel.

wid <- 21L
ceiling(wid/2)
# [1] 11
rxz <- zoo::rollapply(y, width = 21, align = "center", function(x) which.min(x) == ceiling(wid/2), fill = FALSE)
ggplot(my.df, aes(x, y)) + geom_line() + geom_vline(xintercept = x[rxz])

ggplot2 highlighting local minima

Note that I'm intentionally setting the width programmatically to preclude the possibility of inconsistency between rollapply and the inner function call. (I'm inferring that that may be what happened to you: you initially had a width of 3 or 4, where == 2 was more meaningful. I may be wrong, it's just a guess :-)