J'utilise GNU R sur un PC Ubuntu-Lucid qui dispose de 4 processeurs. Afin d'utiliser les 4 CPU, j'ai installé le package "r-cran-multicore". Comme le manuel du paquet manque d'exemples pratiques que je comprends, j'ai besoin de conseils pour optimiser mon script afin d'utiliser les 4 CPU.
Mon jeu de données est un data.frame (appelé P1) qui a 50 000 lignes et 1 600 cols. Pour chaque ligne, je voudrais calculer le maximum, la somme et la moyenne. Mon script ressemble à ceci:
p1max <- 0
p1mean <- 0
p1sum <-0
plength <- length(P1[,1])
for(i in 1:plength){
p1max <- c(p1max, max(P1[i,]))
p1mean <- c(p1mean, mean(P1[i,]))
p1sum <- c(p1sum, sum(P1[i,]))
}
Quelqu'un pourrait-il me dire comment modifier et exécuter le script afin d'utiliser les 4 CPU?
Réponses:
Utilisez foreach et doMC . L'explication détaillée peut être trouvée ici . Votre script va très peu changer, la ligne
devrait être changé en
Les prérequis pour tout script multitâche utilisant ces packages sont
Note de prudence. Selon la documentation, vous ne pouvez pas l'utiliser dans l'interface graphique.
Quant à votre problème, avez-vous vraiment besoin du multitâche? Votre data.frame prend environ 1,2 Go de RAM, il devrait donc tenir dans votre mémoire. Vous pouvez donc simplement utiliser Apply:
Le résultat sera une matrice avec des résumés de chaque ligne.
Vous pouvez également utiliser la fonction mclapply qui se trouve dans le package multicore. Ensuite, votre script pourrait ressembler à ceci:
Cela renverra la liste, où le i-ème élément sera le résumé de la i-ème ligne. Vous pouvez le convertir en matrice en utilisant sapply
la source
Vous avez déjà une réponse sur la façon d'utiliser plus d'un cœur, mais le vrai problème est avec la façon dont vous avez écrit vos boucles. N'étendez jamais votre vecteur / objet résultant à chaque itération d'une boucle . Si vous faites cela, vous forcez R à copier votre vecteur / objet de résultat et à l'étendre, ce qui prend du temps. Au lieu de cela, préallouez suffisamment d'espace de stockage avant de démarrer la boucle et remplissez-la au fur et à mesure. Voici un exemple:
Ou vous pouvez faire ces choses via
apply()
:Mais notez que ce n'est pas plus rapide que de faire la boucle correctement et parfois plus lentement.
Cependant, soyez toujours à la recherche de code vectorisé. Vous pouvez faire des sommes et des moyens de ligne en utilisant
rowSums()
etrowMeans()
qui sont plus rapides que la boucle ou lesapply
versions:Si j'étais un homme de paris, j'aurais de l'argent sur la troisième approche que je mentionne battre
foreach()
ou les autres options multi-core dans un test de vitesse sur votre matrice, car ils devraient accélérer considérablement les choses pour justifier les frais généraux engagés dans la mise en place du des processus séparés qui sont développés sur les différents cœurs de CPU.Mise à jour: Suite au commentaire de @shabbychef, est-il plus rapide de faire les sommes une fois et de les réutiliser dans le calcul de la moyenne?
Pas dans ce test, mais c'est loin d'être exhaustif ...
la source
rowSums
pour calculer les moyennes des lignes (sauf si je manque quelque chose concernant par exemple Na ou NaN). Le code de votre troisième approche additionne chaque colonne deux fois .rowSums
etrowMeans
sont du code compilé hautement optimisé et ce que nous gagnons en ne calculant les sommes qu'une seule fois, nous perdons à nouveau en faisant le calcul moyen en code interprété.system.time({ for (iii in c(1:1000)) { p1max3 <- apply(p1, 1, max) p1mean3 <- rowMeans(p1) p1sum3 <- rowSums(p1) } })
et de la même manièresystem.time({ for (iii in c(1:1000)) { p1max4 <- apply(p1, 1, max) p1sum4 <- rowSums(p1) p1mean4 <- p1sum4 / ncol(p1) } })
; la version qui ne recalcule pas la somme prend 1,368 seconde sur mon ordinateur; celui qui le fait prend 1,396. encore une fois, loin d'être exhaustif, mais plus convaincant ...rowMeans
et à mesure qu'ellesrowSums
seront implémentées dans du code compilé optimisé et efficace, elles seront difficiles à battre.rowMean
sera difficile à battre via un outil R à usage général comme*apply
. Cependant, vous semblez suggérer qu'il est plus rapide de additionner 10000 nombres deux fois viarowMean
etrowSum
plutôt qu'une seule fois et d'utiliser l'opérateur de division intégré de R. Je sais que R a des problèmes d'efficacité ( par exemple, la récente découverte du problème des accolades contre les parenthèses), mais cela semble fou.Jetez un œil aux forfaits neige et chutes de neige . Beaucoup d'exemples avec ceux ...
Si vous voulez accélérer ce code spécifique plutôt que de vous renseigner sur R et le parallélisme, vous devriez le faire
la source