Tom*_*gal 48 python numpy curve-fitting scipy piecewise
我试图将分段线性拟合拟合为数据集,如图1所示

这个数字是通过设置线条获得的.我试图使用代码应用分段线性拟合:
from scipy import optimize
import matplotlib.pyplot as plt
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15])
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03])
def linear_fit(x, a, b):
return a * x + b
fit_a, fit_b = optimize.curve_fit(linear_fit, x[0:5], y[0:5])[0]
y_fit = fit_a * x[0:7] + fit_b
fit_a, fit_b = optimize.curve_fit(linear_fit, x[6:14], y[6:14])[0]
y_fit = np.append(y_fit, fit_a * x[6:14] + fit_b)
figure = plt.figure(figsize=(5.15, 5.15))
figure.clf()
plot = plt.subplot(111)
ax1 = plt.gca()
plot.plot(x, y, linestyle = '', linewidth = 0.25, markeredgecolor='none', marker = 'o', label = r'\textit{y_a}')
plot.plot(x, y_fit, linestyle = ':', linewidth = 0.25, markeredgecolor='none', marker = '', label = r'\textit{y_b}')
plot.set_ylabel('Y', labelpad = 6)
plot.set_xlabel('X', labelpad = 6)
figure.savefig('test.pdf', box_inches='tight')
plt.close()
Run Code Online (Sandbox Code Playgroud)
但是这给了我图中图形的拟合.2,我试着玩这些值,但没有变化,我无法得到合适的上线.对我来说最重要的要求是如何让Python获得渐变变化点.本质上,我希望Python能够在适当的范围内识别和拟合两个线性拟合.如何在Python中完成?

HYR*_*YRY 46
您可以使用numpy.piecewise()创建分段函数然后使用curve_fit(),这是代码
from scipy import optimize
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15], dtype=float)
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03])
def piecewise_linear(x, x0, y0, k1, k2):
return np.piecewise(x, [x < x0], [lambda x:k1*x + y0-k1*x0, lambda x:k2*x + y0-k2*x0])
p , e = optimize.curve_fit(piecewise_linear, x, y)
xd = np.linspace(0, 15, 100)
plt.plot(x, y, "o")
plt.plot(xd, piecewise_linear(xd, *p))
Run Code Online (Sandbox Code Playgroud)
输出:

hak*_*anc 17
您可以执行样条插值方案,以执行分段线性插值并找到曲线的转折点.二阶导数将在转折点处最高(对于单调增加的曲线),并且可以使用阶数> 2的样条插值来计算.
import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15])
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03])
tck = interpolate.splrep(x, y, k=2, s=0)
xnew = np.linspace(0, 15)
fig, axes = plt.subplots(3)
axes[0].plot(x, y, 'x', label = 'data')
axes[0].plot(xnew, interpolate.splev(xnew, tck, der=0), label = 'Fit')
axes[1].plot(x, interpolate.splev(x, tck, der=1), label = '1st dev')
dev_2 = interpolate.splev(x, tck, der=2)
axes[2].plot(x, dev_2, label = '2st dev')
turning_point_mask = dev_2 == np.amax(dev_2)
axes[2].plot(x[turning_point_mask], dev_2[turning_point_mask],'rx',
label = 'Turning point')
for ax in axes:
ax.legend(loc = 'best')
plt.show()
Run Code Online (Sandbox Code Playgroud)

Cha*_*kel 13
您可以使用pwlf在Python中执行连续的分段线性回归。可以使用pip安装该库。
pwlf中有两种方法可以执行您的拟合:
让我们继续使用方法1,因为它更简单,并且可以识别您感兴趣的“渐变更改点”。
在查看数据时,我注意到两个不同的区域。因此,有必要使用两个线段找到最佳的连续分段线。这是方法1。
import numpy as np
import matplotlib.pyplot as plt
import pwlf
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59,
84.47, 98.36, 112.25, 126.14, 140.03])
my_pwlf = pwlf.PiecewiseLinFit(x, y)
breaks = my_pwlf.fit(2)
print(breaks)
Run Code Online (Sandbox Code Playgroud)
[1. 5.99819559 15.]
第一行段从[1.,5.99819559]开始,而第二行段从[5.99819559,15]开始。因此,您要求的梯度变化点将是5.99819559。
我们可以使用预测函数绘制这些结果。
x_hat = np.linspace(x.min(), x.max(), 100)
y_hat = my_pwlf.predict(x_hat)
plt.figure()
plt.plot(x, y, 'o')
plt.plot(x_hat, y_hat, '-')
plt.show()
Run Code Online (Sandbox Code Playgroud)
Mar*_*hke 13
该方法用于Scikit-Learn应用分段线性回归。如果您的点受到噪音的影响,您可以使用此功能。与执行巨大的优化任务(任何超过 3 个参数的任务)相比,它更快、更稳健、更通用。scip.optimizecurve_fit
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()
Run Code Online (Sandbox Code Playgroud)
您正在寻找线性树。它们是以通用和自动化的方式应用分段线性拟合(也适用于多变量和分类上下文)的最佳方法。
线性树与决策树不同,因为它们计算在叶子中拟合简单线性模型的线性近似(而不是常数近似)。
对于我的一个项目,我开发了Linear-tree:一个 Python 库,用于在叶子上构建具有线性模型的模型树。
线性树被开发为可与 scikit-learn 完全集成。
from sklearn.linear_model import *
from lineartree import LinearTreeRegressor, LinearTreeClassifier
# REGRESSION
regr = LinearTreeRegressor(base_estimator=LinearRegression())
regr.fit(X, y)
# CLASSIFICATION
clf = LinearTreeClassifier(base_estimator=RidgeClassifier())
clf.fit(X, y)
Run Code Online (Sandbox Code Playgroud)
LinearTreeRegressor并LinearTreeClassifier作为 scikit-learn 提供BaseEstimator。它们是包装器,可在拟合线性估计器的数据上构建决策树sklearn.linear_model。中的所有可用模型都sklearn.linear_model可以用作线性估计器。
比较决策树与线性树:
考虑到您的数据,概括非常简单:
from sklearn.linear_model import LinearRegression
from lineartree import LinearTreeRegressor
import numpy as np
import matplotlib.pyplot as plt
X = np.array(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15]
).reshape(-1,1)
y = np.array(
[5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03]
)
model = LinearTreeRegressor(base_estimator=LinearRegression())
model.fit(X, y)
plt.plot(X, y, ".", label='TRUE')
plt.plot(X, model.predict(X), label='PRED')
plt.legend()
Run Code Online (Sandbox Code Playgroud)
两个变更点的示例。如果需要,仅根据此示例测试更多的更改点。
np.random.seed(9999)
x = np.random.normal(0, 1, 1000) * 10
y = np.where(x < -15, -2 * x + 3 , np.where(x < 10, x + 48, -4 * x + 98)) + np.random.normal(0, 3, 1000)
plt.scatter(x, y, s = 5, color = u'b', marker = '.', label = 'scatter plt')
def piecewise_linear(x, x0, x1, b, k1, k2, k3):
condlist = [x < x0, (x >= x0) & (x < x1), x >= x1]
funclist = [lambda x: k1*x + b, lambda x: k1*x + b + k2*(x-x0), lambda x: k1*x + b + k2*(x-x0) + k3*(x - x1)]
return np.piecewise(x, condlist, funclist)
p , e = optimize.curve_fit(piecewise_linear, x, y)
xd = np.linspace(-30, 30, 1000)
plt.plot(x, y, "o")
plt.plot(xd, piecewise_linear(xd, *p))
Run Code Online (Sandbox Code Playgroud)