3

例如,k-means 所需的矩阵之间的In matlab/ pairwise 距离通过一个函数调用(参见cvKmeans.m)计算,以两个尺寸为x的矩阵作为参数。octavedistFunc(Codebook, X)KD

如eigen.tuxfamily.orgEigen中所述,可以使用广播对矩阵和一个向量进行此操作

 (m.colwise() - v).colwise().squaredNorm().minCoeff(&index);

但是,在这种情况下v,不仅仅是一个向量,而是一个矩阵。在 Eigen 中计算两个矩阵之间所有条目的这种成对(欧几里得)距离的等效单线器是什么?

4

2 回答 2

1

我认为适当的解决方案是将这个功能抽象为一个函数。该功能很可能是模板化的;它很可能会使用循环——毕竟循环会很短。许多矩阵运算是使用循环实现的——这不是问题。

例如,给定您的示例...

MatrixXd p0(2, 4);
p0 <<
    1, 23, 6, 9,
    3, 11, 7, 2;

MatrixXd p1(2, 2);
p1 <<
    2, 20,
    3, 10;

那么我们可以构造一个矩阵D使得D (i,j) = | p 0 (i) - p 1 (j)| 2

MatrixXd D(p0.cols(), p0.rows());
for (int i = 0; i < p1.cols(); i++)
    D.col(i) = (p0.colwise() - p1.col(i)).colwise().squaredNorm().transpose();

我认为这很好 - 我们可以使用一些广播来避免 2 级嵌套:我们迭代p 1的点,但不超过p 0的点,也不超过它们的维度。

但是,如果您观察到,您可以制作一个单行线| p 0 (i) - p 1 (j)| 2 = | p 0 (i)| 2 + | p 1 (j)| 2 - 2 p 0 (i) T p 1 (j)。特别是,最后一个组件只是矩阵乘法,所以D = -2 p 0 T p 1 + ...

剩下要填的空白是由一个只依赖于行的组件组成的;以及仅依赖于列的组件:这些可以使用逐行和逐列操作来表示。

最后的“oneliner”是:

D = ( (p0.transpose() * p1 * -2
      ).colwise() + p0.colwise().squaredNorm().transpose()
    ).rowwise() + p1.colwise().squaredNorm();

您还可以将 rowwise/colwise 技巧替换为具有1向量的(外部)产品。

两种方法都会产生以下(平方)距离:

  1 410
505  10
 32 205
 50 185

您必须对最快的基准进行基准测试,但是看到循环获胜我不会感到惊讶,而且我希望这也更具可读性。

于 2014-06-07T15:18:47.520 回答
0

Eigen 比我乍一看更令人头疼。

  1. reshape()例如,没有功能(conservativeResize还有别的)。
  2. 似乎(我想更正一下)Map不仅提供数据视图,而且似乎需要对临时变量进行分配。
  3. minCoeff运算符后面的函数不能colwise返回最小元素和该元素的索引。
  4. 我不清楚是否replicate实际上分配了数据的副本。广播背后的原因是这不是必需的。

    matrix_t data(2,4);
    matrix_t means(2,2);
    
    // data points
    data << 1, 23, 6, 9,
            3, 11, 7, 2;
    
    // means
    means << 2, 20,
             3, 10;
    
    std::cout << "Data: " << std::endl;
    std::cout << data.replicate(2,1) << std::endl;
    
    column_vector_t temp1(4);
    temp1 = Eigen::Map<column_vector_t>(means.data(),4);
    
    std::cout << "Means: " << std::endl;
    std::cout << temp1.replicate(1,4) << std::endl;
    
    matrix_t temp2(4,4);
    temp2 = (data.replicate(2,1) - temp1.replicate(1,4));
    std::cout << "Differences: " << std::endl;
    std::cout << temp2 << std::endl; 
    
    matrix_t temp3(2,8);
    temp3 = Eigen::Map<matrix_t>(temp2.data(),2,8);
    std::cout << "Remap to 2xF: " << std::endl;
    std::cout << temp3 << std::endl;
    
    matrix_t temp4(1,8);
    temp4 = temp3.colwise().squaredNorm();
    std::cout << "Squared norm: " << std::endl;
    std::cout << temp4 << std::endl;//.minCoeff(&index);
    
    matrix_t temp5(2,4);
    temp5 = Eigen::Map<matrix_t>(temp4.data(),2,4);
    std::cout << "Squared norm result, the distances: " << std::endl;
    std::cout << temp5.transpose() << std::endl;
    
    //matrix_t::Index x, y;
    std::cout << "Cannot get the indices: " << std::endl;
    std::cout << temp5.transpose().colwise().minCoeff() << std::endl; // .minCoeff(&x,&y);
    

这不是一个很好的单线器,而且似乎只是将每一列data与每一列进行比较means并返回一个包含它们差异的矩阵。然而,Eigen 的多功能性似乎并没有可以写得更短。

于 2013-10-10T13:08:11.200 回答