我有以下数据集:
x = [1, 6, 11, 21, 101]
y = [5, 4, 3, 2, 1]
我的目标是创建一个看起来像这样的平滑曲线:
有没有办法在Python中做到这一点?
我尝试使用here中显示的方法,这是代码:
from scipy.interpolate import spline
import matplotlib.pyplot as plt
import numpy as np
x = [1, 6, 11, 21, 101]
y = [5, 4, 3, 2, 1]
xnew = np.linspace(min(x), max(x), 100)
y_smooth = spline(x, y, xnew)
plt.plot(xnew, y_smooth)
plt.show()
但输出显示一条怪异的线。
最佳答案
首先,interpolate.spline()
has been deprecated,因此您可能不应该使用它。而是使用interpolate.splrep()
和interpolate.splev()
。转换并不困难:
y_smooth = interpolate.spline(x, y, xnew)
变成
tck = interpolate.splrep(x, y)
y_smooth = interpolate.splev(xnew, tck)
但是,这并不是这里真正的问题。默认情况下,
scipy
尝试将3级多项式拟合到您的数据,但实际上并不能完全拟合您的数据。但是由于点太少了,即使这是非直觉的近似,也可以很好地拟合您的数据。您可以将尝试与k=...
参数匹配的多项式的阶数设置为splrep()
。但是,即使是2次多项式,也是如此。它试图拟合一个抛物线,而您的数据可能适合一个在中间有弓的抛物线(现在是这样做的,因为开始时坡度如此陡峭,而中间没有数据点)。在您的情况下,您的数据可以更精确地表示为指数,因此最好拟合指数。我建议使用
scipy.optimize.curve_fit()
。它允许您指定自己的包含参数的拟合函数,它将为您拟合参数:from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import numpy as np
x = [1, 6, 11, 21, 101]
y = [5, 4, 3, 2, 1]
xnew = np.linspace(min(x), max(x), 100)
def expfunc(x, a, b, c):
return a * np.exp(-b * x) + c
popt, pcov = curve_fit(expfunc, x, y)
plt.plot(xnew, expfunc(xnew, *popt))
plt.show()