2013-10-09 79 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的多功能性似乎並不是這樣可以寫得更短。

相關問題