2013-03-03 17 views
7

私は、numpy(最小二乗を使う)を使ってPythonでいくつかのフィッティングを行ってきました。固定小数点の多項式近似を行う方法

いくつかの固定小数点を強制しながらデータを収める方法があるのだろうかと思っていましたか?そうでない場合は、Pythonで別のライブラリがありますか(または別の言語にリンクできますか?たとえばc)?

NOTE私はここで注目されるように、それは、原点に移動し、ゼロに定数項を強制することにより、一つの固定点を通って強制することが可能です知っているが、2以上の固定点のために、より一般的に思っていた。

あなたが curve_fit()を使用している場合

http://www.physicsforums.com/showthread.php?t=523360

+0

わからない補間がここに役立つことを - もし私の多項式モデルは右の点を通らず、補間はできません。 – JPH

+2

固定小数点は、xとyの両方が固定されていることを意味します。これらのポイントを修正しながら補間するには、http://en.wikipedia.org/wiki/Lagrange_polynomialを使用できます。 – dranxo

+1

ありがとう...面白そうです。その瞬間、私は固定小数点をデータに追加して残りの部分を負荷するような作業をしました。... – JPH

答えて

8

は、あなたはすべての点に重みを与えるためにsigma引数を使用することができます。次の例では、最初、真ん中、最後の点は非常に小さいシグマを与えるので、フィッティング結果は、これらの3つのポイントに非常に近いようになります。

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") 

enter image description here

11

固定でフィットを行うための数学的に正しい方法ポイントはLagrange multipliersです。基本的には、最小化する目的関数を変更します。通常、残差の2乗の合計であり、固定小数点ごとに追加のパラメータが追加されます。私はscipyのミニマイザの1つに修正された目的関数を与えることに成功しませんでした。しかし、多項式適合のために、あなたはペンと紙で詳細を把握することができますし、方程式の線形システムのソリューションにあなたの問題を変換します。それが動作することをテストするには

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は、以下を試してくださいポイント数、多項式とf固定点の数のd度:

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() 

enter image description here

そしてもちろんフィット多項式はexacを行きます

>>> yf 
array([ 1.03101335, 2.94879161, 2.87288739]) 
>>> poly(xf) 
array([ 1.03101335, 2.94879161, 2.87288739]) 
+0

https://docs.scipy.org/doc/numpy/reference/generated/numpy.polyfit.htmlで提案されているpoly1d()コンストラクタを使用している場合、paramsスライスの順序は、期待されるものと逆です。簡単な修正は 'return params [:n + 1]'を 'return params [:n + 1] [:: - 1]'に変更することです。 – ijustlovemath

4

一つのシンプルで簡単な方法は、制約が大きめ数Mで重み付けされている制約最小二乗を利用することである、のような:TLY点を

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() 

と生産の出力のような: fits with progressive larger M

編集:を追加しました '正確な' ソリューション:

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.]) 
関連する問題