草庐IT

python - python中用于计算最小范数解或从伪逆获得的解的最准确方法是什么?

coder 2023-08-13 原文

我的目标是解决:

Kc=y

对于伪逆(即最小范数解):
c=K^{+}y

这样的模型(希望)是高次多项式模型。我特别感兴趣的是未确定的情况,在这种情况下,我们有比数据更多的多项式特征(很少有方程太多变量/未知量)f(x) = sum_i c_i x^i。注:columns = deg+1 > N = rows是多项式特征的范德模式矩阵。
我最初使用的是python函数np.linalg.pinv,但后来我注意到了一些奇怪的事情正在发生,正如我在这里注意到的那样:Why do different methods for solving Xc=y in python give different solution when they should not?。在这个问题中,我用一个方阵来学习一个高阶多项式区间上的函数。这里的答案建议我降低多项式的阶数和/或增加区间大小。主要的问题是,在事情变得不可靠之前,我不清楚如何选择间隔或最大程度。我认为我的主要问题是,选择这样一个数值稳定的范围取决于我可以使用的方法。最后我真正关心的是
对于这个多项式拟合问题,我使用的方法与伪逆精确(或非常接近)
它的数值稳定
理想情况下,我想尝试一个大的多项式,但这可能会受到我的机器精度的限制。是否可以使用比浮点数更精确的数值来提高机器的数值精度?
另外,我真的很关心我使用的python中的任何函数,它提供了最接近伪逆的答案(并且希望它的数值稳定,这样我就可以实际使用它)。为了检查伪反转的答案,我编写了以下脚本:
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) ) )

我注意到,很少有K[-1.+1]使用的参数匹配。我知道pinv最终返回伪逆,所以我猜如果我的主要目标是“确保我使用伪逆”,那么使用polyfit是个好主意。然而,我也从数学上知道,伪逆总是最小化最小二乘误差pinv无论什么(证明here定理11.1.2,第446页)。因此,也许我的目标应该是只使用返回最小最小二乘误差的python函数。因此,我(在不确定的情况下)比较了这三种方法
多元土,np.pinv
伪逆,J(c) = || Kc - y ||^2
最小二乘法,J
并比较了他们在数据上给我的误差最小二乘误差:

然后我检查了函数似乎经历的奇怪的下降(如果算法不是随机的,那么这似乎是一个完全的谜,为什么会有下降),对于polyfit,数字通常较小,例如:
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.polyfit。这是最好的办法吗?或者我错过了一些明显的东西?
作为一个额外的说明,我进入了polyfit code来看看究竟是什么使得它有更好的最小二乘误差(现在我用它来表示伪逆的最佳近似值),它似乎有一些奇怪的条件/数值稳定性代码:
# 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

我假设,是什么给np.linalg.pinv没有的polyfit带来了额外的稳定性?
对于我的高阶多项式线性系统逼近任务,这是正确的决定吗?
另外,在这一点上,我愿意使用其他软件,如matlab,如果它提供了正确的伪逆和更多的数值稳定性(对于大多数度和任何边界)。
我刚才还有一个随机的想法,那就是也许有一个很好的方法来对函数进行采样,这样伪逆函数的稳定性就很好了。我的猜测是,用多项式近似一个余弦需要一些类型的样本或样本之间的距离(就像尼奎斯特-香农抽样定理所说的如果基函数是正弦函数…)
应该指出的是,可能是颠倒(或伪ivnerting),然后乘以是一个坏主意。见:
https://www.johndcook.com/blog/2010/01/19/dont-invert-that-matrix/
那个只讲逆,但我假设它也延伸到了伪逆。
现在我的困惑是,通常我们不想显式地计算伪逆,而要得到最小范数解。然而,我本以为np.linalg.lstsq会给出我想要的答案,但它的错误也与其他的大不相同。我发现这非常令人困惑……让我觉得我使用了错误的方法来获得Python中的最小范数解决方案。
我不想得到一个正规化的解决方案。我试图得到最小范数解,而没有其他的,尽可能精确的数值计算。

最佳答案

我的研究领域涉及一种压缩算法,本质上称为傅立叶扩展。最准确的是什么?它高度依赖于向量,我相信这是由于平滑的特性。在夏天,我用了一种叫做Savitsky Golay的东西。有相当稳定的数值和精确的过滤方法。然而,我的顾问有一个相对快速和数值稳定的方法。这个区域称为傅立叶延拓或延拓。怎样?我不知道是否允许我发布它,这里是article.如果我相信我可能已经在夏天在这里发布了部分python。
这与python无关,因为python使用的底层库与大多数数字编码方案(blas和lapack)相同。Netlib在线。
有许多其他类似的快速和数字稳定的想法,可能是合适的,我会推荐。有一整本书专门论述这一点,第6章和第7章都是关于这一点的。它是关于在我想象的信号中,由于潜在的噪声,随正则化的总变化。
其他方面。由于条件不好,您可能需要调整SVD。通常都有专门的书。简单地回答你的问题,什么是最好的算法。算法有多个维度,您还没有真正说明问题的性质。如果你不知道y Boyd.这是使用高度多项式是不利的。
有整整一类厄米多项式来处理吉布斯现象和其他滤波技术,但这并不是很好的提出。您使用的是通用函数。我建议你去买汉森和鲍。有时他们会做切比切夫式的回绝。
K的条件数是多少。另外,当拟合称为梯级现象的多项式时,会发生一些事情。你应该考虑一下。如果条件值太高,请使用需要进行低阶近似的通用函数进行正则化。实际上我刚刚读过。你用的是范德蒙矩阵。我将很容易地证明这一点。范德蒙矩阵不好。不要使用它们。Runge's phenomenon.

v = (1:.5:6);

V = vander(v);

c1 = cond(V)

v2 = (1:.5:12);
c2 = cond(vander(v2));
display(c1)
display(c2)

C1=
6.0469E+12型
C2=
9.3987E+32
我尝试了一个低阶近似,但范德蒙矩阵并不好。看。
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

真的没有什么……如果你不知道当你得到这个倒数时发生了什么,条件数等于最大奇异值超过最小值,所以在机器精度上你有一些非常小的奇异值。
另外,我认为你对最小范数和正则化有些混淆。你说你想要一个最小范数在最小二乘意义上。SVD给出They have knots.
它的属性9,A是由SVD根据基础构造的。这在Trefetten中有介绍,但vandermonde矩阵是病态的。
即使是构造不良的范德蒙矩阵也会丢失它。关于你的解决方案。不要使用范德蒙矩阵。否则构造多项式。一个更好的想法是重心拉格朗日插值。图书馆least squares.
下面是matlab中的一个例子。
t= (0:.01:pi)';
f = cos(t);
data = [t,f];
f1 = barylag(data,t)
display(err =norm(f1-f1))
err =

     0

Barylag取自Matlab网站。由于我不能对你的差异做出真正的评论,你应该认识到LSQR的实际方式。LSQR算法是Krylov方法。这是在特雷费顿。SVD ishere我在我的Quora页面上有一个关于数值稳定性的例子,它是你实际构造这些算法的方法。

关于python - python中用于计算最小范数解或从伪逆获得的解的最准确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46879411/

有关python - python中用于计算最小范数解或从伪逆获得的解的最准确方法是什么?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  5. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  6. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  7. Ruby 方法() 方法 - 2

    我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby​​-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco

  8. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  9. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  10. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

随机推荐