Как разобрать строки в иерархию или дерево в R - PullRequest
1 голос
/ 05 мая 2020

Есть ли способ разобрать строки, представляющие группы, в иерархическую структуру в R?

Скажем, у меня есть группы, структурированные следующим образом:

"1", "1.1", "1.1.1", "1.1.1.1", "1.1.2", "1.1.3", "1.1.3.1", "1.1.3.2", "1.1.3.3", "1.2",       
"1.2.1", "1.2.1.1", "1.2.1.2", "1.2.1.2.1", "1.2.2", "1.2.2.1", "1.2.2.2"

Естественно, Уровень равен «1», за которым следуют два основных разбиения «1.1» и «1.2» и так далее.

Может ли это быть проанализировано в R в иерархическую структуру, а «уровни» легко извлечены (например, как указано выше - если мне нужен второй по величине уровень, R возвращает «1,1» и «1,2»)

Ответы [ 2 ]

2 голосов
/ 05 мая 2020

1) igraph

Мы можем преобразовать x, показанное в примечании в конце, в igraph g, а затем igraph выполнит с ним множество операций.

library(igraph)
DF <- data.frame(parent = sub("\\.\\d+$", "", x), name = x, stringsAsFactors = FALSE)
DF <- subset(DF, parent != name)  # remove loop in root to itself
g <- graph.data.frame(DF)

Parent

node <- "1.1"
setdiff(names(subcomponent(g, node, mode = "in")), node)
## [1] "1"

Потомки узла

node <- "1.2"
setdiff(names(neighborhood(g, nodes = node, mode = "out")[[1]]), node)
## [1] "1.2.1" "1.2.2"

Все потомки узла

node <- "1.2"
setdiff(names(subcomponent(g, node, mode = "out")), node)
## [1] "1.2.1"     "1.2.2"     "1.2.1.2"   "1.2.1.1"   "1.2.2.1"   "1.2.2.2"  
## [7] "1.2.1.2.1"

Глубина каждого узла

dfs(g, root = "1", dist = TRUE)$dist
##         1       1.1     1.1.1     1.1.3       1.2     1.2.1   1.2.1.2     1.2.2 
##         0         1         2         2         1         2         3         2 
##   1.1.1.1     1.1.2   1.1.3.1   1.1.3.2   1.1.3.3   1.2.1.1 1.2.1.2.1   1.2.2.1 
##         3         2         3         3         3         3         4         3 
##   1.2.2.2 
##         3 

Листьев

names(which(degree(g, mode = "out") == 0))
## [1] "1.1.1.1"   "1.1.2"     "1.1.3.1"   "1.1.3.2"   "1.1.3.3"   "1.2.1.1"  
## [7] "1.2.1.2.1" "1.2.2.1"   "1.2.2.2"  

График

plot(g, layout = layout_as_tree(g))

(продолжение после графика)

screenshot

Мы также можем использовать пакет rviewgraph:

library(rviewgraph)
rViewGraph(g)

2) строки

Используя x из примечания в конце, мы можем применить к нему обычные строковые операции напрямую, так что, возможно, нет необходимости преобразовывать данные вообще .

Непосредственные дочерние элементы данного узла

parent <- "1"
pat <- sprintf("^%s\\.\\d+$", parent)
grep(pat, x, value = TRUE)
## [1] "1.1" "1.2"

Все узлы заданной глубины

depth <- 2
pat2 <- sprintf("^\\d+(\\.\\d+){%d}$", depth-1)
grep(pat2, x, value = TRUE)
[1] "1.1" "1.2"

или

depth <- 2
pat2 <- sprintf("^%s$", paste(rep("\\d+", depth), collapse = "\\."))
grep(pat2, x, value = TRUE)
## [1] "1.1" "1.2"

Список с одним компонентом на глубина

Каждый компонент перечисляет все узлы на этой глубине.

