簡體   English   中英

本征中兩個矩陣之間的成對差異

[英]Pairwise differences between two matrices in Eigen

matlab / octave ,例如,k均值所需的矩陣之間的成對距離是通過一個函數調用(請參閱cvKmeans.m )計算到distFunc(Codebook, X)其中兩個參數是維度為K x D矩陣。

Eigen這可以通過使用廣播針對矩陣和一個矢量完成,如eigen.tuxfamily.org所述

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

但是,在這種情況下, v不僅是向量,而且是矩陣。 在Eigen中用於計算兩個矩陣之間所有條目的成對(歐幾里得)距離的等效oneliner是多少?

我認為適當的解決方案是將此功能抽象為一個功能。 該功能很可能是模板化的。 而且很可能會使用一個循環-畢竟,循環真的很短。 許多矩陣運算是使用循環實現的-這不是問題。

例如,假設您有...

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 (1)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();

您也可以將(逐行/逐行欺騙)替換為(向量)為1的乘積。

兩種方法都導致以下(平方)距離:

  1 410
505  10
 32 205
 50 185

您必須對最快的基准進行基准測試,但是看到循環成功,我不會感到驚訝,我希望它也更具可讀性。

比起我一見鍾情,艾根更頭痛。

  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); 

這不是一個很好的方法,只是將data中的每一列與means每一列進行比較,並返回具有其差異的矩陣,似乎有點過頭了。 但是,Eigen的多功能性似乎並不能因此而被簡化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM