TL;DR
comboGrid
から使用RcppAlgos
:
library(RcppAlgos)
comboGrid(c("aa", "ab", "cc"), c("aa", "ab", "cc"))
Var1 Var2
[1,] "aa" "aa"
[2,] "aa" "ab"
[3,] "aa" "cc"
[4,] "ab" "ab"
[5,] "ab" "cc"
[6,] "cc" "cc"
詳細
私は最近、この質問に出くわしましたR - 重複なしでグリッドを展開し、重複を探していたときに、この質問を見つけました。それはもう少し一般的であり、@ Ferdinand.kraftがいくつかの光を当てた追加の制限があるため、正確に重複している質問ではありません。
ここでのソリューションの多くは、何らかの組み合わせ機能を利用していることに注意してください。このexpand.grid
関数は、根本的に異なるデカルト積を返します。
デカルト積は、同じである場合も異なる場合もある複数のオブジェクトで動作します。一般的に言えば、組み合わせ関数は単一のベクトルに適用されます。置換関数についても同じことが言えます。
expand.grid
組み合わせ/順列関数を使用すると、提供されたベクトルが同一である場合にのみ、同等の結果が生成されます。非常に単純な例として、 を考えてみましょうv1 = 1:3, v2 = 2:4
。
ではexpand.grid
、行 3 と 5 が重複していることがわかります。
expand.grid(1:3, 2:4)
Var1 Var2
1 1 2
2 2 2
3 3 2
4 1 3
5 2 3
6 3 3
7 1 4
8 2 4
9 3 4
を使用combn
しても解決には至りません。
t(combn(unique(c(1:3, 2:4)), 2))
[,1] [,2]
[1,] 1 2
[2,] 1 3
[3,] 1 4
[4,] 2 3
[5,] 2 4
[6,] 3 4
また、 を使用した繰り返しgtools
では、あまりにも多く生成されます。
gtools::combinations(4, 2, v = unique(c(1:3, 2:4)), repeats.allowed = TRUE)
[,1] [,2]
[1,] 1 1
[2,] 1 2
[3,] 1 3
[4,] 1 4
[5,] 2 2
[6,] 2 3
[7,] 2 4
[8,] 3 3
[9,] 3 4
[10,] 4 4
expand.grid
実際、デカルト積 (つまり解)にも含まれない結果を生成します。
以下を作成するソリューションが必要です。
Var1 Var2
[1,] 1 2
[2,] 1 3
[3,] 1 4
[4,] 2 2
[5,] 2 3
[6,] 2 4
[7,] 3 3
[8,] 3 4
私はパッケージを作成しRcppAlgos
ましたが、最新のリリースには、まさにこの問題に対処v2.4.3
する機能があります。comboGrid
これは非常に一般的で、柔軟で、高速です。
まず、OP によって提起された特定の質問に答えるには:
library(RcppAlgos)
comboGrid(c("aa", "ab", "cc"), c("aa", "ab", "cc"))
Var1 Var2
[1,] "aa" "aa"
[2,] "aa" "ab"
[3,] "aa" "cc"
[4,] "ab" "ab"
[5,] "ab" "cc"
[6,] "cc" "cc"
また、@ Ferdinand.kraft が指摘するように、出力の特定の行で重複を除外する必要がある場合があります。そのために、次を使用しますrepetition = FALSE
。
comboGrid(c("aa", "ab", "cc"), c("aa", "ab", "cc"), repetition = FALSE)
Var1 Var2
[1,] "aa" "ab"
[2,] "aa" "cc"
[3,] "ab" "cc"
comboGrid
も非常に一般的です。複数のベクトルに適用できます。
comboGrid(rep(list(c("aa", "ab", "cc")), 3))
Var1 Var2 Var3
[1,] "aa" "aa" "aa"
[2,] "aa" "aa" "ab"
[3,] "aa" "aa" "cc"
[4,] "aa" "ab" "ab"
[5,] "aa" "ab" "cc"
[6,] "aa" "cc" "cc"
[7,] "ab" "ab" "ab"
[8,] "ab" "ab" "cc"
[9,] "ab" "cc" "cc"
[10,] "cc" "cc" "cc"
ベクトルが同一である必要はありません。
comboGrid(1:3, 2:4)
Var1 Var2
[1,] 1 2
[2,] 1 3
[3,] 1 4
[4,] 2 2
[5,] 2 3
[6,] 2 4
[7,] 3 3
[8,] 3 4
また、さまざまなタイプのベクトルに適用できます。
set.seed(123)
my_range <- 3:15
mixed_types <- list(
int1 = sample(15, sample(my_range, 1)),
int2 = sample(15, sample(my_range, 1)),
char1 = sample(LETTERS, sample(my_range, 1)),
char2 = sample(LETTERS, sample(my_range, 1))
)
dim(expand.grid(mixed_types))
[1] 1950 4
dim(comboGrid(mixed_types, repetition = FALSE))
[1] 1595 4
dim(comboGrid(mixed_types, repetition = TRUE))
[1] 1770 4
採用されているアルゴリズムは、デカルト積全体の生成を回避し、その後重複を削除します。最終的に、ユーザー 2357112 サポート モニカが重複するプールから順序付けられていない組み合わせを選択する への回答で指摘したように、算術の基本定理と重複排除を使用してハッシュ テーブルを作成します。これらすべてと、それが書かれているという事実は、高速でメモリ効率が高いことを意味します。C++
pools = list(c(1, 10, 14, 6),
c(7, 2, 4, 8, 3, 11, 12),
c(11, 3, 13, 4, 15, 8, 6, 5),
c(10, 1, 3, 2, 9, 5, 7),
c(1, 5, 10, 3, 8, 14),
c(15, 3, 7, 10, 4, 5, 8, 6),
c(14, 9, 11, 15),
c(7, 6, 13, 14, 10, 11, 9, 4),
c(6, 3, 2, 14, 7, 12, 9),
c(6, 11, 2, 5, 15, 7))
system.time(combCarts <- comboGrid(pools))
user system elapsed
0.929 0.062 0.992
nrow(combCarts)
[1] 1205740
## Small object created
print(object.size(combCarts), unit = "Mb")
92 Mb
system.time(cartProd <- expand.grid(pools))
user system elapsed
8.477 2.895 11.461
prod(lengths(pools))
[1] 101154816
## Very large object created
print(object.size(cartProd), unit = "Mb")
7717.5 Mb