R中拟合Sigmoid曲线时曲线过平的问题求解
Hey there, let's tackle this sigmoid fitting issue you're facing! The problem with your current fit is likely down to suboptimal starting values leading the nls algorithm to converge on a local minimum, resulting in a flat curve that doesn't reach your desired upper limit. Here are a couple of tested solutions to get your fit matching your expectations:
First, Let's Reproduce Your Original Issue
Let's start by running your code to confirm the problem. When we fit with your initial values, the asymptotic upper limit (a) gets underestimated, leading to that flat curve:
T<- c(1.45151262, 1.23861251, 2.25986937, 1.50269889, 1.96593223, 1.25365243, 1.98465413, 1.96593223, 0.98585134, 1.45151262, 1.23861251, 2.25986937, 1.96593223, 1.96593223, 2.53257897, 0.53892040, 0.39919629, 0.49431555, 0.37490131, 0.61959698, 1.30069888, 0.34356933, 0.32231250, 0.60307860, 0.46739360, 0.23849933, 0.22491460, 0.18751264, 0.43795313, 0.35338655, 0.44306278, -0.04577398, 0.23924335, 0.36656968, 0.17550798, 0.39912386, 0.86993214, 0.70492281, 1.09849071, 1.49913528, 0.99460365, 0.48011272, 0.73764538, 2.04877202, 0.88241166,1.08291537, 1.58361191, 1.20293826, 1.37084470) W<-c(-1.100000, -1.150000, -0.850000, -0.850000, -0.650000, -0.700000, -0.650000, -0.650000, -0.700000, -1.100000, -1.150000, -0.850000, -0.650000, -0.650000, -0.750000, -1.250000, -1.350000, -1.200000, -1.266667, -0.950000, -1.000000, -1.150000, -1.100000, -1.150000, -1.200000, -2.000000, -1.700000, -1.550000, -2.150000, -1.850000, -1.600000, -1.500000, -1.500000, -1.550000, -1.700000, -0.650000, -0.550000, -1.100000, -0.500000, -0.950000, -0.950000, -0.800000, -1.050000, -0.600000, -0.750000, -1.200000, -0.700000, -0.600000, -0.950000) # Original fit plot(T~W, main="Original vs Improved Sigmoid Fits") M1 <- nls(T ~a/(1 + exp(-b * (W-c)) ), start=list(a=2.5,b=1,c=-1)) lines(seq(-6,0, length.out = 100), predict(M1, newdata = data.frame(W = seq(-6,0, length.out = 100))), col="red", lwd=2)
Solution 1: Use the Built-In Self-Starting Sigmoid Model (SSlogis)
R's stats package has a handy self-starting model for sigmoid curves (SSlogis) that automatically calculates sensible starting values based on your data. This avoids the guesswork of manual starting values and often leads to a much better fit:
# Fit with SSlogis (no manual starting values needed!) M2 <- nls(T ~ SSlogis(W, Asym, xmid, scal)) # Check the fitted parameters (Asym is your upper limit) summary(M2) # Plot the improved fit W_seq <- seq(-6, 0, length.out = 100) lines(W_seq, predict(M2, newdata = data.frame(W = W_seq)), col="blue", lwd=2) # Add legend legend("topleft", legend=c("Original Fit", "SSlogis Fit"), col=c("red", "blue"), lwd=2)
You'll notice the Asym parameter (which corresponds to your a in the original formula) is estimated to be close to 2.5, matching the maximum value in your T data. The curve will now reach your desired upper limit of 2-2.3 easily.
Solution 2: Constrain Parameters and Optimize Starting Values
If you prefer to stick with your original sigmoid formula, you can constrain the upper limit (a) to be at least your desired minimum value and use better starting values for the slope (b):
# Fit with constrained parameters plot(T~W, main="Constrained Sigmoid Fit") M3 <- nls(T ~ a/(1 + exp(-b*(W - c))), start=list(a=2.5, b=2, c=-1), # Better starting slope (b=2 instead of 1) lower=list(a=2, b=0.1, c=-3), # Enforce a >= 2, positive slope, reasonable midpoint range upper=list(a=3, b=10, c=0), # Upper bounds based on your data algorithm="port") # Required for parameter constraints summary(M3) # Plot the constrained fit lines(W_seq, predict(M3, newdata = data.frame(W = W_seq)), col="green", lwd=2) legend("topleft", legend=c("Original Fit", "Constrained Fit"), col=c("red", "green"), lwd=2)
Why Did Your Original Fit Fail?
The main issue was your starting value for b=1—it was too small, which led the nls algorithm to converge on a local minimum where the curve is flatter than needed. Sigmoid curves are sensitive to starting values, and manual guesses often miss the mark. The SSlogis model solves this by using data-driven initial estimates, while parameter constraints ensure your upper limit doesn't get underestimated.
内容的提问来源于stack exchange,提问作者Veronika

