【问题标题】:Finding unique rows in arma::mat在 arma::mat 中查找唯一行
【发布时间】:2016-05-10 15:44:44
【问题描述】:

在 R 中,我们可以使用 unique 方法来查找唯一行

> data <- matrix(c(1,1,0,1,1,1,0,1),ncol = 2)
> data
     [,1] [,2]
[1,]    1    1
[2,]    1    1
[3,]    0    0
[4,]    1    1

> unique(data)
     [,1] [,2]
[1,]    1    1
[2,]    0    0

我们如何在 Rcpp 中为 arma::mat 做到这一点? 这里的 unique 函数返回唯一元素而不是唯一行。

【问题讨论】:

    标签: r unique rcpp armadillo


    【解决方案1】:

    我认为 Armadillo 库中没有内置的方法可以做到这一点,但这里有一个简单的方法:

    // [[Rcpp::depends(RcppArmadillo)]]
    #include <RcppArmadillo.h>
    
    template <typename T>
    inline bool rows_equal(const T& lhs, const T& rhs, double tol = 0.00000001) {
        return arma::approx_equal(lhs, rhs, "absdiff", tol);
    }
    
    // [[Rcpp::export]]
    arma::mat unique_rows(const arma::mat& x) {
        unsigned int count = 1, i = 1, j = 1, nr = x.n_rows, nc = x.n_cols;
        arma::mat result(nr, nc);
        result.row(0) = x.row(0);
    
        for ( ; i < nr; i++) {
            bool matched = false;
            if (rows_equal(x.row(i), result.row(0))) continue;
    
            for (j = i + 1; j < nr; j++) {
                if (rows_equal(x.row(i), x.row(j))) {
                    matched = true;
                    break;
                }
            }
    
            if (!matched) result.row(count++) = x.row(i);
        }
    
        return result.rows(0, count - 1);
    }
    
    /*** R
    
    data <- matrix(c(1,1,0,1,1,1,0,1), ncol = 2)
    all.equal(unique(data), unique_rows(data))
    #[1] TRUE
    
    data2 <- matrix(1:9, nrow = 3)
    all.equal(unique(data2), unique_rows(data2))
    #[1] TRUE
    
    data3 <- matrix(0, nrow = 3, ncol = 3)
    all.equal(unique(data3), unique_rows(data3))
    #[1] TRUE
    
    data4 <- matrix(c(0, 0, 0, 1, 1, 0, 1, 1), ncol = 2)
    all.equal(unique(data4), unique_rows(data4))
    #[1] TRUE
    
    */
    

    正如 mtall 在 cmets 中所建议的,rows_equal 使用 arma::approx_equal 来测试相等性,而不是 operator==,以避免浮点数固有的一些比较问题。此功能中使用的选项有些随意选择,当然可以根据需要进行更改;但是tol 的值大致等于R 的all.equal 使用的默认容差,即.Machine$double.eps^0.5(在我的机器上为~0.00000001490116)。

    【讨论】:

    • 浮点数(floatdouble)是近似值,因此与它们进行相等比较通常是个坏主意。 arma::mat 类的底层存储类型是double。最好使用approx_equal() 而不是==
    • @mtall 不错;谢谢你。我不知道这个功能。
    【解决方案2】:

    受@nrussell 启发的相同方法,略短:

    // [[Rcpp::depends(RcppArmadillo)]]
    #include <RcppArmadillo.h>
    
    template <typename T>
    inline bool approx_equal_cpp(const T& lhs, const T& rhs, double tol = 0.00000001) {
      return arma::approx_equal(lhs, rhs, "absdiff", tol);
    }
    
    // [[Rcpp::export]]
    arma::mat unique_rows(const arma::mat& m) {
    
      arma::uvec ulmt = arma::zeros<arma::uvec>(m.n_rows);
    
      for (arma::uword i = 0; i < m.n_rows; i++) {
        for (arma::uword j = i + 1; j < m.n_rows; j++) {
          if (approx_equal_cpp(m.row(i), m.row(j))) { ulmt(j) = 1; break; }
        }
      }
    
      return m.rows(find(ulmt == 0));
    
    }
    
    // [[Rcpp::export]]
    arma::mat unique_cols(const arma::mat& m) {
    
      arma::uvec vlmt = arma::zeros<arma::uvec>(m.n_cols);
    
      for (arma::uword i = 0; i < m.n_cols; i++) {
        for (arma::uword j = i + 1; j < m.n_cols; j++) {
          if (approx_equal_cpp(m.col(i), m.col(j))) { vlmt(j) = 1; break; }
        }
      }
    
      return m.cols(find(vlmt == 0));
    
    }
    
    /*** R
    
    data <- matrix(c(1,1,0,1,1,1,0,1), ncol = 2)
    all.equal(unique(data), unique_rows(data))
    #[1] TRUE
    
    data2 <- matrix(1:9, nrow = 3)
    all.equal(unique(data2), unique_rows(data2))
    #[1] TRUE
    
    data3 <- matrix(0, nrow = 3, ncol = 3)
    all.equal(unique(data3), unique_rows(data3))
    #[1] TRUE
    
    data4 <- matrix(c(0, 0, 0, 1, 1, 0, 1, 1), ncol = 2)
    all.equal(unique(data4), unique_rows(data4))
    #[1] TRUE
    
    */
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-09
      • 1970-01-01
      • 1970-01-01
      • 2013-06-02
      • 2015-01-14
      • 1970-01-01
      相关资源
      最近更新 更多