如何做固定点的多项式拟合
我一直在使用numpy(使用最小二乘法)在python中进行一些拟合。如何做固定点的多项式拟合
我想知道是否有得到它,以适应数据,同时迫使它通过一些固定点的一种方式?如果不是有Python中的另一个库(或其他语言,我可以链接到 - 例如c)?
注意我知道这是可能通过将其移动到原点,并迫使常数项为零通过一个固定点力,因为在这里要注意,但不知道一般多为2个或多个固定点:
如果使用curve_fit()
,您可以使用sigma
参数给每个点的权重。下面的例子给人的第一,中间,最后一点非常小的西格玛,所以拟合结果将非常接近这三点:
N = 20
x = np.linspace(0, 2, N)
np.random.seed(1)
noise = np.random.randn(N)*0.2
sigma =np.ones(N)
sigma[[0, N//2, -1]] = 0.01
pr = (-2, 3, 0, 1)
y = 1+3.0*x**2-2*x**3+0.3*x**4 + noise
def f(x, *p):
return np.poly1d(p)(x)
p1, _ = optimize.curve_fit(f, x, y, (0, 0, 0, 0, 0), sigma=sigma)
p2, _ = optimize.curve_fit(f, x, y, (0, 0, 0, 0, 0))
x2 = np.linspace(0, 2, 100)
y2 = np.poly1d(p)(x2)
plot(x, y, "o")
plot(x2, f(x2, *p1), "r", label=u"fix three points")
plot(x2, f(x2, *p2), "b", label=u"no fix")
legend(loc="best")
做一个合适具有固定的数学正确方法要点是使用Lagrange multipliers。基本上,您可以修改要最小化的目标函数,这通常是残差的平方和,为每个固定点添加一个额外的参数。我没有成功地将修改后的目标函数提供给scipy的最小化器之一。但是,对于一个多项式拟合,可以计算出笔和纸的细节和转换您的问题转化为线性方程系统的解决方案:
def polyfit_with_fixed_points(n, x, y, xf, yf) :
mat = np.empty((n + 1 + len(xf),) * 2)
vec = np.empty((n + 1 + len(xf),))
x_n = x**np.arange(2 * n + 1)[:, None]
yx_n = np.sum(x_n[:n + 1] * y, axis=1)
x_n = np.sum(x_n, axis=1)
idx = np.arange(n + 1) + np.arange(n + 1)[:, None]
mat[:n + 1, :n + 1] = np.take(x_n, idx)
xf_n = xf**np.arange(n + 1)[:, None]
mat[:n + 1, n + 1:] = xf_n/2
mat[n + 1:, :n + 1] = xf_n.T
mat[n + 1:, n + 1:] = 0
vec[:n + 1] = yx_n
vec[n + 1:] = yf
params = np.linalg.solve(mat, vec)
return params[:n + 1]
为了测试它的工作原理,请尝试以下,其中n
是点的数量,d
的多项式和f
的固定点的数量程度:
n, d, f = 50, 8, 3
x = np.random.rand(n)
xf = np.random.rand(f)
poly = np.polynomial.Polynomial(np.random.rand(d + 1))
y = poly(x) + np.random.rand(n) - 0.5
yf = np.random.uniform(np.min(y), np.max(y), size=(f,))
params = polyfit_with_fixed(d, x , y, xf, yf)
poly = np.polynomial.Polynomial(params)
xx = np.linspace(0, 1, 1000)
plt.plot(x, y, 'bo')
plt.plot(xf, yf, 'ro')
plt.plot(xx, poly(xx), '-')
plt.show()
当然和拟合的多项式去EXAC TLY通过点:
>>> yf
array([ 1.03101335, 2.94879161, 2.87288739])
>>> poly(xf)
array([ 1.03101335, 2.94879161, 2.87288739])
如果使用这里建议的poly1d()构造函数:https://docs.scipy.org/doc/numpy/reference/generated/numpy.polyfit.html,params切片的顺序与预期相反。简单的解决方法是将'return params [:n + 1]'改为'return params [:n + 1] [:: - 1]'。 – ijustlovemath 2017-01-02 23:30:24
一个简单且直接的方式是利用约束,其中约束加权一个相当大的数目M,像最小二乘法:
from numpy import dot
from numpy.linalg import solve
from numpy.polynomial.polynomial import Polynomial as P, polyvander as V
def clsq(A, b, C, d, M= 1e5):
"""A simple constrained least squared solution of Ax= b, s.t. Cx= d,
based on the idea of weighting constraints with a largish number M."""
return solve(dot(A.T, A)+ M* dot(C.T, C), dot(A.T, b)+ M* dot(C.T, d))
def cpf(x, y, x_c, y_c, n, M= 1e5):
"""Constrained polynomial fit based on clsq solution."""
return P(clsq(V(x, n), y, V(x_c, n), y_c, M))
显然,这不是一个真正的所有包容性的银弹的解决方案,但显然它似乎工作以及合理用简单的例子(for M in [0, 4, 24, 124, 624, 3124]
):
In []: x= linspace(-6, 6, 23)
In []: y= sin(x)+ 4e-1* rand(len(x))- 2e-1
In []: x_f, y_f= linspace(-(3./ 2)* pi, (3./ 2)* pi, 4), array([1, -1, 1, -1])
In []: n, x_s= 5, linspace(-6, 6, 123)
In []: plot(x, y, 'bo', x_f, y_f, 'bs', x_s, sin(x_s), 'b--')
Out[]: <snip>
In []: for M in 5** (arange(6))- 1:
....: plot(x_s, cpf(x, y, x_f, y_f, n, M)(x_s))
....:
Out[]: <snip>
In []: ylim([-1.5, 1.5])
Out[]: <snip>
In []: show()
,并产生输出,如:
编辑:增加了 '精确' 的解决方案:
from numpy import dot
from numpy.linalg import solve
from numpy.polynomial.polynomial import Polynomial as P, polyvander as V
from scipy.linalg import qr
def solve_ns(A, b): return solve(dot(A.T, A), dot(A.T, b))
def clsq(A, b, C, d):
"""An 'exact' constrained least squared solution of Ax= b, s.t. Cx= d"""
p= C.shape[0]
Q, R= qr(C.T)
xr, AQ= solve(R[:p].T, d), dot(A, Q)
xaq= solve_ns(AQ[:, p:], b- dot(AQ[:, :p], xr))
return dot(Q[:, :p], xr)+ dot(Q[:, p:], xaq)
def cpf(x, y, x_c, y_c, n):
"""Constrained polynomial fit based on clsq solution."""
return P(clsq(V(x, n), y, V(x_c, n), y_c))
和测试契合:
In []: x= linspace(-6, 6, 23)
In []: y= sin(x)+ 4e-1* rand(len(x))- 2e-1
In []: x_f, y_f= linspace(-(3./ 2)* pi, (3./ 2)* pi, 4), array([1, -1, 1, -1])
In []: n, x_s= 5, linspace(-6, 6, 123)
In []: p= cpf(x, y, x_f, y_f, n)
In []: p(x_f)
Out[]: array([ 1., -1., 1., -1.])
不知道,插值将有助于在这里 - 如果我的多项式模型没有通过正确的点没有任何插值会使它。 – JPH 2013-03-03 21:38:07
通过固定点,你的意思是x和y都是固定的,对吧?您可以使用http://en.wikipedia.org/wiki/Lagrange_polynomial进行插值,同时修复这些点。 – dranxo 2013-03-03 21:47:06
谢谢......看起来很有趣。目前,我已经完成了一项工作,将固定点添加到数据中,并为它们加载更多的负载....似乎可以正常工作... – JPH 2013-03-04 00:38:44