【问题标题】:Create edgelist for all interactions from data.frame为 data.frame 中的所有交互创建边缘列表
【发布时间】:2018-01-26 07:16:35
【问题描述】:

我正在尝试在igraph 中进行网络分析,但在将我拥有的数据集转换为边缘列表(带有权重)时遇到了一些问题,因为列的数量不同。

数据集如下(df1)(当然要大得多):首先是主运营商的id(主运营商也可以是伙伴,反之亦然,所以id在边缘列表中保持不变)挑战在于合作伙伴的数量各不相同(从 0 到 40)并且必须考虑每次交互(不仅仅是“IdMain 到 IdPartnerX”)。

IdMain IdPartner1  IdPartner2  IdPartner3 IdPartner4 .....
1      4           3           7          6
2      3           1          NA          NA
3      1           4           2          NA
4      9           6           3          NA
.
.

我已经得到了使用 reshape 来执行此操作的有用提示,例如:

data_melt <- reshape2::melt(data, id.vars = "IdMain")
edgelist <- data_melt[!is.na(data_melt$value), c("IdMain", "value")]

但是,这只会创建一个“定向”边缘列表(从 Main 到 Partners)。我需要的是像下面这样的东西,每个交互都被记录下来。

Id1 Id2 
1   4    
1   3    
1   7    
1   6        
4   3
4   7
4   6
3   7
etc

有没有人知道最好的方法是什么?我还查看了igraph 库,但找不到执行此操作的函数。

【问题讨论】:

  • 如果您提供正确的reproduicble example,会更容易为您提供帮助。给出一些样本输入并为该样本输入提供所需的输出。理想情况下,我们可以复制/粘贴到 R 中以测试可能的解决方案。

标签: r dataframe igraph reshape reshape2


【解决方案1】:

不需要 reshape(2) 和熔化等。您只需要抓住列对的每个组合,然后将它们绑定在一起。

x <- read.table(text="IdMain IdPartner1  IdPartner2  IdPartner3 IdPartner4
1      4           3           7          6
2      3           1          NA          NA
3      1           4           2          NA
4      9           6           3          NA", header=TRUE)

idx <- t(combn(seq_along(x), 2))
edgelist <- lapply(1:nrow(idx), function(i) x[, c(idx[i, 1], idx[i, 2])])
edgelist <- lapply(edgelist, setNames, c("ID1","ID2"))
edgelist <- do.call(rbind, edgelist)
edgelist <- edgelist[rowSums(is.na(edgelist))==0, ]
edgelist
#    ID1 ID2
# 1    1   4
# 2    2   3
# 3    3   1
# 4    4   9
# 5    1   3
# 6    2   1
# 7    3   4
# 8    4   6
# 9    1   7
# 11   3   2
# 12   4   3
# 13   1   6
# 17   4   3
# 18   3   1
# 19   1   4
# 20   9   6
# 21   4   7
# 23   1   2
# 24   9   3
# 25   4   6
# 29   3   7 <--
# 31   4   2
# 32   6   3
# 33   3   6 <--
# 37   7   6 <--

【讨论】:

  • 感谢@emilliman5!您的解决方案有效,但是,创建的边缘列表仅采用 IdMain 并创建它们与 IdPartnerX 的连接。我理想地想要实现的是记录的所有连接。例如,对于第 1 行,结果还应包含 3,7; 3,6, 7,6 等。
  • 我的结果包含每一行的所有对,减去带有 NA 的那些。
  • 啊,我的错,我再次运行它,它运行良好,谢谢!
【解决方案2】:

使用下面的数据。您可以使用applycombn 实现看起来是您的目标。这将返回一个列表矩阵,其中包含对 data.frame 的行元素的成对比较

 myPairs <- apply(t(dat), 2, function(x) t(combn(x[!is.na(x)], 2)))

请注意,apply 的输出可能很挑剔,这里必须至少有一行带有 NA,这样apply 将返回一个列表而不是矩阵。

如果您想要一个 data.frame 结尾,请使用 do.callrbind 将矩阵放在一起,然后使用 data.framesetNames 进行对象强制并添加名称。

setNames(data.frame(do.call(rbind, myPairs)), c("Id1", "Id2"))
   Id1 Id2
1    1   4
2    1   3
3    1   7
4    1   6
5    4   3
6    4   7
7    4   6
8    3   7
9    3   6
10   7   6
11   2   3
12   2   1
13   3   1
14   3   1
15   3   4
16   3   2
17   1   4
18   1   2
19   4   2
20   4   9
21   4   6
22   4   3
23   9   6
24   9   3
25   6   3

数据

dat <- 
structure(list(IdMain = 1:4, IdPartner1 = c(4L, 3L, 1L, 9L), 
    IdPartner2 = c(3L, 1L, 4L, 6L), IdPartner3 = c(7L, NA, 2L, 
    3L), IdPartner4 = c(6L, NA, NA, NA)), .Names = c("IdMain", 
"IdPartner1", "IdPartner2", "IdPartner3", "IdPartner4"),
class = "data.frame", row.names = c(NA, -4L))

【讨论】:

  • 感谢@lmo!由于某种原因,我似乎无法重现您的结果,我还得到了一个边缘列表,其中只记录了从 IdMainPartnerX 的连接。
  • @julia_3010 如果您复制数据,然后复制并运行这两行代码,您将获得打印在我的答案中的结果。我不太确定您的第二个陈述,但我输出的前 10 行包括您想要的输出中的所有内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-27
  • 1970-01-01
  • 2022-01-09
相关资源
最近更新 更多