expand.grid的非冗余版本

时间:2013-06-18 14:11:12

标签: r combinations

R函数expand.grid返回所提供参数元素之间的所有可能组合。 e.g。

> 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

编辑每个元素与自身的组合最终可能会从答案中丢弃。我在程序中实际上并不需要它,即使(数学上)aa aaVar1的一个元素与var2的另一个元素之间的一个(常规)唯一组合。

解决方案需要从两个向量中生成元素对(即每个输入向量中的一个 - 以便它可以应用于2个以上的输入)

8 个答案:

答案 0 :(得分:29)

如何使用outer?但是这个特殊的函数将它们连接成一个字符串。

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

,您还可以对两个向量的唯一元素使用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"

答案 1 :(得分:12)

如果两个向量相同,则combinations包中有gtools函数:

library(gtools)
combinations(n = 3, r = 2, v = c("aa", "ab", "cc"), repeats.allowed = TRUE)

#      [,1] [,2]
# [1,] "aa" "aa"
# [2,] "aa" "ab"
# [3,] "aa" "cc"
# [4,] "ab" "ab"
# [5,] "ab" "cc"
# [6,] "cc" "cc"

没有"aa" "aa"等等

combinations(n = 3, r = 2, v = c("aa", "ab", "cc"), repeats.allowed = FALSE)

答案 2 :(得分:12)

在基地R中,您可以使用:

expand.grid.unique <- function(x, y, include.equals=FALSE)
{
    x <- unique(x)

    y <- unique(y)

    g <- function(i)
    {
        z <- setdiff(y, x[seq_len(i-include.equals)])

        if(length(z)) cbind(x[i], z, deparse.level=0)
    }

    do.call(rbind, lapply(seq_along(x), g))
}

结果:

> x <- c("aa", "ab", "cc")
> y <- c("aa", "ab", "cc")

> expand.grid.unique(x, y)
     [,1] [,2]
[1,] "aa" "ab"
[2,] "aa" "cc"
[3,] "ab" "cc"

> expand.grid.unique(x, y, include.equals=TRUE)
     [,1] [,2]
[1,] "aa" "aa"
[2,] "aa" "ab"
[3,] "aa" "cc"
[4,] "ab" "ab"
[5,] "ab" "cc"
[6,] "cc" "cc"

答案 3 :(得分:8)

尝试:

factors <- c("a", "b", "c")

all.combos <- t(combn(factors,2))

     [,1] [,2]
[1,] "a"  "b" 
[2,] "a"  "c" 
[3,] "b"  "c"

这不包括每个因素的重复项(例如“a”“a”),但如果需要,您可以轻松添加这些重复项。

dup.combos <- cbind(factors,factors)

     factors factors
[1,] "a"     "a"    
[2,] "b"     "b"    
[3,] "c"     "c"   

all.combos <- rbind(all.combos,dup.combos)

     factors factors
[1,] "a"     "b"    
[2,] "a"     "c"    
[3,] "b"     "c"    
[4,] "a"     "a"    
[5,] "b"     "b"    
[6,] "c"     "c" 

答案 4 :(得分:7)

以前的答案缺乏获得特定结果的方法,即保留自我对,但删除具有不同顺序的那些。 gtools 包有两个用于这些目的的函数,combinationspermutationsAccording to this website

  • 当订单无关紧要时,它就是一个组合。
  • 当订单确实重要时,它就是一个排列。

在这两种情况下,我们都决定是否允许重复,相应地,两个函数都有一个repeats.allowed参数,产生4种组合(美味的元!)。值得一试的是这些。为了便于理解,我将矢量简化为单个字母。

重复排列

最广泛的选择是允许自我关系和不同排序的选项:

> 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的用户来说,这是the Cartesian product/join

有两种方法可以限制: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)!),即(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)!中找到,即(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

答案 5 :(得分:2)

您可以使用“大于”操作来过滤冗余组合。这适用于数字和字符向量。

> grid <- expand.grid(c("aa", "ab", "cc"), c("aa", "ab", "cc"), stringsAsFactors = F)
> grid[grid$Var1 >= grid$Var2, ]
  Var1 Var2
1   aa   aa
2   ab   aa
3   cc   aa
5   ab   ab
6   cc   ab
9   cc   cc

这不应该使您的代码减慢太多。如果您要扩展包含更大元素的向量(例如,两个数据帧列表),则建议使用引用原始向量的数字索引。

答案 6 :(得分:0)

这是一个非常丑陋的版本,适用于我解决类似问题。

AHP_code = letters[1:10] 
 temp. <- expand.grid(AHP_code, AHP_code, stringsAsFactors = FALSE)
  temp. <- temp.[temp.$Var1 != temp.$Var2, ] # remove AA, BB, CC, etc. 
  temp.$combo <- NA 
  for(i in 1:nrow(temp.)){  # vectorizing this gave me weird results, loop worked fine. 
    temp.$combo[i] <- paste0(sort(as.character(temp.[i, 1:2])), collapse = "")
  }
  temp. <- temp.[!duplicated(temp.$combo),]
  temp. 

答案 7 :(得分:0)

TL;DR

使用 main.dll 中的 comboGrid

RcppAlgos

细节

我最近遇到了这个问题 R - Expand Grid Without Duplicates,当我搜索重复项时,我发现了这个问题。那里的问题并不完全是重复的,因为它更笼统,并且有额外的限制,@Ferdinand.kraft 对此有所启发。

需要注意的是,这里的许多解决方案都使用了某种组合功能。 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" 函数返回根本不同的 Cartesian product

笛卡尔积对多个对象进行操作,这些对象可能相同也可能不同。一般来说,组合函数应用于单个向量。置换函数也是如此。

如果提供的向量相同,则使用组合/排列函数只会产生与 expand.grid 相当的结果。作为一个非常简单的例子,考虑 expand.grid

使用 v1 = 1:3, v2 = 2:4,我们看到第 3 行和第 5 行是重复的:

expand.grid

使用 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 可以解决这个问题。它非常通用、灵活且速度快。

首先,回答 OP 提出的具体问题:

comboGrid

正如@Ferdinand.kraft 指出的那样,有时输出可能需要在给定行中排除重复项。为此,我们使用 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" :

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

所采用的算法避免了生成整个笛卡尔积并随后去除重复项。最终,我们使用 Fundamental theorem of arithmetic 和重复数据删除创建了一个哈希表,如 user2357112 supports Monica 在对 Picking unordered combinations from pools with overlap 的回答中指出的那样。所有这些以及它是用 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 编写的事实意味着它速度快且内存高效:

C++
相关问题