使用rcpp计算数据框中的组合数

时间:2016-06-12 03:50:15

标签: r rcpp

给定一个包含多列的data.frame,使用rcpp计算列中值的组合的最快方法是什么,而不仅仅是R以确保更好的性能?

例如,考虑以下data.frame,称为df,列为A,B,C,D,E

     A  B  C  D  E
  1  1  1  1  1  2 
  2  1  1  1  1  2
  3  2  2  2  2  3
  4  2  2  2  2  3 
  5  3  3  3  3  1

预期输出如下:

     A  B  C  D  E count
  1  1  1  1  1  2 2
  2  2  2  2  2  3 2
  3  3  3  3  3  1 1

在R中,可以通过创建一个新列来组合现有列并使用表来查找计数,即:

df$combine <- do.call(paste, c(df, sep = "-"))
tab <- as.data.frame(table(df$combine))

因为数据按摩的性能和R中的表命令有点慢,有没有人知道并且快速的方式在Rcpp中做同样的事情?

1 个答案:

答案 0 :(得分:0)

好的,这是我能想到的一种方式。

首先,我们真的不能在Rcpp::DataFrame中使用Rcpp对象类型,因为它实际上是一个松散的向量列表。因此,我通过创建与采样数据匹配的Rcpp::NumericMatrix来降低此问题的阈值。从这里开始,可以使用std::map来计算唯一行。这是简化的,因为Rcpp::NumericMatrix具有逐行启用.row()属性。因此,每行都会转换为std::vector<T>,用作地图的关键字。然后,我们将每个std::vector<T>添加到std::map并增加其计数值。最后,我们将std::map导出为所需的矩阵格式。

#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::NumericMatrix unique_rows( Rcpp::NumericMatrix & v)
{

  // Initialize a map
  std::map<std::vector<double>, int> count_rows;

  // Clear map
  count_rows.clear();

  // Count each element
  for (int i = 0; i != v.nrow(); ++i) {
    // Pop from R Matrix
    Rcpp::NumericVector a = v.row(i);
    // Convert R vector to STD vector
    std::vector<double> b = Rcpp::as< std::vector<double> >(a);

    // Add to map
    count_rows[ b ] += 1;
  }

  // Make output matrix
  Rcpp::NumericMatrix o(count_rows.size(), v.ncol()+1);

  // Hold count iteration
  unsigned int count = 0;

  // Start at the 1st element and move to the last element in the map.
  for( std::map<std::vector<double>,int>::iterator it = count_rows.begin();
       it != count_rows.end(); ++it )
  {

    // Grab the key of the matrix
    std::vector<double> temp_o = it->first;

    // Tack on the vector, probably can be speed up. 
    temp_o.push_back(it->second);

    // Convert from std::vector to Rcpp::NumericVector
    Rcpp::NumericVector mm = Rcpp::wrap(temp_o);

    // Store in a NumericMatrix
    o.row(count) = mm;

    count++;
  }

  return o;
}

然后我们选择:

a = matrix(c(1, 1, 1, 1, 2, 
1, 1, 1, 1, 2,
2, 2, 2, 2, 3,
2, 2, 2, 2, 3, 
3, 3, 3, 3, 1), ncol = 5, byrow = T)


unique_rows(a)

,并提供:

     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    1    1    1    2    2
[2,]    2    2    2    2    3    2
[3,]    3    3    3    3    1    1