确定哪个点集最符合多项式函数。

3

我目前正在尝试对许多河流的行为进行分类。其中许多河流的行为非常类似于二次多项式。

enter image description here

然而,一些河流存在一些区域与此模式不同。enter image description hereenter image description here 我想通过计算所有点距离简单多项式的距离来对其进行分类。因此,它基本上看起来像这样:

enter image description here

但是为了能够做到这一点,我必须仅为那些“正常行为”的点计算多项式。否则,我的多项式会偏向于发散行为的方向,我将无法正确计算距离。

enter image description hereenter image description here

这是一些示例数据。
x_test = [-150,-140,-130,-120,-110,-100,-90,-80,-70,-60,-50,-40,-30,-20,-10,0,10,20,30,40,50,60,70,70,80,80,90,90,100,100]
y_test = [0.1,0.11,0.2,0.25,0.25,0.4,0.5,0.4,0.45,0.6,0.5,0.5,0.6,0.6,0.7, 0.7,0.65,0.8,0.85,0.8,1,1,1.2,0.8,1.4,0.75,1.4,0.7,2,0.5]

我可以使用numpy从中创建一个多项式。
fit = np.polyfit(x_test, y_test, deg=2, full=True)
polynom = np.poly1d(fit[0]) 
simulated_data = polynom(x)

当我绘制它时,我得到以下结果:
ax = plt.gca()
ax.scatter(x_test,y_test)
ax.plot(x, simulated_data)

enter image description here

正如您所看到的,多项式稍微向下移动,这是由于这里标记为黑色的点所造成的:

enter image description here

有没有一种简单直接的方法来找到那些不遵循主要趋势的点,并将它们排除在创建多项式之外?

需要注意的是,这种方法对于参考框架的选择非常敏感。如果选择的参考框架导致所有点都"向上"或者更糟糕的是,河岸倾斜超过90度,那么很可能无法得到逼近河流的解决方案。不幸的是,我目前还不知道更好的方法,但一旦知道了,我会尽快告诉您。 - Etienne Ott
2个回答

2
这似乎是一个AI问题而不是简单的拟合问题:你个人如何决定哪些不适合 - 特别是在您的第二个分歧图中,如果忽略更大的曲线,短的第一条向上的曲线看起来是多项式的?只需3个点即可计算2次多项式:如何为所有/许多良好水平间隔点的3个采样计算曲线(不能信任第一个或最后一个点),并查看哪个创建的离群值最少 - 距其他点的距离超过90%?
然后,您可以基于其余非异常值点计算曲线,并检查它是否适合您的简单计算曲线。
编辑:“间隔良好”意味着从点的每个水平第三个点中各取一个点 - 使用三个挤在一起的点来尝试外推到其他点是没有意义的。此外,从您提供的数据来看,您想要一个从原点开始并上升的曲线,因此您可以过滤掉一些随机生成的曲线。
编辑:异常值建议很草率-如果您的数据在末尾变宽,例如小号喇叭,您有许多合理的拟合,因此仅当它出现明显的刺时才能清楚地标记异常值。如果计算每个随机曲线与距离的点的直方图,则可以扫描直方图切线中的肩膀和不对称性,以将其从钟形曲线中移开,并在该点处切片异常值。
从根本上说,我认为数据可能过于复杂,需要计算机辅助分析,除非您使用计算机视觉技术:让计算机尽力而为,然后可视化检查注释的图形以确定是否同意它。
将垂直轴的对数绘制出来可能也有所帮助,这样您就可以处理直线。

这个方法可能可行。你能否解释一下“水平间隔良好的点”是什么意思?我认为我对异常值检测有点困惑。如果我检查有多少个点比其他点更远超过了90%,那么这不应该总是10%吗? - F. Jehn
1
@F.Jehn我的回复太长了,无法放在评论中,所以我把它加到答案中! - Tim Baverstock
这基本上适用于我上面提供的示例数据集。然而,我意识到我的示例数据集并没有涵盖我数据中的所有边缘情况。因此,我现在只是使用一个指数函数来拟合数据,这对于大多数数据来说已经满足我的需求了。 - F. Jehn

1
一种可能有效的方法是将点聚类成“主”和“支流”分支,假设有两个分支,其中一个包含更多的点。之后,每个簇可以用于拟合一个多项式,在河流分支合并的点处交叉。这甚至可以通过使用多项式来迭代几次,通过使用点到多项式的距离作为距离度量而不是聚类算法使用的距离度量,从而获得更好的聚类结果。
通常的k-means算法可能不适用,因为簇不是围绕点而是曲线聚集的。像DBSCAN这样的算法可能更适合,因为它们基于给定点周围点的密度工作,这更类似于我们在上面的示例数据集中看到的模式。
这可能看起来像这样(不是有效代码):
points = (x_test, y_test)
labels = dbscan(points, k=2, labels=("main", "offshoot"))
polynomial_main = fit_polynomial([points[x.index] for x in labels if x.label = "main"])
polynomial_off = fit_polynomial([points[x.index] for x in labels if x.label = "offshoot"])

# optionally, purely distance based clustering
# might also use different clustering algorithm using distance as measure
points_main = [p for p in points if distance(p, polynomial_main) < distance(p, polynomial_off)]
points_off = [p for p in points if distance(p, polynomial_off) < distance(p, polynomial_main)]
polynomial_main = fit_polynomial(points_main)
polynomial_off = fit_polynomial(points_off)

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