使用 purrr 递归处理任意层次结构

Posted

技术标签:

【中文标题】使用 purrr 递归处理任意层次结构【英文标题】:Processing arbitrary hierarchies recursively with purrr 【发布时间】:2017-05-25 05:56:22 【问题描述】:

假设我想根据一些特定的标准修剪一棵由 R 中嵌套列表的层次结构组成的树。我可以使用lapply 足够“轻松”地做到这一点:

# Based an example from the NetworkD3 documentation
# https://christophergandrud.github.io/networkD3/

URL <- paste0(
  "https://cdn.rawgit.com/christophergandrud/networkD3/",
  "master/JSONdata//flare.json")

flare <- jsonlite::fromJSON(URL, simplifyDataFrame = FALSE)

# Leaf nodes have a "size" attribute. Let's say we want to 
# prune all the nodes with size < 5000.

prune <- function(tree) 
  if ("children" %in% names(tree)) 
    p <- lapply(tree$children, prune)
    pp <- p[!unlist(lapply(p, is.null))]
    copied_tree = list()
    copied_tree$name = tree$name
    copied_tree$children = pp
    return(copied_tree)
   else if (tree$size < 5000) 
    return(NULL)
  
  return(tree)


pruned <- prune(flare)

R for Data Science 中,Hadley Wickham discusses 在许多场景中,purrr 可以替换 apply 系列函数来处理分层数据。但是,这些示例似乎处理单个嵌套列表,或者处理深度嵌套列表的特定节点。

有没有办法使用purrr 来完成上述递归任务?

【问题讨论】:

也许我之前的这个尝试是相关的? ***.com/a/39869503/6197649 问题是我想保留树结构,除了修剪。我想过创建一个分隔的节点路径(如 xpath),然后展平,最后重建层次结构,但这似乎比仅使用 lapply 更难,更不优雅。 purrr::maplapply 的替代品(带有一些附加功能),但它不会真正改变您在这里所做的事情。您可以查看rapply,它递归的,但要正确工作可能有点挑剔。 @alistaire 是对的,我的回答确实解决了问题的purrr 部分,而不是“递归”部分。我认为这是设计使purrr 缺少这样的递归功能,因为“安全”问题 参见blog.rstudio.org/2016/01/06/purrr-0-2-0,Hadley 说:“Base R 有 unlist(),但它很危险,因为它总是成功”。我认为它也适用于rapply()。我看看我能不能想到一个rapply() 解决方案... 【参考方案1】:
library(purrr)
prune_2 <- function(tree) 
  # print(tree$name)
  # print(map_lgl(tree$children, ~ "size" %in% names(.x)))
  tree$children %<>%  
    map_if(~ "children" %in% names(.x), prune_2) %>% 
    discard(~ if ("size" %in% names(.x)) .x$size < 5000 else FALSE)
  tree

pruned_2 <- prune_2(flare)
identical(pruned, pruned_2)
# [1] TRUE

【讨论】:

这非常优雅(而且令人印象深刻)!你能告诉我波浪号在这里做什么吗?我对这个符号的使用方式很模糊——我知道它用于统计模型和 ggplot 方面,但我不知道 R 是如何解释它的。 谢谢。波浪号用于 R 中通用语法的公式。在这里,它们用作匿名函数的快捷方式,.x.y 作为隐式参数。参见purrr README 或help(map) 例如:~ .x + 1 等价于function(.x) .x + 1

以上是关于使用 purrr 递归处理任意层次结构的主要内容,如果未能解决你的问题,请参考以下文章

利用递归层次遍历句法结构树(Stanfordcorenlp及nltk)

如何使用 Hive/Pig/MapReduce 展平递归层次结构

CTE递归获取树层次结构

使用MySQL 8.0递归CTE查找层次结构表中的直接后代并传播给父级

MySQL 5.7 对具有未知级别的层次结构数据的递归查询

sql SQL - 递归层次结构