python中计算最小范数解或伪逆解的最精确方法是什么?
我的目标是解决:python中计算最小范数解或伪逆解的最精确方法是什么?,python,numpy,precision,linear-algebra,linear-regression,Python,Numpy,Precision,Linear Algebra,Linear Regression,我的目标是解决: Kc=y 使用伪逆(即最小范数解): 这样模型(希望)是高次多项式模型f(x)=sum_i c_i x^i。我特别感兴趣的是欠定情况,在这种情况下,多项式特征比数据多(很少方程,变量/未知数太多)columns=deg+1>N=rows。注K是多项式特征的范德模矩阵 我最初使用的是python函数,但后来我注意到了一些奇怪的事情,正如我在这里指出的那样:。在这个问题中,我使用一个平方矩阵来学习区间[-1.+1]上的函数和高次多项式。那里的答案建议我降低多项式的次数和/或增加区
Kc=y
使用伪逆(即最小范数解):
这样模型(希望)是高次多项式模型f(x)=sum_i c_i x^i
。我特别感兴趣的是欠定情况,在这种情况下,多项式特征比数据多(很少方程,变量/未知数太多)columns=deg+1>N=rows
。注K
是多项式特征的范德模矩阵
我最初使用的是python函数,但后来我注意到了一些奇怪的事情,正如我在这里指出的那样:。在这个问题中,我使用一个平方矩阵来学习区间[-1.+1]
上的函数和高次多项式。那里的答案建议我降低多项式的次数和/或增加区间大小。主要的问题是,在事情变得不可靠之前,我不清楚如何选择间隔或最大度。我认为我的主要问题是,选择这样一个数值稳定的范围取决于我可能使用的方法。最后我真正关心的是
import numpy as np
from sklearn.preprocessing import PolynomialFeatures
def l2_loss(y,y_):
N = y.shape[0]
return (1/N)*np.linalg.norm(y-y_)
## some parameters
lb,ub = -200,200
N=100
D0=1
degree_mdl = 120
## target function
freq_cos = 2
f_target = lambda x: np.cos(freq_cos*2*np.pi*x)
## evaluate target_f on x_points
X = np.linspace(lb,ub,N) # [N,]
Y = f_target(X) # [N,]
# get pinv solution
poly_feat = PolynomialFeatures(degree=degree_mdl)
Kern = poly_feat.fit_transform( X.reshape(N,D0) ) # low degrees first [1,x,x**2,...]
c_pinv = np.dot(np.linalg.pinv( Kern ), Y)
## get polyfit solution
c_polyfit = np.polyfit(X,Y,degree_mdl)[::-1] # need to reverse to get low degrees first [1,x,x**2,...]
##
c_lstsq,_,_,_ = np.linalg.lstsq(Kern,Y.reshape(N,1))
##
print('lb,ub = {} '.format((lb,ub)))
print('differences with c_pinv')
print( '||c_pinv-c_pinv||^2 = {}'.format( np.linalg.norm(c_pinv-c_pinv) ))
print( '||c_pinv-c_polyfit||^2 = {}'.format( np.linalg.norm(c_pinv-c_polyfit) ))
print( '||c_pinv-c_lstsq||^2 = {}'.format( np.linalg.norm(c_pinv-c_lstsq) ))
##
print('differences with c_polyfit')
print( '||c_polyfit-c_pinv||^2 = {}'.format( np.linalg.norm(c_polyfit-c_pinv) ))
print( '||c_polyfit-c_polyfit||^2 = {}'.format( np.linalg.norm(c_polyfit-c_polyfit) ))
print( '||c_polyfit-c_lstsq||^2 = {}'.format( np.linalg.norm(c_polyfit-c_lstsq) ))
##
print('differences with c_lstsq')
print( '||c_lstsq-c_pinv||^2 = {}'.format( np.linalg.norm(c_lstsq-c_pinv) ))
print( '||c_lstsq-c_polyfit||^2 = {}'.format( np.linalg.norm(c_lstsq-c_polyfit) ))
print( '||c_lstsq-c_lstsq||^2 = {}'.format( np.linalg.norm(c_lstsq-c_lstsq) ))
##
print('Data set errors')
y_polyfit = np.dot(Kern,c_polyfit)
print( 'J_data(c_polyfit) = {}'.format( l2_loss(y_polyfit,Y) ) )
y_pinv = np.dot(Kern,c_pinv)
print( 'J_data(c_pinv) = {}'.format( l2_loss(y_pinv,Y) ) )
y_lstsq = np.dot(Kern,c_lstsq)
print( 'J_data(c_lstsq) = {}'.format( l2_loss(y_lstsq,Y) ) )
使用它,我注意到polyfit
很少与pinv
使用的参数匹配。我知道pinv最终返回伪逆,所以我想如果我的主要目标是“确保我使用伪逆”,那么使用np.pinv
是个好主意。然而,我在数学上也知道,无论怎样,伪逆总是最小化最小二乘误差J(c)=| | Kc-y | | ^2
(证明定理11.1.2第446页)。因此,也许我的目标应该是使用python函数,该函数返回最小的最小二乘误差J
。因此,我(在未确定的情况下)比较了三种方法
np.polyfit
np.linalg.pinv
np.linalg.lstsq
lb,ub = (-100, 100)
Data set errors
J_data(c_polyfit) = 5.329753025633029e-12
J_data(c_pinv) = 0.06670557822873546
J_data(c_lstsq) = 0.7479733306782645
鉴于这些结果以及伪逆是最小二乘法的极小值,似乎最好忽略np.pinv
。这是最好的办法吗?还是我遗漏了一些明显的东西
作为一个额外的注意事项,我去看看到底是什么使得它具有更好的最小二乘误差(我现在用它来表示它是伪逆的最佳近似值),它似乎有一些奇怪的条件/数值稳定性代码:
# scale lhs to improve condition number and solve
scale = NX.sqrt((lhs*lhs).sum(axis=0))
lhs /= scale
c, resids, rank, s = lstsq(lhs, rhs, rcond)
c = (c.T/scale).T # broadcast scale coefficients
我想,是什么给polyfit带来了pinv
所没有的额外稳定性
在我的高次多项式线性系统近似任务中使用polyfit
是正确的决定吗
此外,在这一点上,我愿意使用其他软件,如matlab,如果它为我提供了正确的伪逆和更多的数值稳定性(对于大多数度和任何边界)
我刚才的另一个随机想法是,也许有一种很好的方法对函数进行采样,这样伪逆的稳定性就好了。我的猜测是,用多项式近似余弦需要某种类型的样本数或样本之间的距离(如奈奎斯特-香农采样定理所说,如果基函数是正弦函数…)
应该指出的是,很可能先反转(或伪反转),然后再相乘是个坏主意。见: 那个只讨论逆,但我假设它也扩展到伪逆
现在我的困惑是,通常我们不想显式地计算伪逆,而是做
A^+y=x_min_norm
来获得最小范数解。然而,我本以为np.lstsq
会得到我想要的答案,但它的错误也与另一个大不相同。我发现这非常令人困惑……让我觉得我使用了错误的方法来获得python中的最小范数解决方案
我不想得到一个正规化的解决方案。我试图得到最小范数解,而不是别的,尽可能精确地计算数值。我的研究领域涉及一种基本上被称为傅里叶扩展的压缩算法。什么是最准确的?它高度依赖于向量,我相信这是由于平滑的特性。在夏天,我用了一种叫做。有相当稳定和精确的数值滤波方法。然而,我的顾问有一种相对快速且数值稳定的方法。该区域称为傅立叶延拓或延拓。怎么用?我不知道我是否被允许发布它,这里是如果我相信我可能已经在这个夏天发布在这里的python部分 这与python无关,因为python使用与大多数数字编码方案相同的底层库,即BLAS和LAPACK。是在线的 还有许多其他类似的fast和numeri
# scale lhs to improve condition number and solve
scale = NX.sqrt((lhs*lhs).sum(axis=0))
lhs /= scale
c, resids, rank, s = lstsq(lhs, rhs, rcond)
c = (c.T/scale).T # broadcast scale coefficients
v = (1:.5:6);
V = vander(v);
c1 = cond(V)
v2 = (1:.5:12);
c2 = cond(vander(v2));
display(c1)
display(c2)
function B = lowapprox(A)
% Takes a matrix A
% Returns a low rank approx of it
% utilizing the SVD
chi = 1e-10;
[U,S,V] = svd(A,0);
DS = diag(S);
aa = find(DS > chi);
s= S(aa,aa);
k = length(aa);
Un = U(:,1:k);
Vn = V(:,1:k)';
B = Un*s*Vn;
end
V2 = vander(v2);
r2 = rank(V2);
c2=cond(V2);
B = lowapprox(V2);
c3 = cond(B);
display(c3)
c2 =
9.3987e+32
c3 =
3.7837e+32
t= (0:.01:pi)';
f = cos(t);
data = [t,f];
f1 = barylag(data,t)
display(err =norm(f1-f1))
err =
0