【问题标题】:Eigen3 select rows out based on column conditionsEigen3 根据列条件选择行
【发布时间】:2019-10-12 03:11:46
【问题描述】:

我有一个特征矩阵,它是二维的,例如:

122 443 544 456 0.9
324 435 5465 645 0.8
32 434 545 546 0.778
435 546 6565 656 0.6878
546 6565 656 3453 54 0.7788
5456 546 545 6565 3434 0.244
435 5456 656 656 6565 0.445
.....

当最后一列的值大于 0.3 时,我想选择所有行(或取出它的行索引)。

我知道我可以通过迭代所有行并判断最后一个元素来做到这一点,但我可能有 10000 行,这样做,迭代会很慢。

有没有更好的方法来做到这一点?

【问题讨论】:

    标签: c++ eigen eigen3


    【解决方案1】:

    相关行的选择可以在一行中完成,通过将最后一列中所有元素的比较结果存储到布尔数组中,该数组可以转换为 VectorXi。

    VectorXi is_selected = (mat.col(last_col).array() > 0.3).cast<int>();
    

    然后可以使用此信息来准备一个仅包含选定行的新矩阵。使用此方法的完整代码如下所示。

    #include <Eigen/Dense>
    #include <iostream>    
    using namespace Eigen;
    
    int main() {
      const int nr = 10;
      const int nc = 5;
      MatrixXd mat = MatrixXd::Random(nr,nc);
      std::cout << "original:\n" << mat << std::endl;
      int last_col = mat.cols() - 1;
    
      VectorXi is_selected = (mat.col(last_col).array() > 0.3).cast<int>();
    
      MatrixXd mat_sel(is_selected.sum(), mat.cols());
      int rownew = 0;
      for (int i = 0; i < mat.rows(); ++i) {
        if (is_selected[i]) {       
           mat_sel.row(rownew) = mat.row(i);
           rownew++;
        }
      }
      std::cout << "selected:\n" << mat_sel << std::endl;
    }
    

    演示:https://godbolt.org/z/f0_fC0

    编辑:使用新功能(Eigen 3.4 或 3.3.90 开发分支)

    Eigen 的开发分支提供了 MatrixX 构造函数的新重载,允许给定矩阵的直接子集。

    MatrixXd mat_sel = mat(keep_rows, keep_cols); 
    

    应保留的列和行存储在Eigen::VectorXistd::vector&lt;int&gt; 中:

    #include <Eigen/Dense>
    #include <iostream>
    #include <vector>
    using namespace Eigen;
    
    int main() {
      MatrixXd mat = MatrixXd::Random(10,5);
      std::cout << "original:\n" << mat << std::endl;
      std::vector<int> keep_rows;  
      for (int i = 0; i < mat.rows(); ++i) {
        if (mat(i,mat.cols() - 1) > 0.3) {
           keep_rows.push_back(i);
         }     
      }
      VectorXi keep_cols = VectorXi::LinSpaced(mat.cols(), 0, mat.cols());
      MatrixXd mat_sel = mat(keep_rows, keep_cols);          
      std::cout << "selected:\n" << mat_sel << std::endl; 
    }
    

    演示:https://godbolt.org/z/Ag7g7f

    【讨论】:

    • 非常感谢您的回答先生!看起来完美的工作仍然有最后一个问题:如果我有 10000 行怎么办?迭代它们是最快的方法吗?有没有原始的方法可以做到这一点?我检查了 Eigen 文档,它说从 3.39 开始,有一种方法 a(Eigen::all, indcies) 可以做到这一点,但默认特征是 3.35 没有 Eigen::all
    • 我对 10000 个示例进行了测试,获得选定矩阵大约需要 2 毫秒。这有点慢。
    • 抛开语法糖,我认为行的选择几乎不可能以比我提到的单行快得多的方式进行。可以考虑使用if(mat(i,last_col) &gt; 0.3) 而不是if(is_selected[i]) 即时选择行,即不预先存储is_selected 向量。这基本上就是@ignacio 所建议的。但是在循环开始时我们不知道会选择多少行,并且由于没有row_push_back()方法,所以最后需要额外的操作来调整矩阵的大小mat_sel .
    • @NicholasJela 请看一下编辑。 Eigen 的一个新特性允许将矩阵mat_sel 直接构造为mat 的子集。我认为这比第一部分中显示的循环要快得多。
    • 谢谢先生,这是最丰富的答案!
    【解决方案2】:

    您可以尝试使用列而不是行并将最后一列与 0.3 的向量 [n x 1] 进行比较

    【讨论】:

    • 哦,你真是个天才。
    • 但是怎么做呢?有sn-ps吗?
    • @RHertel 为你写了一篇
    猜你喜欢
    • 2011-11-12
    • 1970-01-01
    • 2016-11-02
    • 2016-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多