3

我目前正在尝试根据它们的行为对一堆河流进行分类。许多河流的行为与二次多项式非常相似。

在此处输入图像描述

然而,一些河流有一些区域与这种模式不同。 在此处输入图像描述在此处输入图像描述

我想通过计算所有点与简单多项式的距离来对此进行分类。所以它基本上看起来像这样:

在此处输入图像描述

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

在此处输入图像描述在此处输入图像描述

这是一些示例数据。

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)

在此处输入图像描述

如您所见,多项式略微向下移动,这是由此处标记为黑色的点引起的:

在此处输入图像描述

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

4

2 回答 2

2

这看起来更像是一个人工智能问题,而不是一个简单的拟合问题:你如何个人决定什么不合适——特别是在你的第二个发散图中,如果你忽略较大的曲线,那么短的第一条向上曲线看起来是多项式的?

您只需要 3 个点来计算 2 多项式:如何计算 3 个水平间隔良好的点的所有/多个采样的曲线(不一定相信第一个或最后一个点),看看哪个创建的异常值最少 - 点哪些比其他 90% 更远?

然后,您可以根据剩余的非异常点计算曲线,并检查它是否适合您简单计算的曲线。

编辑:“间隔良好”的意思是每个水平三分之一的点各有一个点 - 使用三个全部卡在一起的点来尝试推断其他点是没有意义的。此外,从您提供的数据的外观来看,您需要一条围绕原点开始向上的曲线,因此您可以过滤一些随机生成的曲线。

编辑:离群值的建议是草率的——如果你的数据最后变得更宽,就像一个喇叭,你有很多合理的拟合,所以只有在它有明显的马刺的地方,你才能有一个明确的离群值标记。如果您计算点与距每条随机曲线的距离的直方图,您可以扫描直方图切线中的肩部和不对称,使其远离钟形曲线,并在该点切出异常值。

从根本上说,我认为数据可能比计算机辅助分析更复杂,除非你打破计算机视觉技术:让计算机尽其所能,然后目视检查带注释的图表,看看你是否同意它。

它也可能有助于绘制垂直轴的日志,因此您正在处理直线。

于 2019-08-23T11:07:56.217 回答
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)
于 2019-08-28T11:39:23.333 回答