【问题标题】:How to remove a certain row or column while using Eigen Library c++如何在使用 Eigen Library c++ 时删除特定的行或列
【发布时间】:2012-11-08 13:58:25
【问题描述】:

我正在为我的项目使用 Eigen 库。我正在搜索如何从 Eigen 中的给定矩阵中删除特定的行或列。我没有成功。

MatrixXd A = X1 X2 X3 X4
             Y1 Y2 Y3 Y4
             Z1 Z2 Z3 Z4
             A1 A2 A3 A4
MatrixXd Atransform = X1 X2 X4
                      Y1 Y2 Y4
                      Z1 Z2 Z4
                      A1 A2 A4
enter code here

除了遍历整个矩阵或对矩阵 A 使用块操作。有没有简单的方法。

【问题讨论】:

  • 我认为除了使用块操作之外没有其他方法。

标签: c++ eigen


【解决方案1】:

使用块函数更简洁:

void removeRow(Eigen::MatrixXd& matrix, unsigned int rowToRemove)
{
    unsigned int numRows = matrix.rows()-1;
    unsigned int numCols = matrix.cols();

    if( rowToRemove < numRows )
        matrix.block(rowToRemove,0,numRows-rowToRemove,numCols) = matrix.block(rowToRemove+1,0,numRows-rowToRemove,numCols);

    matrix.conservativeResize(numRows,numCols);
}

void removeColumn(Eigen::MatrixXd& matrix, unsigned int colToRemove)
{
    unsigned int numRows = matrix.rows();
    unsigned int numCols = matrix.cols()-1;

    if( colToRemove < numCols )
        matrix.block(0,colToRemove,numRows,numCols-colToRemove) = matrix.block(0,colToRemove+1,numRows,numCols-colToRemove);

    matrix.conservativeResize(numRows,numCols);
}

【讨论】:

  • 这通常应该有效,但不能保证 Eigen 会从左到右(或从上到下)复制块,因此理论上您可能会遇到混叠问题。
  • @chtz:要避免这个问题,请使用.eval() 函数。
【解决方案2】:

使用 Eigen 3.3.0+(2016.08 发布)可以更轻松、更短地完成此操作:

vector<int> indicesToKeep = vector<int>{ 1, 2, 3 };
VectorXi indicesToKeepVector = VectorXi(indicesToKeep.data(), indicesToKeep.size());
MatrixXf matrix = MatrixXf(); // your data should be here!
matrix = matrix(Eigen::placeholders::all, indicesToKeepVector); // select columns you want to keep(indicesToKeep), discard others
matrix = matrix(indicesToKeepVector, Eigen::placeholders::all); // select rows you want to keep(indicesToKeep), discard others
matrix = matrix(Eigen::seq(5, 10), Eigen::placeholders::all); // keep rows from 5 to 10
matrix = matrix(Eigen::placeholders::all, Eigen::seq(5, 10)); // keep columns from 5 to 10
matrix = matrix(Eigen::seqN(5, 5), Eigen::placeholders::all); // keep rows from 5 to 10
matrix = matrix(Eigen::placeholders::all, Eigen::seqN(5, 5)); // keep columns from 5 to 10

