【问题标题】:Count all possible combinations no matter the column order无论列顺序如何,计算所有可能的组合
【发布时间】:2020-02-15 08:05:07
【问题描述】:

我有一个看起来像的数据集

df <- data.frame(rbind(c("A","B","D",NA,NA,NA,3),
c("B","A","D","C",NA,NA,1),
c("B","C","E","A","D",NA,5),
c("A","B",NA,NA,NA,NA,4),
c("A","B","C","D","E","F",2)))


    X1      X2       X3        X4       X5        X6    N
    A        B        D        NA       NA        NA    3 
    B        A        D        C        NA        NA    1 
    B        C        E        A         D        NA    5 
    A        B        NA       NA       NA        NA    4 
    A        B        C        D         E         F    2 

N 列是组合发生的次数。

并且我希望获得无序列的累积总和(无论字母位于哪一列),这样:

     X1      X2       X3        X4       X5        X6     N
    A       NA        NA       NA        NA        NA     15
    B       NA        NA       NA        NA        NA     15
    C       NA        NA       NA        NA        NA     8
    D       NA        NA       NA        NA        NA     11
    E       NA        NA       NA        NA        NA     7
    F       NA        NA       NA        NA        NA     2
    A        B        NA       NA        NA        NA     15 
    A        B        C        NA        NA        NA     8 
    A        B        C        D         NA        NA     8 
    A        B        C        D         E         NA     7 
    A        B        C        D         E         F      1 
    B        C        NA       NA        NA        NA     8
    ....

所以想法是拥有所有可能的组合和频率,但考虑到列中出现的顺序不相关。

【问题讨论】:

  • 为什么N 列是3,1,5,4,2?你能解释一下吗?
  • 这些数字是特定组合的频率。例如,在所需的数据帧中,组合 (A,B,C) 具有 N=8,因为恰好具有这三个字母的是 N 的总和,例如(B,A,D,C) + (B,C,E,A,D) + (A,B,C,D,E,F) = 1 + 5 + 2 = 8。
  • 不是直接关于这个问题:通过调用rbind,你已经制作了一个矩阵而不是一个数据框,所以你的列N被强制转换为字符,然后data.frame默认变成字符列(在这种情况下,all 您的列)到因子。所以现在N 是一个试图代表一个数字的因素。不需要rbind;只需将向量全部放入数据框中
  • 对不起,我误读了rbind 的目的。实际上,通过创建混合类型(字符串和数字)的向量,您可以将计数转换为字符串,然后再转换为因子。不想过多脱轨,但想指出可能出现的数据类型问题

标签: r dplyr count data.table


【解决方案1】:

这是一种按行生成值组合列表的方法,将其添加到原始数据框中,按组取消嵌套和计数 N。

library(dplyr)
library(tidyr)

df %>%
  mutate(comblist = apply(.[1:6], 1, function(x) {
    x <- sort(na.omit(x))
    unlist(sapply(seq_along(x), function(y)
      list(combn(x, y,
        FUN = function(l)
          list(toString(l))
      ))))
  })) %>%
  select(comblist, N) %>%
  unnest(comblist) %>%
  group_by(comblist) %>%
  summarise(x = sum(N))

# A tibble: 63 x 2
   comblist             N
   <chr>            <dbl>
 1 A                   15
 2 A, B                15
 3 A, B, C              8
 4 A, B, C, D           8
 5 A, B, C, D, E        7
 6 A, B, C, D, E, F     2
 7 A, B, C, D, F        2
 8 A, B, C, E           7
 9 A, B, C, E, F        2
10 A, B, C, F           2
# ... with 53 more rows

