Search code examples
rmagrittr

A tidy way to find the max of a function in an interval: pipes, sequences and subsetting


I'm looking for an idiomatic (pipe-based) way to find the minimum/maximum of a given function in an interval. Let's say I have an arbitrary function, such as

f<-function(x){return(x^2-10*x)}

I'm looking for its minimum value in [xmin:xmax]. Of course with the above example, this is trivial but obviously a real-life application would use a much more complex f, probably with parameters, etc, etc.

The "plain" R way would be, for instance (e.g. here)

xmin <- 0
xmax <- 10

df<-curve(f,xmin,xmax)
df$x[which(df$y==(min(df$y,na.rm = TRUE)))]

or

optimize(f, interval=c(xmin,xmax), maximum=F)$min

For the sake of curiosity (and understanding plumbing), let's assume I want a "tidy" equivalent of the first solution, using pipes. I managed to construct

seq(xmin,xmax,length.out = 100) %>% f %>% which.min()

which gives me the index of the lowest value. Of course I can now do

idx <- seq(xmin,xmax,length.out = 100) %>% f %>% which.min()
seq(xmin,xmax,length.out = 100)[idx]

but surely there is a more idiomatic way to pipe the result of my construction and get the X-value without intermediate variables (xmin, xmax and idx) ?

(yes, I know that this gives me only an approximate value, to the nearest step in my sequence, and yes this is a somewhat construed example - I'm trying to improve my understanding of pipes)


Solution

  • This should do it

    xmin <- 0
    xmax <- 10
    
    f<-function(x){
      return(x^2-10*x)
    }
    
    curve(f,xmin,xmax) %>% 
    as_tibble() %>%
    filter(y == min(y)) %>%
    pull(x)
    

    or:

    curve(f,xmin,xmax) %>% 
      {.$x[which.min(.$y)]}