2013-07-01 4 views
14

J'utilise foreach avec un .combine = rbindlist. Cela ne semble pas fonctionner, bien que cela fonctionne bien si j'utilise .combine = rbind.R foreach avec .combine = rbindlist

Pour illustrer l'aide d'un exemple simple -

> t2 <- data.table(col1=c(1,2,3)) 
> foreach (i=1:3, .combine=rbind) %dopar% unique(t2) 
    col1 
1: 1 
2: 2 
3: 3 
4: 1 
5: 2 
6: 3 
7: 1 
8: 2 
9: 3 

# But using rbindlist gives an error 

> foreach (i=1:3, .combine=rbindlist) %dopar% unique(t2) 
error calling combine function: 
<simpleError in fun(result.1, result.2): unused argument(s) (result.2)> 
NULL 

Quelqu'un at-il été en mesure de faire ce travail?

Merci d'avance.

+0

Je comprends que nous devrions appeler rbindlist sur un objet liste - rbindlist (liste (dt1, dt2)) ... mais je ne sais pas comment l'utiliser avec la fonction foreach .combine. – xbsd

Répondre

16

Il est essentiellement ce que vous avez dit - rbindlist suppose un argument list, et l'erreur que vous obtenez est le même que celui-ci:

result.1 = data.table(blah = 23) 
result.2 = data.table(blah = 34) 

rbindlist(result.1, result.2) 
#Error in rbindlist(result.1, result.2) : unused argument (result.2) 

Si vous souhaitez utiliser rbindlist, la façon de le faire serait être ceci:

rbindlist(foreach (i = 1:3) %dopar% unique(t2)) 

ou ceci:

foreach (i=1:3, .combine=function(x,y)rbindlist(list(x,y))) %dopar% unique(t2) 
+0

Merci! Fonctionne très bien. – xbsd

+0

Votre première solution utilisant '.combine = list' échoue lorsqu'il y a plus de 100 résultats puisque vous obtenez une liste imbriquée dans ce cas. Il suffit de laisser de côté les arguments '.combine' et' .multicombine' et cela fonctionne bien puisque le comportement par défaut est de retourner les résultats dans une liste. J'aime mieux votre deuxième solution, et cela fonctionne avec n'importe quel nombre de résultats. –

+0

@SteveWeston voir le commentaire .maxcombine et? Foreach – eddi

11

est ici un moyen à la fois rbindlist d'utilisation que votre .combine fonction et ont .multicombine=TRUE:

foreach (i=1:3, 
     .combine=function(...) rbindlist(list(...)), 
     .multicombine=TRUE) %dopar% unique(t2) 

Si vous avez une quantité décente de résultats séparés pour agréger, cela pourrait être un peu plus rapide que ne combinant deux à -a-temps.

Pour une seule instruction foreach, le résultat est le même que foreach par défaut .combine pour lister et encapsuler avec rbindlist, comme dans la première solution d'eddi. Je ne suis pas sûr de ce qui est le plus rapide, même si je m'attendrais à ce qu'ils soient proches.

Pour les petits, foreach mono emplois que j'aime l'emballage avec rbindlist, mais quand enchaînant plusieurs s ensemble foreach de » avec %:% Je pense que l'approche ci-dessus (probablement dans le premier foreach) semble plus propre.

+2

Ce type de fonction de combinaison fonctionne bien avec un backend parallèle qui appelle la fonction de combinaison à la volée. Cela permet au maître d'effectuer un post-traitement en parallèle avec les travailleurs. C'est encore plus utile lorsque la fonction de combinaison effectue une réduction. –

+2

Vous pouvez également utiliser 'rbindlist' directement en tant que fonction" .final "avec la fonction de combinaison par défaut, car cela produit une liste. C'est une solution très propre, mais j'utiliserais votre fonction de combinaison. –

+1

Ah je ne connaissais pas '.final'! J'ai quelques endroits qui auront l'air plus propres. En ce qui concerne votre premier commentaire, c'est exactement ce que j'ai utilisé, avec le paquet 'doMPI'. C'est vraiment bien de ne pas attendre que tous les enfants finissent avant que le parent ne fasse quoi que ce soit quand vous avez des milliers d'emplois individuels. – ClaytonJY