【发布时间】:2015-11-23 06:39:09
【问题描述】:
我目前正在使用ddply 将我编写的函数应用到数据框。该函数根据列中的值评估每一行,然后将许多其他函数应用于该行中的数据。结果是一个与输入数据帧具有相同结构的数据帧和一个附加列,其中包含每行应用函数的结果。
我的问题是数据集相当大,因此使用 ddply 需要很长时间 - 太长了!
当时间很重要时,我已经阅读了许多其他关于替换 ddply 的 SO 问题和博客文章。大多数帖子要么建议使用 data.table ,要么建议使用 dplyr 包中的一些函数组合 do。虽然速度是最重要的,但我从未使用过 data.table,所以易用性/直观性也很重要。
同样,虽然this question 在解释如何结合您自己的函数使用不同的dplyr 函数时非常有用,但我还需要将其他对象传递给我的函数,我不确定如何使用答案在问题中。
我在下面创建了一个简化的示例。然后我的问题是如何使用dplyr 或data table 复制下面的ddply 函数调用给我以上几点。
首先,我设置了一些数据来模拟实际数据的结构
noObs <- 1e5
dataIn <- data.frame(One = rep(c("J", "K"), noObs/2), Two = rep(c("ID", "BR", "LB", "OZ"), noObs/4),
Three = runif(noObs))
secondaryData <- data.frame(Two = c("ID", "BR", "LB", "OZ"), Size = c(300, 500, 250, 400))
下面是我的函数的一个简化示例(实际上,函数参数大于2,它本身调用了其他函数)
MyFunction <- function(dataIn, secondaryData){
groupNames <- c("BR", "LB")
if(dataIn$One == "J"){
if(!(dataIn$Two%in%groupNames)){
if(dataIn$Two == "ID"){
idx <- match(dataIn$Two, secondaryData$Two)
value <- secondaryData[idx, "Size"]
dataIn$newCalc <- dataIn$Three*value
}else{
dataIn$newCalc <- dataIn$Three*1000
}
}else{
idx <- match(dataIn$Two, secondaryData$Two)
value <- secondaryData[idx, "Size"]
dataIn$newCalc <- dataIn$Three*value+1
}
}else{
idx <- match(dataIn$Two, secondaryData$Two)
value <- secondaryData[idx, "Size"]
dataIn$newCalc <- dataIn$Three*value
}
return(dataIn)
}
ddply 调用看起来像
dataOut <- ddply(dataIn, names(dataIn), MyFunction, secondaryData)
最后,一些我尝试过的例子(我还没有尝试过data.table)
dataIn %>% group_by(names(dataIn)) %>% do(MyFunction(dataIn, secondaryData))
dataIn %>% group_by(names(dataIn)) %>% MyFunction(dataIn, secondaryData)
dataIn %>% group_by(.dots = names(dataIn)) %>% MyFunction(secondaryData)
编辑
我已经能够找到一种使用dplyr 的方法,但它比ddply 还要慢,而且我不知道如何将group_by 与names 一起使用。这对我来说似乎不对,因为dplyr 意味着更快。
另外,我一直在尝试使用data.table,但一直无法让它工作。同样,我正在寻找比ddply运行更快的东西
#Plyr
start <- proc.time()
dataOut <- ddply(dataIn, names(dataIn), MyFunction, secondaryData)
plyrTime <- proc.time() - start
#Dplyr
#Works
start <- proc.time()
res <- dataIn %>% group_by(One, Two, Three) %>% do(MyFunction(.,secondaryData))
dplyrTime <- proc.time() - start
#Doesn't work
res <- dataIn %>% group_by(.,names(dataIn)) %>% do(MyFunction(.,secondaryData))
#Data.table
dataInDT <- data.table(dataIn)
dataInDT[,.(MyFunction(.,secondaryData)), by=.(One, Two, Three)]
【问题讨论】:
-
也许是
library(dplyr); dataIn %>% group_by_(.dots = names(dataIn)) %>% myFunction(projSettings, secondaryData)。请提供一个可重现的例子。 -
SO 不是代码编写服务。向我们展示您已经尝试过的内容(包括reproducible example)。
-
@lukeA 我添加了一个可重现的示例。希望这会有所帮助
-
谢谢。
dataIn %>% group_by_(.dots = names(dataIn)) %>% MyFunction(secondaryData)的结果有什么问题?我看不出你试过了。 -
@lukeA 谢谢你的评论。我确实尝试过,但它会产生警告。经过进一步调查,您可以看到建议的方法没有正确应用算法,换句话说,它只需要第一个元素
标签: r data.table dplyr plyr