Python SciPy单变量样条与R平滑样条

mspsb9vt  于 2022-12-05  发布在  Python
关注(0)|答案(2)|浏览(143)

我正在将一个用R编写的脚本移植到Python中。在R中我使用smooth.spline,在Python中我使用SciPy UnivariateSpline。它们产生的结果不一样(即使它们都是基于三次样条方法)。有没有一种方法,或者UnivariateSpline的替代方法,使Python样条返回与R相同的样条?
我是一个数学家,我了解样条函数的一般概念,但不了解它们在Python或R中实现的细节。
这是R和Python的代码,两者的输入数据相同。
下面是输入数据:

x =  0.0,  0.1,  0.2,  0.3,  0.4,  0.5,  0.6,  0.7,  0.8,  0.9,  1.0
y =   -1,    1,    1,   -1,    1,    0,   .5,   .5,   .4,   .5,   -1

这是R代码

x = seq(0,1, by = .1); 
y = c(-1,1,1, -1,1,0, .5,.5,.4,  .5, -1);
spline_xy = smooth.spline(x,y)
predict(spline_xy,x)

其输出:

$x
 [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0

$y
 [1]  0.120614583  0.170800975  0.210954680  0.238032338  0.253672155
 [6]  0.253684815  0.236432643  0.200264536  0.145403302  0.074993797
[11] -0.004853825

下面是Python代码

import numpy as np
from scipy.interpolate import UnivariateSpline
x = np.linspace(0, 1, num = 11, endpoint=True)    
y = np.array([-1,1,1, -1,1,0, .5,.5,.4,  .5, -1]) 
spline_xy = UnivariateSpline(x,y)
print('x =', x)
print('ysplined =',spline_xy(x))

其输出:

x = [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]

ysplined = 
[-0.26433566 -0.02587413  0.18857809 0.36585082  0.49277389  
  0.55617716 0.54289044  0.43974359  0.23356643 -0.08881119 
 -0.54055944]

我希望R $y和Python ysplined的输出是一样的,但事实并非如此。
任何帮助,例如如何设置参数,或解释将不胜感激!提前感谢。

vu8f3i0k

vu8f3i0k1#

在我看来,这些是不同的平滑方法。
R中的smooth.spline是一个“平滑样条”,它是一个过度参数化的自然样条(每个数据点都有节点,内部是三次样条,线性外推),用惩罚最小二乘来选择参数。你可以阅读帮助页面了解如何计算惩罚的细节。
另一方面,Python的UnivariateSpline出现在这里的文档中:https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.UnivariateSpline.html为回归样条,通过最小二乘法拟合,无惩罚。它似乎自适应地选择节点数。
这是完全不同的算法,我不希望它们给予相同的结果。我不知道是否有一个R包使用与Python相同的自适应选择结。答案是:https://stackoverflow.com/a/55481248/2554330声称引用了Python中的自然平滑样条实现,但我不知道它是否与R的实现相匹配。

4zcjmb1e

4zcjmb1e2#

可以在Python中将R函数与rpy2一起使用:

import numpy as np
import rpy2.robjects as robjects
x = np.linspace(0, 1, num = 11, endpoint=True)    
y = np.array([-1,1,1, -1,1,0, .5,.5,.4,  .5, -1])

r_x = robjects.FloatVector(x)
r_y = robjects.FloatVector(y)
r_smooth_spline = robjects.r['smooth.spline'] #extract R function
spline_xy = r_smooth_spline(x=r_x, y=r_y)
print('x =', x)
print('ysplined =',np.array(robjects.r['predict'](spline_xy,robjects.FloatVector(x)).rx2('y')))

其输出:

x = [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]
ysplined = [ 0.12061458  0.17080098  0.21095468  0.23803234  0.25367215  0.25368481
0.23643264  0.20026454  0.1454033   0.0749938  -0.00485382]

就像你希望的那样
如果要直接设置lambdaspline_xy = r_smooth_spline(x=r_x, y=r_y, lambda=42)不起作用,因为lambda在Python中已经有了另一种含义,但是有一个解决方案:How to use the lambda argument of smooth.spline in RPy WITHOUT Python interprating it as lambda
请注意,此代码与最新版本rpy2的Jupyter-notebook不完全兼容。您可以通过使用NotImplementedError中所述的!pip install -Iv rpy2==3.4.2来修复此问题:只有在我运行代码两次之后,才为类型为“〈class 'rpy2.rinterface.SexpClosure'〉”的对象定义转换“rpy 2 py”

相关问题