【问题标题】:Omitting the rows of a data frame in which their elements are the same省略数据框中元素相同的行
【发布时间】:2020-05-14 14:55:52
【问题描述】:

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

DataFrame ref = DataFrame::create( Named("sender") = sender , Named("receiver") = receiver);

对应的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))) 

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

例子:

【问题讨论】:

  • 欢迎来到 StackOverflow。听起来你想学习data.table。您可能无需学习或编写编译代码即可获得相同的性能。此外,模拟数据集和示例输出(可能是较慢的 R 代码?)将使您的问题更强大,并可能吸引更好的答案。
  • @Mori 我想ref 这里是示例数据集,但是 Dirk Eddelbuettel 提到的一些非常有用但仍然没有出现的内容是示例 output。您想要执行的操作并不完全清楚(至少对我而言),但如果您显示您希望从模拟数据集中获得的输出,可能会更清楚。
  • @DirkEddelbuettel 谢谢。我编辑了问题并按照您的建议添加了一个数字示例。现在请看是否清楚您可以给我更具体的答案。
  • 在我看来,当您的任务是对数据框的行进行子集化时,您非常不太可能使用Rcpp 击败基本 R 或 data.table 之类的东西.在很多情况下,您可以使用 Rcpp 获得更好的性能,但我认为这不是其中之一。
  • @Mori:您“没有添加示例”。您添加了指向图像的链接。简而言之:“不要那样做。”。 StackOverflow 更喜欢一个您可能会在您访问的其他帖子中看到的实际示例。

标签: r rcpp


【解决方案1】:

我认为这个问题可以解释为 this Stack Overflow question 的重复,但我在这里单独回答以证明我在 cmets 中的观点,如果你这样做是为了提高性能,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]);
}

但是,我们可以看到 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")
}
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

【讨论】:

  • 出色的工作。现在我终于可以到处告诉人们使用base R,因为它比Rcpp 快:) 或者,就像我通常做的那样(见上面的第一条评论)使用data.table,这很可能胜过所有人的袜子'时间。
  • 开玩笑,不知道为什么我们在那里烂。在Rcpp::DataFrame 的情况下,必须有另一个内存分配和复制。
  • @DirkEddelbuettel 是的,data.table 在快速数据处理方面被低估了! DataFrame 案例只是 Rcpp 的一个特殊案例,我认为你是对的,它与内存分配有关,但不确定 data.table 在幕后做了什么......可以看看如果我的好奇心水平和空闲时间水平都上升,那么有一天在源头
  • 请在这种情况下使用as.data.table 而不是setDT,当然要重新运行基准测试,您最终可能会发现base R 比现在稍快
  • 为什么它可能更快:1. subsetDT,在 C 级别导出以供其他包使用,是并行化的,它已经采用行索引,使用 setDTthreads(0) 使用所有内核可能会加快它甚至更多,bc DT 默认使用 50% 的内核。 2.目前我们无法将sender != receiver优化为二分搜索(由于!= op),所以我现在能想到的就这么多了。
猜你喜欢
  • 2010-12-18
  • 1970-01-01
  • 1970-01-01
  • 2022-10-14
  • 2018-07-06
  • 1970-01-01
  • 1970-01-01
  • 2021-07-21
  • 2021-07-23
相关资源
最近更新 更多