我目前正在使用ddply
来应用我写入数据框的函数。该函数根据列中的值计算每一行,然后将许多其他函数应用于该行中的数据。结果是一个数据框,其结构与输入数据框相同,另外一列包含每行应用函数的结果。
我的问题是数据集相当大,因此使用ddply
需要很长时间 - 为此目的太长了!
当时间非常重要时,我已经阅读了许多关于ddply
替换的其他SO问题和博客文章。大多数帖子建议使用dplyr
包中的data.table或某些功能组合do
。虽然速度是最重要的,但我从未使用过data.table,因此易用性/直观性也很重要。
同样,虽然this question在解释如何结合自己的函数使用不同的dplyr
函数时非常有用,但我还需要将其他对象传递给我的函数,我不确定如何使用问题中的答案。
我在下面创建了一个简化示例。我的问题是如何使用ddply
或dplyr
复制以下data table
函数调用给出我的上述观点。
首先,我设置了一些数据来模仿实际数据的结构
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)]
答案 0 :(得分:0)
我找到了使用data.table
的解决方案。值得注意的是,它为每一行执行正确的计算,但速度要快得多。函数的格式不同,以适应data.table
的不同风格。我确信使用data.table
有更好或更正确的解决方法,但下面的解决方案效果很好。
dataInDT <- data.table(dataIn)
groupNames <- c("BR", "LB")
start <- proc.time()
dataInDT[, NewCalc := {
if(One == "J"){
if(!(Two%in%groupNames)){
if(Two == "ID"){
Three*secondaryData[match(Two, secondaryData$Two), "Size"]
}else{
Three*1000
}
}else{
Three*secondaryData[match(Two, secondaryData$Two), "Size"]+1
}
}else{
Three*secondaryData[match(Two, secondaryData$Two), "Size"]
}}, by=.(One, Two, Three)]
datTableTime <- proc.time() - start
将此与旧解决方案进行比较,您可以看到速度大大提高
start <- proc.time()
dataOut <- ddply(dataIn, names(dataIn), MyFunction, secondaryData)
plyrTime <- proc.time() - start
当然,在实践中,我使用的data.table
函数更复杂,特别是by
部分更长。
我无法使用dplyr
找到解决方案,我仍然很想知道它是如何工作的。