2017-01-10 10 views
2

Предположим, что я хотел обрезать дерево, состоящее из иерархии вложенных списков в R, на основе определенного критерия. Я могу сделать это «легко» достаточно с помощью lapply:Рекурсивно обрабатывать произвольные иерархии с помощью purrr

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

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

+0

Возможно, эта предыдущая моя работа уместна? http://stackoverflow.com/a/39869503/6197649 –

+0

Проблема в том, что я хочу сохранить древовидную структуру, за исключением обрезки. Я думал о создании пути с ограниченным узлом (например, xpath), затем сглаживался и, наконец, восстанавливал иерархию, но это казалось более сложным и более неэлегантным, чем просто использование лапши. –

+1

'purrr :: map' является заменой для' lapply' (с некоторыми дополнительными функциями), но это не изменит того, что вы здесь делаете. Вы можете проверить «rapply», который является рекурсивным, но который может быть немного затруднительным, чтобы работать правильно. – alistaire

ответ

3
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 
+0

Это очень элегантный (и впечатляющий)! Не могли бы вы рассказать мне, что здесь делает тильда? Я не понимаю, как этот символ используется - я знаю, что он используется в статистических моделях и графах ggplot, но я не знаю, как это интерпретируется R. –

+1

Спасибо. Тильда для формул, которые являются универсальным синтаксисом в R. Здесь они используются как ярлык для анонимных функций с '.x' и' .y' как неявные аргументы. См. 'Purrr' README или' help (map) 'например:' ~ .x + 1' эквивалентно 'function (.x) .x + 1' –

 Смежные вопросы

  • Нет связанных вопросов^_^