Home > front end >  Finding the data point in vector when the slope changes in R
Finding the data point in vector when the slope changes in R

Time:04-04

If I have a vector that is showing the change in slope (produced by the sign function) how do I find the data point/points when the slope change from 1 to -1.

Example vector

1 1 1 1 -1 -1 -1 -1 1 1 1 1 -1 -1 -1 -1 1 1 1 1

Or is there a way to somehow just have an output that tells me how many minima are in the vector defined by when a line segment with a negative slope is followed by a line segment with a positive slope (/). In the above example there would be two minima so the example output would be:

minima 
2

In a perfect world, I would love to have an output that looks like this

Minima Location
1        8
1        9
2        16
2        17

CodePudding user response:

There is a nice trick for all of these types of problems. You take a copy of the vector and shift it one to the left and then use a vectorised compare and the minima occur wherever the shifted vector is not equal to the original vector.

So for example:

> a = c(1,1,-1,-1,1,-1)
> n = length(a)
> b = a[-1]  # Drop the first element
> d = a[-n]  # Drop the last element
> b
[1]  1 -1 -1  1 -1
> d
[1]  1  1 -1 -1  1
> minima = which(b!=d)
> minima
[1] 2 4 5
> 

CodePudding user response:

I am not really clear on how you define "minima" locations. But the following returns a vector of locations that matches your expected output.

x <- c(1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1)
which(c(0, diff(x)) > 0 | c(diff(x), 0) > 0)
[1]  8  9 16 17

Or if you want to return a data.frame, perhaps something like this

library(dplyr)
x %>%
    enframe(name = "Location") %>%
    mutate(is_minimum = c(0, diff(value)) > 0 | c(diff(value), 0) > 0) %>%
    filter(is_minimum) %>%
    mutate(Minima = cumsum(c(0, diff(Location)) != 1)) %>%
    select(-c(value, is_minimum))
## A tibble: 4 x 2
#  Location Minima
#     <int>  <int>
#1        8      1
#2        9      1
#3       16      2
#4       17      2

CodePudding user response:

Another way in base R:

w = which(diff(a) > 0)
# [1]  8 16

length(w) #minima
# [1] 2

data.frame(Minima = rep(seq(w), each = 2),
           Location = c(rbind(w, w 1)))
#  Minima Location
#1      1        8
#2      1        9
#3      2       16
#4      2       17
  • Related