49

このR関数expand.gridは、指定されたパラメーターの要素間のすべての可能な組み合わせを返します。例えば

> expand.grid(c("aa", "ab", "cc"), c("aa", "ab", "cc"))
  Var1 Var2
1   aa   aa
2   ab   aa
3   cc   aa
4   aa   ab
5   ab   ab
6   cc   ab
7   aa   cc
8   ab   cc
9   cc   cc

expand.grid提供されたベクトル間の「一意の」組み合わせのみを直接取得する効率的な方法を知っていますか?出力は次のようになります。

  Var1 Var2
1   aa   aa
2   ab   aa
3   cc   aa
5   ab   ab
6   cc   ab
9   cc   cc

各要素とそれ自体の組み合わせを編集すると、最終的に回答から破棄される可能性があります。(数学的に) の 1 つの要素と の別のaa aa要素との間の 1 つの (通常の) 一意の組み合わせであっても、実際には私のプログラムでは必要ありません。Var1var2

ソリューションでは、両方のベクトルから要素のペアを生成する必要があります (つまり、入力ベクトルのそれぞれから 1 つ - 2 つ以上の入力に適用できるようにするため)。

4

9 に答える 9

33

を使用してはouterどうですか?しかし、この特定の関数はそれらを 1 つの文字列に連結します。

outer( c("aa", "ab", "cc"), c("aa", "ab", "cc") , "paste" )
#     [,1]    [,2]    [,3]   
#[1,] "aa aa" "aa ab" "aa cc"
#[2,] "ab aa" "ab ab" "ab cc"
#[3,] "cc aa" "cc ab" "cc cc"

combn繰り返し要素が必要ない場合は、2 つのベクトルの一意の要素に対しても使用できます (例: aa aa) 。

vals <- c( c("aa", "ab", "cc"), c("aa", "ab", "cc") )
vals <- unique( vals )
combn( vals , 2 )
#     [,1] [,2] [,3]
#[1,] "aa" "aa" "ab"
#[2,] "ab" "cc" "cc"
于 2013-06-18T14:15:21.667 に答える
13

以前の回答には、特定の結果を得る方法、つまり自己ペアを保持し、順序が異なるものを削除する方法がありませんでした。gtoolsパッケージには、これらの目的のための 2 つの機能combinationspermutations. このウェブサイトによると

  • 順序が問題にならない場合は、コンビネーションです。
  • 順序が重要な場合、それは順列です。

どちらの場合も、繰り返しを許可するかどうかを決定する必要があり、それに対応して、両方の関数にrepeats.allowed引数があり、4 つの組み合わせが生成されます (おいしいメタ!)。これらのそれぞれについて検討する価値があります。わかりやすくするために、ベクトルを 1 文字に簡略化しました。

繰り返しのある順列

最も広範なオプションは、自己関係と異なる順序のオプションの両方を許可することです。

> permutations(n = 3, r = 2, repeats.allowed = T, v = c("a", "b", "c"))
      [,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" 

これにより、9 つのオプションが得られます。n^rこの値は、単純な式、すなわちから見つけることができます3^2=9。これは、 SQL に精通しているユーザー向けのデカルト積/結合です。

これを制限するには 2 つの方法があります: 1) 自己関係を削除する (繰り返しを許可しない)、または 2) 異なる順序のオプション (つまり、組み合わせ) を削除する。

繰り返しとの組み合わせ

異なる順序のオプションを削除したい場合は、次を使用します。

> combinations(n = 3, r = 2, repeats.allowed = T, v = c("a", "b", "c"))
     [,1] [,2]
[1,] "a"  "a" 
[2,] "a"  "b" 
[3,] "a"  "c" 
[4,] "b"  "b" 
[5,] "b"  "c" 
[6,] "c"  "c" 

これにより、6 つのオプションが得られます。この値の式は(r+n-1)!/(r!*(n-1)!)ie(2+3-1)!/(2!*(3-1)!)=4!/(2*2!)=24/4=6です。

繰り返しのない順列

代わりに繰り返しを禁止したい場合は、次を使用します。

> permutations(n = 3, r = 2, repeats.allowed = F, v = c("a", "b", "c"))
     [,1] [,2]
[1,] "a"  "b" 
[2,] "a"  "c" 
[3,] "b"  "a" 
[4,] "b"  "c" 
[5,] "c"  "a" 
[6,] "c"  "b" 

これも 6 つのオプションを提供しますが、それらは異なります。オプションの数は上記と同じですが、偶然です。n!/(n-r)!値は、式ieから見つけることができます(3*2*1)/(3-2)!=6/1!=6

繰り返しのない組み合わせ

最も制限的なのは、自己関係/繰り返しまたは異なる順序のオプションのいずれも必要ない場合です。この場合、次を使用します。

> combinations(n = 3, r = 2, repeats.allowed = F, v = c("a", "b", "c"))
     [,1] [,2]
[1,] "a"  "b" 
[2,] "a"  "c" 
[3,] "b"  "c" 

選択肢は 3 つしかありません。n!/(r!(n-r)!)オプションの数は、かなり複雑な式、つまりから計算できます3*2*1/(2*1*(3-2)!)=6/(2*1!)=6/2=3

于 2016-11-10T12:01:41.613 に答える
2

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
于 2021-06-19T21:28:48.543 に答える