我有2个点(x,y)阵列,我可以绘制2条曲线。
任何人都有想法如何计算这些曲线的相似之处?
答案 0 :(得分:16)
您始终可以计算这两条曲线之间的区域。 (如果端点匹配,这会更容易一些。)如果面积很小,曲线是相似的,如果面积不小,则曲线不相似。
请注意,我没有定义'小'。那是故意的。然后,你没有定义'相似'。
修改
有时区域不是最佳指标。例如,考虑函数f(x)= 0和f(x)= 1e6 * sin(x)。如果x的范围是2 * pi的某个整数倍,则这些曲线之间的面积为零。在正负一百万之间振荡的函数不是f(x)= 0的良好近似值。
需要更好的衡量标准。这是一对夫妇。注意:我在这里假设两组中的x值相同;唯一不同的是y值。
平方和。对于每个x值,计算delta_y i = y 1,i - y 2,i 并累积delta_y i 2 。该度量是最小二乘优化的基础,其目标是最小化误差平方和。这是一种广泛使用的方法,因为它通常很容易实现。
最大偏差。找到abs_delta_y i = | y 1,i - y 2,i |最大化| y 1,i - y 2,i |对于所有x值。该度量标准是数学库中许多函数实现的基础,其目标是最小化最大错误。这些数学库实现是真实函数的近似值。作为这种近似的消费者,我通常更关心近似对我的应用程序做的最糟糕的事情,而不是关心这种近似将如何平均表现。
答案 1 :(得分:4)
您可能需要考虑使用动态时间扭曲(DTW)或 Frechet距离。
动态时间扭曲对整个曲线中的差异求和。它可以处理两个不同大小的数组。以下是Wikipedia关于代码外观的代码段。该解决方案使用二维阵列。费用是两点之间的距离。数组DTW [n,m]的最终值包含累积距离。
int DTWDistance(s: array [1..n], t: array [1..m]) {
DTW := array [0..n, 0..m]
for i := 1 to n
DTW[i, 0] := infinity
for i := 1 to m
DTW[0, i] := infinity
DTW[0, 0] := 0
for i := 1 to n
for j := 1 to m
cost:= d(s[i], t[j])
DTW[i, j] := cost + minimum(DTW[i-1, j ], // insertion
DTW[i , j-1], // deletion
DTW[i-1, j-1]) // match
return DTW[n, m]
}
DTW与Jacopson的答案相似。
Frechet distance计算曲线分开的最远距离。这意味着曲线上的所有其他点都比这个距离更近。这种方法通常用狗和所有者表示,如下所示: Frechet Distance Example
根据您的阵列,您可以比较点的距离并使用最大值。
答案 2 :(得分:3)
我假设曲线是实数上的2D点数组,数组的大小是N
,所以我称p[i]
为曲线的i
点; i
从0
转到N-1
。
我还假设两条曲线具有相同的大小,并且将第一条曲线的i
点与第二条曲线的i
点进行“比较”是有意义的。
我将Delta
称为实数,即两条曲线的比较结果。
Delta
可按如下方式计算:
Delta = 0;
for( i = 0; i < N; i++ ) {
Delta = Delta + distance(p[i],q[i]);
}
其中p
是第一条曲线的点,q
是第二条曲线的点。
现在你必须根据你的问题选择合适的distance
函数:函数有两个点作为参数并返回一个实数。
例如distance
可以是平面上两点的通常距离(毕达哥拉斯定理和http://en.wikipedia.org/wiki/Euclidean_distance)。
C ++中方法的一个例子:
#include <numeric>
#include <vector>
#include <cmath>
#include <iostream>
#include <functional>
#include <stdexcept>
typedef double Real_t;
class Point
{
public:
Point(){}
Point(std::initializer_list<Real_t> args):x(args.begin()[0]),y(args.begin()[1]){}
Point( const Real_t& xx, const Real_t& yy ):x(xx),y(yy){}
Real_t x,y;
};
typedef std::vector< Point > Curve;
Real_t point_distance( const Point& a, const Point& b )
{
return hypot(a.x-b.x,a.y-b.y);
}
Real_t curve_distance( const Curve& c1, const Curve& c2 )
{
if ( c1.size() != c2.size() ) throw std::invalid_argument("size mismatch");
return std::inner_product( c1.begin(), c1.end(), c2.begin(), Real_t(0), std::plus< Real_t >(), point_distance );
}
int main(int,char**)
{
Curve c1{{0,0},
{1,1},
{2,4},
{3,9}};
Curve c2{{0.1,-0.1},
{1.1,0.9},
{2.1,3.9},
{3.1,8.9}};
std::cout << curve_distance(c1,c2) << "\n";
return 0;
}
如果你的两条曲线有不同的大小,那么你必须考虑如何扩展前面的方法,例如你可以通过合适的算法减小最长曲线的大小(例如Ramer–Douglas–Peucker algorithm可以是一个起点),以使其与最短曲线的大小相匹配。
我刚刚描述了一种非常简单的方法,你也可以采取不同的方法;例如,您可以将两条曲线拟合到两组点,然后使用表示为数学函数的两条曲线。
答案 3 :(得分:0)
这也可以解决,只要考虑分布。
尤其是值的位置在数组中是否可互换。
然后,您可以计算两个阵列的均值和标准差(以及其他分布特征)。然后计算这些特征之间的差异。