【讨论】:

    【解决方案3】:

    要改进 Andrew 的答案,请使用 bottomRows/rightCols。

    void removeRow(Eigen::MatrixXd& matrix, unsigned int rowToRemove)
    {
        unsigned int numRows = matrix.rows()-1;
        unsigned int numCols = matrix.cols();
    
        if( rowToRemove < numRows )
            matrix.block(rowToRemove,0,numRows-rowToRemove,numCols) = matrix.bottomRows(numRows-rowToRemove);
    
        matrix.conservativeResize(numRows,numCols);
    }
    
    void removeColumn(Eigen::MatrixXd& matrix, unsigned int colToRemove)
    {
        unsigned int numRows = matrix.rows();
        unsigned int numCols = matrix.cols()-1;
    
        if( colToRemove < numCols )
            matrix.block(0,colToRemove,numRows,numCols-colToRemove) = matrix.rightCols(numCols-colToRemove);
    
        matrix.conservativeResize(numRows,numCols);
    }
    

    【讨论】:

      【解决方案4】:

      您可能会发现以下静态版本更适合某些用途(并且更符合 Eigen 编译时效率的精神)。在这种情况下,您将创建一个没有行的新矩阵。可以使用.leftCols() .rightCols()为列构造类似的函数

      template<typename T>
      inline constexpr auto removeRow(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& matrix, const int& rowNum)
      {
          return (Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>(matrix.rows() - 1, matrix.cols())
              << static_cast<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>(matrix.topRows(rowNum - 1)),
              static_cast<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>(matrix.bottomRows(matrix.rows() - rowNum))).finished();
      }
      

      享受吧!

      【讨论】:

        【解决方案5】:

        我知道这是一个老问题,但似乎 Eigen 现在支持创建由索引的行和列定义的子矩阵: http://eigen.tuxfamily.org/bz/show_bug.cgi?id=329 http://eigen.tuxfamily.org/dox-devel/classEigen_1_1DenseBase.html#a0b44220621cd59a75cd0f48cc499518f

        它似乎不在文档中......

        【讨论】:

          【解决方案6】:
            inline Eigen::MatrixXd removeMatrixRow(const Eigen::MatrixXd original_matrix, const int row_to_remove)
            {
              // New matrix has one fewer rows
              Eigen::MatrixXd new_matrix(original_matrix.rows()-1, original_matrix.cols());
              // Track rows in new matrix. Skip one at row_to_remove.
              int row_to_fill = 0;
              for (int orig_matrix_row = 0; orig_matrix_row < original_matrix.rows(); ++orig_matrix_row)
              {
                if (orig_matrix_row != row_to_remove)
                {
                  new_matrix.row(row_to_fill) = original_matrix.row(orig_matrix_row);
                  ++row_to_fill;
                }
              }
              return new_matrix;
            }
          

          【讨论】:

          • 点评来源: 您好,请不要只回答源代码。尝试对您的解决方案如何工作提供一个很好的描述。请参阅:How do I write a good answer?。谢谢
          【解决方案7】:

          我是 C++ 新手,但此代码适用于可能的应用程序。

          它只适用于全动态矩阵,但可以适应它。

          如果有人有更好的方法,请告诉我我真的很想学习。

          template<typename ScalarType>
          void MatrixXdRemoveCol(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, int colindex)
          {
              Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *auxmat = new Eigen::Matrix<ScalarType,-1,-1,0,-1,-1>;
          
              *auxmat = *mat;
          
              mat->resize(mat->rows(),mat->cols()-1);
          
              int rightColsSize = auxmat->cols()-colindex-1;
          
              mat->leftCols(colindex) = auxmat->leftCols(colindex);
              mat->rightCols(rightColsSize) = auxmat->rightCols(rightColsSize);
          }
          
          template<typename ScalarType>
          void MatrixXdRemoveCols(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, std::vector<int>* cols)
          {
              for(auto iter = cols->rbegin();iter != cols->rend();iter++)
                  MatrixXdRemoveCol<ScalarType>(mat,*iter);
          }
          
          template<typename ScalarType>
          void MatrixXdRemoveRow(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, int rowindex)
          {
              Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *auxmat = new Eigen::Matrix<ScalarType,-1,-1,0,-1,-1>;
          
              *auxmat = *mat;
          
              mat->resize(mat->rows()-1,mat->cols());
          
              int BottomRowsSize = auxmat->rows()-rowindex-1;
          
              mat->topRows(rowindex) = auxmat->topRows(rowindex);
              mat->bottomRows(BottomRowsSize) = auxmat->bottomRows(BottomRowsSize);
          }
          

          【讨论】:

          • 我不熟悉 eigen 库,但从一般 c++ 的角度来看,您的函数中似乎存在内存泄漏:您分配 auxmats 但不删除它们。
          • 通常,在编写 C++ 时应避免使用new —— 除非您确实需要并且知道自己在做什么。而是只写Eigen::Matrix&lt;ScalarType,-1,-1,0,-1,-1&gt; auxmat = mat(并通过引用而不是指针传递mat
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-05-04
          • 1970-01-01
          相关资源
          最近更新 更多