Python中的分段线性回归
4 个回答
0
你只需要把X按从小到大的顺序排列,然后创建几个线性回归模型。可以使用sklearn里的LinearRegression。
比如,把曲线分成两部分就像这样:
from sklearn.linear_model import LinearRegression
import numpy as np
import matplotlib.pyplot as plt
X = np.array([-5,-4,-3,-2,-1,0,1,2,3,4,5])
Y = X**2
X=X.reshape(-1,1)
reg1 = LinearRegression().fit(X[0:6,:], Y[0:6])
reg2 = LinearRegression().fit(X[6:,:], Y[6:])
fig = plt.figure('Plot Data + Regression')
ax1 = fig.add_subplot(111)
ax1.plot(X, Y, marker='x', c='b', label='data')
ax1.plot(X[0:6,],reg1.predict(X[0:6,]), marker='o',c='g', label='linear r.')
ax1.plot(X[6:,],reg2.predict(X[6:,]), marker='o',c='g', label='linear r.')
ax1.set_title('Data vs Regression')
ax1.legend(loc=2)
plt.show()
我做了一个类似的实现,这里是代码:https://github.com/mavaladezt/Segmented-Algorithm
3
如上面的评论所提到的,分段线性回归会面临很多自由参数的问题。因此,我决定不采用那种需要 n_segments * 3 - 1 个参数的方法(也就是 n_segments - 1 个分段位置、n_segment 的 y 偏移量和 n_segment 的斜率),并且还要进行数值优化。相反,我想寻找那些已经有大致恒定斜率的区域。
算法
- 计算所有点的斜率
- 将斜率相似的点聚类成段(通过决策树完成)
- 对在上一步找到的段进行线性回归
这里使用决策树而不是聚类算法,是为了得到相连的段,而不是一组(不相邻的)点。分段的具体细节可以通过决策树的参数进行调整(目前使用的是 max_leaf_nodes
)。
代码
import numpy as np
import matplotlib.pylab as plt
from sklearn.tree import DecisionTreeRegressor
from sklearn.linear_model import LinearRegression
# parameters for setup
n_data = 20
# segmented linear regression parameters
n_seg = 3
np.random.seed(0)
fig, (ax0, ax1) = plt.subplots(1, 2)
# example 1
#xs = np.sort(np.random.rand(n_data))
#ys = np.random.rand(n_data) * .3 + np.tanh(5* (xs -.5))
# example 2
xs = np.linspace(-1, 1, 20)
ys = np.random.rand(n_data) * .3 + np.tanh(3*xs)
dys = np.gradient(ys, xs)
rgr = DecisionTreeRegressor(max_leaf_nodes=n_seg)
rgr.fit(xs.reshape(-1, 1), dys.reshape(-1, 1))
dys_dt = rgr.predict(xs.reshape(-1, 1)).flatten()
ys_sl = np.ones(len(xs)) * np.nan
for y in np.unique(dys_dt):
msk = dys_dt == y
lin_reg = LinearRegression()
lin_reg.fit(xs[msk].reshape(-1, 1), ys[msk].reshape(-1, 1))
ys_sl[msk] = lin_reg.predict(xs[msk].reshape(-1, 1)).flatten()
ax0.plot([xs[msk][0], xs[msk][-1]],
[ys_sl[msk][0], ys_sl[msk][-1]],
color='r', zorder=1)
ax0.set_title('values')
ax0.scatter(xs, ys, label='data')
ax0.scatter(xs, ys_sl, s=3**2, label='seg lin reg', color='g', zorder=5)
ax0.legend()
ax1.set_title('slope')
ax1.scatter(xs, dys, label='data')
ax1.scatter(xs, dys_dt, label='DecisionTree', s=2**2)
ax1.legend()
plt.show()
6
可能可以使用Numpy的numpy.piecewise()
工具。
更详细的描述可以在这里找到:
如何在Python中应用分段线性拟合?
如果这不是你需要的,那么你可能会在以下问题中找到一些有用的信息:
https://datascience.stackexchange.com/questions/8266/is-there-a-library-that-would-perform-segmented-linear-regression-in-python
还有这里:
https://datascience.stackexchange.com/questions/8457/python-library-for-segmented-regression-a-k-a-piecewise-regression