【发布时间】:2025-12-08 23:05:02
【问题描述】:
我有 2 个点数组 (x,y),用这些点我可以绘制 2 条曲线。
有人知道如何计算这些曲线的相似度吗?
【问题讨论】:
-
除非您定义“相似”的含义
-
对这个问题的回答可能会有所帮助*.com/questions/10826625/…
标签: math
我有 2 个点数组 (x,y),用这些点我可以绘制 2 条曲线。
有人知道如何计算这些曲线的相似度吗?
【问题讨论】:
标签: math
您始终可以计算这两条曲线之间的面积。 (如果端点匹配,这会容易一些。)如果面积小,曲线相似,如果面积不小,曲线就不那么相似。
请注意,我没有定义“小”。那是故意的。再说一次,你没有定义“相似”。
编辑
有时面积不是最好的指标。例如,考虑函数 f(x)=0 和 f(x)=1e6*sin(x)。如果 x 的范围是 2*pi 的某个整数倍,则这些曲线之间的面积为零。在正负一百万之间振荡的函数不是 f(x)=0 的良好近似值。
需要一个更好的指标。这里有一对。注意:我在这里假设两组中的 x 值相同;唯一不同的是 y 值。
平方和。对于每个 x 值,计算 delta_yi = y1,i - y2,i 并累加 delta_yi2。该指标是最小二乘优化的基础,其目标是最小化误差的平方和。这是一种广泛使用的方法,因为它通常很容易实现。
最大偏差。求 abs_delta_yi = |y1,i - y2,i|最大化 |y1,i - y2,i|对于所有 x 值。该指标是数学库中许多函数实现的基础,其目标是最小化最大误差。这些数学库实现是真实函数的近似值。作为这种近似值的使用者,我通常更关心近似值将对我的应用程序造成的最坏的影响,而不是该近似值的平均表现。
【讨论】:
您可能需要考虑使用动态时间扭曲 (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 Distance Example.
根据您的数组,您可以比较点的距离并使用最大值。
【讨论】:
我假设曲线是实数上的二维点数组,数组的大小是N,所以我称p[i]为曲线的第i点; i 从 0 变为 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) 以使其与最短曲线的大小相匹配。
我刚才描述了一个很简单的方法,你也可以采取不同的方法;例如,您可以将两条曲线拟合到两组点,然后使用表示为数学函数的两条曲线。
【讨论】:
这也可以从分布的角度来解决。
特别是如果一个值的位置在数组中是可以互换的。
然后您可以计算两个数组的均值和标准差(以及其他分布特征)。并计算这些特征之间的差异。
【讨论】: