permutaciones - muestras sin orden y con reemplazo
R: Permutaciones y combinaciones con/sin reemplazo y para elementos distintos/no distintos/multiset (2)
Un paseo a través de una rebanada de combinatoria en R *
A continuación, examinamos los paquetes equipados con la capacidad de generar combinaciones y permutaciones. Si me he dejado algún paquete, perdóneme y deje un comentario o, mejor aún, edite esta publicación.
Esquema de análisis:
- Introducción
- Combinaciones
- Permutaciones
- Multisets
- Resumen
- Memoria
Antes de comenzar, notamos que las combinaciones / permutaciones con el reemplazo de elementos distintos vs. no distintivos elegidos m a la vez son equivalentes. Esto es así, porque cuando tenemos reemplazo, no es específico. Por lo tanto, no importa cuántas veces se produzca originalmente un elemento en particular, la salida tendrá una (s) instancia (s) de ese elemento repetidas de 1 am .
1. Introducción
-
gtools
v 3.8.1 -
combinat
v 0.0-8 -
multicool
vmulticool
-
partitions
v 1.9-19 -
RcppAlgos
v 2.0.1 (soy el autor) -
arrangements
v 1.1.0 -
gRbase
vgRbase
No permute
, permutations
, o gRbase::aperm/ar_perm
ya que no están realmente destinados a atacar este tipo de problemas.
| --------------------------------------- DESCRIPCIÓN GENERAL --------- ------------------------------- |
|_______________| 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 | | |
Las tareas, m at a time
y general vector
, se refieren a la capacidad de generar resultados " m a la vez" (cuando m es menor que la longitud del vector) y reorganizar un "vector general" en lugar de 1:n
. En la práctica, generalmente nos preocupa encontrar reordenamientos de un vector general, por lo tanto, todos los exámenes a continuación reflejarán esto (cuando sea posible).
Todos los puntos de referencia se ejecutaron en 3 configuraciones diferentes.
- Macbook Pro i7 16Gb
- Macbook Air i5 4Gb
- Lenovo ejecuta Windows 7 i5 8Gb
Los resultados enumerados se obtuvieron de la configuración # 1 (es decir, MBPro). Los resultados para los otros dos sistemas fueron similares. Además, se llama periódicamente a gc()
para garantizar que toda la memoria esté disponible (consulte ?gc
).
2. Combinaciones
Primero, examinamos las combinaciones sin reemplazo elegidas m a la vez.
-
RcppAlgos
-
combinat
(outils
) -
gtools
-
arrangements
-
gRbase
Cómo:
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
Punto de referencia:
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
Ahora, examinamos las combinaciones con reemplazo elegido m a la vez.
-
RcppAlgos
-
gtools
-
arrangements
Cómo:
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
Punto de referencia:
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
3. Permutaciones
Primero, examinamos permutaciones sin reemplazo elegidas m a la vez.
-
RcppAlgos
-
gtools
-
arrangements
Cómo:
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
Punto de referencia:
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
A continuación, examinamos las permutaciones sin reemplazo con un vector general (devolviendo todas las permutaciones).
-
RcppAlgos
-
gtools
-
combinat
-
multicool
-
arrangements
Cómo:
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
Punto de referencia:
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
Ahora, examinamos permutaciones sin reemplazo para 1:n
(devolviendo todas las permutaciones).
-
RcppAlgos
-
gtools
-
combinat
-
multicool
-
partitions
-
arrangements
Cómo:
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
Punto de referencia:
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
Por último, examinamos permutaciones con reemplazo.
-
RcppAlgos
-
iterpc
-
gtools
-
arrangements
Cómo:
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)
Este próximo punto de referencia es un poco sorprendente dados los resultados hasta ahora.
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
Ese no es un error tipográfico ... gtools::permutations
es casi tan rápido como las otras funciones compiladas. Recomiendo al lector que revise el código fuente de gtools::permutations
ya que es una de las pantallas más elegantes de programación ( R
o de otro tipo).
4. Multisets
Primero, examinamos combinaciones de multisets.
-
RcppAlgos
-
arrangements
Para encontrar combinaciones / permutaciones de conjuntos RcppAlgos
, con RcppAlgos
use los argumentos freqs
para especificar cuántas veces se repite cada elemento del vector fuente, v
.
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
Punto de referencia:
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
Para permutaciones de multisets elegidos m a la vez, tenemos:
-
RcppAlgos
-
arrangements
Cómo:
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
Punto de referencia:
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
Para permutaciones de multisets que devuelven todas las permutaciones, tenemos:
-
RcppAlgos
-
multicool
-
arrangements
Cómo:
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
Punto de referencia:
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
5. Resumen
Tanto gtools
como combinat
son paquetes bien establecidos para reorganizar elementos de un vector. Con gtools
hay algunas opciones más (consulte la descripción general más arriba) y con combinat
, puede reorganizar los factors
. Con multicool
, uno es capaz de reorganizar multisets. Si bien las partitions
y gRbase
están limitadas para los propósitos de esta pregunta, son potencias repletas de funciones altamente eficientes para tratar con particiones y objetos de matriz respectivamente.
arrangements
- La salida está en orden de diccionario.
- Permite al usuario especificar el formato mediante el argumento de
layout
(r = row-major
,c = column-major
yl = list
). - Ofrece métodos convenientes, como
collect
ycollect
getnext
cuando se trabaja con iteradores. - Permite la generación de más de
2^31 - 1
combinaciones / permutaciones a través degetnext
. NBRcppAlgos
(a través delower/upper
ver más abajo) ymulticool
(a través denextPerm
) también son capaces de hacer esto. - Hablando de
getnext
, esta función permite un número específico de resultados utilizando el argumentod
. - Admite los enteros grandes de gmp para calcular el número de combinaciones / permutaciones.
Observar:
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
Esta característica es realmente agradable cuando solo desea algunas combinaciones / permutaciones. Con los métodos tradicionales, tendría que generar todas las combinaciones / permutaciones y luego un subconjunto. Esto haría imposible el ejemplo anterior ya que hay más de 10^17
resultados (es decir, ncombinations(1000, 7, bigz = TRUE)
= 194280608456793000).
Esta característica, junto con las mejoras de los generadores en los arrangements
, le permite ser muy eficiente con respecto a la memoria.
RcppAlgos
- La salida está en orden de diccionario.
- Hay características de restricción convenientes que no discutiremos aquí ya que están fuera de tema para esta pregunta. Solo señalaré que los tipos de problemas que se pueden resolver utilizando estas características fueron la motivación para crear este paquete.
- Hay un argumento
upper
(formalmenterowCap
) que es análogo al argumentod
degetnext
.
Observar:
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
- Además, a partir de la
2.0.0
, hay un argumento llamadolower
que permite iniciar la generación en una combinación / permutación específica. Esto se configura muy bien para la paralelización y permite una generación rápida más allá de2^31 - 1
ya que los fragmentos se generan de forma independiente.
Ejemplo paralelo con más de 6 mil millones de combinaciones:
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
En caso de que se esté preguntando cómo se escala cada paquete, lo dejaré con este último ejemplo que mide la rapidez con que cada paquete puede generar más de 100 millones de resultados (NB gtools::combinations
se gtools::combinations
aquí ya que arrojará el error: la evaluation nested too deeply...
). Además, estamos llamando explícitamente a combn
desde el paquete utils
porque no pude obtener una ejecución exitosa de combinat::combn
. Las diferencias en el uso de la memoria entre estos dos son bastante extrañas dado que solo son ligeramente diferentes (consulte ?utils::combn
en la sección "Autores").
Observar:
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
6. memoria
Al ejecutar comboGeneral
y también a las arrangements::combinations
, la memoria saltará casi 2 Gbs antes de llamar a gc
. Esto parece correcto como #rows * #nols * bytesPerCell / 2^30 bytes = choose(1000,3) * 3 * 4 / 2^30 bytes = (166167000 * 3 * 4)/2^30 = 1.857 Gbs
). Sin embargo, al ejecutar combn
, el comportamiento de la memoria era eratico (por ejemplo, a veces usaba todos los 16 Gb de memoria y otras solo aumentaba un par de Gbs). Cuando probé esto en la configuración de Windows, a menudo fallaba.
Podemos confirmar esto utilizando Rprof
junto con summaryRporf
. Observar:
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
Con RcppAlgos
& arrangements
, mem.total
registra poco más de 1900 Mb
.
Y aquí está el perfil de memoria en un vector más pequeño que compara gtools
, utils
y 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
Curiosamente, utils::combn
y combinat::combn
usan diferentes cantidades de memoria y toman diferentes cantidades de tiempo para ejecutarse. Esto no se sostiene con vectores más pequeños:
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
Y con gtools
la memoria total utilizada es un poco más de 3 veces más que utils
. Cabe señalar que para estos 3 paquetes, obtuve diferentes resultados cada vez que los ejecuté (por ejemplo, para combinat::combn
veces obtendría 9000 Mb y luego obtendría 13000 Mb).
Aún así, ninguno puede igualar los arrangements
RcppAlgos
OR . Ambos solo usan 51 Mb cuando se ejecutan en el ejemplo anterior.
script de referencia: https://gist.github.com/randy3k/bd5730a6d70101c7471f4ae6f453862e (representado por https://github.com/tidyverse/reprex )
*: Un homenaje a Un paseo por la combinatoria de Miklós Bóna
En este hilo, estoy tratando de incluir todas las preguntas frecuentes y sus respuestas aquí. Espero que esto sea de utilidad para alguien.
Pregunta general : ¿Cómo generar secuencias de r
objetos desde n
objetos?
- combinación vs permutación.
- Con reemplazo vs sin reemplazo.
- elementos distintos frente a elementos no distintos (conjuntos múltiples).
Hay en total 2^3=8
preguntas de este tipo.
[Actualizar]
Josh O''Brien sugiere que las 8 preguntas están relacionadas de doce maneras . De hecho, las preguntas "distintas" se incluyen de doce maneras, mientras que las preguntas "distintas" no están incluidas. De todos modos, es interesante comparar las 8 preguntas aquí con doce formas. Vea los comentarios para más lecturas.
EDITAR : He actualizado la respuesta para utilizar un paquete de arrangements
más eficiente
Empezando a usar el arrangement
arrangements contienen algunos generadores e iteradores eficientes para permutaciones y combinaciones. Se ha demostrado que los arrangements
superan a la mayoría de los paquetes existentes de tipo similar. Algunos puntos de referencia se pueden encontrar here .
Aquí están las respuestas a las preguntas anteriores.
# 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"
Compara con otros paquetes
Hay pocas ventajas de utilizar arrangements
sobre los paquetes existentes.
Marco integral: no es necesario utilizar diferentes paquetes para diferentes métodos.
Es muy eficiente. Consulte here para ver algunos puntos de referencia.
Es memoria eficiente, es capaz de generar los 13! permutación de 1 a 13, los paquetes existentes no lo harán debido a la limitación del tamaño de la matriz. El método
getnext()
de los iteradores permite a los usuarios obtener los arreglos uno por uno.Los arreglos generados están en orden de diccionario, lo que puede ser deseado por algunos usuarios.