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

如何拟合并绘制平滑的Sigmoid函数曲线?拟合结果异常求助

Sigmoid曲线拟合异常:得到非平滑类平方曲线的解决方法

问题描述

尝试为现有数据拟合并绘制Sigmoid曲线,但得到的是类似非平滑的类平方曲线。使用的代码如下:

import numpy as np
import pyplot
from scipy.optimize import curve_fit

def sigmoid(x, a, b):
    return 1.0 / (1.0 + np.exp(-a*(x-b)))

xdata = [ 26457.28874429,  32614.0743368 ,  36375.76229015,  39371.21198926,
    41892.69310906,  44162.12906554,  46223.90776821,  48197.46060769,
    50022.99546123,  51848.03215704,  53568.91252972,  55354.78073918,
    57040.61643994,  58818.59692639,  60676.00000216,  62510.8110985 ,
    64586.59777512,  66562.62315247,  68742.97216949,  71078.33629888,
    73648.94810531,  76587.27871678,  79749.19546409,  83334.78854123,
    87282.81262044,  91925.69906738,  97551.59686331, 104496.29453508,
   112988.76665607, 124907.20130917, 144733.52923071, 193062.81222137]
ydata = [0.        , 0.57224724, 0.67521945, 0.76716544, 0.7535795 ,
   0.69637917, 0.81766149, 0.80906626, 0.71942446, 0.7670196 ,
   0.77549438, 0.80370093, 0.77160494, 0.78232104, 0.87796313,
   0.89326037, 1.05848115, 1.08499096, 1.13992674, 1.16009281,
   1.36193537, 1.58227848, 1.78731153, 1.98694295, 2.19359185,
   2.51098556, 2.92349108, 3.47826087, 3.82897412, 4.23472474,
   4.19622344, 5.19657584]

         
popt, pcov = curve_fit(sigmoid, xdata, ydata, method='dogbox', bounds=([min(ydata), min(xdata)],[max(ydata), max(xdata)]))
print(popt)

x = np.linspace(np.min(xdata), np.max(xdata))
y = sigmoid(x, *popt)

pyplot.plot(xdata, ydata, 'o', label='data')
pyplot.plot(x,y, label='fit')
pyplot.legend(loc='best')
pyplot.show()

问题根源与修复方案

你的Sigmoid函数定义和拟合参数设置存在两个核心问题:

  • Sigmoid函数的取值范围不匹配
    你当前的Sigmoid函数1.0 / (1.0 + np.exp(-a*(x-b)))输出范围固定为(0,1),但你的ydata取值范围是0到5.2左右,完全超出这个区间,导致拟合算法无法找到合理参数,最终输出错误曲线。

    修复:扩展Sigmoid函数,加入上下限参数,适配任意y值范围:

    def sigmoid(x, a, b, c, d):
        # c=下限,d=上限,a=斜率,b=中点
        return c + (d - c) / (1.0 + np.exp(-a*(x - b)))
    
  • 拟合参数的边界设置错误
    原代码中bounds只给了两个参数的边界,且将斜率参数a的边界设为ydata范围,这完全不合理——a是控制曲线陡峭程度的参数,和y值范围无关。

    修复:重新设置合理边界,同时提供初始猜测值帮助算法收敛:

    # 初始猜测值:a设为极小正数,b取x均值,c取y最小值,d取y最大值
    p0 = [1e-5, np.mean(xdata), np.min(ydata), np.max(ydata)]
    # 边界限制:a>0,b在x范围内,c略小于y最小值,d略大于y最大值
    bounds = ([1e-6, np.min(xdata), -np.inf, np.max(ydata)*0.9], 
             [1e-4, np.max(xdata), np.min(ydata)*1.1, np.max(ydata)*1.1])
    popt, pcov = curve_fit(sigmoid, xdata, ydata, p0=p0, bounds=bounds, method='dogbox')
    

完整修复后的代码

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

def sigmoid(x, a, b, c, d):
    return c + (d - c) / (1.0 + np.exp(-a*(x - b)))

xdata = [ 26457.28874429,  32614.0743368 ,  36375.76229015,  39371.21198926,
    41892.69310906,  44162.12906554,  46223.90776821,  48197.46060769,
    50022.99546123,  51848.03215704,  53568.91252972,  55354.78073918,
    57040.61643994,  58818.59692639,  60676.00000216,  62510.8110985 ,
    64586.59777512,  66562.62315247,  68742.97216949,  71078.33629888,
    73648.94810531,  76587.27871678,  79749.19546409,  83334.78854123,
    87282.81262044,  91925.69906738,  97551.59686331, 104496.29453508,
   112988.76665607, 124907.20130917, 144733.52923071, 193062.81222137]
ydata = [0.        , 0.57224724, 0.67521945, 0.76716544, 0.7535795 ,
   0.69637917, 0.81766149, 0.80906626, 0.71942446, 0.7670196 ,
   0.77549438, 0.80370093, 0.77160494, 0.78232104, 0.87796313,
   0.89326037, 1.05848115, 1.08499096, 1.13992674, 1.16009281,
   1.36193537, 1.58227848, 1.78731153, 1.98694295, 2.19359185,
   2.51098556, 2.92349108, 3.47826087, 3.82897412, 4.23472474,
   4.19622344, 5.19657584]

# 设置初始猜测值和边界
p0 = [1e-5, np.mean(xdata), np.min(ydata), np.max(ydata)]
bounds = ([1e-6, np.min(xdata), -np.inf, np.max(ydata)*0.9], 
          [1e-4, np.max(xdata), np.min(ydata)*1.1, np.max(ydata)*1.1])
popt, pcov = curve_fit(sigmoid, xdata, ydata, p0=p0, bounds=bounds, method='dogbox')
print("拟合参数:", popt)

# 生成更多点数让曲线更平滑
x = np.linspace(np.min(xdata), np.max(xdata), 1000)
y = sigmoid(x, *popt)

plt.plot(xdata, ydata, 'o', label='原始数据')
plt.plot(x, y, label='拟合曲线')
plt.legend(loc='best')
plt.show()

额外说明

  • 原代码中的import pyplot需改为import matplotlib.pyplot as plt,否则会出现导入错误。
  • 增加linspace的点数(如1000)可让拟合曲线显示更平滑。
  • 初始猜测值p0的设置能帮助curve_fit快速收敛,避免陷入局部最优解。

内容的提问来源于stack exchange,提问作者Marlon Teixeira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 23:54:28