我有一个205,000多行的数据框格式如下:
df <- data.frame(project.id = c('SP001', 'SP001', 'SP001', 'SP017', 'SP018', 'SP017'),
supplier.id = c('1224', '5542', '7741', '1224', '2020', '9122'))
在实际数据框中,有{67}个唯一值project.id
。我想创建一个边缘列表,将已经参与同一项目的供应商配对。
project.id = SP001
所需的最终结果:
to from
1224 5542
1224 7741
5542 7741
到目前为止,我已尝试使用split
按project.id创建列表,然后运行lapply+combn
以生成每个列表/组中supplier.id
的所有可能组合:
try.list <- split(df, df$project.id)
try.output <- lapply(try.list, function(x) combn(x$supplier.id, 2))
是否有更优雅/高效(阅读&#34;计算时间不到2小时&#34;)的方式来生成这样的东西?
非常感谢任何帮助
答案 0 :(得分:3)
你可以将它与自身合并,从而获得所有笛卡尔对:
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
答案 1 :(得分:3)
我们可以尝试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"
答案 2 :(得分:2)
您可以使用split
包,而不是lapply
和dplyr
。
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