给定点之间的距离矩阵,是否有一种算法可以确定一组具有这些距离的 n 维点?(或至少最小化错误)
有点像收费公路问题的 n 维版本。
我能想到的最好的方法是使用多维缩放。
您在多维缩放 (MDS) 方面走在正确的轨道上,但 MDS 对于大型数据集是不切实际的,因为它的时间复杂度是点数的二次方。你可能想看看 FastMap,它具有线性时间复杂度,更适合索引。看:
Christos Faloutsos 和 King-Ip Lin:“FastMap:传统和多媒体数据集的索引、数据挖掘和可视化的快速算法,在Proc. SIGMOD中,1995 年,doi:10.1145/223784.223812
您可以“作弊”并为此使用迭代数值方法。最初将所有点置于某些“随机”位置,然后循环遍历它们,使它们按所需距离成比例地彼此远离。这将更喜欢一些点,但在应用它们之前取平均移动,然后应用平均将消除这个问题。这是一个 O(n²) 算法,但实现和理解非常简单。在下面的二维示例中,误差为 << 10%,但如果给定的距离不切实际,它可能表现不佳。
C++ 示例:
#include <conio.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define DAMPING_FACTOR 0.99f
class point
{
public:
float x;
float y;
public:
point() : x(0), y(0) {}
};
// symmetric matrix with distances
float matrix[5][5] = {
{ 0.0f, 4.5f, 1.5f, 2.0f, 4.0f },
{ 4.5f, 0.0f, 4.0f, 3.0f, 3.5f },
{ 1.5f, 4.0f, 0.0f, 1.0f, 5.0f },
{ 2.0f, 3.0f, 1.0f, 0.0f, 4.5f },
{ 4.0f, 3.5f, 5.0f, 4.5f, 0.0f }
};
int main(int argc, char** argv)
{
point p[5];
for(unsigned int i = 0; i < 5; ++i)
{
p[i].x = (float)(rand()%100)*0.1f;
p[i].y = (float)(rand()%100)*0.1f;
}
// do 1000 iterations
float dx = 0.0f, dy = 0.0f, d = 0.0f;
float xmoves[5], ymoves[5];
for(unsigned int c = 0; c < 1000; ++c)
{
for(unsigned int i = 0; i < 5; ++i) xmoves[i] = ymoves[i] = 0.0f;
// iterate across each point x each point to work out the results of all of the constraints in the matrix
// collect moves together which are slightly less than enough (DAMPING_FACTOR) to correct half the distance between each pair of points
for(unsigned int i = 0; i < 5; ++i)
for(unsigned int j = 0; j < 5; ++j)
{
if(i==j) continue;
dx = p[i].x - p[j].x;
dy = p[i].y - p[j].y;
d = sqrt(dx*dx + dy*dy);
dx /= d;
dy /= d;
d = (d - matrix[i][j])*DAMPING_FACTOR*0.5f*0.2f;
xmoves[i] -= d*dx;
ymoves[i] -= d*dy;
xmoves[j] += d*dx;
ymoves[j] += d*dy;
}
// apply all at once
for(unsigned int i = 0; i < 5; ++i)
{
p[i].x += xmoves[i];
p[i].y += ymoves[i];
}
}
// output results
printf("Result:\r\n");
for(unsigned int i = 0; i < 5; ++i)
{
for(unsigned int j = 0; j < 5; ++j)
{
dx = p[i].x - p[j].x;
dy = p[i].y - p[j].y;
printf("%f ", sqrt(dx*dx + dy*dy));
}
printf("\r\n");
}
printf("\r\nDesired:\r\n");
for(unsigned int i = 0; i < 5; ++i)
{
for(unsigned int j = 0; j < 5; ++j)
{
printf("%f ", matrix[i][j]);
}
printf("\r\n");
}
printf("Absolute difference:\r\n");
for(unsigned int i = 0; i < 5; ++i)
{
for(unsigned int j = 0; j < 5; ++j)
{
dx = p[i].x - p[j].x;
dy = p[i].y - p[j].y;
printf("%f ", abs(sqrt(dx*dx + dy*dy) - matrix[i][j]));
}
printf("\r\n");
}
printf("Press any key to continue...");
while(!_kbhit());
return 0;
}
Programming Collective Intelligence , p.中有一个算法可以做到这一点。49,“在二维中查看数据”,可适用于 n 维。
嘿 - 这是多维缩放 - 所以我猜你是在正确的轨道上。
我无法编辑原件,因为我没有足够的代表,但我试图在这里重申问题。
OP 有一个输入 NxN 距离矩阵。他想创建一个大小为 N 的输出数组,其 N 维坐标表示点,其中每个点之间的距离存储在输入矩阵中。
请注意,这在一般情况下是无法解决的:
假设我有一个这样的矩阵
美国广播公司 一个 x 1 2 乙×0 Cx
A 距离 B 1 个单位的距离(例如 1 米),A 距离 C 1 米。但 B 和 C 在同一个位置。
在这种特殊情况下,误差的最小总和为 1 米,并且有无数种解决方案可以实现该结果