【问题标题】:R: Convert pairwise data to adjacency dataset in R [duplicate]R:将成对数据转换为R中的邻接数据集[重复]
【发布时间】:2018-08-09 17:57:52
【问题描述】:

假设我有以下数据集:

set.seed(42)
test <- data.frame(event_id = stringi::stri_rand_strings(1000, 2, '[A-Z]'), person_id = floor(runif(1000, min=0, max=500)))

>head(test)
  event_id person_id
1       EP       438
2       IX       227
3       AV       212
4       GX       469
5       QF       193
6       MM       222

我想将其转换为邻接数据集,其中行和列是 person_id,值是这些人出现的 event_id 总数。

我试着做这样的事情:

adjacency_df <- test %>%
  select('event_id', 'person_id') %>%
  melt('event_id', value.name = 'invitee_id') %>%
  dcast(invitee_id~invitee_id, fun.aggregate = n_distinct, value.var = 'event_id')

但是在尝试将其转换为邻接矩阵,然后计算不是对角项的非零值的总数,如下所示:

#convert to a matrix, and rename rownames
adjacency_matrix <- as.matrix(sapply(adjacency_df[, -1], as.numeric))  
rownames(adjacency_matrix) <- colnames(adjacency_matrix)

#identify if only the diagonal of the matrix is non-zero
all(adjacency_matrix[lower.tri(adjacency_matrix)] == 0, adjacency_matrix[upper.tri(adjacency_matrix)] == 0)

我知道所有非对角线值都为零。

> all(adjacency_matrix[lower.tri(adjacency_matrix)] == 0, adjacency_matrix[upper.tri(adjacency_matrix)] == 0)
[1] TRUE

最有效的方法是什么(注意数据集包含 200 万个观测值)?

我已经尝试了 cmets 部分中建议的技术,并在我的实际数据集上得到以下错误:

