我有许多数据集,它们从较高的 y 轴值开始,然后逐渐减小。这种情况发生在传统的 S 曲线方式中,因此它实际上看起来像反向 S 形曲线。我成功地翻转了 y 数据,使得最大值位于 y 轴的底部,并且向上减小。所以,数据绘制得很好。曲线现在看起来像标准的 S 形曲线。
大问题: 我无法将 sigmoid 拟合到它。这几天我能想到的都做了。
我得到的最好的结果是在附图中。 我有很多拟合看起来不完整,与 sigmoid 拟合应该有的样子相差甚远。
我的代码:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# 1. Data set:
x_data = np.array([130, 125, 120, 115, 110, 105, 100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40,
35, 30, 25])
y_data = np.array([81, 81, 80.5, 79, 77.5, 76, 74.5, 71.5, 68.5, 67, 64, 59.5, 55, 48.5, 44, 42.5, 42,
41.5, 41.5, 41, 41, 41])
# 2. Reverse the y-values:
y_data_reversed = np.flip(y_data)
y_range = np.linspace(41, 61.75, 81)
# 3. Sigmoid function defined:
def sigmoid(x, U, k, a, b):
b = 81 #-the maxmimum y_data value.
return (U / (1 + np.exp(-k * (x - 77.5))))**a + b
p0 = [np.max(y_data), np.median(x_data), 1, np.min(y_data)] #-as an initial guess for the fit
calculation.
popt, pcov = curve_fit(sigmoid, x_data, y_data, p0, maxfev = 10000) #method = 'lm')
# 4. Sigmoid fit to data:
x_fit = np.linspace(25, 77.5, 130) #-min(x_data), np.median(x_data), max(x_data)).
y_fit = sigmoid(x_fit, *popt)
# 5. Plot data and sigmoid fit:
plt.plot(x_data, y_data_reversed, marker='o', linestyle='', color='b', label='Data')
plt.plot(x_fit, y_fit, color='r', label='Sigmoid Fit')
plt.xlabel('Temperature (°C)')
plt.ylabel('Length (mm)')
plt.title('Sigmoid Fit for Contraction Data')
plt.gca().invert_yaxis() # ...Invert y-axis to start with highest value at the top
plt.legend()
plt.grid(True)
plt.show()
一般来说,将指数作为参数(如代码中的
a
参数)是危险的,因为如果优化器为此参数选择高/低值,则很容易导致数值上溢/下溢。
您的
b
参数是多余的,因为您将 b
设置为 sigmoid 函数内的固定值。这是故意的吗?
这是我根据您的数据拟合的简化模型,没有
a
或 b
参数。
我没有费心翻转 y 数据,因为它会造成混乱。
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# 1. Data set:
x_data = np.array([130, 125, 120, 115, 110, 105, 100, 95, 90, 85, 80, 75, 70, 65, 60, 55
, 50, 45, 40,
35, 30, 25])
y_data = np.array([81, 81, 80.5, 79, 77.5, 76, 74.5, 71.5, 68.5, 67, 64, 59.5, 55, 48.5,
44, 42.5, 42,
41.5, 41.5, 41, 41, 41])
# 3. Sigmoid function defined:
def sigmoid(x, U, k):
a = 1
b = 81
return (U / (1 + np.exp(-k * (x - 77.5))))**a + b
p0 = [-40, -0.1]
x_fit = np.linspace(25, 130, 101)
y_init = sigmoid(x_fit, *p0)
popt, pcov = curve_fit(sigmoid, x_data, y_data, p0, maxfev = 10000)
y_est = sigmoid(x_data, *popt)
mse = np.mean((y_data - y_est) ** 2)
print(f"Mean-squared error: {mse}")
# 4. Sigmoid fit to data:
y_fit = sigmoid(x_fit, *popt)
# 5. Plot data and sigmoid fit:
plt.plot(x_data, y_data, marker='o', linestyle='', color='b', label='Data')
plt.plot(x_fit, y_init, color='r', label='Initial guess')
plt.plot(x_fit, y_fit, color='g', label='Sigmoid Fit')
plt.xlabel('Temperature (°C)')
plt.ylabel('Length (mm)')
plt.title('Sigmoid Fit for Contraction Data')
plt.gca().invert_yaxis() # ...Invert y-axis to start with highest value at the top
plt.legend()
plt.grid(True)
plt.show()
输出:
Mean-squared error: 1.7366871891164086