2013-10-09 81 views
2

matlab/octave。通过一个函数调用(参见cvKmeans.m)计算k均值,以distFunc(Codebook, X)作为参数两个尺寸为K x D的矩阵。Eigen中两个矩阵之间的成对差异根据所需的矩阵之间的成对距离如

Eigen这是可以做到对一个矩阵,并通过使用广播一个载体,作为eigen.tuxfamily.org解释:

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

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

回答

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)= | (i) - p (i) - p (j)|

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的点,但不超过p的积分,也不超过它们的尺寸。

但是,如果您观察到了这种情况,您可以制作一个oneliner | (i) - p (i) - p (j)| = | p (i)| + | p (j)| - 2 p (ⅰ)Ťp (j)的。尤其是,最后的组件只是矩阵乘法,所以d = -2 pŤp + ...

坯件离开待填充是由仅取决于行的组件组成;以及仅取决于列的组件:这些可以使用rowwise和columnwise操作来表示。

最后的 “oneliner” 则是:

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

您也可以与(外)的产物与矢量更换横行/ colwise欺骗。

两种方法都导致以下(平方)距离:

1 410 
505 10 
32 205 
50 185 

你不得不基准,这是最快的,但我也不会惊讶地看到环夺冠,我希望这是更也可读。

0

Eigen比我一见钟情更让人头疼。

  1. 没有reshape()功能,例如(和conservativeResize是另一回事)。
  2. 似乎(我想纠正)Map不只是提供一个数据视图,但临时变量的分配似乎是必需的。
  3. colwise运算符后面的minCoeff函数不能返回该元素的最小元素和索引。
  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); 
    

这不是一个很好的oneliner,似乎矫枉过正只是每列data每列means比较,并与他们之间的分歧返回一个矩阵。然而,Eigen的多功能性似乎并不是这样可以写得更短。

相关问题