adjacency_df <- crossprod(table(test)
Error in table(adjacency_df) : 
  attempt to make a table with >= 2^31 elements

所以我需要一个更好的方法

【问题讨论】:

  • 看看这个问题:stackoverflow.com/questions/13281303/…。 A5C1D2H2I1M1N2O1R2T1 的回答提到了crossprod(table(df))
  • 请参阅编辑。我尝试过crossprod方法,但效果不佳。
  • igraph 库是否满足您的需求?即,类似library(igraph) ; g &lt;- graph_from_edgelist(as.matrix(test), directed = F) ; V(g)$type &lt;- V(g)$name %in% test$event_id ; as_adj(bipartite_projection(g, which = "false"))

标签: r


【解决方案1】:

由于矩阵大小似乎是问题所在,您可以使用crossprodMatrix 版本执行此操作,如下所示:

library(Matrix)

mat <- with(
  test,
  sparseMatrix(
    i = as.numeric(factor(event_id)),
    j = as.numeric(factor(person_id)),
    dimnames = list(levels(factor(event_id)), levels(factor(person_id)))
  )
)

crossprod(mat)

Matrix 包创建稀疏矩阵,因此它应该能够处理更多的单元格。

【讨论】:

  • 非常感谢。我已经在这个问题上工作了一个星期——这和你提交的评论都有效。 igraph 解决方案很好,因为我可以方便地从中生成边缘列表。有没有一种从稀疏矩阵生成边缘列表的简单方法?
  • 很高兴这对您有所帮助。看起来summary(mat) 会这样做:stackoverflow.com/questions/15849641/…
  • 您是否碰巧将生成的邻接矩阵转换为可以在 igraph 库中解释的图形对象?我已经尝试了一个小时,似乎无法弄清楚如何让它在通过这个产生的邻接矩阵中读取。 @杰克费希尔
  • @Parseltongue 为此,我会坚持我在对您的问题的评论中提到的方法。在那里的代码中,g 是 igraph 图形对象。如果你想要二分投影,你会做类似bp &lt;- bipartite_projection(g, which = "false")的事情。
【解决方案2】:

不确定这是否会解决您使用crossprod 的错误-但也许可以尝试这样。数据如上:

library(dplyr)

 set.seed(42)
  test <-
    data.frame(
      event_id = stringi::stri_rand_strings(1000, 2, '[A-Z]'),
      person_id = floor(runif(1000, min = 0, max = 500))
    )

event_id 分组并从中制作一个表格:

out <- test %>%
  group_by(event_id) %>%
  table() 

使用该分组输出作为crossprod 的输入:

x <- crossprod(out)

看看那个大矩阵的一小部分:

> x[1:20, 1:20]
         person_id
person_id 0 2 3 4 5 6 9 10 11 12 13 14 15 16 17 18 19 20 21 23
       0  1 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0
       2  0 5 0 0 0 0 0  0  0  0  0  0  0  1  0  0  0  0  0  0
       3  0 0 4 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0
       4  0 0 0 3 0 0 0  0  0  0  1  0  0  0  0  0  0  0  0  0
       5  0 0 0 0 1 0 0  0  0  0  0  0  0  0  0  0  0  0  0  0
       6  0 0 0 0 0 1 0  0  0  0  0  0  0  0  0  0  0  0  0  0
       9  0 0 0 0 0 0 3  0  0  0  0  0  0  0  0  0  0  0  0  0
       10 0 0 0 0 0 0 0  4  0  0  0  0  0  0  0  0  0  0  0  0
       11 0 0 0 0 0 0 0  0  1  0  0  0  0  0  0  0  0  0  0  0
       12 0 0 0 0 0 0 0  0  0  2  0  0  0  0  0  0  0  0  0  0
       13 0 0 0 1 0 0 0  0  0  0  2  0  0  0  0  0  0  0  0  0
       14 0 0 0 0 0 0 0  0  0  0  0  3  0  0  0  0  0  0  0  0
       15 0 0 0 0 0 0 0  0  0  0  0  0  1  0  0  0  0  0  0  0
       16 0 1 0 0 0 0 0  0  0  0  0  0  0  3  0  0  0  0  0  0
       17 0 0 0 0 0 0 0  0  0  0  0  0  0  0  1  0  0  0  0  0
       18 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  5  0  0  0  0
       19 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  3  0  0  0
       20 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  3  0  0
       21 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  2  0
       23 0 0 0 0 0 0 0  0  0  0  0  0  0  0  0  0  0  0  0  3

这是否接近您期望的输出?很难判断它是否有效——也许看看这个较小的示例数据集:

{
  set.seed(42)
  test <-
    data.frame(
      event_id = sample(c("AB", "LM", "YZ"), size = 10, replace = TRUE),
      person_id = 1:10
    )
  out <- test %>%
    group_by(event_id) %>%
    table() 
  x <- crossprod(out)
  print(out)
  x
}

        person_id
event_id 1 2 3 4 5 6 7 8 9 10
      AB 0 0 1 0 0 0 0 1 0  0
      LM 0 0 0 0 1 1 0 0 1  0
      YZ 1 1 0 1 0 0 1 0 0  1
         person_id
person_id 1 2 3 4 5 6 7 8 9 10
       1  1 1 0 1 0 0 1 0 0  1
       2  1 1 0 1 0 0 1 0 0  1
       3  0 0 1 0 0 0 0 1 0  0
       4  1 1 0 1 0 0 1 0 0  1
       5  0 0 0 0 1 1 0 0 1  0
       6  0 0 0 0 1 1 0 0 1  0
       7  1 1 0 1 0 0 1 0 0  1
       8  0 0 1 0 0 0 0 1 0  0
       9  0 0 0 0 1 1 0 0 1  0
       10 1 1 0 1 0 0 1 0 0  1

【讨论】:

  • 感谢您的想法。不幸的是,我得到了同样的内存错误:&gt; out &lt;- calendar_subset %&gt;% + select('meeting_id', 'invitee_id') %&gt;% + group_by('meeting_id') %&gt;% + table() Error in table(.) : attempt to make a table with &gt;= 2^31 elements
  • @Parseltongue - 很公平,真的不足为奇!希望杰克的回答能彻底解决您的问题。
  • 非常感谢您抽出宝贵的时间!
猜你喜欢
  • 2014-07-31
  • 1970-01-01
  • 2015-09-08
  • 1970-01-01
  • 2018-06-26
  • 2018-08-19
  • 2019-01-16
  • 2020-06-14
  • 2022-06-10
相关资源
最近更新 更多