SportSci
SportSci

Reputation: 247

Create exponential function in R from 2 points

I would like to create an exponential function in R when only 2 points that the line passes through are given. I'd like to use the basic f(x) = ab^x format. I understand how to do this by hand, by creating two equations and then separately solving for b and a, but I'm having issues coding this in R. For example, when I try to assign a variable with another variable in it, I get the "object not found error" on the first step of this process.

x <- c(4, 3, 1.8, 1.1, .6, .3, .02) 
y <- c(2, 7, 16, 27, 40, 51, 66)  
df <- data.frame(x,y)
a <- df$y[1]/b^df$x[1]

Error: object 'b' not found

I understand why I'm getting this error, but I don't know a way around it.

I could create an exponential model by only using the first 2 the points, but the coefficients are no where close to the actual data values.

expmod <- lm(log(df$y[1:2])~df$x[1:2])
exp(expmod$coefficients)

(Intercept)        df$x 
300.1250000   0.2857143

The intercept should be closer to 66 based on the data (y = 66, when x = 0.02)

I eventually want to be able to use this function to take two points on a line and then both plot the line and produce values based on other x inputs (i.e. c(0,1,2,3,4)), but I'm running into trouble early on.

edit: I am not necessarily trying to create a model from 2 points and expecting a great prediction. I am trying do determine the exponential function of a line that passes through two points, similar to this, but coded in R. (The line won't be perfect, because it's made up data.)

Upvotes: 0

Views: 1437

Answers (1)

Allan Cameron
Allan Cameron

Reputation: 173803

The reason you are not getting the intercept you want is that the first two points in your data frame are not on the same exponential curve as the other points. We can see this by plotting log(y) against x:

plot(x, log(y))

enter image description here

Now let's draw the regression using only your first two points (the two rightmost points)

abline(lm(log(y) ~ x, data = df[1:2, ]), col = "red")

enter image description here

and add a line for the other 5 points:

abline(lm(log(y) ~ x, data = df[-c(1:2), ]), col = "blue")

enter image description here

You can see that if we only use two points, then the gradient and intercept are very sensitive to any experimental deviations from a perfect exponential curve.

There is a larger point here, which is that if you are trying to make predictions using only two experimental data points, then your predictions will not be very accurate.

Conversely, if we use all the points, we get a reasonable prediction for the relationship as a whole:

plot(x, y)
lines(new_frame$x, new_frame$y, col = "red")

enter image description here

And the numerical prediction for the intercept is closer to your expectations:

exp(lm(log(y) ~ x, data = df)$coef)
#> (Intercept)           x 
#>  68.2345853   0.4335491 

EDIT

To calculate the equation "manually" from two points, you need to take the log of the y values, then you can calculate the gradient of the log line between two points by doing:

gradient <- (log(y2) - log(y1)) / (x2 - x1)

and you can get the intercept by solving y = gradient * x + intercept for intercept, that is:

intercept <- log(y1) - gradient * x1

you can then exponentiate the gradient and the intercept to find the coefficients of your original line. For example, using this function:

exp_line <- function(x1, x2, y1, y2) {
  gradient  <- (log(y2) - log(y1)) / (x2 - x1)
  intercept <- log(y1) - gradient * x1
  cat("y = ", exp(gradient), "^x * ", exp(intercept), "\n", sep = "")
}

We get

exp_line(x[1], x[2], y[1], y[2])
#> y = 0.2857143^x * 300.125

exp_line(x[4], x[5], y[4], y[5])
#> y = 0.455625^x * 64.10553

And if we want to draw an exponential curve between any two points, we can do the following:

draw_exp_line <- function(x1, x2, y1, y2, col) {
  gradient  <- (log(y2) - log(y1)) / (x2 - x1)
  intercept <- log(y1) - gradient * x1
  x <- seq(0, 5, 0.1)
  lines(x, exp(gradient)^x * exp(intercept), col = col)
}

plot(x, y)
draw_exp_line(x[2], x[1], y[2], y[1], "red")

enter image description here

Upvotes: 2

Related Questions