我有一个非常大的 data.frame
我想要应用一个相当复杂的函数来计算一个新列。我想要并行完成。这类似于over on the r listserve发布的问题,但第一个答案是错误的,第二个答案是无益的。
由于parallel
包,我得到了一切,除了如何将输出放回到数据框之外。这是一个显示我所得到的MWE:
library(parallel)
# Example Data
data <- data.frame(a = rnorm(200), b = rnorm(200),
group = sample(letters, 200, replace = TRUE))
# Break into list
datagroup <- split(data, factor(data$group))
# execute on each element in parallel
options(mc.cores = detectCores())
output <- mclapply(datagroup, function(x) x$a*x$b)
output
中的结果是数字向量列表。我需要将它们添加到我可以附加到data
的列中。我一直在查看do.call(cbind, ...)
的行,但我有两个名称相同的列表,而不是我加入的单个列表。 melt(output)
为我提供了一个向量,但其行与data
的顺序不同。
答案 0 :(得分:4)
从评论转换为答案..
这似乎有效:
data <-
do.call(
rbind, mclapply(
split(data, data$group),
function(x){
z <- x$a*x$b
x <- as.data.frame(cbind(x, newcol = z))
return(x)
}))
rownames(data) <- seq_len(nrow(data))
head(data)
# a b group newcol
#1 -0.6482428 1.8136254 a -1.17566963
#2 0.4397603 1.3859759 a 0.60949714
#3 -0.6426944 1.5086339 a -0.96959055
#4 -1.2913493 -2.3984527 a 3.09724030
#5 0.2260140 0.1107935 a 0.02504087
#6 2.1555370 -0.7858066 a -1.69383520
由于您使用的是“非常大”的data.frame(大致有多大?),您是否考虑过使用dplyr
或data.table
来做什么?对于大型数据集,使用其中之一可能比使用mclapply
更好。相当于:
library(dplyr)
data %>%
group_by(group) %>%
mutate(newcol = a * b)
library(data.table)
setDT(data)[, newcol := a*b, by=group]
答案 1 :(得分:1)
有点过时了,但这可能会有所帮助。
如果你有很多分裂,rbind会在性能方面杀死你。使用unsplit功能要快得多。
results <- mclapply( split(data, data$group), function(x) x$a*x$b)
resultscombined <- unsplit (results, data$group)
data$newcol <- resultscombined
是的,内存命中,取决于你喜欢什么。
答案 2 :(得分:0)
我目前无法将parallel
软件包下载到我的电脑上。在这里,我发布了一个适用于我常用设置的解决方案,使用snow
包进行并行计算。
解决方案只是在开始时对data.frame进行排序,然后合并调用c()
的输出列表。见下文:
library(snow)
library(rlecuyer)
# Example data
data <- data.frame(a = rnorm(200), b = rnorm(200),
group = sample(letters, 200, replace = TRUE))
data <- data[order(data$group),]
# Cluster setup
clNode <- list(host="localhost")
localCl <- makeSOCKcluster(rep(clNode, 2))
clusterSetupRNG(localCl, type="RNGstream", seed=sample(0:9,6,replace=TRUE))
clusterExport(localCl, list=ls())
# Break into list
datagroup <- split(data, factor(data$group))
output <- clusterApply(localCl, datagroup, function(x){ x$a*x$b })
# Put back and check
data$output <- do.call(c, output)
data$check <- data$a*data$b
all(data$output==data$check)
# Stop cluster
stopCluster(localCl)
答案 3 :(得分:0)
受@beginneR和我们对dplyr
的共同爱好的启发,我做了一些更多的摆弄,并认为实现这一目标的最佳方法是
rbind_all( mclapply(split(data, data$group), fun(x) as.data.frame(x$a*x$b)))
答案 4 :(得分:0)
使用多核过程按组计算平均值:
library(dplyr)
x <- group_by(iris, Species)
indices <- attr(x,"indices")
labels <- attr(x,"labels")
require(parallel)
result <- mclapply(indices, function(indx){
data <- slice(iris, indx + 1)
## Do something...
mean(data$Petal.Length)
}, mc.cores =2)
out <- cbind(labels,mean=unlist(result))
out
## Species mean
## 1 setosa 1.462
## 2 versicolor 4.260
## 3 virginica 5.552