获取每个组的所有级别组合

问题描述 投票:0回答:2

我有一个客户 ID 列表,每个 ID 都有一个他们使用的独特产品的列表。理论上最多可以有 150 种独特的产品。

df <- tibble(ID = c(1,1,1,2,2,3,3,4),
             prod = c("Prod1", "Prod2", "Prod3", "Prod1", "Prod4", "Prod3", "Prod5", "Prod2"))

由此,我需要为每个 ID 获取所有可能的产品组合,而不仅仅是在最高级别(按 ID 分组)。也就是说,包括所有产品的组合,如 expand_grid() 所做的那样,但也包括 1,...,n 元素的所有组合,其中 n 是 ID 具有的唯一产品的数量。

最终数据集应该是这样的:

df_results <- tibble(ID = c(1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4),
                     combo = c("Prod1", "Prod2", "Prod3", "Prod1|Prod2", "Prod1|Prod3", "Prod2|Prod3", "Prod1|Prod2|Prod3",
                               "Prod1", "Prod4", "Prod1|Prod4",
                               "Prod3", "Prod5", "Prod3|Prod5",
                               "Prod2"))
r combinations expand
2个回答
2
投票

规范答案的扩展

library(dplyr)
df %>% 
  group_by(ID) %>% 
  reframe(combo = as.character(do.call(c, lapply(seq_along(prod), \(m) combn(x = prod, m = m, FUN = \(x) paste(x, collapse = "|"))))))
# A tibble: 14 × 2
      ID combo            
   <dbl> <chr>            
 1     1 Prod1            
 2     1 Prod2            
 3     1 Prod3            
 4     1 Prod1|Prod2      
 5     1 Prod1|Prod3      
 6     1 Prod2|Prod3      
 7     1 Prod1|Prod2|Prod3
 8     2 Prod1            
 9     2 Prod4            
10     2 Prod1|Prod4      
11     3 Prod3            
12     3 Prod5            
13     3 Prod3|Prod5      
14     4 Prod2           

或在基数R中:

stack(tapply(df$prod, df$ID, 
       \(prod) do.call(c, lapply(seq_along(prod), \(m) combn(prod, m, FUN = \(x) paste(x, collapse = "|"))))))[2:1]

0
投票

这是另一个基本的 R 选项,使用

intToBits
将所有组合映射到整数索引的二进制表示

with(
  df,
  setNames(
    rev(
      stack(
        by(
          Prod, ID,
          function(p) {
            sapply(
              seq(2^length(p) - 1),
              function(k) paste0(p[which(intToBits(k) > 0)], collapse = "|")
            )
          }
        )
      )
    ), names(df)
  )
)

这给

   ID              Prod
1   1             Prod1
2   1             Prod2
3   1       Prod1|Prod2
4   1             Prod3
5   1       Prod1|Prod3
6   1       Prod2|Prod3
7   1 Prod1|Prod2|Prod3
8   2             Prod1
9   2             Prod4
10  2       Prod1|Prod4
11  3             Prod3
12  3             Prod5
13  3       Prod3|Prod5
14  4             Prod2

如果你想探索使用

expand.grid
的可能性(但不推荐它,因为它相当低效),你可以尝试下面的代码

with(
  df,
  setNames(
    rev(
      stack(
        lapply(
          split(Prod, ID),
          function(x) {
            unique(
              apply(
                expand.grid(rep(list(x), length(x))),
                1,
                function(v) {
                  paste0(sort(unique(v)), collapse = "|")
                }
              )
            )
          }
        )
      )
    ), names(df)
  )
)

这给

   ID              Prod
1   1             Prod1
2   1       Prod1|Prod2
3   1       Prod1|Prod3
4   1 Prod1|Prod2|Prod3
5   1             Prod2
6   1       Prod2|Prod3
7   1             Prod3
8   2             Prod1
9   2       Prod1|Prod4
10  2             Prod4
11  3             Prod3
12  3       Prod3|Prod5
13  3             Prod5
14  4             Prod2
© www.soinside.com 2019 - 2024. All rights reserved.