You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用R语言nls拟合Sigmoid函数时出现singular gradient错误的解决建议咨询

Fixing the "Singular Gradient" Error in Sigmoid Curve Fitting with nls()

Hey there! That singular gradient error is super common when using nls() for curve fitting—it usually boils down to poor initial parameter guesses or a model parameterization that causes collinearity between parameters. Let's break down how to fix this for your sigmoid fit.

First, Understand the Root Cause

Your original sigmoid function phi1/(1 + exp(-phi3 * x - phi2)) is mathematically valid, but the way parameters are combined (-phi3*x - phi2) makes it hard to pick good starting values, and can lead the optimizer to hit a "singular gradient" where it can't adjust parameters effectively. Also, your initial guesses (especially phi3 = 0.0005) were way too small to match your data's growth rate.

Step 1: Re-Parameterize the Sigmoid for Better Interpretability

Switch to a more intuitive sigmoid form where parameters map directly to meaningful features of your data:

  • phi1: The upper asymptote (matches the maximum value in your cumulativo column)
  • phi3: The x-value where the curve inflects (the point of fastest growth)
  • phi2: The steepness of the curve (negative for an increasing sigmoid)

Here's the adjusted function:

f <- function(x, phi1, phi2, phi3) {
  phi1 / (1 + exp(phi2 * (x - phi3)))
}

Step 2: Set Realistic Initial Values

Looking at your data:

  • cumulativo tops out around 19639, so set phi1 = 19700 (a little higher than the max)
  • The fastest growth happens between 2000-2005, so set phi3 = 2005 (the inflection point)
  • For a moderate growth steepness, start with phi2 = -0.5 (negative because we want an increasing S-curve)

Your initial values list becomes:

st <- list(phi1 = 19700, phi2 = -0.5, phi3 = 2005)

The base nls() is sensitive to initial values. The nlsLM() function from the minpack.lm package uses a more robust algorithm that handles poor initial guesses better.

Full Working Code

library(ggplot2)
library(minpack.lm) # Load the package for nlsLM

# Your original data
data <- structure(list(cumulativo = c(2, 3, 17, 191, 819, 1699, 2679, 3907, 5535, 7254, 9226, 11543, 13809, 15542, 16852, 17709, 18246, 18661, 18976, 19256, 19412, 19539, 19639), eixox = 1994:2016), class = "data.frame", row.names = c(NA, -23L))

# Plot raw data to visualize trend
plot(cumulativo ~ eixox, data = data)

# Re-parameterized sigmoid function
f <- function(x, phi1, phi2, phi3) {
  phi1 / (1 + exp(phi2 * (x - phi3)))
}

# Realistic initial values
st <- list(phi1 = 19700, phi2 = -0.5, phi3 = 2005)

# Fit the model with nlsLM (more robust than base nls)
curvaS <- nlsLM(cumulativo ~ f(eixox, phi1, phi2, phi3), start = st, data = data, trace = TRUE)

# Check the fit summary
summary(curvaS)

# Add predicted values to your data frame
data$predicted <- predict(curvaS, newdata = data)

# Plot the fit against raw data
ggplot(data, aes(x = eixox)) +
  geom_point(aes(y = cumulativo), color = "black") +
  geom_line(aes(y = predicted), color = "red", linewidth = 1) +
  labs(title = "Sigmoid Fit to Cumulative Data", x = "Year", y = "Cumulative Value")

What If You Want to Stick With Your Original Model?

If you prefer your original sigmoid form, adjust the initial values to match the re-parameterized version. For example, since -phi3*x - phi2 = phi2_new*(x - phi3_new), you can calculate:

  • phi3_original = -phi2_new = 0.5
  • phi2_original = phi2_new * phi3_new = -0.5 * 2005 = -1002.5

Your initial values would be:

st <- list(phi1=20000, phi2=-1002.5, phi3=0.5)

Then you can use this with base nls()—though nlsLM() is still more reliable.

内容的提问来源于stack exchange,提问作者Antonio Abrantes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 15:57:34