split(x, nchar(gsub("\\d", "", x)) + 1)
## $`1`
## [1] "1"
##
## $`2`
## [1] "1.1" "1.2"
##
## $`3`
## [1] "1.1.1" "1.1.2" "1.1.3" "1.2.1" "1.2.2"
##
## $`4`
## [1] "1.1.1.1" "1.1.3.1" "1.1.3.2" "1.1.3.3" "1.2.1.1" "1.2.1.2" "1.2.2.1"
## [8] "1.2.2.2"
##
## $`5`
## [1] "1.2.1.2.1"

Родитель данного узла

Мы можем опустить строку, отмеченную ##, если это нормально иметь root п ode быть его собственным родителем.

node <- "1.1"
parent <- sub("\\.\\d+$", "", node)
parent <- setdiff(parent, node) ##
parent
## [1] "1"

Братья и сестры данного узла

Получить потомков родителя, а затем удалить входной узел из этого результата.

node <- "1.1"
parent <- sub("\\.\\d+$", "", node)
pat <- sprintf("^%s\\.\\d+$", parent)
setdiff(grep(pat, x, value = TRUE), node)
## [1] "1.2"

Все потомки данный узел

node <- "1.2"
x[startsWith(x, paste0(node, "."))]
## [1] "1.2.1"     "1.2.1.1"   "1.2.1.2"   "1.2.1.2.1" "1.2.2"     "1.2.2.1"  
## [7] "1.2.2.2" 

Все предки данного узла

node <- "1.2.1"
x[startsWith(node, paste0(x, "."))]
## [1] "1"   "1.2"

Листовые узлы

leaf <- x[sapply(x, function(st) sum(startsWith(x, st))) == 1]
leaf
## [1] "1.1.1.1"   "1.1.2"     "1.1.3.1"   "1.1.3.2"   "1.1.3.3"   "1.2.1.1"  
## [7] "1.2.1.2.1" "1.2.2.1"   "1.2.2.2"  

Внутренние узлы

setdiff(x, leaf)
## [1] "1"       "1.1"     "1.1.1"   "1.1.3"   "1.2"     "1.2.1"   "1.2.1.2"
## [8] "1.2.2"  

Примечание

x <- c("1", "1.1", "1.1.1", "1.1.1.1", "1.1.2", "1.1.3", "1.1.3.1", 
"1.1.3.2", "1.1.3.3", "1.2",       
"1.2.1", "1.2.1.1", "1.2.1.2", "1.2.1.2.1", "1.2.2", "1.2.2.1", "1.2.2.2")
1 голос
/ 05 мая 2020

Одним из вариантов может быть использование str_split для определения уровня глубины.

library(stringr)
library(dplyr)
library(purrr)
strings <- c("1", "1.1", "1.1.1", "1.1.1.1", "1.1.2", "1.1.3", "1.1.3.1", "1.1.3.2", "1.1.3.3", "1.2","1.2.1", "1.2.1.1", "1.2.1.2", "1.2.1.2.1", "1.2.2", "1.2.2.1", "1.2.2.2")


strings %>%
  strsplit("\\.") %>%
  map(~set_names(.x,paste0("DepthLevel",seq_along(.x)))) %>%
  bind_rows
## A tibble: 17 x 5
#   DepthLevel1 DepthLevel2 DepthLevel3 DepthLevel4 DepthLevel5
#   <chr>       <chr>       <chr>       <chr>       <chr>      
# 1 1           NA          NA          NA          NA         
# 2 1           1           NA          NA          NA         
# 3 1           1           1           NA          NA         
# 4 1           1           1           1           NA         
# 5 1           1           2           NA          NA         
# 6 1           1           3           NA          NA         
# 7 1           1           3           1           NA         
# 8 1           1           3           2           NA         
# 9 1           1           3           3           NA         
#10 1           2           NA          NA          NA         
#11 1           2           1           NA          NA         
#12 1           2           1           1           NA         
#13 1           2           1           2           NA         
#14 1           2           1           2           1          
#15 1           2           2           NA          NA         
#16 1           2           2           1           NA         
#17 1           2           2           2           NA   
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...