【问题标题】:Return All Possible Combinations of Values返回所有可能的值组合
【发布时间】:2018-07-29 12:50:30
【问题描述】:

我有下表:

Group Value
----  ----
1     A
1     B
1     C
1     D
2     A
2     B
2     C

对于两组中的每一个,我都想返回所有可能的值组合。对于第 1 组,例如,可能的组合是 (A,B)、(A,C)、(A,D)、(B,C)、(B,D)、(C,D)、(A, B,C), (B,D,C), (D,C,A), (C,A,B)。类似地,对于第 2 组,它是 (A,B), (A,C), (B,C) [备注:我不想考虑 (1) 只有一个值的组合,(2) 与所有值和(3)没有值的组合。因此,对于 n 个不同的值,我有 2^(n)-n-1-1 种组合]。

我想在附加列“Combi”的帮助下列出所有这些组合。此列连续编号不同的组合。

Group Combi Value
----  ----  ----
1     1     A
1     1     B
1     2     A
1     2     C
1     3     A
1     3     D
1     4     B
1     4     C
1     5     B
1     5     D
1     6     C
1     6     C
1     7     A
1     7     B
1     7     C
1     8     B
1     8     C
1     8     D
1     9     C
1     9     D
1     9     A
1     10    D
1     10    A
1     10    B
2     11    A
2     11    B
2     12    A
2     12    C
2     13    B
2     13    C

我如何在 R 中做到这一点?

【问题讨论】:

标签: r combinations combinatorics


【解决方案1】:

data.table 的可能解决方案:

library(data.table)
setDT(dat)[, .(Value = {n <- 2:(uniqueN(Value)-1);
                        unlist(lapply(n, function(x) combn(Value, x)))})
           , by = Group
           ][, Combi := cumsum(c(1, diff(match(Value, LETTERS)) < 0))][]

给出:

    Group Value Combi
 1:     1     A     1
 2:     1     B     1
 3:     1     A     2
 4:     1     C     2
 5:     1     A     3
 6:     1     D     3
 7:     1     B     4
 8:     1     C     4
 9:     1     B     5
10:     1     D     5
11:     1     C     6
12:     1     D     6
13:     1     A     7
14:     1     B     7
15:     1     C     7
16:     1     A     8
17:     1     B     8
18:     1     D     8
19:     1     A     9
20:     1     C     9
21:     1     D     9
22:     1     B    10
23:     1     C    10
24:     1     D    10
25:     2     A    11
26:     2     B    11
27:     2     A    12
28:     2     C    12
29:     2     B    13
30:     2     C    13

【讨论】:

  • ABC 不能是组 2 的排列,因为它包含所有项目
【解决方案2】:

这是一个基本解决方案。内嵌评论。

#for each length (not incl. 1 and number of unique values), create all possible combinations using combn
combiLs <- by(dat, dat$Group, function(x) {
    #number of elements to choose excl. 1 and all values
    idx <- seq_along(x$Value)[-c(1, nrow(x))]

    do.call(rbind, lapply(idx, function(m) {
        #for each number of elements, generate all combinations
        sets <- combn(x$Value, m, simplify=FALSE)

        #get OP's desired format
        combi <- rep(seq_along(sets), each=m)
        data.frame(
            Group=x$Group[1],
            Combi=paste(x$Group[1], combi, sep="."),
            Value=unlist(sets))
    }))
})

#final output
do.call(rbind, combiLs)

同时使用choosecombn 的另一个可能的data.table 实现:

res <- setDT(dat)[, {
        idx <- seq_along(Value)[-c(1, .N)]
        list(
            Set=paste0(Group[1], ".", unlist(lapply(idx, function(m) rep(seq_len(choose(.N, m)), each=m)))),
            Value=unlist(lapply(idx, function(m) as.vector(combn(Value, m))))
        )
    }, by=Group]

res[, Combi := unlist(Map(rep, x=seq_along(rle(Set)$values), each=rle(Set)$lengths))]

数据:

dat <- data.frame(Group=c(rep(1,4), rep(2,3)), Value=c("A","B","C","D","A","B","C"))
dat

【讨论】:

    【解决方案3】:

    这是一个通用的 tidyverse 解决方案,应该适用于包含 3 个以上项目的值集。

    这个想法是使用combn(m = 2 然后 3 等)并将输出格式化为tibble,用于不同的Groupm 值。从那里我们可以使用tidyverse 函数map_dfrunnest。最后,由于我们有多个 id 而不是一个,因此我们构建了一个唯一 id 表,构建了唯一的 combi id 并将其连接回我们的结果。

    # convenience fonction to store combinations in a long format
    combi_as_tibble <- function(n,values) combn(values,n) %>%
      {tibble(id = rep(seq(ncol(.)),each=nrow(.)),Value=c(.))}    
    combi_as_tibble(2,letters[1:3]) # example
    # # A tibble: 6 x 2
    #      id Value
    #   <chr> <chr>
    # 1     1     a
    # 2     1     b
    # 3     2     a
    # 4     2     c
    # 5     3     b
    # 6     3     c
    
    
    df1 %>% group_by(Group) %>%
      summarize(combis = list(
        map_dfr(2:(length(unique(Value))-1),combi_as_tibble,Value,.id="id2")
      ))     %>% # by Group, build a long tibble with all combinations
      unnest %>% # unnest to get a long unnested table
      left_join(.,select(.,Group,id2,id) %>% distinct %>% mutate(combi=row_number())
      )      %>% # build combi ids
      select(Group,Value,combi) %>%
      as.data.frame
    
    #    Group Value combi
    # 1      1     A     1
    # 2      1     B     1
    # 3      1     A     2
    # 4      1     C     2
    # 5      1     A     3
    # 6      1     D     3
    # 7      1     B     4
    # 8      1     C     4
    # 9      1     B     5
    # 10     1     D     5
    # 11     1     C     6
    # 12     1     D     6
    # 13     1     A     7
    # 14     1     B     7
    # 15     1     C     7
    # 16     1     A     8
    # 17     1     B     8
    # 18     1     D     8
    # 19     1     A     9
    # 20     1     C     9
    # 21     1     D     9
    # 22     1     B    10
    # 23     1     C    10
    # 24     1     D    10
    # 25     2     A    11
    # 26     2     B    11
    # 27     2     A    12
    # 28     2     C    12
    # 29     2     B    13
    # 30     2     C    13
    

    数据

    df1 <- read.table(text="Group Value
    1     A
    1     B
    1     C
    1     D
    2     A
    2     B
    2     C",h=T,strin=F)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-12
      • 2019-07-15
      • 1970-01-01
      • 2011-12-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多