按列1值的升序对特征矩阵列值进行排序

时间:2016-09-26 02:32:08

标签: c++ sorting matrix

我在Eigen中有一个n x 3矩阵。我想通过按升序排序第1列中的值来重新排列第2和第3列的值。 例如,在排序之前:

  1  4  6
 -2  5  2
  3  1  0

按照第1列值的升序排序后:

 -2 5 2
  1 4 6
  3 1 0

我对如何解决这个问题感到茫然。我可以将每列读入一个向量并使用std :: sort对列1向量进行排序但是我无法看到如何在第1列中为第1列中的排序值保留相应的值.n的值已知并且是固定的,如果这有任何帮助。

4 个答案:

答案 0 :(得分:1)

这不是很漂亮,并且依赖于使用模板参数分离矩阵 - 但它可以工作。

#include <Eigen/Core>
#include <algorithm>
#include <vector>

// Simple little templated comparison functor
template <typename MatrixT>
bool compareRows(MatrixT a, MatrixT b) {
    return a(0,0) < b(0,0);
}

// These are the 6 template arguments to every Eigen matrix
template <typename Scalar, int rows, int cols, int options, int maxRows, int maxCols> 
Eigen::Matrix<Scalar, rows, cols, options, maxRows, maxCols> sortMatrix(
    Eigen::Matrix<Scalar, rows, cols, options, maxRows, maxCols> target
) {
    // Manually construct a vector of correctly-typed matrix rows
    std::vector<Eigen::Matrix<Scalar, 1, cols>> matrixRows;
    for (unsigned int i = 0; i < target.rows(); i++) 
            matrixRows.push_back(target.row(i));
    std::sort(
            matrixRows.begin(),
            matrixRows.end(),
            compareRows<Eigen::Matrix<Scalar, 1, cols>>
    );

    Eigen::Matrix<Scalar, rows, cols, options, maxRows, maxCols> sorted;
    for (unsigned int i = 0; i < matrixRows.size(); i++)
            sorted.row(i) = matrixRows[i];
    return sorted;
}

值得庆幸的是,由于模板参数推断,您可以简单地将此类问题称为:

Eigen::Matrix3f myMatrix;
// Fill in contents here
Eigen::Matrix3f sorted = sortMatrix(myMatrix);

我几乎是肯定的,这是一种更优雅的方式,但我现在无法想到它。而且,因为它使用std::vector,您需要使用-std=c++11或更好的方式进行编译。

答案 1 :(得分:1)

基于second Option by xjcl,我创建了一个基于lambda的选项,可以轻松地将其包含在头文件中:

#include <Eigen>
#include <algorithm>
#include <vector>

void eigen_sort_rows_by_head(Eigen::MatrixXd& A_nx3)
{
    std::vector<Eigen::VectorXd> vec;
    for (int64_t i = 0; i < A_nx3.rows(); ++i)
        vec.push_back(A_nx3.row(i));

    std::sort(vec.begin(), vec.end(), [](Eigen::VectorXd const& t1, Eigen::VectorXd const& t2){ return t1(0) < t2(0); } );

    for (int64_t i = 0; i < A_nx3.rows(); ++i)
        A_nx3.row(i) = vec[i];
};

此选项还通过引用获取目标矩阵。不过,我想可以改善它,希望对您有所帮助:

  • 使用Eigen SWAP使它就位
  • 允许指定可变数量的列(0到n),以给定的顺序在比较中使用。其余列按字典顺序用于打破联系。
  • 允许传递(可选)函数/ PRNG来打破平局,如果有的话。

此外,尽管Eigen发出警告,我们还是不能将auto用于自动模板推导吗?

答案 2 :(得分:1)

我已经实现了此功能,您需要:

#include <Eigen/Dense>
#include <Eigen/Core>

函数是:

Eigen::MatrixXd sortMatrix(const Eigen::MatrixXd &original_matrix) {

  Eigen::MatrixXd sorted_matrix(original_matrix.rows(), original_matrix.cols());
  Eigen::VectorXd sorted_rows = original_matrix.col(0);
  Eigen::VectorXd::Index min_row;

  for ( int i = 0; i < original_matrix.rows(); i++) {
    sorted_rows.minCoeff(&min_row);
    sorted_matrix.row(i) = original_matrix.row(min_row);
    sorted_rows(min_row) = std::numeric_limits<double>::max();
  }

   return sorted_matrix;
}

该函数创建要在新向量中排序的矩阵第一列的副本。它将最小值复制到另一个矩阵中。复制后,该值将被销毁(向量中分配的最大值,因此不会再次识别为最小值),因此它将继续查找和排序最小值,直到所有辅助向量都没有原始值并且订购新矩阵。如果有两个完全相同的值,则不能保证将订购第二列,而只关注第一列。 它是一个O(n ^ 2)算法,因此随着矩阵大小的增加,效率会降低。 有关使用的命令的一些信息:

Block operations in Eigen ( col(), row() )

Matrix and vector arithmetic in Eigen, ( minCoeff() )

答案 3 :(得分:0)

我提出的最佳解决方案是将行复制到std::vector然后继续排序:

#include <Eigen/Core>
#include <algorithm>    // std::sort
#include <vector>       // std::vector

bool compare_head(const Eigen::VectorXd& lhs, const Eigen::VectorXd& rhs)
{
    return lhs(0) < rhs(0);
}

Eigen::MatrixXd sorted_rows_by_head(Eigen::MatrixXd A_nx3)
{
    std::vector<Eigen::VectorXd> vec;
    for (int64_t i = 0; i < A_nx3.rows(); ++i)
        vec.push_back(A_nx3.row(i));

    std::sort(vec.begin(), vec.end(), &compare_head);

    for (int64_t i = 0; i < A_nx3.rows(); ++i)
        A_nx3.row(i) = vec[i];

    return A_nx3;
}