我正在将一个用R编写的脚本移植到Python上。在R中,我使用smooth.spline,在Python中,我使用SciPy 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
这是蟒蛇代码
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 中的输出是相同的。但事实并非如此。
任何帮助,例如如何设置参数或解释将不胜感激!提前谢谢你。
在我看来,这些是不同的平滑方法。
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 的实现匹配。
你可以在 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]
完全如你所愿。
如果你想直接设置lambda
:spline_xy = r_smooth_spline(x=r_x, y=r_y, lambda=42)
不起作用,因为lambda
在 Python 中已经有另一个含义,但有一个解决方案:如何在 RPy 中使用 smooth.spline 的 lambda 参数,而无需 Python 将其作为 lambda 插入。
请注意,此代码与最新版本的 Jupyter 笔记本不完全兼容rpy2
。您可以使用 NotImplementError 中所述的!pip install -Iv rpy2==3.4.2
来解决此问题:仅在我运行代码两次后,才为类型为"rpy2.rinterface.SexpClosure"> 类型的对象定义转换 'rpy2py'<</sub>