我有一组数据,这些数据不是以任何特定的方式排序的,但是在绘制时显然具有两个不同的趋势。由于两个系列之间有明显区别,因此简单的线性回归在此实际上并不足够。是否有一种简单的方法来获取两个独立的线性趋势线?
作为记录,我使用Python,并且对编程和数据分析(包括机器学习)相当满意,但在绝对必要的情况下愿意跳到R。
我有一组数据,这些数据不是以任何特定的方式排序的,但是在绘制时显然具有两个不同的趋势。由于两个系列之间有明显区别,因此简单的线性回归在此实际上并不足够。是否有一种简单的方法来获取两个独立的线性趋势线?
作为记录,我使用Python,并且对编程和数据分析(包括机器学习)相当满意,但在绝对必要的情况下愿意跳到R。
Answers:
为了解决您的问题,一个好的方法是定义一个与您的数据集假设相匹配的概率模型。在您的情况下,您可能需要混合使用线性回归模型。通过将不同的数据点与不同的混合成分相关联,可以创建类似于高斯混合模型的“回归混合”模型。
我已包含一些代码来帮助您入门。该代码为两个回归变量的混合实现了EM算法(扩展到较大的混合相对容易)。对于随机数据集,该代码似乎相当健壮。但是,与线性回归不同,混合模型具有非凸面目标,因此对于真实数据集,您可能需要使用不同的随机起点进行一些试验。
import numpy as np
import matplotlib.pyplot as plt
import scipy.linalg as lin
#generate some random data
N=100
x=np.random.rand(N,2)
x[:,1]=1
w=np.random.rand(2,2)
y=np.zeros(N)
n=int(np.random.rand()*N)
y[:n]=np.dot(x[:n,:],w[0,:])+np.random.normal(size=n)*.01
y[n:]=np.dot(x[n:,:],w[1,:])+np.random.normal(size=N-n)*.01
rx=np.ones( (100,2) )
r=np.arange(0,1,.01)
rx[:,0]=r
#plot the random dataset
plt.plot(x[:,0],y,'.b')
plt.plot(r,np.dot(rx,w[0,:]),':k',linewidth=2)
plt.plot(r,np.dot(rx,w[1,:]),':k',linewidth=2)
# regularization parameter for the regression weights
lam=.01
def em():
# mixture weights
rpi=np.zeros( (2) )+.5
# expected mixture weights for each data point
pi=np.zeros( (len(x),2) )+.5
#the regression weights
w1=np.random.rand(2)
w2=np.random.rand(2)
#precision term for the probability of the data under the regression function
eta=100
for _ in xrange(100):
if 0:
plt.plot(r,np.dot(rx,w1),'-r',alpha=.5)
plt.plot(r,np.dot(rx,w2),'-g',alpha=.5)
#compute lhood for each data point
err1=y-np.dot(x,w1)
err2=y-np.dot(x,w2)
prbs=np.zeros( (len(y),2) )
prbs[:,0]=-.5*eta*err1**2
prbs[:,1]=-.5*eta*err2**2
#compute expected mixture weights
pi=np.tile(rpi,(len(x),1))*np.exp(prbs)
pi/=np.tile(np.sum(pi,1),(2,1)).T
#max with respect to the mixture probabilities
rpi=np.sum(pi,0)
rpi/=np.sum(rpi)
#max with respect to the regression weights
pi1x=np.tile(pi[:,0],(2,1)).T*x
xp1=np.dot(pi1x.T,x)+np.eye(2)*lam/eta
yp1=np.dot(pi1x.T,y)
w1=lin.solve(xp1,yp1)
pi2x=np.tile(pi[:,1],(2,1)).T*x
xp2=np.dot(pi2x.T,x)+np.eye(2)*lam/eta
yp2=np.dot(pi[:,1]*y,x)
w2=lin.solve(xp2,yp2)
#max wrt the precision term
eta=np.sum(pi)/np.sum(-prbs/eta*pi)
#objective function - unstable as the pi's become concentrated on a single component
obj=np.sum(prbs*pi)-np.sum(pi[pi>1e-50]*np.log(pi[pi>1e-50]))+np.sum(pi*np.log(np.tile(rpi,(len(x),1))))+np.log(eta)*np.sum(pi)
print obj,eta,rpi,w1,w2
try:
if np.isnan(obj): break
if np.abs(obj-oldobj)<1e-2: break
except:
pass
oldobj=obj
return w1,w2
#run the em algorithm and plot the solution
rw1,rw2=em()
plt.plot(r,np.dot(rx,rw1),'-r')
plt.plot(r,np.dot(rx,rw2),'-g')
plt.show()
在此线程的其他地方,user1149913提供了很好的建议(定义概率模型)和代码,以提供功能强大的方法(EM估计)。 有两个问题有待解决:
如何应对概率模型的偏离(这在2011-2012年的数据中非常明显,而在不太倾斜的点的波动中则很明显)。
如何为EM算法(或任何其他算法)识别良好的起始值。
要解决#2,请考虑使用霍夫变换。这是一种特征检测算法,可以找到特征的线性延伸,并可以有效地将其计算为Radon变换。
在霍夫变换中。当原始图中的特征沿着一条公共线落下或接近一条公共线时,则它们在霍夫变换中生成的曲线的集合往往会具有与该公共线相对应的公共交点。通过在霍夫变换中找到这些强度最大的点,我们可以读出原始问题的良好解决方案。
为了开始使用这些数据,我首先裁剪了辅助内容(轴,刻度线和标签),并很好地裁剪了右下角明显偏远的点,并沿底轴进行了撒布。(当这些东西没有被裁剪出来时,该过程仍然可以很好地工作,但是它也可以检测轴,框架,刻度线的线性序列,标签的线性序列,甚至偶数地位于底轴上的点!)
img = Import["http://i.stack.imgur.com/SkEm3.png"]
i = ColorNegate[Binarize[img]]
crop2 = ImageCrop[ImageCrop[i, {694, 531}, {Left, Bottom}], {565, 467}, {Right, Top}]
(此代码和其余代码在Mathematica中。)
该图像中的每个点对应霍夫变换中的狭窄曲线范围,在此处可见。它们是正弦波:
hough2 = Radon[crop2, Method -> "Hough"] // ImageAdjust
这从视觉上体现了问题是线聚类问题的意义:霍夫变换将其简化为点聚类问题,我们可以将其应用任何喜欢的聚类方法。
在这种情况下,聚类是如此清晰,以至于霍夫变换的简单后处理就足够了。为了确定变换中强度最大的位置,我增加了对比度,并在大约1%的半径范围内模糊了变换:这与原始图像中绘图点的直径相当。
blur = ImageAdjust[Blur[ImageAdjust[hough2, {1, 0}], 8]]
对结果进行阈值处理会将其范围缩小到两个微小的斑点,这些斑点的质心可以合理地识别出最大强度的点:这些点估计拟合线。
comp = MorphologicalComponents[blur, 0.777]) // Colorize
图像的左侧对应于0度(水平)的方向,并且当我们从左到右看时,该角度线性增加到180度。内插,我计算出两个斑点分别以19度和57.1度为中心。我们还可以从斑点的垂直位置读取截距。此信息产生初始拟合:
width = ImageDimensions[blur][[1]];
slopes = Module[{x, y, z}, ComponentMeasurements[comp, "Centroid"] /.
Rule[x_, {y_, z_}] :> Round[((y - 1/2)/(width - 1)) 180., 0.1]
]
{19.,57.1}
可以类似的方式计算与这些斜率相对应的截距,从而得出以下拟合值:
(红线对应于上一张照片中的粉红色小点,蓝线对应于较大的水色斑点。)
这种方法在很大程度上自动解决了第一个问题:线性度偏差会抹去强度最大的点,但通常不会使它们发生太大的移动。坦率地说,外围点将在整个Hough变换中产生低电平噪声,该噪声在后处理过程中将消失。
在这一点上,可以将这些估计值作为EM算法或似然最小化器的起始值(如果给出了良好的估计值,它们将迅速收敛)。不过,更好的方法是使用健壮的回归估算器,例如迭代地加权最小二乘法。它能够为每个点提供回归权重。低权重表示一个点不“属于”一条线。如果需要,可以利用这些权重将每个点分配给其适当的线。然后,在对点进行分类之后,可以分别在两组点上使用普通最小二乘法(或任何其他回归过程)。
rotation
最初设置为零,因此没有区别。
我发现这个问题与另一个问题有关。我实际上对这种问题进行了学术研究。请检查我的答案“最小平方根”是否合适?具有多个最小值的拟合方法,以获取更多详细信息。
whuber基于Hough变换的方法对于您所给出的简单场景是一个非常好的解决方案。我处理了具有更复杂数据的方案,例如:
我和我的合著者将此称为“数据关联”问题。当您尝试解决它时,主要问题通常是组合的,因为可能的数据组合呈指数级增长。
我们有出版物“ 数据关联问题的高斯过程的重叠混合物 ”,我们用迭代技术解决了N曲线的一般问题,给出了很好的结果。您可以在本文中找到链接的Matlab代码。
[更新]可以在GPClust库中找到OMGP技术的Python实现。
我还有另一篇论文,我们放宽了问题以获得凸优化问题,但是尚未被发表。它专用于2条曲线,因此可以完美地处理您的数据。让我知道你是否有兴趣。