Адрес igraph
. Эта функция принимает результат от Parse_annotator
в качестве своего ввода, поэтому ptext
в вашем примере. NLP::Tree_parse
уже создает приятную древовидную структуру, поэтому идея здесь состоит в том, чтобы пересечь ее рекурсивно и создать edgelist для подключения к igraph
. Edgelist - это всего лишь 2-столбчатая матрица значений head-> tail.
Для того, чтобы создать грани между соответствующими узлами, они должны иметь уникальные идентификаторы. Я сделал это, добавив последовательность целых чисел (используя regmatches<-
) в слова в тексте до использования Tree_parse
.
Внутренняя функция edgemaker
проходит по дереву, заполняя edgelist
как оно идет. Есть варианты окраски листьев отдельно от остальных узлов, но если вы передадите опцию vertex.label.color
, она будет окрашивать их все одинаково.
## Make a graph from Tree_parse result
parse2graph <- function(ptext, leaf.color='chartreuse4', label.color='blue4',
title=NULL, cex.main=.9, ...) {
stopifnot(require(NLP) && require(igraph))
## Replace words with unique versions
ms <- gregexpr("[^() ]+", ptext) # just ignoring spaces and brackets?
words <- regmatches(ptext, ms)[[1]] # just words
regmatches(ptext, ms) <- list(paste0(words, seq.int(length(words)))) # add id to words
## Going to construct an edgelist and pass that to igraph
## allocate here since we know the size (number of nodes - 1) and -1 more to exclude 'TOP'
edgelist <- matrix('', nrow=length(words)-2, ncol=2)
## Function to fill in edgelist in place
edgemaker <- (function() {
i <- 0 # row counter
g <- function(node) { # the recursive function
if (inherits(node, "Tree")) { # only recurse subtrees
if ((val <- node$value) != 'TOP1') { # skip 'TOP' node (added '1' above)
for (child in node$children) {
childval <- if(inherits(child, "Tree")) child$value else child
i <<- i+1
edgelist[i,1:2] <<- c(val, childval)
}
}
invisible(lapply(node$children, g))
}
}
})()
## Create the edgelist from the parse tree
edgemaker(Tree_parse(ptext))
## Make the graph, add options for coloring leaves separately
g <- graph_from_edgelist(edgelist)
vertex_attr(g, 'label.color') <- label.color # non-leaf colors
vertex_attr(g, 'label.color', V(g)[!degree(g, mode='out')]) <- leaf.color
V(g)$label <- sub("\\d+", '', V(g)$name) # remove the numbers for labels
plot(g, layout=layout.reingold.tilford, ...)
if (!missing(title)) title(title, cex.main=cex.main)
}
Таким образом, используя ваш пример, строка x
и ее аннотированный версия ptext
, которая выглядит как
x <- 'Scroll bar does not work the best either.'
ptext
# [1] "(TOP (S (NP (NNP Scroll) (NN bar)) (VP (VBZ does) (RB not) (VP (VB work) (NP (DT the) (JJS best)) (ADVP (RB either))))(. .)))"
Создание графа по телефону
library(igraph)
library(NLP)
parse2graph(ptext, # plus optional graphing parameters
title = sprintf("'%s'", x), margin=-0.05,
vertex.color=NA, vertex.frame.color=NA,
vertex.label.font=2, vertex.label.cex=1.5, asp=0.5,
edge.width=1.5, edge.color='black', edge.arrow.size=0)
Хорошо, но что после этого? – Indi
Возможно через https://en.wikibooks.org/wiki/LaTeX/Linguistics#tikz-qtree? – Reactormonk