更快地根据R中的列汇总变量

use*_*119 10 r dplyr data.table

我希望根据列总结我的数据框中的一些变量.但是我的数据框相当大(> 30,000,000行),并且使用dplyr中的汇总函数需要很长时间才能运行.R中是否有更快的方法来加速汇总过程?

我有一个格式的数据框df:

  proid  X1  X2  X3 X4
1     1  zz   a   e  a
2     2  ff   g   z  b
3     1  cd   s   f  d 
4     3  ab   t   e  e
5     2  ta   b   h  k
      ....
Run Code Online (Sandbox Code Playgroud)

我希望在它们具有相同的prodid值时连接变量X1到X4.连接的字符串用逗号分隔.所以上面的表应该给我新表:

  proid     X1   X2   X3  X4
1     1  zz,cd  a,s  e,f a,d 
2     2  ff,ta  g,b  z,h b,k
3     3     ab    t    e   e
      ....
Run Code Online (Sandbox Code Playgroud)

我使用了以下dplyr代码:

concat <- function(x){
  x <- na.omit(x)
  if(length(x)==0){
    return(as.character(NA))
  }else{
    return(paste(x,collapse=","))
  }
}

dg<-group_by(df,proid)
df<-summarise(dg,proid,concat(X1),concat(X2),concat(X3),concat(X4))
Run Code Online (Sandbox Code Playgroud)

tal*_*lat 11

编辑注释:删除了我的答案的原始部分,没有解决NA处理并添加了基准.

concat2 <- function(x) if(all(is.na(x))) NA_character_ else paste(na.omit(x), collapse = ",")
Run Code Online (Sandbox Code Playgroud)

使用data.table:

setDT(df)[, lapply(.SD, concat2), by = proid, .SDcols = -c("X4")]
#   proid    X1  X2  X3
#1:     1 zz,cd a,s e,f
#2:     2 ff,ta g,b z,h
#3:     3    NA   t   e
Run Code Online (Sandbox Code Playgroud)

使用dplyr:

df %>% group_by(proid) %>% summarise_each(funs(concat2), -X4)
Run Code Online (Sandbox Code Playgroud)

基准测试,比实际使用情况更小的数据而且没有完全代表性,所以只是想得到一个concat2比较concat等等的印象.

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

N <- 1e6
x <- c(letters, LETTERS)
df <- data.frame(
  proid = sample(1e4, N, TRUE),
  X1 = sample(sample(c(x, NA), N, TRUE)),
  X2 = sample(sample(c(x, NA), N, TRUE)),
  X3 = sample(sample(c(x, NA), N, TRUE)),
  X4 = sample(sample(c(x, NA), N, TRUE))
  )

dt <- as.data.table(df)

concat <- function(x){
  x <- na.omit(x)
  if(length(x)==0){
    return(as.character(NA))
  }else{
    return(paste(x,collapse=","))
  }
}

concat2 <- function(x) if(all(is.na(x))) NA_character_ else paste(na.omit(x), collapse = ",")

concat.dplyr <- function(){
  df %>% group_by(proid) %>% summarise_each(funs(concat), -X4)
}

concat2.dplyr <- function(){
  df %>% group_by(proid) %>% summarise_each(funs(concat2), -X4)
}

concat.data.table <- function(){
  dt[, lapply(.SD, concat), by = proid, .SDcols = -c("X4")]
}

concat2.data.table <- function(){
  dt[, lapply(.SD, concat2), by = proid, .SDcols = -c("X4")]
}


microbenchmark(concat.dplyr(), 
               concat2.dplyr(), 
               concat.data.table(), 
               concat2.data.table(),
               unit = "relative",
               times = 10L)
Unit: relative
                 expr      min       lq   median       uq      max neval
       concat.dplyr() 1.058839 1.058342 1.083728 1.105907 1.080883    10
      concat2.dplyr() 1.057991 1.065566 1.109099 1.145657 1.079201    10
  concat.data.table() 1.024101 1.018443 1.093604 1.085254 1.066560    10
 concat2.data.table() 1.000000 1.000000 1.000000 1.000000 1.000000    10
Run Code Online (Sandbox Code Playgroud)

调查结果:data.table在样本数据上的执行速度比dplyr快concat2一点,速度比concat.但是,此样本数据集的差异仍然很小.

  • 这两个解决方案都没有在OP的函数中占用'na.omit()`但是... @ eipi10,与`dplyr`的速度差异很大程度上取决于a)组的数量,以及b)行数(in那个订单)... (4认同)
  • 没有理由保留不解决"NA"的答案部分,是吗?另外,你可能想要在结果中添加一行显示修改结果的'NA`,`df [4,"X1"] < - NA`也许?最后,OP的`concat`功能出了什么问题?对我来说似乎很好,并且在`concat2`中没有`is.na`和`na.omit`的冗余. (3认同)
  • 好的,@ Arun,最初忽略了这一部分.eddi的评论很有希望 (2认同)