1

我在代码中提供了具有负斜率和正斜率的数据,如图所示:

在此处输入图像描述

使用这篇文章中应用的代码拟合由两种不同状态组成的数据的曲线,我创建了这个代码。它适用于相同的斜率,无论是正的还是负的,但是当一个是正的,另一个是负的时,它不能正确地拟合线条。

from scipy import optimize
from scipy import optimize, interpolate
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import numpy as np


x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
y = np.array([4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4])


def two_lines(x, a, b, c, d):
    one = a*x + b
    two = c*x + d
    return np.maximum(one, two)


'''Compute approximate slope and intercept of the two lines'''
poly_low = np.polyfit(x[0:int(0.5*(len(x) + 1))], y[0:int(0.5*(len(x) + 1))], deg=1)
poly_high = np.polyfit(x[int(0.5*(len(x) + 1)):len(x)], y[int(0.5*(len(x) + 1)):len(x)], deg=1)

# This part of the code credit goes to askewchan
pw0 = (poly_low[0], poly_low[1], poly_high[0], poly_high[1]) # a guess for slope, intercept, slope, intercept
pw, cov = curve_fit(two_lines, x, y, pw0)
crossover = (pw[3] - pw[1]) / (pw[0] - pw[2])


figure = plt.figure(figsize=(5.15, 5.15))
figure.clf()
plot = plt.subplot(111)
plt.plot(x, y, 'o', x, two_lines(x, *pw), '-')
plot.set_ylabel('Y', labelpad = 6)
plot.set_xlabel('X', labelpad = 6)
plt.show()

输出

对于不同的坡度: 在此处输入图像描述

对于相同的斜率都是负的(也适用于正斜率):

在此处输入图像描述

我有两个问题:

  1. 如何在 Python 中对此类情况应用分段线性拟合?
  2. 如何将其扩展到三个或更多政权?
4

2 回答 2

0

您可以将蒙面区域用于分段函数:

def two_lines(x, a, b, c, d):
    out = np.empty_like(x)
    mask = x < 10
    out[mask] = a*x[mask] + b
    out[~mask] = c*x[~mask] + d
    return out

首先使用两个不同的正斜率进行测试:

x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
              17, 18, 19, 20])
y = np.array([4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25, 26, 27, 28, 29,
    30, 31, 32, 33, 34])

在此处输入图像描述

具有正斜率和负斜率的第二次测试(来自您的示例的数据):

在此处输入图像描述

于 2015-05-01T17:22:45.697 回答
0

您所拥有的基本上适用于您所呈现的特定问题和数据,但更普遍地解决此问题是错误的方法。它不能轻易扩展到更广泛的情况,例如,多个段、线性段之间转换更复杂的数据、需要调整拟合的特定方面的情况等。主要原因是您处理以最一般和最困难的方式(高维、多参数拟合)简单的特定和高度约束的问题(拟合多个不重叠的线段)。除其他问题外,这种泛化将使拟合更难落在参数空间的正确区域中。 这是一个关于容易局部拟合的问题,您试图用一个困难的广义全局解决方案来解决。 我看到了它的吸引力,但除了玩具示例之外,它不太可能适用于任何东西。

也就是说,只要一个以正确的斜坡符号开头,您所拥有的就可以用于玩具示例。至少它从(1,1,-1,1)and开始起作用(10,10,-10,10),但是根据您对 的定义,您还需要知道这些two_lines,所以我并没有真正假设您没有做任何事情。此外,您需要定义two_lines以便它可以匹配(您的原始三角形具有向下的三角形而不是向上的三角形,这也可能是它适用于两条“负斜率”线的原因 - 不是因为它们是负斜率,而是因为它们可以匹配根据您的原始定义)。

在此处输入图像描述

from scipy import optimize
from scipy import optimize, interpolate
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import numpy as np

x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
y = np.array([4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4])

def two_lines(x, a, b, c, d):
    one = a*x + b
    two = c*x + d
    return np.minimum(one, two)

pw, cov = curve_fit(two_lines, x, y, (10, 10, -10, 10))

figure = plt.figure(figsize=(5.15, 5.15))
figure.clf()
plot = plt.subplot(111)
plt.plot(x, y, 'o')
plt.plot(x, two_lines(x, *pw), '-')
plot.set_ylabel('Y', labelpad = 6)
plot.set_xlabel('X', labelpad = 6)
plt.show()

显而易见的替代方法是沿着曲线移动,采用独立的分段线性拟合。这种方法简单、快速、灵活,并且可能更符合您的直觉。这种方法也很容易扩展到无限数量的段(而您的全局解决方案可能最多为两个),并且还允许对线性部分的拟合不会被不是完全线性的曲线部分弄乱(例如,圆角过渡)。

于 2015-05-01T21:38:15.803 回答