从 ID 和分组向量生成边列表

Generating an edge list from ID and grouping vectors

我有一个 205,000 多行的数据框,格式如下:

df <- data.frame(project.id = c('SP001', 'SP001', 'SP001', 'SP017', 'SP018', 'SP017'),
                 supplier.id = c('1224', '5542', '7741', '1224', '2020', '9122'))

在实际的数据框中有 6700+ project.id 的唯一值。我想创建一个边缘列表,将参与过同一项目的供应商配对。

project.id = SP001 的预期最终结果:

to     from
1224   5542
1224   7741
5542   7741

到目前为止,我已经尝试使用 split 通过 project.id 创建列表,然后 运行 lapply+combn 生成 supplier.id 的所有可能组合在每个 list/group:

try.list <- split(df, df$project.id)
try.output <- lapply(try.list, function(x) combn(x$supplier.id, 2))

是否有更多 elegant/efficient(阅读 "computed in less than 2hrs")的方法来生成这样的东西?

任何帮助将不胜感激

您可以将它与自身合并,从而获得所有笛卡尔对:

 temp <- merge(df,df, by="project.id")
 res <- temp[ temp$supplier.id.x != temp$supplier.id.y , ]

> res

   project.id supplier.id.x supplier.id.y
2       SP001          1224          5542
3       SP001          1224          7741
4       SP001          5542          1224
6       SP001          5542          7741
7       SP001          7741          1224
8       SP001          7741          5542
11      SP017          1224          9122
12      SP017          9122          1224

您可以使用 dplyr 包来代替 splitlapply

df <- data.frame(project.id = c('SP001', 'SP001', 'SP001', 'SP017', 'SP018', 'SP017'),
                 supplier.id = c('1224', '5542', '7741', '1224', '2020', '9122'),
                 stringsAsFactors = FALSE)

library(dplyr)

df %>% group_by(project.id) %>%
  filter(n()>=2) %>% group_by(project.id) %>%
 do(data.frame(t(combn(.$supplier.id, 2)), stringsAsFactors=FALSE))
# Source: local data frame [4 x 3]
# Groups: project.id [2]

#   project.id    X1    X2
#        (chr) (chr) (chr)
# 1      SP001  1224  5542
# 2      SP001  1224  7741
# 3      SP001  5542  7741
# 4      SP017  1224  9122

我们可以试试 igraph

library(igraph)
m1 <- get.edgelist(graph.adjacency(crossprod(table(df))))
m1[m1[,1]!= m1[,2],]
#      [,1]   [,2]  
#[1,] "1224" "5542"
#[2,] "1224" "7741"
#[3,] "1224" "9122"
#[4,] "5542" "1224"
#[5,] "5542" "7741"
#[6,] "7741" "1224"
#[7,] "7741" "5542"
#[8,] "9122" "1224"