省略数据框中元素相同的行

Mor*_*ori 9 r rcpp

假设我们有一个这样的数据框

DataFrame ref = DataFrame::create( Named("sender") = sender , Named("receiver") = receiver);
Run Code Online (Sandbox Code Playgroud)

对应的R代码如下:

edge <- as.data.frame(edge) %>%
set_colnames(c("time", "sender", "receiver"))
edge <- rbind(c(0,0,0), edge)
ref  <- data.frame(sender = rep(1:n, times = n),
                receiver = rep(1:n, each = n)

 ) %>%
filter(sender != receiver) %>%
mutate(teller = 1:(n*(n-1))) 
Run Code Online (Sandbox Code Playgroud)

此数据框中的某些行具有相同的元素,例如 2 2,我想找到它们并将它们从数据框中删除。然后我想向这个数据框添加另一列,它就像从 1 到新数据框的行数的数字。

例子:

请看这里

duc*_*ayr 11

我认为这个问题可以解释为这个 Stack Overflow 问题的重复,但我在这里单独回答以证明我在评论中的观点,如果你这样做是为了提高性能,Rcpp可能不是这个特定的方法任务。也就是说,有许多任务Rcpp是我为了提高性能而去的地方,但是对数据帧行进行子集化并不是这些任务之一。

按照我链接的答案中的方法,代码很容易设置:

#include <Rcpp.h>

// [[Rcpp::export]]
Rcpp::DataFrame foo(Rcpp::DataFrame x) {
    Rcpp::NumericVector sender = x["sender"];
    Rcpp::NumericVector receiver = x["receiver"];
    Rcpp::LogicalVector indices = sender != receiver;
    return Rcpp::DataFrame::create(Rcpp::Named("sender") = sender[indices],
                                   Rcpp::Named("receiver") = receiver[indices]);
}
Run Code Online (Sandbox Code Playgroud)

但是,我们可以看到,this 的执行速度实际上比 base R(并且data.table可以略微超越 base R的性能):

library(dplyr)
library(Rcpp)
library(microbenchmark)
library(data.table)

sourceCpp("so.cpp")

for ( n in 10^(1:3) ) {
    ref  <- data.frame(sender = rep(1:n, times = n),  ## If you're using
                       receiver = rep(1:n, each = n)) ## data frames
    refDT <- setDT(ref) ## If you're using data.table
    cat("For n =", n, "(a data frame with", nrow(ref), "rows)\n")
    print(microbenchmark(base = ref[ref$sender != ref$receiver, ],
                         dplyr = ref %>% filter(sender != receiver),
                         rcpp = foo(ref),
                         data.table = refDT[sender != receiver]))
    cat("\n")
}
Run Code Online (Sandbox Code Playgroud)
For n = 10 (a data frame with 100 rows)
Unit: microseconds
       expr     min       lq     mean   median       uq     max neval
       base 123.917 140.0025 160.7615 155.1905 170.7825 302.520   100
      dplyr 397.308 430.7595 478.0543 446.9185 492.5705 900.716   100
       rcpp 189.473 212.9530 238.8270 223.3305 240.7950 461.452   100
 data.table 122.436 135.9185 160.6607 154.0565 166.7825 460.739   100

For n = 100 (a data frame with 10000 rows)
Unit: microseconds
       expr     min       lq     mean   median       uq     max neval
       base 205.978 224.9760 250.7321 244.3315 265.5060 510.079   100
      dplyr 519.276 581.4535 629.2837 615.7095 662.8060 989.698   100
       rcpp 369.276 430.3510 463.1586 471.3195 486.4450 736.907   100
 data.table 198.012 221.8445 248.9371 246.2385 267.5325 341.935   100

For n = 1000 (a data frame with 1000000 rows)
Unit: milliseconds
       expr       min        lq      mean    median        uq      max
       base  6.535990  6.892702  7.664697  7.203983  7.554144 11.42160
      dplyr  8.795884  9.239173 10.024997  9.618395  9.992066 15.04914
       rcpp 15.116928 15.598556 17.164895 16.216766 17.066418 30.45578
 data.table  6.624728  6.905202  7.543284  7.137171  7.482922 11.67061
 neval
   100
   100
   100
   100
Run Code Online (Sandbox Code Playgroud)

  • 很棒的工作。现在我终于可以告诉人们使用base R,因为无论如何它都比`Rcpp`更快:)或者,像我通常做的那样(参见上面的第一条评论)使用`data.table`,它很可能击败所有的袜子他们的。 (6认同)
  • 为什么它可能更快: 1. `subsetDT`,在 C 级别导出以供其他包使用,是并行化的,它已经需要行索引,使用 `setDTthreads(0)` 来使用所有核心可能会加快速度,bc DT 默认使用 50% 的核心。2.到目前为止,我们无法将`sender !=receiver`优化为二分搜索(由于`!=`操作),所以这就是我现在能想到的。 (4认同)
  • 开个玩笑,不知道为什么我们在那里很糟糕。在“Rcpp::DataFrame”情况下必须有另一种内存分配和复制。 (3认同)
  • 请在该上下文中使用 `as.data.table` 而不是 `setDT`,当然,重新运行基准测试,您最终可能会发现基础 R 比现在稍快 (3认同)