【讨论】:

    【解决方案2】:

    这是一个基本的 R 解决方案

    l <- Map(function(x) c(na.omit(x)),data.frame(t(df[1:6]),stringsAsFactors = FALSE))
    lout <- Map(function(x) c(na.omit(x)),data.frame(t(dfout),stringsAsFactors = FALSE))
    
    dfout$N <- sapply(lout, function(x) sum(as.numeric(df$X7)[sapply(l, function(v) all(x %in% v))]))
    

    这样

    > dfout
       X1   X2   X3   X4   X5   X6  N
    1   A <NA> <NA> <NA> <NA> <NA> 15
    2   B <NA> <NA> <NA> <NA> <NA> 15
    3   C <NA> <NA> <NA> <NA> <NA>  8
    4   D <NA> <NA> <NA> <NA> <NA> 11
    5   E <NA> <NA> <NA> <NA> <NA>  7
    6   F <NA> <NA> <NA> <NA> <NA>  2
    7   A    B <NA> <NA> <NA> <NA> 15
    8   A    B    C <NA> <NA> <NA>  8
    9   A    B    C    D <NA> <NA>  8
    10  A    B    C    D    E <NA>  7
    11  A    B    C    D    E    F  2
    12  B    C <NA> <NA> <NA> <NA>  8
    

    数据

    df <- structure(list(X1 = structure(c(1L, 2L, 2L, 1L, 1L), .Label = c("A", 
    "B"), class = "factor"), X2 = structure(c(2L, 1L, 3L, 2L, 2L), .Label = c("A", 
    "B", "C"), class = "factor"), X3 = structure(c(2L, 2L, 3L, NA, 
    1L), .Label = c("C", "D", "E"), class = "factor"), X4 = structure(c(NA, 
    2L, 1L, NA, 3L), .Label = c("A", "C", "D"), class = "factor"), 
        X5 = structure(c(NA, NA, 1L, NA, 2L), .Label = c("D", "E"
        ), class = "factor"), X6 = structure(c(NA, NA, NA, NA, 1L
        ), .Label = "F", class = "factor"), X7 = structure(c(3L, 
        1L, 5L, 4L, 2L), .Label = c("1", "2", "3", "4", "5"), class = "factor")), class = "data.frame", row.names = c(NA, 
    -5L))
    
    dfout <- structure(list(X1 = c("A", "B", "C", "D", "E", "F", "A", "A", 
    "A", "A", "A", "B"), X2 = c(NA, NA, NA, NA, NA, NA, "B", "B", 
    "B", "B", "B", "C"), X3 = c(NA, NA, NA, NA, NA, NA, NA, "C", 
    "C", "C", "C", NA), X4 = c(NA, NA, NA, NA, NA, NA, NA, NA, "D", 
    "D", "D", NA), X5 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, "E", 
    "E", NA), X6 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "F", 
    NA)), row.names = c(NA, -12L), class = "data.frame")
    

    【讨论】:

    • 您发布的dfout 只是总行数的一个子集,对吧?
    • @camille 我只是从 OP 的帖子中复制的,而不是从我的代码生成的。我的代码只计算 N
    • 哦,好的。但是获得 A...F 的组合不是任务的一部分,而不仅仅是将它们的出现相加吗?
    • @camille 我不确定 OP 是否需要生成所有这些组合,或者只是想要针对给定组合的出现......但我猜你是前者
    【解决方案3】:

    使用RcppAlgos::comboGeneral 生成组合并使用data.table::cube 生成组合的选项(引用自?cube计算各个级别的聚合,生成多个(子)总计。

    library(data.table)
    library(RcppAlgos)
    
    v <- unique(unlist(df[-ncol(df)]))
    v <- sort(v[!is.na(v)])
    nc <- length(v)
    
    DT <- melt(setDT(df)[, rn:=.I], id.vars=c("rn", "X7"), na.rm=TRUE, variable.factor=FALSE)
    combi <- DT[, as.data.table(do.call(rbind, lapply(1L:.N, function(m) {
        rcom <- comboGeneral(value, m)
        M <- matrix("", nrow=nrow(rcom), ncol=nc)
    
        M[cbind(rep(1L:nrow(rcom), ncol(rcom)), match(rcom, v))] <- rcom
        M
    }))), .(rn, COUNT=as.integer(X7))]
    ans <- cube(combi, .(COUNT=sum(COUNT)), by=paste0("V", 1:6))
    setorderv(ans[complete.cases(ans)], paste0("V", 6:1))[]
    

    输出:

        V1 V2 V3 V4 V5 V6 COUNT
     1:  A                   15
     2:     B                15
     3:  A  B                15
     4:        C              8
     5:  A     C              8
     6:     B  C              8
     7:  A  B  C              8
     8:           D          11
     9:  A        D          11
    10:     B     D          11
    11:  A  B     D          11
    12:        C  D           8
    13:  A     C  D           8
    14:     B  C  D           8
    15:  A  B  C  D           8
    16:              E        7
    17:  A           E        7
    18:     B        E        7
    19:  A  B        E        7
    20:        C     E        7
    21:  A     C     E        7
    22:     B  C     E        7
    23:  A  B  C     E        7
    24:           D  E        7
    25:  A        D  E        7
    26:     B     D  E        7
    27:  A  B     D  E        7
    28:        C  D  E        7
    29:  A     C  D  E        7
    30:     B  C  D  E        7
    31:  A  B  C  D  E        7
    32:                 F     2
    33:  A              F     2
    34:     B           F     2
    35:  A  B           F     2
    36:        C        F     2
    37:  A     C        F     2
    38:     B  C        F     2
    39:  A  B  C        F     2
    40:           D     F     2
    41:  A        D     F     2
    42:     B     D     F     2
    43:  A  B     D     F     2
    44:        C  D     F     2
    45:  A     C  D     F     2
    46:     B  C  D     F     2
    47:  A  B  C  D     F     2
    48:              E  F     2
    49:  A           E  F     2
    50:     B        E  F     2
    51:  A  B        E  F     2
    52:        C     E  F     2
    53:  A     C     E  F     2
    54:     B  C     E  F     2
    55:  A  B  C     E  F     2
    56:           D  E  F     2
    57:  A        D  E  F     2
    58:     B     D  E  F     2
    59:  A  B     D  E  F     2
    60:        C  D  E  F     2
    61:  A     C  D  E  F     2
    62:     B  C  D  E  F     2
    63:  A  B  C  D  E  F     2
        V1 V2 V3 V4 V5 V6 COUNT
    

    【讨论】:

      【解决方案4】:

      不确定您想要做什么,添加minimal reproducible example 以及预期示例会很有帮助。这样你就可以帮助别人帮助你!但是,如果您想要 anyall 列中的字母计数:

      library(dplyr)
      library(tidyr)
      df %>% 
      pivot_longer(cols =everything()) %>%
      group_by(value) %>%
      summarise(N = n())
      

      【讨论】:

      • 感谢您的回复。我添加了一个小例子来说明数据在 R 中的样子。整个想法是计算每个元素(A、B、C...)的出现次数。因此,例如,第一行中的个人将为 (A)、(B)、(D)、(A,B)、(A,D)、(B,D)、(A,B、 D),不管列的顺序是什么。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-12
      • 1970-01-01
      • 1970-01-01
      • 2015-11-10
      • 2022-12-03
      • 1970-01-01
      相关资源
      最近更新 更多