【问题标题】:Using purrr or igraph (or any other method instead of nested loops) to generate all possible combinations of directed connections?使用 purrr 或 igraph(或任何其他方法而不是嵌套循环)来生成有向连接的所有可能组合?
【发布时间】:2019-12-26 04:33:28
【问题描述】:

我有一个具有这种结构的数据集:

df
#>   Instance Alice_prefers Bob_prefers Charlie_prefers
#> 1        1           Bob     Charlie           Alice
#> 2        2           Bob       Alice             Bob
#> 3        3           Bob     Charlie             Bob

我想要的输出是一个数据框,其中:

  • 数据帧的每一行都是 Alice、Bob 和 Charlie 可能偏好的一种组合
  • 数据帧包含所有可能的组合,即数据帧中的行数等于可能的组合数。
  • 在任何给定的组合(即行)中,一个人偏爱另一个人,他们不能偏爱自己,即爱丽丝可以选择偏爱鲍勃或查理,但不能偏爱爱丽丝,也不能偏爱鲍勃和 em> 查理在同一个例子中。

    因此,完整的期望输出是:

#>   instance alice_prefers bob_prefers charlie_prefers
#> 1        1           Bob       Alice           Alice
#> 2        2           Bob       Alice             Bob
#> 3        3           Bob     Charlie           Alice
#> 4        4           Bob     Charlie             Bob
#> 5        5       Charlie       Alice           Alice
#> 6        6       Charlie       Alice             Bob
#> 7        7       Charlie     Charlie           Alice
#> 8        8       Charlie     Charlie             Bob

我当前的解决方案有效(代码如下),但看起来非常笨拙,而且显然不能推广到更多人,而不仅仅是 Alice、Bob 和 Charlie (k = 3)。我正在使用嵌套循环。

我有两个问题:

  1. 必须有一种更简单的方法来生成此输出,可以使用purrrigraph 或其他方式——有更好的方法吗?我之前没用过igraph

  2. 目前,问题针对 3 个人 (k = 3):Alice、Bob、Charlie。有没有什么方法可以很容易地概括解决方案来增加更多的人,所以如果我想生成 Alice、Bob、Charlie、Don 和 Enid 的组合,我可以调用一个函数,传递 k = 5作为论据?人名可以是任何名称,我只是将他们设置为按照字母表来帮助我处理这个问题。

choices_alice <- c("Bob", "Charlie")
choices_bob <- c("Alice", "Charlie")
choices_charlie <- c("Alice", "Bob")

get_combinations <- function(choices_alice, choices_bob, choices_charlie) {
  instance <- numeric()
  alice_prefers <- character()
  bob_prefers <- character()
  charlie_prefers <- character()
  id <- 1
  for (a_counter in seq_along(choices_alice)) {
    for (b_counter in seq_along(choices_bob)){
      for (c_counter in seq_along(choices_charlie)){
        alice_prefers[id] <- choices_alice[a_counter]
        bob_prefers[id] <- choices_bob[b_counter]
        charlie_prefers[id] <- choices_charlie[c_counter]
        instance[id] <- id
        id <- id + 1
      }

    }
  }
  data.frame(instance, alice_prefers, bob_prefers, charlie_prefers, stringsAsFactors=FALSE)
}

df <- get_combinations(choices_alice, choices_bob, choices_charlie)
df

【问题讨论】:

  • 您需要expand.grid(choices_alice, choices_bob, choices_charlie) 吗?

标签: r igraph tidyverse purrr


【解决方案1】:

tidyr 中的 crossing 函数(或 base 中的 expand.grid)可以将多个向量转换为所有组合的表。

但要让您的解决方案扩展到任意数量的节点(并确保每个节点不包含自身),您可能还需要使用一些 purrr。

library(tidyr)
library(purrr)

# Can be any number of nodes
nodes <- c("Alice", "Bob", "Charlie")

# Create a list: for each node, what are all other nodes
possible_nodes <- map(nodes, ~ setdiff(nodes, .))
names(possible_nodes) <- nodes

# Call tidyr's crossing on all of these arguments
crossing(!!!possible_nodes)

请注意,!!! 告诉 cross 您想使用该列表中的所有参数调用它,因此它类似于 crossing(Alice = --, Bob = --, Charlie = --)


以上代码适用于任意数量的节点。例如,将nodes 设置为

nodes <- c("Alice", "Bob", "Charlie", "Dave", "Eric", "Frank")

导致结果

# A tibble: 15,625 x 6
   Alice Bob   Charlie Dave  Eric  Frank  
   <chr> <chr> <chr>   <chr> <chr> <chr>  
 1 Bob   Alice Alice   Alice Alice Alice  
 2 Bob   Alice Alice   Alice Alice Bob    
 3 Bob   Alice Alice   Alice Alice Charlie
 4 Bob   Alice Alice   Alice Alice Dave   
 5 Bob   Alice Alice   Alice Alice Eric   
 6 Bob   Alice Alice   Alice Bob   Alice  
 7 Bob   Alice Alice   Alice Bob   Bob    
 8 Bob   Alice Alice   Alice Bob   Charlie
 9 Bob   Alice Alice   Alice Bob   Dave   
10 Bob   Alice Alice   Alice Bob   Eric   
# … with 15,615 more rows

【讨论】:

  • 应该是possible_nodes &lt;- map(nodes, ~ setdiff(nodes, .)),而不是possible_nodes &lt;- map(nodes, ~ setdiff(people, .))?感谢 Dave 和 Ronak。我应该让你们都知道,你们各自的工作让我的生活变得更好、更快乐,所以谢谢你们。当然,Stack Overflow 会要求我删除这部分评论,我会的。
  • 我想知道crossing(!!!possible_nodes) 中的!!! 是做什么的?我试过谷歌搜索,但谷歌一直忽略标点符号。
  • 三次感叹号是修改dplyr中的非标准评估的功能,这是一个深兔子洞。更多信息johnmackintosh.com/2018-02-19-theory-free-tidyeval
  • @JeremyK。是的,它应该是nodes 而不是people(已修复)。我还尝试添加!!! 的解释。很高兴它对您有所帮助!
猜你喜欢
  • 1970-01-01
  • 2023-03-12
  • 2019-10-17
  • 2018-01-11
  • 2021-11-18
  • 1970-01-01
  • 2017-08-05
  • 2021-03-29
  • 1970-01-01
相关资源
最近更新 更多