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

Python中Sigmoid函数曲线拟合与外推效果不佳求解决方案

问题描述

给定如下数据集,需用Python的curve_fit工具对y从1下降到0的曲线进行校准与外推:

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

# 给定数据点
xdata = np.array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26])
ydata = np.array([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.99330715, 0.98201379, 0.95257413, 0.88079708, 0.73105858, 0.5])

# 绘制数据
plt.plot(xdata, ydata)
plt.xlabel('x')
plt.ylabel('sigmoid(x)')
plt.xlim([-1,31])
plt.ylim(0, 1.05)
plt.show()

数据特征为:前21个x对应的y值保持1,从x=21开始y逐渐下降,到x=26时降至0.5。

尝试使用Sigmoid函数(公式:$y = \frac{1}{1+e^{k(x-x_0)}}$),但选择了用y求解x的反向函数拟合,代码如下:

# 定义用于拟合xdata的Sigmoid函数
def sigmoid(y, x0, k):
    x = x0 + ((1/k)*(np.log((1/y)-1)))
    return x

# 初始猜测参数
p0 = [np.median(xdata),       # x0
      0.1]                    # k

# 初始化曲线拟合
popt, pcov = curve_fit(sigmoid,
                       ydata,
                       xdata)

# 定义y的取值范围
y = np.arange(1,0,-0.001)

# 计算对应的x值
x = sigmoid(y, *popt)

# 绘制实际数据与拟合曲线
plt.plot(xdata, ydata, 'o', label='data')
plt.plot(x,y, label='fit')
plt.xlim([-10,31])
plt.ylim(0, 1.05)
plt.legend(loc='best')
plt.show()

拟合效果极差,曲线无法贴合实际数据,需改进方法得到贴合的拟合曲线。

解决方案

拟合失效的核心问题是拟合方向错误,同时原数据中大量y=1的点会导致反向函数计算报错($\log((1/1)-1)=\log(0)$无意义),以下是修正步骤:

1. 使用正向Sigmoid函数拟合(y关于x)

回归原始Sigmoid公式,定义y作为x的函数,符合curve_fit常规逻辑(输入自变量x,输出因变量y):

def sigmoid(x, x0, k):
    return 1 / (1 + np.exp(k * (x - x0)))

其中x0是曲线中点(y=0.5对应的x值),k控制曲线陡峭程度,下降趋势下k为负数。

2. 处理y=1的特殊点

原数据中前21个点y=1,直接代入会引发数值问题,可选择两种处理方式:

  • 给y=1的点添加极小偏移(如1 - 1e-8),避免$\log(0)$;
  • 仅使用y<1的点拟合,再外推到全范围。

3. 优化初始参数猜测

根据数据特征,x0应接近y=0.5对应的x=26,k设为负数,初始参数可设为p0=[26, -0.5],比中位数更贴合数据趋势。

完整修正代码

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

# 给定数据点
xdata = np.array([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26])
ydata = np.array([1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0.99330715, 0.98201379, 0.95257413, 0.88079708, 0.73105858, 0.5])

# 处理y=1的点,添加极小偏移
ydata_adjusted = np.where(ydata == 1, 1 - 1e-8, ydata)

# 定义正向Sigmoid函数
def sigmoid(x, x0, k):
    return 1 / (1 + np.exp(k * (x - x0)))

# 优化初始参数:x0接近y=0.5的x=26,k为负数(下降趋势)
p0 = [26, -0.5]

# 执行拟合
popt, pcov = curve_fit(sigmoid, xdata, ydata_adjusted, p0=p0)
print(f"拟合参数:x0={popt[0]:.2f}, k={popt[1]:.2f}")

# 生成拟合曲线的x范围
x_fit = np.linspace(-1, 35, 1000)
y_fit = sigmoid(x_fit, *popt)

# 绘制结果
plt.plot(xdata, ydata, 'o', label='原始数据')
plt.plot(x_fit, y_fit, '-', label='拟合曲线')
plt.xlabel('x')
plt.ylabel('y')
plt.xlim([-1, 35])
plt.ylim(0, 1.05)
plt.legend(loc='best')
plt.show()

效果说明

修正后的拟合曲线会完美贴合x≥21的下降段,同时外推x<21时y趋近于1,完全匹配原始数据的平台+下降特征;若仅用y<1的点拟合,结果会更精准,因为前21个y=1的点本身就符合Sigmoid左半段的平台趋势。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 06:32:19