使用局部加权回归(LOESS/LOWESS)对新数据进行预测

23
如何在Python中拟合局部加权回归,以便可以用于对新数据进行预测?
有一个名为statsmodels.nonparametric.smoothers_lowess.lowess的方法,但它仅返回原始数据集的估计值;因此它似乎只能同时执行fitpredict,而不能像我期望的那样分别执行。 scikit-learn总是有一个fit方法,允许对象稍后用predict来处理新数据;但它没有实现lowess

6
@JesseBakker,它肯定可以用于预测。https://stat.ethz.ch/R-manual/R-devel/library/stats/html/predict.loess.html。另请参阅https://dev59.com/KGcs5IYBdhLWcg3wdz5m。 - max
3
@JesseBakker,lowess 是一种使用局部加权最小二乘法拟合曲线(而不是直线)的方法,可以帮助揭示趋势。虽然不常用于预测,但确实可以用于预测。 - Sarah
目前正在审核一个pull request,该请求扩展了LOWESS插值的实现。但它不会捕获拟合/预测语义。 - normanius
5个回答

19

当与插值相结合时,Lowess 在预测方面表现出色!我认为代码非常简单易懂-- 如果您有任何问题,请告诉我!Matplolib 图片

import matplotlib.pyplot as plt
%matplotlib inline
from scipy.interpolate import interp1d
import statsmodels.api as sm

# introduce some floats in our x-values
x = list(range(3, 33)) + [3.2, 6.2]
y = [1,2,1,2,1,1,3,4,5,4,5,6,5,6,7,8,9,10,11,11,12,11,11,10,12,11,11,10,9,8,2,13]

# lowess will return our "smoothed" data with a y value for at every x-value
lowess = sm.nonparametric.lowess(y, x, frac=.3)

# unpack the lowess smoothed points to their values
lowess_x = list(zip(*lowess))[0]
lowess_y = list(zip(*lowess))[1]

# run scipy's interpolation. There is also extrapolation I believe
f = interp1d(lowess_x, lowess_y, bounds_error=False)

xnew = [i/10. for i in range(400)]

# this this generate y values for our xvalues by our interpolator
# it will MISS values outsite of the x window (less than 3, greater than 33)
# There might be a better approach, but you can run a for loop
#and if the value is out of the range, use f(min(lowess_x)) or f(max(lowess_x))
ynew = f(xnew)


plt.plot(x, y, 'o')
plt.plot(lowess_x, lowess_y, '*')
plt.plot(xnew, ynew, '-')
plt.show()

12
这将使用线性插值。虽然这不是不合理的,但并不完全等同于“使用lowess进行预测”。Lowess被定义为对训练点子集进行加权线性回归。它对新数据点的预测应该基于该回归的结果,而不是基于对训练集中两个附近点的预测,然后用一条直线连接它们。对于密集的数据集,这种差异微不足道。超出范围的点也应该使用相应邻域内的加权线性回归来预测,而不是使用一个固定值。 - max
@max 刚刚遇到了一个类似问题的问题。虽然sklearn没有实现LOESS,但它有一个RANSAC实现,对于我这个没有经验的人来说似乎足够相似了。希望这对某些人有用:http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.RANSACRegressor.html - Aleksander Lidtke
@max 这个方法一点也不过分,我已经使用类似的非参数化方法来扩展代谢组学数据有一段时间了。我将范围之外的点缩放到 LOWESS 曲线的最大值或最小值,并对其他所有内容进行线性插值。如果没有足够的点进行适当的线性插值,则在我看来没有足够的点进行适当的 LOWESS 曲线。 另一个注意点是,我一直在使用 R 库来进行 LOWESS,而不是 Python 库。Python 库存在一些边缘效应问题,我无法解决。必须喜欢 RPy2。 - Daniel Hitchcock
2
如果点数不足以进行适当的线性插值,那么在我看来就没有足够的点来绘制适当的LOWESS曲线。我同情您的观点,但这是因为我个人偏爱超级简单的技术。我肯定不会试图说服许多使用LOWESS的数据科学家放弃它而采用线性插值。我没有对您的答案进行投票,但我可以理解SO用户可能认为这并没有回答我的原始问题。 - max
@AleksanderLidtke RANSAC 可能在类似于 LOWESS(或线性插值)可用的情况下可用。但它肯定是一种非常不同的算法(它是非确定性的;它对异常值的敏感度较低,因为它试图去除它们)。 - max
显示剩余4条评论

8
我已经创建了一个名为moepy的模块,它为LOWESS模型提供了类似于sklearn的API(包括fit/predict)。这使得可以使用底层的局部回归模型进行预测,而不是在其他答案中描述的插值方法。下面展示了一个极简的示例。

# Imports
import numpy as np
import matplotlib.pyplot as plt
from moepy import lowess

# Data generation
x = np.linspace(0, 5, num=150)
y = np.sin(x) + (np.random.normal(size=len(x)))/10

# Model fitting
lowess_model = lowess.Lowess()
lowess_model.fit(x, y)

# Model prediction
x_pred = np.linspace(0, 5, 26)
y_pred = lowess_model.predict(x_pred)

# Plotting
plt.plot(x_pred, y_pred, '--', label='LOWESS', color='k', zorder=3)
plt.scatter(x, y, label='Noisy Sin Wave', color='C1', s=5, zorder=1)
plt.legend(frameon=False)

enter image description here

如何使用该模型(以及置信度和预测区间变体)的更详细指南可以在此处找到。


4
考虑使用核回归代替。 statmodels有一个 实现。 如果您有太多的数据点,为什么不使用sk.learn的radiusNeighborRegression并指定三次权重函数呢?

2
@David_R,如果您提供更清晰的意思(实际展示您的实现),这个答案将会非常出色。只是一个建议。 - benjaminmgross
@benjaminmgross,谢谢你的留言。也许我这周末或下周有时间详细说明一下。 - David R

1

0

目前还不清楚是否好的想法是拥有一个专门的LOESS对象,其中包含类似于Scikit-Learn中常见的独立适应/预测方法。相比之下,对于神经网络,您可以拥有仅存储少量权重的对象。拟合方法将使用非常大的训练数据集来优化“少量”权重。预测方法仅需要权重来进行新的预测,而不需要整个训练集。

另一方面,基于LOESS和最近邻居的预测需要整个训练集才能进行新的预测。适合方法唯一能做的就是将训练集存储在对象中以供以后使用。如果x和y是训练数据,并且x0 是进行新预测的点,则面向对象的适应/预测解决方案将看起来像以下内容:

model = Loess()
model.fit(x, y)         # No calculations. Just store x and y in model.
y0 = model.predict(x0)  # Uses x and y just stored.

相比之下,我在我的localreg库中选择了简单性:

y0 = localreg(x, y, x0)

这实际上取决于设计选择,因为性能将是相同的。 fit/predict方法的一个优点是,您可以像Scikit-Learn中那样拥有统一的接口,其中一个模型可以轻松地被另一个模型替换。fit/predict方法还鼓励以机器学习方式思考它,但在这种意义上,LOESS不是非常高效,因为它需要存储和使用每个新预测的所有数据。后一种方法更倾向于将LOESS作为散点图平滑算法的起源,这也是我喜欢思考它的方式。这也可能解释了为什么statsmodel以他们的方式执行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接