Dans ce fil, j'essaie d'inclure ici toutes les questions fréquemment posées et leurs réponses. J'espère que cela sera utile pour quelqu'un.
Question générale : Comment générer des séquences d'objets r
à partir d'objets n
?
Il y a au total 2^3=8
questions de ce type.
[Mise à jour]
Josh O'Brien suggère que les 8 questions sont liées à douze fois . En effet, les questions "distinctes" sont incluses en douze volets, tandis que les questions "non distinctes" ne sont pas incluses. Quoi qu'il en soit, il est intéressant de comparer les 8 questions ici de manière décuplée. Voir les commentaires pour d'autres lectures.
[~ # ~] modifier [~ # ~]: J'ai mis à jour la réponse pour utiliser un package plus efficace arrangements
arrangement
arrangements contient quelques générateurs et itérateurs efficaces pour les permutations et les combinaisons. Il a été démontré que arrangements
surpasse la plupart des packages existants de type similaire. Quelques repères ont pu être trouvés ici .
Voici les réponses aux questions ci-dessus
# 1) combinations: without replacement: distinct items
combinations(5, 2)
[,1] [,2]
[1,] 1 2
[2,] 1 3
[3,] 1 4
[4,] 1 5
[5,] 2 3
[6,] 2 4
[7,] 2 5
[8,] 3 4
[9,] 3 5
[10,] 4 5
# 2) combinations: with replacement: distinct items
combinations(5, 2, replace=TRUE)
[,1] [,2]
[1,] 1 1
[2,] 1 2
[3,] 1 3
[4,] 1 4
[5,] 1 5
[6,] 2 2
[7,] 2 3
[8,] 2 4
[9,] 2 5
[10,] 3 3
[11,] 3 4
[12,] 3 5
[13,] 4 4
[14,] 4 5
[15,] 5 5
# 3) combinations: without replacement: non distinct items
combinations(x = c("a", "b", "c"), freq = c(2, 1, 1), k = 2)
[,1] [,2]
[1,] "a" "a"
[2,] "a" "b"
[3,] "a" "c"
[4,] "b" "c"
# 4) combinations: with replacement: non distinct items
combinations(x = c("a", "b", "c"), k = 2, replace = TRUE) # as `freq` does not matter
[,1] [,2]
[1,] "a" "a"
[2,] "a" "b"
[3,] "a" "c"
[4,] "b" "b"
[5,] "b" "c"
[6,] "c" "c"
# 5) permutations: without replacement: distinct items
permutations(5, 2)
[,1] [,2]
[1,] 1 2
[2,] 1 3
[3,] 1 4
[4,] 1 5
[5,] 2 1
[6,] 2 3
[7,] 2 4
[8,] 2 5
[9,] 3 1
[10,] 3 2
[11,] 3 4
[12,] 3 5
[13,] 4 1
[14,] 4 2
[15,] 4 3
[16,] 4 5
[17,] 5 1
[18,] 5 2
[19,] 5 3
[20,] 5 4
# 6) permutations: with replacement: distinct items
permutations(5, 2, replace = TRUE)
[,1] [,2]
[1,] 1 1
[2,] 1 2
[3,] 1 3
[4,] 1 4
[5,] 1 5
[6,] 2 1
[7,] 2 2
[8,] 2 3
[9,] 2 4
[10,] 2 5
[11,] 3 1
[12,] 3 2
[13,] 3 3
[14,] 3 4
[15,] 3 5
[16,] 4 1
[17,] 4 2
[18,] 4 3
[19,] 4 4
[20,] 4 5
[21,] 5 1
[22,] 5 2
[23,] 5 3
[24,] 5 4
[25,] 5 5
# 7) permutations: without replacement: non distinct items
permutations(x = c("a", "b", "c"), freq = c(2, 1, 1), k = 2)
[,1] [,2]
[1,] "a" "a"
[2,] "a" "b"
[3,] "a" "c"
[4,] "b" "a"
[5,] "b" "c"
[6,] "c" "a"
[7,] "c" "b"
# 8) permutations: with replacement: non distinct items
permutations(x = c("a", "b", "c"), k = 2, replace = TRUE) # as `freq` doesn't matter
[,1] [,2]
[1,] "a" "a"
[2,] "a" "b"
[3,] "a" "c"
[4,] "b" "a"
[5,] "b" "b"
[6,] "b" "c"
[7,] "c" "a"
[8,] "c" "b"
[9,] "c" "c"
Il y a peu d'avantages à utiliser arrangements
par rapport aux packages existants.
Framework intégré: vous n'avez pas besoin d'utiliser différents packages pour différentes méthodes.
C'est très efficace. Voir https://randy3k.github.io/arrangements/articles/benchmark.html pour certains repères.
Il est efficace en mémoire, il est capable de générer les 13! permutation de 1 à 13, les packages existants ne le feront pas en raison de la limitation de la taille de la matrice. La méthode getnext()
des itérateurs permet aux utilisateurs d'obtenir les arrangements un par un.
Les dispositions générées sont dans l'ordre du dictionnaire, ce qui peut être souhaité pour certains utilisateurs.
Ci-dessous, nous examinons les packages équipés des capacités de génération de combinaisons et de permutations. Si j'ai omis un colis, veuillez me pardonner et laisser un commentaire ou mieux encore, modifier ce post.
Aperçu de l'analyse:
Avant de commencer, nous notons que les combinaisons/permutations avec remplacement des éléments distincts et non distint choisis m at un temps sont équivalents. Il en est ainsi, car lorsque nous avons un remplacement, ce n'est pas spécifique. Ainsi, quel que soit le nombre de fois où un élément particulier se produit à l'origine, la sortie aura une ou des instances de cet élément répétées de 1 à m fois.
gtools
v 3.8.1combinat
v 0.0-8multicool
v 0,1-10partitions
v 1.9-19RcppAlgos
v 2.0.1 (je suis l'auteur)arrangements
v 1.1.0gRbase
v 1.8-3Je n'ai pas inclus permute
, permutations
ou gRbase::aperm/ar_perm
Car ils ne sont pas vraiment destinés à attaquer ces types de problèmes.
| --------------------------------------- [ ~ # ~] présentation [~ # ~] ------------------------------- ------
|_______________| gtools | combinat | multicool | partitions |
| comb rep | Yes | | | |
| comb NO rep | Yes | Yes | | |
| perm rep | Yes | | | |
| perm NO rep | Yes | Yes | Yes | Yes |
| perm multiset | | | Yes | |
| comb multiset | | | | |
|accepts factors| | Yes | | |
| m at a time | Yes | Yes/No | | |
|general vector | Yes | Yes | Yes | |
| iterable | | | Yes | |
|parallelizable | | | | |
| big integer | | | | |
|_______________| iterpc | arrangements | RcppAlgos | gRbase |
| comb rep | Yes | Yes | Yes | |
| comb NO rep | Yes | Yes | Yes | Yes |
| perm rep | Yes | Yes | Yes | |
| perm NO rep | Yes | Yes | Yes | * |
| perm multiset | Yes | Yes | Yes | |
| comb multiset | Yes | Yes | Yes | |
|accepts factors| | Yes | Yes | |
| m at a time | Yes | Yes | Yes | Yes |
|general vector | Yes | Yes | Yes | Yes |
| iterable | | Yes | Partially | |
|parallelizable | | Yes | Yes | |
| big integer | | Yes | | |
Les tâches, m at a time
Et general vector
, Font référence à la capacité de générer des résultats " m à la fois" (lorsque m = est inférieur à la longueur du vecteur) et réorganise un "vecteur général" par opposition à 1:n
. Dans la pratique, nous nous préoccupons généralement de trouver des réarrangements d'un vecteur général, donc tous les examens ci-dessous le refléteront (si possible).
Tous les benchmarks ont été exécutés sur 3 configurations différentes.
Les résultats répertoriés ont été obtenus à partir de la configuration n ° 1 (c'est-à-dire MBPro). Les résultats pour les deux autres systèmes étaient similaires. De plus, gc()
est périodiquement appelée pour s'assurer que toute la mémoire est disponible (voir ?gc
).
Tout d'abord, nous examinons les combinaisons sans remplacement choisies m à la fois.
RcppAlgos
combinat
(ou utils
)gtools
arrangements
gRbase
Comment:
library(RcppAlgos)
library(arrangements)
library(microbenchmark)
options(digits = 4)
set.seed(13)
testVector1 <- sort(sample(100, 17))
m <- 9
t1 <- comboGeneral(testVector1, m) ## returns matrix with m columns
t3 <- combinat::combn(testVector1, m) ## returns matrix with m rows
t4 <- gtools::combinations(17, m, testVector1) ## returns matrix with m columns
identical(t(t3), t4) ## must transpose to compare
#> [1] TRUE
t5 <- combinations(testVector1, m)
identical(t1, t5)
#> [1] TRUE
t6 <- gRbase::combnPrim(testVector1, m)
identical(t(t6)[do.call(order, as.data.frame(t(t6))),], t1)
#> [1] TRUE
Référence:
microbenchmark(cbRcppAlgos = comboGeneral(testVector1, m),
cbGRbase = gRbase::combnPrim(testVector1, m),
cbGtools = gtools::combinations(17, m, testVector1),
cbCombinat = combinat::combn(testVector1, m),
cbArrangements = combinations(17, m, testVector1),
unit = "relative")
#> Unit: relative
#> expr min lq mean median uq max neval
#> cbRcppAlgos 1.064 1.079 1.160 1.012 1.086 2.318 100
#> cbGRbase 7.335 7.509 5.728 6.807 5.390 1.608 100
#> cbGtools 426.536 408.807 240.101 310.848 187.034 63.663 100
#> cbCombinat 97.756 97.586 60.406 75.415 46.391 41.089 100
#> cbArrangements 1.000 1.000 1.000 1.000 1.000 1.000 100
Maintenant, nous examinons les combinaisons avec le remplacement choisi m à la fois.
RcppAlgos
gtools
arrangements
Comment:
library(RcppAlgos)
library(arrangements)
library(microbenchmark)
options(digits = 4)
set.seed(97)
testVector2 <- sort(rnorm(10))
m <- 8
t1 <- comboGeneral(testVector2, m, repetition = TRUE)
t3 <- gtools::combinations(10, m, testVector2, repeats.allowed = TRUE)
identical(t1, t3)
#> [1] TRUE
## arrangements
t4 <- combinations(testVector2, m, replace = TRUE)
identical(t1, t4)
#> [1] TRUE
Référence:
microbenchmark(cbRcppAlgos = comboGeneral(testVector2, m, TRUE),
cbGtools = gtools::combinations(10, m, testVector2, repeats.allowed = TRUE),
cbArrangements = combinations(testVector2, m, replace = TRUE),
unit = "relative")
#> Unit: relative
#> expr min lq mean median uq max neval
#> cbRcppAlgos 1.000 1.000 1.000 1.000 1.000 1.00000 100
#> cbGtools 384.990 269.683 80.027 112.170 102.432 3.67517 100
#> cbArrangements 1.057 1.116 0.618 1.052 1.002 0.03638 100
Tout d'abord, nous examinons les permutations sans remplacement choisies m à la fois.
RcppAlgos
gtools
arrangements
Comment:
library(RcppAlgos)
library(arrangements)
library(microbenchmark)
options(digits = 4)
set.seed(101)
testVector3 <- as.integer(c(2, 3, 5, 7, 11, 13, 17, 19, 23, 29))
## RcppAlgos... permuteGeneral same as comboGeneral above
t1 <- permuteGeneral(testVector3, 6)
## gtools... permutations same as combinations above
t3 <- gtools::permutations(10, 6, testVector3)
identical(t1, t3)
#> [1] TRUE
## arrangements
t4 <- permutations(testVector3, 6)
identical(t1, t4)
#> [1] TRUE
Référence:
microbenchmark(cbRcppAlgos = permuteGeneral(testVector3, 6),
cbGtools = gtools::permutations(10, 6, testVector3),
cbArrangements = permutations(testVector3, 6),
unit = "relative")
#> Unit: relative
#> expr min lq mean median uq max neval
#> cbRcppAlgos 1.079 1.027 1.106 1.037 1.003 5.37 100
#> cbGtools 158.720 92.261 85.160 91.856 80.872 45.39 100
#> cbArrangements 1.000 1.000 1.000 1.000 1.000 1.00 100
Ensuite, nous examinons les permutations sans remplacement par un vecteur général (renvoyant toutes les permutations).
RcppAlgos
gtools
combinat
multicool
arrangements
Comment:
library(RcppAlgos)
library(arrangements)
library(microbenchmark)
options(digits = 4)
set.seed(89)
testVector3 <- as.integer(c(2, 3, 5, 7, 11, 13, 17, 19, 23, 29))
testVector3Prime <- testVector3[1:7]
## For RcppAlgos, & gtools (see above)
## combinat
t4 <- combinat::permn(testVector3Prime) ## returns a list of vectors
## convert to a matrix
t4 <- do.call(rbind, t4)
## multicool.. we must first call initMC
t5 <- multicool::allPerm(multicool::initMC(testVector3Prime)) ## returns a matrix with n columns
all.equal(t4[do.call(order,as.data.frame(t4)),],
t5[do.call(order,as.data.frame(t5)),])
#> [1] TRUE
Référence:
microbenchmark(cbRcppAlgos = permuteGeneral(testVector3Prime, 7),
cbGtools = gtools::permutations(7, 7, testVector3Prime),
cbCombinat = combinat::permn(testVector3Prime),
cbMulticool = multicool::allPerm(multicool::initMC(testVector3Prime)),
cbArrangements = permutations(x = testVector3Prime, k = 7),
unit = "relative")
#> Unit: relative
#> expr min lq mean median uq max neval
#> cbRcppAlgos 1.152 1.275 0.7508 1.348 1.342 0.3159 100
#> cbGtools 965.465 817.645 340.4159 818.137 661.068 12.7042 100
#> cbCombinat 280.207 236.853 104.4777 238.228 208.467 9.6550 100
#> cbMulticool 2573.001 2109.246 851.3575 2039.531 1638.500 28.3597 100
#> cbArrangements 1.000 1.000 1.0000 1.000 1.000 1.0000 100
Maintenant, nous examinons les permutations sans remplacement pour 1:n
(Renvoyant toutes les permutations).
RcppAlgos
gtools
combinat
multicool
partitions
arrangements
Comment:
library(RcppAlgos)
library(arrangements)
library(microbenchmark)
options(digits = 4)
set.seed(89)
t1 <- partitions::perms(7) ## returns an object of type 'partition' with n rows
identical(t(as.matrix(t1)), permutations(7,7))
#> [1] TRUE
Référence:
microbenchmark(cbRcppAlgos = permuteGeneral(7, 7),
cbGtools = gtools::permutations(7, 7),
cbCombinat = combinat::permn(7),
cbMulticool = multicool::allPerm(multicool::initMC(1:7)),
cbPartitions = partitions::perms(7),
cbArrangements = permutations(7, 7),
unit = "relative")
#> Unit: relative
#> expr min lq mean median uq max
#> cbRcppAlgos 1.235 1.429 1.412 1.503 1.484 1.720
#> cbGtools 1152.826 1000.736 812.620 939.565 793.373 499.029
#> cbCombinat 347.446 304.866 260.294 296.521 248.343 284.001
#> cbMulticool 3001.517 2416.716 1903.903 2237.362 1811.006 1311.219
#> cbPartitions 2.469 2.536 2.801 2.692 2.999 2.472
#> cbArrangements 1.000 1.000 1.000 1.000 1.000 1.000
#> neval
#> 100
#> 100
#> 100
#> 100
#> 100
#> 100
Enfin, nous examinons les permutations avec remplacement.
RcppAlgos
iterpc
gtools
arrangements
Comment:
library(RcppAlgos)
library(arrangements)
library(microbenchmark)
options(digits = 4)
set.seed(34)
testVector3 <- as.integer(c(2, 3, 5, 7, 11, 13, 17, 19, 23, 29))
t1 <- permuteGeneral(testVector3, 5, repetition = TRUE)
t3 <- gtools::permutations(10, 5, testVector3, repeats.allowed = TRUE)
t4 <- permutations(x = testVector3, k = 5, replace = TRUE)
Ce prochain benchmark est un peu surprenant compte tenu des résultats obtenus jusqu'à présent.
microbenchmark(cbRcppAlgos = permuteGeneral(testVector3, 5, TRUE),
cbGtools = gtools::permutations(10, 5, testVector3, repeats.allowed = TRUE),
cbArrangements = permutations(x = testVector3, k = 5, replace = TRUE),
unit = "relative")
#> Unit: relative
#> expr min lq mean median uq max neval
#> cbRcppAlgos 1.106 0.9183 1.200 1.030 1.063 1.701 100
#> cbGtools 2.426 2.1815 2.068 1.996 2.127 1.367 100
#> cbArrangements 1.000 1.0000 1.000 1.000 1.000 1.000 100
Ce n'est pas une faute de frappe ... gtools::permutations
Est presque aussi rapide que les autres fonctions compilées. J'encourage le lecteur à consulter le code source de gtools::permutations
Car il s'agit de l'un des affichages de programmation les plus élégants (R
ou autre).
Tout d'abord, nous examinons les combinaisons de multisets.
RcppAlgos
arrangements
Pour trouver des combinaisons/permutations de multisets, avec RcppAlgos
utilisez les arguments freqs
pour spécifier combien de fois chaque élément du vecteur source, v
, est répété.
library(RcppAlgos)
library(arrangements)
library(microbenchmark)
options(digits = 4)
set.seed(496)
myFreqs <- sample(1:5, 10, replace = TRUE)
## This is how many times each element will be repeated
myFreqs
#> [1] 2 4 4 5 3 2 2 2 3 4
testVector4 <- as.integer(c(1, 2, 3, 5, 8, 13, 21, 34, 55, 89))
t1 <- comboGeneral(testVector4, 12, freqs = myFreqs)
t3 <- combinations(freq = myFreqs, k = 12, x = testVector4)
identical(t1, t3)
#> [1] TRUE
Référence:
microbenchmark(cbRcppAlgos = comboGeneral(testVector4, 12, freqs = myFreqs),
cbArrangements = combinations(freq = myFreqs, k = 12, x = testVector4),
unit = "relative")
#> Unit: relative
#> expr min lq mean median uq max neval
#> cbRcppAlgos 1.000 1.000 1.000 1.000 1.000 1.000 100
#> cbArrangements 1.254 1.221 1.287 1.259 1.413 1.173 100
Pour les permutations de multi-ensembles choisis m à la fois, nous avons:
RcppAlgos
arrangements
Comment:
library(RcppAlgos)
library(arrangements)
library(microbenchmark)
options(digits = 4)
set.seed(8128)
myFreqs <- sample(1:3, 5, replace = TRUE)
testVector5 <- sort(runif(5))
myFreqs
#> [1] 2 2 2 1 3
t1 <- permuteGeneral(testVector5, 7, freqs = myFreqs)
t3 <- permutations(freq = myFreqs, k = 7, x = testVector5)
identical(t1, t3)
#> [1] TRUE
Référence:
microbenchmark(cbRcppAlgos = permuteGeneral(testVector5, 7, freqs = myFreqs),
cbArrangements = permutations(freq = myFreqs, k = 7, x = testVector5),
unit = "relative")
#> Unit: relative
#> expr min lq mean median uq max neval
#> cbRcppAlgos 1.461 1.327 1.282 1.177 1.176 1.101 100
#> cbArrangements 1.000 1.000 1.000 1.000 1.000 1.000 100
Pour les permutations de multi-ensembles renvoyant toutes les permutations, nous avons:
RcppAlgos
multicool
arrangements
Comment:
library(RcppAlgos)
library(arrangements)
library(microbenchmark)
options(digits = 4)
set.seed(8128)
myFreqs2 <- c(2,1,2,1,2)
testVector6 <- (1:5)^3
## For multicool, you must have the elements explicitly repeated
testVector6Prime <- rep(testVector6, times = myFreqs2)
t3 <- multicool::allPerm(multicool::initMC(testVector6Prime))
## for comparison
t1 <- permuteGeneral(testVector6, freqs = myFreqs2)
identical(t1[do.call(order,as.data.frame(t1)),],
t3[do.call(order,as.data.frame(t3)),])
#> [1] TRUE
Référence:
microbenchmark(cbRcppAlgos = permuteGeneral(testVector6, freqs = myFreqs2),
cbMulticool = multicool::allPerm(multicool::initMC(testVector6Prime)),
cbArrangements = permutations(freq = myFreqs2, x = testVector6),
unit = "relative")
#> Unit: relative
#> expr min lq mean median uq max neval
#> cbRcppAlgos 1.276 1.374 1.119 1.461 1.39 0.8856 100
#> cbMulticool 2434.652 2135.862 855.946 2026.256 1521.74 31.0651 100
#> cbArrangements 1.000 1.000 1.000 1.000 1.00 1.0000 100
gtools
et combinat
sont des packages bien établis pour réorganiser les éléments d'un vecteur. Avec gtools
, il y a quelques autres options (voir l'aperçu ci-dessus) et avec combinat
, vous pouvez réorganiser factors
. Avec multicool
, on est capable de réorganiser les multisets. Bien que partitions
et gRbase
soient limités pour les besoins de cette question, ce sont des puissances remplies de fonctions très efficaces pour traiter respectivement les partitions et les objets de tableau.
arrangements
layout
(r = row-major
, c = column-major
Et l = list
).collect
& getnext
lorsque vous travaillez avec des itérateurs.2^31 - 1
Combinaisons/permutations via getnext
. N.B. RcppAlgos
(via lower/upper
voir ci-dessous) et multicool
(via nextPerm
) sont également capables de le faire.getnext
, cette fonction permet un nombre spécifique de résultats en utilisant l'argument d
.Observer:
library(arrangements)
icomb <- icombinations(1000, 7)
icomb$getnext(d = 5)
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#> [1,] 1 2 3 4 5 6 7
#> [2,] 1 2 3 4 5 6 8
#> [3,] 1 2 3 4 5 6 9
#> [4,] 1 2 3 4 5 6 10
#> [5,] 1 2 3 4 5 6 11
Cette fonctionnalité est vraiment sympa lorsque vous ne voulez que quelques combinaisons/permutations. Avec les méthodes traditionnelles, vous devrez générer toutes les combinaisons/permutations puis sous-ensemble. Cela rendrait l'exemple précédent impossible car il y a plus de 10^17
Résultats (c'est-à-dire ncombinations(1000, 7, bigz = TRUE)
= 194280608456793000).
Cette fonctionnalité ainsi que les améliorations apportées aux générateurs dans arrangements
, lui permettent d'être très efficace en termes de mémoire.
RcppAlgos
upper
(formellement rowCap
) qui est analogue à l'argument d
de getnext
.Observer:
library(RcppAlgos)
comboGeneral(1000, 7, upper = 5)
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#> [1,] 1 2 3 4 5 6 7
#> [2,] 1 2 3 4 5 6 8
#> [3,] 1 2 3 4 5 6 9
#> [4,] 1 2 3 4 5 6 10
#> [5,] 1 2 3 4 5 6 11
2.0.0
, Il existe un argument appelé lower
qui permet de démarrer la génération à une combinaison/permutation spécifique. Cela se met bien en place pour la parallélisation et permet une génération rapide au-delà de 2^31 - 1
Car les morceaux sont générés indépendamment.Exemple parallèle avec plus de 6 milliards de combinaisons:
system.time(parallel::mclapply(seq(1,6397478649,4390857), function(x) {
a <- comboGeneral(25, 15, freqs = c(rep(1:5, 5)), lower = x, upper = x + 4390856)
## do something
x
}, mc.cores = 7))
#> user system elapsed
#> 510.623 140.970 109.496
Au cas où vous vous demanderiez comment chaque package évolue, je vous laisse avec cet exemple final qui mesure la vitesse à laquelle chaque package peut générer plus de 100 millions de résultats (NB gtools::combinations
Est laissé ici car il générera l'erreur: evaluation nested too deeply...
). En outre, nous appelons explicitement combn
à partir du package utils
car je n'ai pas pu obtenir une exécution réussie à partir de combinat::combn
. Les différences d'utilisation de la mémoire entre ces deux sont assez bizarres étant donné qu'elles ne sont que légèrement différentes (voir ?utils::combn
Dans la section "Auteurs").
Observer:
library(RcppAlgos)
library(arrangements)
library(microbenchmark)
options(digits = 4)
set.seed(2187)
testVector7 <- sort(sample(10^7, 10^3))
system.time(utils::combn(testVector7, 3))
#> user system elapsed
#> 179.956 5.687 187.159
system.time(RcppAlgos::comboGeneral(testVector7, 3))
#> user system elapsed
#> 1.136 0.758 1.937
system.time(arrangements::combinations(x = testVector7, k = 3))
#> user system elapsed
#> 1.963 0.930 2.910
system.time(RcppAlgos::permuteGeneral(testVector7[1:500], 3))
#> user system elapsed
#> 1.095 0.631 1.738
system.time(arrangements::permutations(x = testVector7[1:500], k = 3))
#> user system elapsed
#> 1.399 0.584 1.993
Lors de l'exécution de comboGeneral
ainsi que arrangements::combinations
, La mémoire sautera de près de 2 Go avant d'appeler gc
. Cela semble à peu près correct comme #rows * #nols * bytesPerCell / 2^30 bytes = choose(1000,3) * 3 * 4 / 2^30 bytes = (166167000 * 3 * 4)/2^30 = 1.857 Gbs
). Cependant, lors de l'exécution de combn
, le comportement de la mémoire était effacé (par exemple, il utilisait parfois les 16 Go de mémoire et d'autres fois, il ne dépassait que quelques Go). Lorsque je testais cela sur la configuration Windows, cela plantait souvent.
Nous pouvons le confirmer en utilisant Rprof
avec summaryRporf
. Observer:
Rprof("RcppAlgos.out", memory.profiling = TRUE)
t1 <- RcppAlgos::comboGeneral(testVector7, 3)
Rprof(NULL)
summaryRprof("RcppAlgos.out", memory = "both")$by.total
total.time total.pct mem.total self.time self.pct
"CombinatoricsRcpp" 1.2 100 1901.6 1.2 100
"RcppAlgos::comboGeneral" 1.2 100 1901.6 0.0 0
Rprof("arrangements.out", memory.profiling = TRUE)
t3 <- arrangements::combinations(10^3, 3, testVector7)
Rprof(NULL)
summaryRprof("arrangements.out", memory = "both")$by.total
total.time total.pct mem.total self.time self.pct
".Call" 2.08 99.05 1901.6 2.08 99.05
Avec RcppAlgos
& arrangements
, mem.total
Enregistre un peu plus de 1900 Mb
.
Et voici le profil de mémoire sur un vecteur plus petit comparant gtools
, utils
et combinat
.
testVector7Prime <- testVector7[1:300]
Rprof("combinat.out", memory.profiling = TRUE)
t3 <- combinat::combn(testVector7Prime, 3)
Rprof(NULL)
summaryRprof("combinat.out", memory = "both")$by.total
total.time total.pct mem.total self.time self.pct
"combinat::combn" 3.98 100.00 1226.9 3.72 93.47
Rprof("utils.out", memory.profiling = TRUE)
t4 <- utils::combn(testVector7Prime, 3)
Rprof(NULL)
summaryRprof("utils.out", memory = "both")$by.total
total.time total.pct mem.total self.time self.pct
"utils::combn" 2.52 100.00 1952.7 2.50 99.21
Rprof("gtools.out", memory.profiling = TRUE)
t5 <- gtools::combinations(300, 3, testVector7Prime)
Rprof(NULL)
summaryRprof("gtools.out", memory = "both")$by.total
total.time total.pct mem.total self.time self.pct
"rbind" 4.94 95.00 6741.6 4.40 84.62
Il est intéressant de noter que utils::combn
Et combinat::combn
Utilisent différentes quantités de mémoire et prennent différents temps pour s'exécuter. Cela ne tient pas avec des vecteurs plus petits:
microbenchmark(combinat::combn(2:13, 6), utils::combn(2:13, 6))
Unit: microseconds
expr min lq mean median uq max neval
combinat::combn(2:13, 6) 527.378 567.946 629.1268 577.163 604.3270 1816.744 100
utils::combn(2:13, 6) 663.150 712.872 750.8008 725.716 771.1345 1205.697 100
Et avec gtools
la mémoire totale utilisée est un peu plus de 3x autant que utils
. Il convient de noter que pour ces 3 packages, j'obtenais des résultats différents à chaque fois que je les exécutais (par exemple pour combinat::combn
Parfois j'obtiendrais 9000 Mb puis j'obtiendrais 13000 Mb).
Pourtant, aucun ne peut correspondre à RcppAlgos
[~ # ~] ou [~ # ~] arrangements
. Les deux n'utilisent que 51 Mo lorsqu'ils sont exécutés sur l'exemple ci-dessus.
script de référence: --- (https://Gist.github.com/randy3k/bd5730a6d70101c7471f4ae6f453862e (rendu par https://github.com/tidyverse/reprex )
*: Un hommage à Une promenade à travers la combinatoire par Miklós Bóna