求助:为数据拟合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,最终生成水平线 - 初始参数猜测与数据实际分布偏差较大,导致优化方向错误
具体修正步骤
- 归一化y值:将
y除以100,使其范围与期望的0-1渐近线匹配 - 固定渐近线:修改logistic函数,直接固定
d=0、c=1,减少优化参数数量,避免无意义的参数波动 - 优化初始猜测:根据数据分布设置更合理的初始参数,尤其是控制陡峭度的
a和中点b - 添加参数边界:限制
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
相关产品推荐
相关产品推荐

