【问题标题】:how to compare two curves (arrays of points)如何比较两条曲线(点数组)
【发布时间】:2025-12-08 23:05:02
【问题描述】:

我有 2 个点数组 (x,y),用这些点我可以绘制 2 条曲线。

有人知道如何计算这些曲线的相似度吗?

【问题讨论】:

标签: math


【解决方案1】:

您始终可以计算这两条曲线之间的面积。 (如果端点匹配,这会容易一些。)如果面积小,曲线相似,如果面积不小,曲线就不那么相似。

请注意,我没有定义“小”。那是故意的。再说一次,你没有定义“相似”。

编辑
有时面积不是最好的指标。例如,考虑函数 f(x)=0 和 f(x)=1e6*sin(x)。如果 x 的范围是 2*pi 的某个整数倍,则这些曲线之间的面积为零。在正负一百万之间振荡的函数不是 f(x)=0 的良好近似值。

需要一个更好的指标。这里有一对。注意:我在这里假设两组中的 x 值相同;唯一不同的是 y 值。

  1. 平方和。对于每个 x 值,计算 delta_yi = y1,i - y2,i 并累加 delta_yi2。该指标是最小二乘优化的基础,其目标是最小化误差的平方和。这是一种广泛使用的方法,因为它通常很容易实现。

  2. 最大偏差。求 abs_delta_yi = |y1,i - y2,i|最大化 |y1,i - y2,i|对于所有 x 值。该指标是数学库中许多函数实现的基础,其目标是最小化最大误差。这些数学库实现是真实函数的近似值。作为这种近似值的使用者,我通常更关心近似值将对我的应用程序造成的最坏的影响,而不是该近似值的平均表现。

【讨论】:

  • 如果两条曲线有多个交点,计算两条曲线之间的面积会很棘手。他必须做一个分段求和
  • 行不通。 a1 = [(0, 10), (5, 0)], a2 = [(0,0),(5,10)]。面积差 = 0,但“曲线”非常不同。
  • 没错。面积是一个指标,只是不是一个很好的指标。查看更新后的回复。
  • 好主意。我建议Area^2。每个点的面积平方避免负面积和正面积加起来为零问题。
  • 我认为应该将相关系数添加到您的列表中。偏移量和缩放比例可以不同,但​​它可以衡量曲线形状的比较方式。另外,也许看看stats.stackexchange.com/questions/27861/…
【解决方案2】:

您可能需要考虑使用动态时间扭曲 (DTW) 或Frechet 距离

动态时间扭曲

动态时间扭曲对整个整个曲线的差异求和。它可以处理两个不同大小的数组。这是来自Wikipedia 的关于代码外观的 sn-p。此解决方案使用二维数组。成本将是两点之间的距离。数组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 距离

Frechet 距离计算曲线分离的最远距离。这意味着曲线上的所有其他点都比这个距离更近。这种方法通常用狗和主人来表示,如下所示: Frechet Distance Example.

根据您的数组,您可以比较点的距离并使用最大值。

【讨论】:

  • DTW 取决于两个数组的值的范围,对吧?例如,如果一个数组的值在 (0,1000) 范围内,而另一个数组的值在 (0,100) 范围内,但形状相似,是否可以使用 DTW 来衡量相似度?
  • @Kanmani 您可以将两条曲线标准化为 0,1 之间的范围,然后执行 DTW ...标准化无论如何都不会影响形状..
【解决方案3】:

我假设曲线是实数上的二维点数组,数组的大小是N,所以我称p[i]为曲线的第i点; i0 变为 N-1

我还假设两条曲线具有相同的大小,并且将第一条曲线的i-th 点与第二条曲线的i-th 点进行“比较”是有意义的。

我叫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可以是一个开始point) 以使其与最短曲线的大小相匹配。

我刚才描述了一个很简单的方法,你也可以采取不同的方法;例如,您可以将两条曲线拟合到两组点,然后使用表示为数学函数的两条曲线。

【讨论】:

    【解决方案4】:

    这也可以从分布的角度来解决。

    特别是如果一个值的位置在数组中是可以互换的。

    然后您可以计算两个数组的均值和标准差(以及其他分布特征)。并计算这些特征之间的差异

    【讨论】: