给定两组向量,如何在第一组中为每个向量找到第二组中最接近的向量?

时间:2015-11-11 21:48:08

标签: matlab vector cluster-analysis nearest-neighbor

给定:维度为{S1, S2}的向量的两组DS1N*D矩阵表示,因此S2M*D矩阵表示。

我正在寻找一种优雅的方式来获取s1 S1s2S2中每个向量dist = norm(s1 - s2); 和相应距离。

一个简单的方法当然是有两个for循环并得到

{{1}}

然而,必须有一种更优雅和有效的方法来做到这一点。

2 个答案:

答案 0 :(得分:9)

烨。拥有bsxfunpermute的强大力量,一边是sum,一边是reshape。这将是第一部分,您可以计算S1中某点与S2中另一个点之间的成对距离:

out = reshape(sqrt(sum(bsxfun(@minus, S1, permute(S2, [3 2 1])).^2, 2)), size(S1,1), size(S2,1));

您现在需要做的最后一件事是确定S2中每个S1中最接近的向量。这可以使用min

完成
[dist,ind] = min(out, [], 2);

dist将包含S1中某个点与S2中某个点之间的最小距离,ind会告诉您哪个点是。

这段代码看起来非常令人生畏,但让我们把它分解成碎片。

  1. permute(S2, [3 2 1]):这会使用矩阵S2,这是一个M x D矩阵,并对维度进行混洗,使其成为1 x D x M矩阵....现在我们为什么要这样做?让我们进入下一部分,它会更有意义。

  2. bsxfun(@minus, S1, ...)bsxfun代表 B inary S ingleton E X pansion FUN ction。 bsxfun的作用是,如果您有两个输入,其中一个或两个输入都具有单个维度,或者如果两个输入中的任何一个只有一个值为1的维度,则每个输入都以其单个维度进行复制以匹配另一个输入的大小,然后将元素操作一起应用于这些输入以产生输出。在这种情况下,我想一起减去这两个新形成的输入。

    因此,鉴于S1N x D ......或者从技术角度来看,这是N x D x 1,并且鉴于S2M x D,我是1 x D x M置换使其变为N x D x M,我们将创建一个S1长的新矩阵。第一个输入将自身复制为3D矩阵,其中每个切片等于N x D,即S2N现在是一个3D矩阵,但它以这样一种方式表示,即原始矩阵中的每一行都是3D矩阵中的一个切片,其中每个切片只包含一行。对于@minus行,这会重复。

    我们现在应用i操作,其效果是对于此新矩阵中的每个输出切片i,这为您提供了点S2之间的组件明智差异在S1S2中的所有其他点。例如,对于切片#1,行#1为您提供S1中的点#1和S2中的点#1之间的组件明智差异。第2行为您提供S1中的第1点和第2点sum((...).^2, 2)之间的组件明智差异,依此类推。

  3. N:我们希望找到一个点与另一个点之间的欧几里德距离,因此我们将每个列的平均距离相加。这会生成一个新的3D矩阵,其中每个切片包含N个值,其中每个M点的距离都为S2。例如,第一个切片将为您提供S1中#1点的距离与out = reshape(..., size(S1,1), size(S2,1));中所有其他点的距离。

  4. M x N:我们现在对其进行整形,使其成为(i,j)矩阵,以便i的每对行和列对都为您提供点{{1}之间的距离} S1中的jS2中的[dist,ind] = min(out, [], 2);,从而完成了计算。

  5. 执行S1确定S2中某点与dist中其他点之间的最小距离。 ind会给你最小的距离,dist会告诉你它是哪个向量。因此,对于i中的每个元素,它会为您提供S1中的S2点与ind中的一个点之间的最小距离,S2会告诉您哪个属于S1的载体。

  6. 我们可以通过使用您提出的循环每对点并计算范数的方法来验证这给出了正确的结果。让我们创建S2S1 = [1 2 3; 4 5 6; 7 8 9; 10 11 12]; S2 = [-1 -1 -1; 0 9 8];

    >> S1
    
    S1 =
    
         1     2     3
         4     5     6
         7     8     9
        10    11    12
    
    >> S2
    
    S2 =
    
        -1    -1    -1
         0     9     8
    

    更整齐地展示:

    out = zeros(size(S1,1), size(S2,1));
    for ii = 1 : size(S1,1)
        for jj = 1 :size(S2,1) 
            out(ii,jj) = norm(S1(ii,:) - S2(jj,:));
        end
    end
    

    使用循环方法,我们有这个代码:

    >> out
    
    out =
    
        5.3852    8.6603
       10.4881    6.0000
       15.6525    7.1414
       20.8327   10.9545
    

    我们得到这个矩阵:

    >> out = reshape(sqrt(sum(bsxfun(@minus, S1, permute(S2, [3 2 1])).^2, 2)), size(S1,1), size(S2,1))
    
    out =
    
        5.3852    8.6603
       10.4881    6.0000
       15.6525    7.1414
       20.8327   10.9545
    

    同样,如果我们运行我编写的代码,我们也会得到:

    >> [dist,ind] = min(out, [], 2);
    >> dist
    
    dist =
    
        5.3852
        6.0000
        7.1414
       10.9545
    
    >> ind
    
    ind =
    
         1
         2
         2
         2
    

    要完成此过程,请找到最小距离和相应的向量:

    S1

    因此,对于S2中的第一个向量,S1中与此最接近的向量是第一个,距离为5.3852。同样,S2中的第二个向量,{{1}}中最接近的向量是第二个向量,距离为6.您可以对其他值重复此操作,并查看它是否正确。

答案 1 :(得分:5)

一行怎么样?

[dist, ind] = min(pdist2(S2,S1));

indS2S1中每个向量的最近向量的索引,dist给出了相应的最小距离。

借用@rayryeng's example

S1 = [1 2 3; 4 5 6; 7 8 9; 10 11 12];
S2 = [-1 -1 -1; 0 9 8];

结果

dist =
   5.385164807134504   6.000000000000000   7.141428428542850  10.954451150103322
ind =
    1     2     2     2