我有以下数据:
>>> x
array([ 3.08, 3.1 , 3.12, 3.14, 3.16, 3.18, 3.2 , 3.22, 3.24,
3.26, 3.28, 3.3 , 3.32, 3.34, 3.36, 3.38, 3.4 , 3.42,
3.44, 3.46, 3.48, 3.5 , 3.52, 3.54, 3.56, 3.58, 3.6 ,
3.62, 3.64, 3.66, 3.68])
>>> y
array([ 0.000857, 0.001182, 0.001619, 0.002113, 0.002702, 0.003351,
0.004062, 0.004754, 0.00546 , 0.006183, 0.006816, 0.007362,
0.007844, 0.008207, 0.008474, 0.008541, 0.008539, 0.008445,
0.008251, 0.007974, 0.007608, 0.007193, 0.006752, 0.006269,
0.005799, 0.005302, 0.004822, 0.004339, 0.00391 , 0.003481,
0.003095])
现在,我想用 4 次多项式来拟合这些数据。所以我这样做:
>>> coefs = np.polynomial.polynomial.polyfit(x, y, 4)
>>> ffit = np.poly1d(coefs)
现在我为 x 值创建一个新网格来评估拟合函数
ffit
:
>>> x_new = np.linspace(x[0], x[-1], num=len(x)*10)
当我使用命令完成所有绘图(数据集和拟合曲线)时:
>>> fig1 = plt.figure()
>>> ax1 = fig1.add_subplot(111)
>>> ax1.scatter(x, y, facecolors='None')
>>> ax1.plot(x_new, ffit(x_new))
>>> plt.show()
我得到以下信息:
我期望的是拟合函数能够正确拟合(至少接近数据的最大值)。我做错了什么?
不幸的是,
np.polynomial.polynomial.polyfit
以与np.polyfit
和np.polyval
相反的顺序返回系数(或者,如您使用的np.poly1d
)。举例说明:
In [40]: np.polynomial.polynomial.polyfit(x, y, 4)
Out[40]:
array([ 84.29340848, -100.53595376, 44.83281408, -8.85931101,
0.65459882])
In [41]: np.polyfit(x, y, 4)
Out[41]:
array([ 0.65459882, -8.859311 , 44.83281407, -100.53595375,
84.29340846])
一般来说:
np.polynomial.polynomial.polyfit
返回系数[A, B, C]
到A + Bx + Cx^2 + ...
,而np.polyfit
返回:... + Ax^2 + Bx + C
。
所以如果你想使用这个函数组合,你必须颠倒系数的顺序,如下所示:
ffit = np.polyval(coefs[::-1], x_new)
但是,文档明确指出要避免
np.polyfit
、np.polyval
和np.poly1d
,而只使用新的(呃)包。
仅使用多项式包是最安全的:
import numpy.polynomial.polynomial as poly
coefs = poly.polyfit(x, y, 4)
ffit = poly.polyval(x_new, coefs)
plt.plot(x_new, ffit)
或者,创建多项式函数:
ffit = poly.Polynomial(coefs) # instead of np.poly1d
plt.plot(x_new, ffit(x_new))
请注意,您可以直接使用 Polynomial 类进行拟合并返回 Polynomial 实例。
from numpy.polynomial import Polynomial
p = Polynomial.fit(x, y, 4)
plt.plot(*p.linspace())
p
使用缩放和移动的 x 值来实现数值稳定性。如果您需要系数的通常形式,则需要遵循
pnormal = p.convert(domain=(-1, 1))
执行数据拟合时需要注意的关键行(在下面的完整代码中)是,例如:
import matplotlib.pyplot as plt
from numpy.polynomial import Polynomial
# ...
cheby_series = Chebyshev.fit(x, y, deg=5)
x_cheby, y_cheby = cheby_series.linspace()
poly_series = Polynomial.fit(x, y, deg=5)
x_poly, y_poly = poly_series.linspace()
# ...
plt.plot(x_cheby, y_cheby, linewidth=6, alpha=0.5,
label="Chebyshev Series 5th degree\nleast squares best fit curve")
plt.plot(x_poly, y_poly, 'k', linewidth=1,
label="Polynomial Series 5th degree\nleast squares best fit curve")
这是我的完整程序的输出如下(不是来自上面的部分程序片段):
即使在阅读了这里的所有答案之后,由于 Matplotlib 的变化以及我遇到的一些其他问题,我真的一直在努力解决这个问题,直到我终于找到了这个演示!:https://numpy.org/doc/stable /reference/routines.polynomials.classes.html.
它在最底部的“配件”部分下包含一个很好的示例!:
import numpy as np
import matplotlib.pyplot as plt
from numpy.polynomial import Chebyshev as T
np.random.seed(11)
x = np.linspace(0, 2*np.pi, 20)
y = np.sin(x) + np.random.normal(scale=.1, size=x.shape)
p = T.fit(x, y, 5)
plt.plot(x, y, 'o')
xx, yy = p.linspace()
plt.plot(xx, yy, lw=2)
p.domain
p.window
plt.show()
这是它的增强版本,包含我的修改和一些有用的评论。我从我的 eRCaGuy_hello_world 存储库中的 plot_best_fit_polynomial.py 演示修改了下面的代码:
import matplotlib.pyplot as plt
from numpy.polynomial import Chebyshev
from numpy.polynomial import Polynomial
# data to fit
x = [0. , 0.33069396, 0.66138793, 0.99208189, 1.32277585,
1.65346982, 1.98416378, 2.31485774, 2.64555171, 2.97624567,
3.30693964, 3.6376336 , 3.96832756, 4.29902153, 4.62971549,
4.96040945, 5.29110342, 5.62179738, 5.95249134, 6.28318531]
y = [ 0.17494547, 0.29609217, 0.5657562 , 0.57183462, 0.9685718 ,
0.96462136, 0.86211039, 0.76726418, 0.51805246, 0.05803429,
-0.25321856, -0.52352074, -0.66675568, -0.85965411, -1.12713934,
-1.08134779, -0.76348274, -0.45674931, -0.32780698, -0.06834466]
# Obtain a 5th degree (order) least-squares fit curve to the x, y data using a
# Chebyshev Series
cheby_series = Chebyshev.fit(x, y, deg=5)
# Lines-space: get evenly-spaced points to plot a line; see:
# https://numpy.org/doc/stable/reference/generated/numpy.polynomial.chebyshev.Chebyshev.linspace.html
x_cheby, y_cheby = cheby_series.linspace()
# Now do the same things with a 5th order Polynomial Series fit as well!
# see: https://numpy.org/doc/stable/reference/generated/numpy.polynomial.polynomial.Polynomial.html
poly_series = Polynomial.fit(x, y, deg=5)
x_poly, y_poly = poly_series.linspace()
# plot all the data
f1 = plt.figure()
plt.plot(x, y, 'o')
plt.plot(x_cheby, y_cheby, linewidth=6, alpha=0.5,
label="Chebyshev Series 5th degree\nleast squares best fit curve")
plt.plot(x_poly, y_poly, 'k', linewidth=1,
label="Polynomial Series 5th degree\nleast squares best fit curve")
plt.legend()
plt.show()