特征中两个矩阵之间的成对差异

时间:2013-10-09 19:22:19

标签: c++ matlab matrix eigen

matlab / octave矩阵之间的成对距离,例如,根据需要k-means由一个函数调用(参见cvKmeans.m),distFunc(Codebook, X)计算,其中包含两个维度K x D的矩阵作为参数。

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

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

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

2 个答案:

答案 0 :(得分: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 < / em>的

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,您可以制作oneliner (j)| 2 = | p 0 (i)| 2 + | p 1 (j)| 2 - 2 p 0 (i) T p 1 (j)。特别是,最后一个组件只是矩阵乘法,所以 D = -2 p 0 < sup> T p 1 + ...

要填充的空白由仅依赖于行的组件组成;和一个仅依赖于列的组件:这些可以使用行和列操作表示。

决赛&#34; oneliner&#34;那么:

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

你也可以用带有 1 向量的(外部)产品替换rowwise / colwise trickery。

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

  1 410
505  10
 32 205
 50 185

你必须以最快的速度进行基准测试,但看到循环获胜我不会感到惊讶,我希望它也更具可读性。

答案 1 :(得分: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);
    
  5. 这不是一个好的oneliner,只是将data中的每一列与means中的每一列进行比较并且返回一个带有差异的矩阵似乎有点过分。然而,Eigen的多功能性似乎并不是这样可以写得更短。