【问题标题】:Creating a dataframe of edges from node information in R?从R中的节点信息创建边缘数据框?
【发布时间】:2021-10-26 14:59:06
【问题描述】:

我正在尝试基于二进制拆分创建一个边缘列表。 如果我有一个只包含节点号和其他一些指标的数据框,那么我可以手动为节点创建一个边列表。例如,如果我的数据框如下所示:

dfTest <- data.frame(
  node = c(1,2,3,4,5),
  var = c("milk", NA, "coffee", NA, NA),
  isLeaf = c(F, T, F, T, T)
)

> dfTest
  node    var isLeaf
1    1   milk  FALSE
2    2   <NA>   TRUE
3    3 coffee  FALSE
4    4   <NA>   TRUE
5    5   <NA>   TRUE

然后,基于varisLeaf 列,我可以手动创建一个边列表来连接节点。例如,由于节点 2 是叶节点,我知道节点 1 必须转到节点 2。然后(因为它们是二元拆分)我知道节点 1 也必须连接到节点 3。由于节点 4 和 5 是叶节点,我知道他们必须在节点 3 上拆分。

手动创建边缘列表如下所示:

edges <- data.frame(
  from = c(1, 1, 3, 3),
  to   = c(2, 3, 4, 5)
)

to 列很容易找到...它始终是c(2:length(dfTest$nodes))。在这种情况下2,3,4,5。但事实证明,from 专栏很难找到。

只是为了视觉帮助,生成的树看起来像这样:

有什么方法可以做到这一点而无需手动计算边缘?


编辑: 作为对答案的回应,我添加了一个稍大的数据集以供使用:

dfTest <- data.frame(
  node = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
  var = c("milk", "milk", NA, NA, "coffee", "sugar", NA, NA, "milk", NA, NA),
  isLeaf = c(F, F, T, T, F, F, T, T, F, T, T)
)

一点解释: 从var 列我知道牛奶(根/节点1)分裂成另一个牛奶(节点2)。然后我可以看到节点 2 拆分为 NA(节点 3)和 NA(节点 4)。我知道它们是二进制拆分,我知道节点 2 不能再拆分。所以,我必须回到上一个只有 1 个拆分的节点……在这种情况下,节点 1(即牛奶)然后在咖啡上向右拆分(节点 5)。同样,由于它们是二元拆分,我现在知道咖啡(节点 5)必须拆分为糖(节点 6)。 Sugar(节点 6)后跟 2 个 NA(节点 7 和 8)。现在,我必须回到咖啡(节点 5)并向右拆分以获取牛奶(节点 9),牛奶拆分为 2 个 NA(节点 10 和 11)

所需的节点/边缘列表应如下所示:

edges <- data.frame(
  from = c(1,2,2,1,5,6,6,5,9,9),
  to   = c(2,3,4,5,6,7,8,9,10,11)
)

这会产生这样的树:

【问题讨论】:

  • dfTest中的节点是否按拓扑顺序排列?
  • 老实说,我现在正在谷歌搜索图的拓扑排序。我以前没有听说过这个词。所以,我不确定
  • 我的意思是从您的数据中,如果您交换数据中节点 1 和 3 的行,您会得到不同的图表。所以为了得到一个特定的图,我们需要假设 dfTest 中的节点有一些排序
  • 你说得对,如果我们交换节点 1 和 3,我们会得到不同的图表。所以(根据我有限和简短的理解)我会说,是的,dfTest 中的节点是拓扑顺序的
  • 您无法以更好的格式获取数据?如果我得到这样的数据,我会很生气。也就是说,仅使用这些数据,您就可以根据 isLeaf 值的运行计数创建组(rleid 很有用),但我不确定这是否会扩展到更大的数据集。树需要变得更大/更深多少?

标签: r tree igraph edges


【解决方案1】:

根据你的更新,也许你可以试试下面的代码

grps <- split(dfTest, ~ cumsum(!isLeaf))

edges <- do.call(
  rbind,
  lapply(
    grps,
    function(x) {
      with(x, expand.grid(from = node[!isLeaf], to = node[isLeaf]))
    }
  )
)

for (k in seq_along(grps)) {
  if (nrow(grps[[k]]) == 1) {
    lleaf <- with(grps[[k + 1]], node[!isLeaf])
    rleaf <- with(grps[[k + 2]], node[!isLeaf])
    edges <- rbind(edges, data.frame(from = grps[[k]]$node, to = c(lleaf, rleaf)))
  }
}

edges <- `row.names<-`(edges[with(edges, order(from, to)), ], NULL)

给了

> edges
   from to
1     1  2
2     1  5
3     2  3
4     2  4
5     5  6
6     5  9
7     6  7
8     6  8
9     9 10
10    9 11

可视化

library(igraph)
graph_from_data_frame(edges) %>%
  plot(layout = layout_as_tree)

【讨论】:

  • igraph之王:D
  • @AnoushiravanR 哈哈,谢谢。我还在学习igraph :)
  • 你在开玩笑吧?!我很快就会开始,会有很多问题:D
  • @AnoushiravanR 不开玩笑。 igraph 对于很多应用有这么多的功能,但我所知道的只是对于一些常见的图问题的一小部分。
  • @AnoushiravanR 当然,您的问题也是我了解更多信息的好机会 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 1970-01-01
  • 2016-04-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多