Python中的单调样条

机器算法验证 回归 曲线拟合 样条 约束回归 等渗
2022-04-01 09:10:22

我正在尝试找到一个在 Python 中单调拟合数据的过程。

数据不一定是单调的。由于理论假设,我只想实现单调拟合。

我想这样做的一种方法是运行等渗回归,然后使用三次样条插值。有更简单的选择吗?

例如,在 R 中;我会将 cob 包用于约束样条曲线。Python中是否存在类似的东西?

如果有效的话,实现相同结果的其他方法也很好(例如,在数据的单调变换上拟合曲线,以保持关系的整体形状)。

谢谢!

2个回答

嗨,我不知道您的问题的具体情况,但您可能会发现以下参考资料非常有趣:Eilers,2006(尤其是第 3 段)。参考中提出的想法实现起来相当简单(附录中应该还有一些matlab代码)。无论如何,你会在下面找到我自己的尝试:-)

一点上下文

该论文使用了一种更平滑的技术,称为 P 样条。Eilers 和 Marx 于 1991 年引入了 P 样条曲线,并结合了 B 样条曲线(在等间距已知上定义)和样条系数的有限差分正则化(第二个参考文献还包含一些代码,您可以使用这些代码来习惯该方法,如果你要)。

在我的回答中,我将使用 P 样条的特殊情况,即 Whittaker 分级方法(参见Eilers,2003,其中还包含附录中的一些计算机代码)。

强制平滑器是单调的:不对称惩罚

为了实现单调性,我们希望估计的 Whittaker 平滑器的一阶差分具有相同的符号(全部为负或正)。假设我们想要一个单调递增的 fitEilers, 2006之后,我们可以将问题写为

S=yz2+λΔ(3)z2+κvi(Δ(1)zi)2
其中是未知数向量,是三阶差分算子,是相邻平滑值之间的一阶差分算子,加权因子如果,则值为 1,否则为 0,是一个平滑参数,是一个大常数(假设等于)。zΔ(3)Δ(1)viΔ(1)zi>0λκ106

下面你会发现一个比较单调和非单调拟合的小例子。

import math
import numpy 
import matplotlib.pyplot as plt

# Simulate data
N   = 100
xlo = 0.001
xhi = 2*numpy.pi
x   = numpy.arange(xlo, xhi, step = (xhi-xlo)/N)
y0  = numpy.sin(x) + numpy.log(x) 
y   = y0 + numpy.random.randn(N) * 0.5

# Prepare bases (Imat) and penalty
dd = 3
E  = numpy.eye(N)
D3 = numpy.diff(E, n = dd, axis=0)
D1 = numpy.diff(E, n = 1, axis=0)
la = 100
kp = 10000000

# Monotone smoothing
ws = numpy.zeros(N - 1)

for it in range(30):
    Ws      = numpy.diag(ws * kp)
    mon_cof = numpy.linalg.solve(E + la * D3.T @ D3 + D1.T @ Ws @ D1, y)
    ws_new  = (D1 @ mon_cof < 0.0) * 1
    dw      = numpy.sum(ws != ws_new)
    ws      = ws_new
    if(dw == 0): break  
    print(dw)

# Monotonic and non monotonic fits
z  = mon_cof
z2 = numpy.linalg.solve(E + la * D3.T @ D3, y)

# Plots
plt.scatter(x, y, linestyle = 'None', color = 'gray', s = 0.5, label = 'raw data')
plt.plot(x, z, color = 'red', label = 'monotonic smooth')
plt.plot(x, z2, color = 'blue', linestyle = '--', label = 'unconstrained smooth')
plt.legend(loc="lower right")
plt.show()

在此处输入图像描述

我希望这会有所帮助(或者至少你觉得它很有趣)。

我不知道明确适合样条曲线的 python 包,但你应该能够在最新版本的 scikit-learn 中通过梯度提升来实现你的目标(https://scikit-learn.org/stable/auto_examples/release_highlights /plot_release_highlights_0_23_0.html)。

具体来说,您可以使用HistGradienBoostingRegressor和 setting拟合广义加法模型max_depth=1,这可确保特征之间没有交互(如果这是您想要的)。然后,您可以使用monotonic_cst为每个特征指定单调性约束。

此选项也存在于XGBoost中。