R数据帧和c ++中的.min()等价物

时间:2011-07-13 03:02:33

标签: c++ r rcpp

我正在将R代码翻译成c ++,我想找到一个等效(最佳)结构,它允许与数据框相同的操作,但在c ++中。

操作是:

  • 添加元素(行)
  • 从索引
  • 中删除元素(行)
  • 获取最低值的索引

e.g。 :

a <- data.frame(i = c(4, 9, 3, 1, 8, 2, 7, 10, 6, 6), 
                j = c(8, 8, 8, 4, 3, 9, 1, 4,  8, 9) , 
                v = c(1.9, 18, 1.3, 17, 1.5, 14, 11, 1.4, 18, 2.0), 
                o = c(3, 3, 3, 3, 1, 2, 1, 2, 3, 3))

a[which.min(a$v), c('i', 'j')] # find lowest v value and get i,j value
a <- a[-which.min(a$v)] # remove row from index
a <- cbind(a, data.frame(i = 3, j = 9, v = 2, o = 2)) # add a row

因为我正在使用Rcpp,所以Rcpp :: DataFrame可能是一个选项(我不知道我会怎么做。但它),但我想这个任务很慢,因为这些操作需要重复很多,我不需要将它运回给R。

编辑:

目标。为了明确这里的目标是提高速度。这是明显的原因,为什么人们会将代码从R转换为C ++(可能还有其他代码,这就是我澄清的原因)。但是,维护和简单实施排在第二位。

操作更精确。算法是:向数组中添加大量数据(多行),然后提取最低值并删除它。重复。 这就是为什么我不会去寻找一个有序矢量,而是总是按需搜索最低数据,因为数组经常更新(添加)。我认为它更快,但也许我错了。

5 个答案:

答案 0 :(得分:1)

我认为矢量矢量应该做你想要的。您需要手动实现min-finding(两个嵌套循环),这是您可以在不增加开销的情况下实现的最快速度。 您可以通过跟踪每行中最小元素的位置以及行来加速最小发现。

答案 1 :(得分:1)

这个问题有点陈旧,但我想我会提供一些关于这类任务的一般性观察。

如果要将行集合保持在有序状态(这可能是您的which.min策略的假设),那么有效支持的最困难的操作是行插入,如果这是常见操作。你很难不使用list<>数据结构,可能导致which.min变成线性操作,因为列表对于二分搜索不是很好。

如果保留无序集合,则可以通过将帧末尾的记录复制到删除空出的行并从行计数中减去1来处理删除。或者,您可以使用另一个bool向量标记删除,直到删除计数达到sqrt(N)之类的阈值,此时您执行合并副本。对于插入/删除,你会出现优于摊销的O(N ^ 2),但是.min将是每次对整个向量进行线性搜索。

当您需要将min / max元素标识为常见操作时,通常需要使用某种优先级队列,有时会复制索引列的数据。在我的头脑中,将一个数据列上的优先级队列与由于非列表实现中的删除操作而移动的数据帧的行同步将是棘手的。

如果行仅标记已删除,则优先级队列将保持同步(尽管您必须丢弃从队列中弹出的元素,这些元素对应于随后删除的行,直到您获得一个好的行) ;在合并副本之后,您将重新索引优先级队列,如果您不经常这样做,这将非常快。通常,如果你有足够的内存来将结构增长到一个很大的尺寸,那么如果结构缩小,你就不会过度压缩内存。如果您的结构倾向于以高水位附近的大小持续存在,那么曾经需要合并并不明显,但请注意优先级队列已过期且对同一存储的新引用的情况行,因为您将新数据写入先前删除的行。为了提高效率,有时您最终会使用辅助列表来跟踪标记为已删除的行,以便您可以在不到线性的时间内找到插入行的存储空间。

从优先级队列的内容中提取陈旧项目可能很困难,因为这些项目往往只是为了在队列顶部删除而设计的;通常你必须把陈旧的物品留在那里,如果它们稍后浮出水面就会安排忽略它们。

当你进入具有性能目标的C ++时,有许多方法可以使猫,并且你需要比原始R代码所表达的更精确的性能权衡,以获得所有必需操作的良好执行时间。

答案 2 :(得分:0)

data.frame实际上只是一个向量列表。在C ++中,我们实际上只有那些向量添加行的向量列表。

删除行的同意 - 当Rcpp在原始R表示上工作时,您总是需要复制所有剩余的值。

至于which.min()等价物:我认为在列表中出现一次,你可以用STL习语做一些简单的事情。我不记得我们在API中有这个。

答案 3 :(得分:0)

C ++术语中的R 数据框是对象的容器(An R matrix 可能是向量的向量,但如果你关心效率,你不太可能以这种方式实施。)

因此,用这个类代表数据框:

class A{
public:
  int i,j,o;
  double v;
public:
  A(int i_,int j_,int v_,int o_):i(i_),j(j_),v(v_),o(o_){}
}

并准备此算法参数函数以帮助找到最小值:

bool comp(A &x,A &y){
return x.v<y.v;
}

(在生产代码中,我更可能使用仿函数对象(参见Meyer的Effective STL,第46项),或boost lambda,或者最重要的是,使用C ++ 0x的lambdas)

然后是这个代码体:

std::vector<A> a;
a.push_back(A(4,8,1.9,3));
a.push_back(A(9,8,18,3));
a.push_back(A(1,4,1.3,3));
//...

std::vector<A>::iterator lowest=std::min_element(a.begin(),a.end(),comp);
std::cout<< lowest->i << ',' << lowest->j <<"\n";

a.erase(lowest);

a.push_back( A(3,9,2,0) );

根据您的确在做什么,首先排序a可能更有效率,最好先排序。然后,如果你想删除最低的项目,你只需截断向量。 如果您实际上正在删除所有地方,并且which.min()仅仅是为了示例,您可能会发现链接列表更有效。

答案 4 :(得分:0)

没有, data.frame比矢量矢量稍微复杂一点。

我可能会说最简单的速度设计是将每个列存储在一个类型化的向量中,并创建一个列表作为行的标题。然后在它上面创建一个侵入性列表。