0

I am trying to find the x-values of the inflection points in the curve of a Kernel density plot that I computed with the density() function.

I found the following answered question helpful in finding the turning points:

How to find all the turning points on a kernel density curve when window width varies.

So I would think there must be a way to fnd the x-values of the inflection points, too. Would be great if somene has a tipp.

Becca
  • 3
  • 2

1 Answers1

1

By definition, an inflection point is the point where the second derivative of the function equals zero. In the practice, this means that an inflection point will be a point where the slope passes from increasing to decreasing, or v.v. Using this definition, I came with this approximate and non-automatic approach: Let's say that you have a dataframe, that I will call all, which contains the x-values in the first column, and the result of the density computation in the second one. From this dataframe, we can calculate the slope of two consecutive points like this :

slopes <- vector()
for(i in (2:nrow(all))){
  x1 <- all[i-1, 1]
  x2 <- all[i, 1]
  y1 <- all[i-1, 2]
  y2 <- all[i, 2]
  slope_i <- (y2-y1)/(x2-x1)
  slopes <- append(slopes, slope_i)
}

By the definition of inflection point, we can now calculate if, from one point to another, the slope gets larger or smaller:

increment <- vector()
for(j in 2:length(slopes)){
  increment_j <- slopes[j] - slopes[j-1]
  increment <- append(increment, increment_j)
}

The inflection points will be those points were this increment passes from positive to negative, or v.v.

Now, let's separate these increments in positive and negative:

pos <- which(increment>0)
neg <- which(increment<0

Now, whenever there is a jump in these pos or neg vectors, it means we have an inflection point. So, once again:

steps_p <- vector()
for(k in 2:length(pos)){
  steps_k <- pos[k] - pos[k-1]
  steps_p <- append(steps_p, steps_k)
}
steps_n <- vector()
for(k in 2:length(neg)){
  steps_k <- neg[k] - neg[k-1]
  steps_n <- append(steps_n, steps_k)
}

Now, just ask R:

which(steps_p>1)
which(steps_n>1)

This are the indices of your inflection points, now just go to your original dataframe and ask for the x value:

all[pos[which(steps_p>1)],1]
all[neg[which(steps_n>1)],1]

Take in mind that the x value will be close to exact, but not quite, as during every loop we lose one index, but it will still be a very close solution.

Javier
  • 427
  • 2
  • 11
  • That sounds pretty good. I tried to compute it, but it gives me an error for the calculation below, saying "Error in 2:nrow(all) : Argument of length zero" Do youhave an idea what went wrong here? I am sorry that I am asking again... I am quite a dummy in statistics .... – Becca Jul 09 '20 at 12:34
  • I suspect you are applying the loop to a vector and not a dataframe. You first have to create a dataframe for my code to work. If you apply your density function to the vector x: result <- density(x). Build the dataframe like all <- as.data.frame(cbind(result$x, result$y)), and then try the code – Javier Jul 09 '20 at 12:59
  • 1
    Thank you again! I was able to follow through with everything, but I am getting negative values in the end that dont make any sense to me. I will try to attach my dataset here. Maybe yu can see what went wong? – Becca Jul 09 '20 at 13:55
  • You are absolutely right, @Becca . My fault, I didn't index correctly the last step. Hopefully it works now. At least it does in my dummy example – Javier Jul 09 '20 at 14:28
  • I've tested with your data, it works. The values I find are: 5.069415, 21.997896, 12.26125. As I told you, be aware that these are not the exact x values, because of the several loopings; however, they are less than 3 data points away from the real ones. Visual inspection of the graph also shows that these are indeed true inflection points. Best regards, mark the answer as solving the question and vote positive if you found it useful! – Javier Jul 09 '20 at 14:51
  • Thank you so much @Javier ! Unfortunately I am still getting the same negative values... I must have done something wrong when putting in the codings. Will try again later. Thanks so much for your help! – Becca Jul 09 '20 at 15:21