【问题标题】:tidyverse: all permutations of categoriestidyverse:类别的所有排列
【发布时间】:2019-12-15 09:37:51
【问题描述】:

这里有一个问题:我有来自一组 N 个元素的 M 个元素的所有可能组合(N 选择 M)。每个组合都有一个分配的值。

N = 5 和 M = 3 的示例:

library(tidyverse)

df <- letters[1:5] %>% combn( m = 3 ) %>% t() %>% 
  as_tibble( .name_repair = function(x) {paste0('id', 1:length(x))} )
df$val <- runif( nrow(df) )

这给出了一组 10 种组合:

# A tibble: 10 x 4
   id1   id2   id3      val
   <chr> <chr> <chr>  <dbl>
 1 a     b     c     0.713 
 2 a     b     d     0.314 
 3 a     b     e     0.831 
 4 a     c     d     0.555 
 5 a     c     e     0.915 
 6 a     d     e     0.954 
 7 b     c     d     0.131 
 8 b     c     e     0.0583
 9 b     d     e     0.533 
10 c     d     e     0.857 

现在我想添加组合,使得结果表示选择 M 个元素而不替换 (N!/(NM)!),但保留每个 M 个元素集合的值

因此,继续使用示例,结果应该包含 543=60 行。例如,我可以在列的“手动”排列中做到这一点:

# add missing combinations
df_perm <- df %>% bind_rows(
  # 1, 3, 2
  df %>% mutate( tmp = id2, id2 = id3, id3 = tmp ) %>%
    select( -tmp )
) %>% bind_rows(
  # 2, 1, 3
  df %>% mutate( tmp = id1, id1 = id2, id2 = tmp ) %>%
    select( -tmp )
) %>% bind_rows(
  # 2, 3, 1
  df %>% mutate( tmp = id1, id1 = id2, id2 = id3, id3 = tmp ) %>%
    select( -tmp )
) %>% bind_rows(
  # 3, 1, 2
  df %>% mutate( tmp = id2, id2 = id1, id1 = id3, id3 = tmp ) %>%
    select( -tmp )
) %>% bind_rows(
  # 3, 2, 1
  df %>% mutate( tmp = id3, id3 = id1, id1 = tmp ) %>%
    select( -tmp )
)

但是,对于 M>3,这很快变得不可行。

实现相同结果的更优雅的方法是什么?

【问题讨论】:

  • 最好设置种子,以便轻松验证结果。
  • 感谢@JosephWood 的指点,下次我会记住的。

标签: r dplyr combinations permutation tidyverse


【解决方案1】:

当我阅读您的问题时,您似乎已经从一组大小为 N 的大小 M 的每个可能组合分配了一个值。然后您希望将每个组合的值映射到其排列。

例如,如果a, b, d 的组合值为 0.4,那么您希望 a, b, da, d, bb, a, db, d, ad, b, ad, a, b 的值为0.4。

首先,获取向量1:M 的所有可能排列,其中M 是上面定义的每个组合的元素数:

M <- 3
perm_mat <- gtools::permutations(M, M)

然后按照上述排列排列df 的列:

perm_df <- purrr::map_df(1:nrow(perm_mat), function(i){
  df_curr <- df[,c(perm_mat[i,], M+1)]
  colnames(df_curr) <- colnames(df)
  df_curr
})

这会产生以下输出(前二十行):

   V1    V2    V3       val
   <chr> <chr> <chr>  <dbl>
 1 a     b     c     0.0682
 2 a     b     d     0.735 
 3 a     b     e     0.0336
 4 a     c     d     0.965 
 5 a     c     e     0.889 
 6 a     d     e     0.796 
 7 b     c     d     0.792 
 8 b     c     e     0.508 
 9 b     d     e     0.606 
10 c     d     e     0.623 
11 a     c     b     0.0682
12 a     d     b     0.735 
13 a     e     b     0.0336
14 a     d     c     0.965 
15 a     e     c     0.889 
16 a     e     d     0.796 
17 b     d     c     0.792 
18 b     e     c     0.508 
19 b     e     d     0.606 
20 c     e     d     0.623 

请注意,values 列中的数字与原始帖子不同,因为我在运行 runif 之前使用了不同的种子。

【讨论】:

  • 是的,这会产生所需的输出。太感谢了!您的解决方案以动态方式有效地执行了我手动执行的相同操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-19
  • 1970-01-01
  • 1970-01-01
  • 2015-12-16
  • 1970-01-01
相关资源
最近更新 更多