I\'m trying to fit a Boltzmann sigmoid 1/(1+exp((x-p1)/p2))
to this small experimental dataset:
xdata <- c(-60,-50,-40,-30,-20,-10,-0,10)
yda
It is not possible to force the fit to go through 0 using the function you provide (without an off-set) as we discussed in the comments below your question.
However, you can force the curve to go through other data points by setting weights
for individual data points. So e.g. if you give a data point A a weight equals 1 and a data point B a weight equals 1000, the data point B is much more important (in terms of the contribution to the sum of residuals which is going to be minimized) for the fit than A and the fit will therefore be forced to go through B.
Here is the entire code and I explain it in more detail below:
# your data
xdata <- c(-60, -50, -40, -30, -20, -10, -0, 10)
ydata <- c(0.04, 0.09, 0.38, 0.63, 0.79, 1, 0.83, 0.56)
plot(xdata, ydata, ylim=c(0, 1.1))
fit <-nls(ydata ~ 1 / (1 + exp((xdata - p1) / p2)), start=list(p1=mean(xdata), p2=-5))
# plot the fit
xr = data.frame(xdata = seq(min(xdata), max(xdata), len=200))
lines(xr$xdata, predict(fit, newdata=xr))
# set all weights to 1, do the fit again; the plot looks identical to the previous one
we = rep(1, length(xdata))
fit2 = nls(ydata ~ 1 / (1 + exp((xdata - p1) / p2)), weights=we, start=list(p1=mean(xdata) ,p2=-5))
lines(xr$xdata, predict(fit2, newdata=xr), col='blue')
# set weight for the data point -30,0.38, and fit again
we[3] = 1000
fit3 = nls(ydata ~ 1 / (1 + exp((xdata - p1) / p2)), weights=we, start=list(p1=mean(xdata), p2=-5))
lines(xr$xdata, predict(fit3, newdata=xr), col='red')
legend('topleft', c('fit without weights', 'fit with weights 1', 'weighted fit for -40,0.38'),
lty=c(1, 1, 1),
lwd=c(2.5, 2.5, 2.5),
col=c('black', 'blue', 'red'))
The output looks as follows; as you can see the fit now goes through the desired data point (red line):
So what is going on: I first fit as you did, then I fit with weights whereby all weights are set to 1; therefore, the plot looks identical to the one before and the blue line hides the black line. Then - for fit3
- I change the weight for the third data point to 1000 which means that it is now much more "important" for the least square fit than the other points and the new fit goes through this data point (the red line).
Here is also a second example where I changed the line
we[3] = 1000
to
we[2] = 1000
which forces the fit to go through the second data point:
If you want to get more information about the weights
argument you can read here: documentation