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

求助:为数据拟合S曲线时无法调整参数使曲线变陡

问题描述

你使用Python结合scipy.optimize.curve_fit拟合S曲线时,遇到两个核心问题:

  • 当前拟合曲线与数据匹配度差,无法达到期望的陡峭程度
  • 调整参数后曲线常变为水平线,且需要曲线渐近线固定为0和1

附上你的原始代码:

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

def logistic(x, a, b, c, d=0):
    """
    Logistic function that maps x to a value between two asymptotes d and c.

    Parameters:
    - x: The independent variable or array of variables.
    - a: Defines the steepness of the curve.
    - b: Midpoint of the function where the maximum growth occurs.
    - c: The maximum value (upper asymptote) of the function.
    - d: The minimum value (lower asymptote) of the function, defaults to 0.

    Returns:
    - The calculated logistic value(s).
    """
    return d + (c - d) / (1 + np.exp(-a * (x - b)))

# Define the data
x = np.array([-4.49,-5.53,-6.66,-4.82,-7.01,-8.62,-9.86,-11.64,-12.41,-3.06,-4.48,-7.86,-3.09,
              -11.21,-2.01,-0.47,-4.60,-1.72,-4.21,-1.04,-2.90,-20.91,-2.47,-4.16,-2.81,-2.62,
              -2.57,-5.81,-7.34,-5.67,12.16,-6.82,-3.63,-20.75,-3.05,3.22,-0.91,-10.40,-3.66,
              -3.90,-4.69,60.39,-6.88,12.83,22.23,12.00,42.54,63.11,30.29,28.07,
              10.11,-2.99,2.18,1.14,1.49,-9.55])

y = np.array([0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.23,7.01,10.00,15.37,16.93,17.79,
              18.01,18.06,18.61,20.60,21.22,24.40,28.09,30.28,30.56,34.33,46.07,47.64,51.50,
              58.96,64.92,68.02,75.59,76.65,80.39,83.19,83.76,85.83,87.03,87.84,88.01,92.55,
              93.84,95.42,96.10,96.19,100.00,100.00,100.00,100.00,100.00,100.00,100.00,
              100.00,100.00,100.00,100.00,100.00])

# Use curve_fit to estimate the logistic function parameters
p0 = [1, 0, 1] # initial guesses for parameters a, b, and c
params, pcov = curve_fit(logistic, x, y, p0)

# Generate values for the x-axis to plot the curve
x_fit = np.linspace(x.min(), x.max(), 1000)

# Generate predictions for the y-axis using the estimated parameters
y_fit = logistic(x_fit, *params)

# Plot the data and the curve fit
plt.scatter(x, y)
plt.plot(x_fit, y_fit, 'r-', label='S-curve fit')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()
解决方案

核心问题分析

  • 你的y值范围是0-100,但期望渐近线是0和1,数值尺度不匹配导致优化器难以收敛
  • 未固定渐近线参数,优化过程中可能出现c和d趋近于相等,或a趋近于0,最终生成水平线
  • 初始参数猜测与数据实际分布偏差较大,导致优化方向错误

具体修正步骤

  1. 归一化y值:将y除以100,使其范围与期望的0-1渐近线匹配
  2. 固定渐近线:修改logistic函数,直接固定d=0、c=1,减少优化参数数量,避免无意义的参数波动
  3. 优化初始猜测:根据数据分布设置更合理的初始参数,尤其是控制陡峭度的a和中点b
  4. 添加参数边界:限制a为正数,确保曲线方向正确且能达到陡峭效果

修改后的完整代码

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

def logistic(x, a, b):
    """
    Logistic function with fixed asymptotes at 0 (lower) and 1 (upper).
    
    Parameters:
    - x: Independent variable/array
    - a: Steepness of the curve (positive value for increasing curve)
    - b: Midpoint of the curve (where y=0.5)
    
    Returns:
    - Calculated logistic values
    """
    return 1 / (1 + np.exp(-a * (x - b)))

# 数据准备:归一化y值到0-1范围
x = np.array([-4.49,-5.53,-6.66,-4.82,-7.01,-8.62,-9.86,-11.64,-12.41,-3.06,-4.48,-7.86,-3.09,
              -11.21,-2.01,-0.47,-4.60,-1.72,-4.21,-1.04,-2.90,-20.91,-2.47,-4.16,-2.81,-2.62,
              -2.57,-5.81,-7.34,-5.67,12.16,-6.82,-3.63,-20.75,-3.05,3.22,-0.91,-10.40,-3.66,
              -3.90,-4.69,60.39,-6.88,12.83,22.23,12.00,42.54,63.11,30.29,28.07,
              10.11,-2.99,2.18,1.14,1.49,-9.55])
y = np.array([0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.23,7.01,10.00,15.37,16.93,17.79,
              18.01,18.06,18.61,20.60,21.22,24.40,28.09,30.28,30.56,34.33,46.07,47.64,51.50,
              58.96,64.92,68.02,75.59,76.65,80.39,83.19,83.76,85.83,87.03,87.84,88.01,92.55,
              93.84,95.42,96.10,96.19,100.00,100.00,100.00,100.00,100.00,100.00,100.00,
              100.00,100.00,100.00,100.00,100.00]) / 100  # 归一化

# 设置初始参数:a=5(控制陡峭度,初始值偏大确保曲线陡峭),b=-2.5(数据中点对应的x值)
p0 = [5, -2.5]
# 添加参数边界:a必须大于0,避免曲线反转或变平
bounds = ([0, -np.inf], [np.inf, np.inf])
params, pcov = curve_fit(logistic, x, y, p0, bounds=bounds)

# 生成拟合曲线数据
x_fit = np.linspace(x.min(), x.max(), 1000)
y_fit = logistic(x_fit, *params)

# 绘图(如果需要展示原始y值刻度,可将y_fit乘以100)
plt.scatter(x, y * 100, label='Original Data')  # 显示原始0-100刻度
plt.plot(x_fit, y_fit * 100, 'r-', label='S-curve fit')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()

# 输出拟合参数
print(f"拟合参数:a={params[0]:.4f}, b={params[1]:.4f}")

效果说明

  • 固定渐近线后,优化器只需专注调整陡峭度a和中点b,不会出现水平线问题
  • 归一化后数值尺度匹配,优化收敛更稳定
  • 初始猜测和参数边界确保曲线向陡峭方向优化,最终拟合结果会更贴近你期望的S曲线形态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 16:44:53