簡體   English   中英

將`mclapply`結果放回data.frame

[英]putting `mclapply` results back onto data.frame

我有一個非常大的 data.frame ,我想對其應用相當復雜的功能,以計算新列。 我想並行執行。 這類似於在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順序不同。

從評論轉換為答案

這似乎可行:

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(大約有多大?),因此您是否考慮過使用dplyrdata.table來做什么? 對於大型數據集,使用其中之一可能會比使用mclapply 等效為:

library(dplyr)
data %>%
  group_by(group) %>%
  mutate(newcol = a * b)

library(data.table) 
setDT(data)[, newcol := a*b, by=group]

有點過時,但這可能有所幫助。

如果您有很多分歧,rbind會殺死您的表現。

使用unsplit函數要快得多。

results <- mclapply( split(data, data$group), function(x) x$a*x$b) 

resultscombined <- unsplit (results, data$group)

data$newcol <-  resultscombined 

是的,記憶力大減,因此要取決於您的需求。

我目前無法將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)

受到@beginneR和我們對dplyr熱愛的dplyr ,我做了一些擺弄,並認為實現這一目標的最佳方法是

 rbind_all( mclapply(split(data, data$group), fun(x) as.data.frame(x$a*x$b)))

使用多核過程按組計算均值:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM