web-dev-qa-db-ja.com

置換あり/なしの順列と組み合わせ、明確な/明確でないアイテム/マルチセット

このスレッドでは、よくある質問とその回答をすべてここに含めようとしています。これが誰かに役立つことを願っています。

一般的な質問rオブジェクトからnオブジェクトのシーケンスを生成する方法?

  • 組み合わせと順列。
  • 交換ありと交換なし。
  • 明確なアイテムと明確でないアイテム(マルチセット)。

合計で2^3=8このタイプの質問。

[更新]

Josh O'Brienは、8つの質問は 12通りの方法 に関連していると示唆しています。実際、「明確な」質問は12通りの方法で含まれていますが、「明確でない」質問は含まれていません。とにかく、ここで8つの質問を12通りの方法と比較するのは興味深いことです。詳細については、コメントを参照してください。

26
Randy Lai

[〜#〜] edit [〜#〜]:より効率的なパッケージを使用するように回答を更新しました arrangements

arrangementの使用を開始する

arrangements には、順列と組み合わせのための効率的なジェネレーターとイテレーターが含まれています。 arrangementsは、類似の種類の既存のパッケージのほとんどよりも優れていることが実証されています。いくつかのベンチマークが見つかりました here

上記の質問に対する回答です

_# 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" 
_

他のパッケージと比較する

既存のパッケージと比較してarrangementsを使用する利点はほとんどありません。

  1. 統合フレームワーク:メソッドごとに異なるパッケージを使用する必要はありません。

  2. とても効率的です。ベンチマークについては https://randy3k.github.io/arrangements/articles/benchmark.html を参照してください。

  3. メモリ効率がよく、13個すべてを生成できます。 1から13の順列は、既存のパッケージがマトリックスサイズの制限のためにそうすることに失敗します。イテレータのgetnext()メソッドを使用すると、ユーザーは配置を1つずつ取得できます。

  4. 生成された配置は、一部のユーザーにとって望ましい可能性がある辞書順です。

22
Randy Lai

R *の組み合わせ論のスライスのウォークスルー

以下では、組み合わせと順列を生成する機能を備えたパッケージを調べます。パッケージを省略した場合は、ご容赦ください。コメントを残すか、この投稿を編集してください。

分析の概要:

  1. 前書き
  2. 組み合わせ
  3. 順列
  4. マルチセット
  5. 概要
  6. 記憶

始める前に、組み合わせ/順列withが、選択された個別アイテムと非個別アイテムの置き換えmを一度に置き換えることに注意してください同等です。これはそうです、私たちが交換をするとき、それは特定ではありません。したがって、特定の要素が最初に何回発生しても、出力にはその要素のインスタンスが1からm回繰り返されます。

1.はじめに

  1. gtools v 3.8.1
  2. combinat v 0.0-8
  3. multicool v 0.1-10
  4. partitions v 1.9-19
  5. RcppAlgos v 2.0.1(私は作成者です)
  6. arrangements v 1.1.0
  7. gRbase v 1.8-3

permutepermutations、または_gRbase::aperm/ar_perm_は、これらのタイプの問題を攻撃することを意図していないため、含めませんでした。

| ---------------------------------------[ 〜#〜]概要[〜#〜]------------------------------- ------

_|_______________| 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      |           |        |
_

タスク_m at a time_および_general vector_は、結果を生成する機能を参照します "m一度に"(-mが長さより小さい場合)ベクトルの)および_1:n_とは対照的に「一般的なベクトル」を再配置します。実際には、一般的に一般的なベクトルの再配置を見つけることに関心があるため、以下のすべての検査はこれを反映します(可能な場合)。

すべてのベンチマークは、3つの異なるセットアップで実行されました。

  1. Macbook Pro i7 16Gb
  2. Macbook Air i5 4Gb
  3. Windows 7 i5 8Gbを実行するLenovo

リストされた結果は、セットアップ#1(つまり、MBPro)から取得されました。他の2つのシステムの結果は同様でした。また、gc()は定期的に呼び出され、すべてのメモリが使用可能であることを確認します(_?gc_を参照)。

2.組み合わせ

最初に、置換なしの組み合わせを選択しますmを一度に調べます。

  1. RcppAlgos
  2. combinat(またはutils
  3. gtools
  4. arrangements
  5. gRbase

方法:

_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
_

基準:

_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
_

ここで、置換を選択した組み合わせmを一度に調べます。

  1. RcppAlgos
  2. gtools
  3. arrangements

方法:

_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
_

基準:

_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.順列

最初に、置換なしの順列を選択しますmを一度に調べます。

  1. RcppAlgos
  2. gtools
  3. arrangements

方法:

_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
_

基準:

_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
_

次に、一般的なベクトルで置換せずに順列を調べます(すべての順列を返します)。

  1. RcppAlgos
  2. gtools
  3. combinat
  4. multicool
  5. arrangements

方法:

_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
_

基準:

_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
_

ここで、_1:n_の代わりに置換を調べます(すべての置換を返します)。

  1. RcppAlgos
  2. gtools
  3. combinat
  4. multicool
  5. partitions
  6. arrangements

方法:

_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
_

基準:

_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
_

最後に、置換による置換を調べます。

  1. RcppAlgos
  2. iterpc
  3. gtools
  4. arrangements

方法:

_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)
_

この次のベンチマークは、これまでの結果を考えると少し意外です。

_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
_

これはタイプミスではありません... _gtools::permutations_は、他のコンパイル済み関数とほぼ同じくらい高速です。 _gtools::permutations_のソースコードをチェックすることをお勧めします(Rまたはそれ以外の場合)。

4.マルチセット

最初に、マルチセットの組み合わせを調べます。

  1. RcppAlgos
  2. arrangements

マルチセットの組み合わせ/順列を見つけるには、RcppAlgosを使用してfreqs引数を使用し、ソースベクトル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
_

基準:

_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
_

mを一度に選択したマルチセットの順列の場合、次のようになります。

  1. RcppAlgos
  2. arrangements

方法:

_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
_

基準:

_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
_

すべての順列を返すマルチセットの順列の場合、次のようになります。

  1. RcppAlgos
  2. multicool
  3. arrangements

方法:

_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
_

基準:

_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.まとめ

gtoolscombinatはどちらも、ベクトルの要素を再配置するための確立されたパッケージです。 gtoolsを使用すると、さらにいくつかのオプションがあり(上記の概要を参照)、combinatを使用すると、factorsを再配置できます。 multicoolを使用すると、マルチセットを再配置できます。 partitionsgRbaseはこの質問の目的のために制限されていますが、パーティションと配列オブジェクトをそれぞれ処理するための非常に効率的な関数が詰め込まれた強力な会社です。

arrangements

  1. 出力は辞書順です。
  2. ユーザーがlayout引数(_r = row-major_、_c = column-major_、および_l = list_)を介して形式を指定できるようにします。
  3. イテレータを操作するときにcollectgetnextなどの便利なメソッドを提供します。
  4. getnextを介して_2^31 - 1_を超える組み合わせ/順列の生成を可能にします。 N.B. RcppAlgos(_lower/upper_を介して以下を参照)およびmulticoolnextPermを介して)もこれを実行できます。
  5. getnextと言えば、この関数は、d引数を利用して特定の数の結果を可能にします。
  6. 組み合わせ/順列の数を計算するためにgmpの大きな整数をサポートします。

