fitting loess in R with one inflection point only

34 Views Asked by At

Is there a way to fit loess to data with the constraint that it can only have one inflection point? If not how can I approximate it? I understand that I could use a larger span with loess, but that is not what I am looking for.

df <- structure(list(testage = c(0, 11, 15, 16, 17, 18, 19, 20, 21, 
            23, 24, 25, 27, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 
            42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 
            58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 71), val = c(-6, 
            -0.72, 0.415, 0.479, 0.36, 0.556, 0.682, 0.695, 0.631, 0.685, 
            0.662, 0.538, 0.33, 0.64, 0.755, 0.48, 0.554, 0.675, 0.56, 0.545, 
            0.631, 0.611, 0.45, 0.395, 0.532, 0.536, 0.37, 0.552, 0.429, 
            0.45, 0.331, 0.316, 0.47, 0.144, -0.044, 0.065, 0.17, 0.29, 0.111, 
            -0.007, -0.018, -0.048, -0.187, -0.292, -0.273, -0.175, -0.476, 
            -0.145, -0.603, -0.279, -0.528, -0.626, -0.641), n = c(10000, 
            1670, 52, 43, 52, 66, 26, 9, 10, 10, 13, 11, 7, 57, 27, 40, 37, 
            31, 68, 59, 55, 63, 66, 91, 64, 74, 50, 49, 84, 55, 55, 68, 60, 
            76, 45, 64, 44, 29, 33, 25, 17, 25, 21, 20, 18, 32, 13, 20, 13, 
            8, 7, 7, 8)), class = "data.frame", row.names = c(NA, -53L))

df %>%
  ggplot(aes(x=testage, y=val, weight=n)) +
  geom_point() +
  scale_x_continuous(name = 'Age', limits = c(0,70)) +
  scale_y_continuous(limits = c(-6,0.8), name = expression(paste("Avg. ",theta))) +
  geom_smooth(size = 1, se=T, fullrange =T, span = 0.3) +
  geom_hline(yintercept=0) +
  geom_vline(xintercept=0)

Average test results by age

1

There are 1 best solutions below

1
Jake On

If you use the geom_smooth() geometry in ggplot2, you can specify the number of smoothing points as n = 3. (You need this to be 3 because the first two are the first and last data point; the third will be the inflection point in the middle.)

You can try smoothing it out further by increasing the span argument. It's still not terribly smooth around the inflection point, but possibly the best you're going to get.

df %>% 
  ggplot+ 
  geom_smooth(aes(x, y), n = 3, span = 100)