Рекурсивная обработка произвольных иерархий с помощью purrr

Предположим, что я хочу обрезать дерево, состоящее из иерархии вложенных списков в 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 Хэдли Уикхэм обсуждает число сценариев, в которых purrr может заменить семейство функций apply для обработки иерархических данных. Однако эти примеры, похоже, имеют дело либо с одиночными вложенными списками, либо с конкретными узлами глубоко вложенных списков.

Есть ли способ использовать purrr для выполнения рекурсивных задач, подобных описанной выше?


person David Bruce Borenstein    schedule 10.01.2017    source источник
comment
Может быть, эта моя предыдущая попытка актуальна? stackoverflow.com/a/39869503/6197649   -  person Aurèle    schedule 10.01.2017
comment
Проблема в том, что я хочу сохранить древовидную структуру, кроме обрезки. Я думал создать путь узла с разделителями (например, xpath), затем сгладить и, наконец, восстановить иерархию, но это казалось более сложным и неэлегантным, чем просто использование lapply.   -  person David Bruce Borenstein    schedule 10.01.2017
comment
purrr::map является заменой lapply (с некоторыми дополнениями), но на самом деле это не изменит того, что вы здесь делаете. Вы можете проверить rapply, который является рекурсивным, но может быть немного привередливым, чтобы правильно работать.   -  person alistaire    schedule 11.01.2017
comment
@alistaire прав, и мой ответ действительно касается purrr части вопроса, а не «рекурсивной» части. Я думаю, что purrr не имеет такой рекурсивной функции по замыслу из соображений безопасности.   -  person Aurèle    schedule 11.01.2017
comment
См. blog.rstudio.org/2016/01/06/ purrr-0-2-0, где Хэдли говорит: В Base R есть unlist(), но это опасно, потому что всегда завершается успешно. Думаю, это относится и к rapply(). Я посмотрю, смогу ли я придумать rapply() решение...   -  person Aurèle    schedule 11.01.2017


Ответы (1)


person    schedule
comment
Это очень элегантно (и впечатляюще)! Можете ли вы сказать мне, что здесь делает тильда? Я не совсем понимаю, как используется этот символ — я знаю, что он используется в статистических моделях и аспектах ggplot, но я не знаю, как он интерпретируется Р. - person David Bruce Borenstein; 11.01.2017
comment
Спасибо. Тильда предназначена для формул, которые являются универсальным синтаксисом в R. Здесь они используются в качестве ярлыка для анонимных функций с .x и .y в качестве неявных аргументов. См. purrr README или help(map), например: ~ .x + 1 эквивалентно function(.x) .x + 1 - person Aurèle; 11.01.2017