観察する:

_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
_

この機能は、いくつかの組み合わせ/順列だけが必要な場合に非常に便利です。従来の方法では、すべての組み合わせ/順列を生成してからサブセットを生成する必要がありました。 _10^17_を超える結果(つまり、ncombinations(1000, 7, bigz = TRUE) = 194280608456793000)があるため、前の例は不可能になります。

この機能とarrangementsのジェネレーターの改善により、メモリーに関して非常に効率的になります。

RcppAlgos

  1. 出力は辞書順です。
  2. 便利な制約機能がいくつかありますが、これらはこの質問に対してトピック外であるため、ここでは説明しません。これらの機能を利用して解決できる問題の種類が、このパッケージを作成する動機だったということだけを指摘しておきます。
  3. upperrowCap引数に類似した引数d(正式にはgetnext)があります。

観察する:

_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
_
  1. さらに、_2.0.0_以降、lowerと呼ばれる引数があり、特定の組み合わせ/順列で生成を開始できます。これにより、並列化が適切に設定され、チャンクが独立して生成されるため、_2^31 - 1_を超える高速生成が可能になります。

60億を超える組み合わせの並列例:

_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
_

各パッケージがどのようにスケーリングするのか疑問に思っている場合は、各パッケージが1億を超える結果を生成できる速さを測定するこの最後の例を残します(NB _gtools::combinations_はエラーをスローするため、ここでは省略します:_evaluation nested too deeply..._)。また、_combinat::combn_から正常に実行できなかったため、combnパッケージから明示的にutilsを呼び出しています。これら2つのメモリ使用量の違いは、ごくわずかしか異なることを考えると、かなり奇妙です(「作成者」セクションの_?utils::combn_を参照)。

観察する:

_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.メモリ

comboGeneralと_arrangements::combinations_を実行すると、gcを呼び出す前にメモリがほぼ2 GBジャンプします。これは#rows * #nols * bytesPerCell / 2^30 bytes = choose(1000,3) * 3 * 4 / 2^30 bytes = (166167000 * 3 * 4)/2^30 = 1.857 Gbs)とほぼ同じです。ただし、combnを実行すると、メモリの動作が不安定になります(たとえば、16 Gbのメモリすべてを使用することもあれば、2、3 Gbしかスパイクしないこともあります)。これをWindowsセットアップでテストしたところ、クラッシュすることがよくありました。

これは、RprofsummaryRporfを使用して確認できます。観察する:

_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
_

RcppAlgosarrangementsを使用すると、_mem.total_は_1900 Mb_のすぐ上に登録されます。

そして、これがgtoolsutils、および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
_

興味深いことに、_utils::combn_と_combinat::combn_は異なるメモリ量を使用し、実行に異なる時間を要します。これは、より小さなベクトルでは成り立ちません。

_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
_

また、gtoolsを使用すると、使用される合計メモリはutilsの3倍強になります。これらの3つのパッケージでは、実行するたびに異なる結果が得られたことに注意してください(たとえば、_combinat::combn_の場合、9000 Mbを取得してから13000 Mbを取得することがあります)。

それでも、どれもRcppAlgos[〜#〜]または[〜#〜]arrangementsに一致することはできません。上記の例で実行した場合、どちらも51 Mbのみを使用します。

ベンチマークスクリプト:---(https://Gist.github.com/randy3k/bd5730a6d70101c7471f4ae6f453862ehttps://github.com/tidyverse/reprex によってレンダリング)

*:A Comb through Combinatorics]へのオマージュMiklósBóna作

17
Joseph Wood