20

私は、numpy(最小二乗法を使用)を使用してPythonでフィッティングを行っています。

いくつかの固定小数点を強制的に通過させながら、データをデータに適合させる方法があるかどうか疑問に思いました。そうでない場合は、Python(またはリンクできる別の言語-たとえばc)に別のライブラリがありますか?

ここに記載されているように、1つの固定点を原点に移動し、定数項を強制的にゼロにすることで強制的に通過できることはわかっていますが、2つ以上の固定点についてはより一般的に疑問に思っていました。

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

4

3 に答える 3

23

固定小数点で近似を行う数学的に正しい方法は、ラグランジュ乗数を使用することです。基本的に、最小化する目的関数を変更します。これは通常、残差の二乗和であり、固定点ごとに追加のパラメーターを追加します。変更された目的関数を 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は点の数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_points(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()

ここに画像の説明を入力

そしてもちろん、当てはめられた多項式は点を正確に通過します:

>>> yf
array([ 1.03101335,  2.94879161,  2.87288739])
>>> poly(xf)
array([ 1.03101335,  2.94879161,  2.87288739])
于 2013-03-04T07:32:20.183 に答える
15

を使用するcurve_fit()と、引数を使用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")

ここに画像の説明を入力

于 2013-03-04T01:53:23.017 に答える
7

シンプルで簡単な方法の 1 つは、次のように、制約が大きな数 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()

次のような出力を生成します。 プログレッシブより大きい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.])
于 2013-03-07T21:07:13.817 に答える