2015-11-02 7 views
6

Ich möchte die Analyse (POS-Tagging) von openNLP als eine Baumstruktur Visualisierung anzeigen. Im Folgenden stelle ich den Parse-Baum von openNLP, aber ich kann nicht als visueller Baum gemeinsamen Python's parsing plotten.Visualisieren Parse Struktur

install.packages(
    "http://datacube.wu.ac.at/src/contrib/openNLPmodels.en_1.5-1.tar.gz", 
    repos=NULL, 
    type="source" 
) 

library(NLP) 
library(openNLP) 

x <- 'Scroll bar does not work the best either.' 
s <- as.String(x) 

## Annotators 
sent_token_annotator <- Maxent_Sent_Token_Annotator() 
word_token_annotator <- Maxent_Word_Token_Annotator() 
parse_annotator <- Parse_Annotator() 

a2 <- annotate(s, list(sent_token_annotator, word_token_annotator)) 
p <- parse_annotator(s, a2) 
ptext <- sapply(p$features, `[[`, "parse") 
ptext 
Tree_parse(ptext) 

## > 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))))(. .)))" 
## > Tree_parse(ptext) 
## (TOP 
## (S 
##  (NP (NNP Scroll) (NN bar)) 
##  (VP (VBZ does) (RB not) (VP (VB work) (NP (DT the) (JJS best)) (ADVP (RB either)))) 
##  (. .))) 

Die Baumstruktur sollte wie folgt aussehen:

enter image description here

Gibt es eine Möglichkeit, diesen Baum Visualisierung angezeigt werden?

Ich habe this related tree viz Frage für das Plotten von numerischen Ausdrücken gefunden, die von Nutzen sein können, aber das ich nicht generalisieren konnte, um Parse-Visualisierung zu verallgemeinern.

+0

Okay, wie

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))))(. .)))" 

Erstellen Sie das Diagramm sieht, aber was danach? – Indi

+2

Vielleicht über https://en.wikibooks.org/wiki/LaTeX/Linguistics#tikz-qtree? – Reactormonk

Antwort

8

Hier ist eine igraph Version. Diese Funktion nimmt das Ergebnis von Parse_annotator als Eingabe, also ptext in Ihrem Beispiel. NLP::Tree_parse erstellt bereits eine schöne Baumstruktur, so dass die Idee hier ist, sie rekursiv zu durchlaufen und eine Editierliste zu erstellen, um sie in igraph zu stecken. Die Kantenliste ist nur eine zweispaltige Matrix von Kopf-> Schwanzwerten.

Damit igraph Kanten zwischen den richtigen Knoten erstellen können, müssen sie eindeutige Bezeichner haben. Ich tat dies, indem ich eine Sequenz von ganzen Zahlen (unter Verwendung regmatches<-) an die Wörter in dem Text vor der Verwendung von Tree_parse anhängen.

Die interne Funktion edgemaker durchquert den Baum und füllt edgelist so wie es geht. Es gibt Optionen, um die Blätter getrennt von den übrigen Knoten zu färben, aber wenn Sie die Option vertex.label.color übergeben, werden sie alle gleich gefärbt.

## 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) 
} 

Also, mit Ihrem Beispiel die Zeichenfolge x und seine kommentierten Version ptext, die durch den Aufruf

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) 

enter image description here

+1

Ich weinte :-) Ich schätze die Arbeit an dieser +500 –

+0

wert die Punkte, die ich in R seit 3 ​​Jahren haben wollte. Ich komme zurück zu einem Paket, das einfaches Parsen ermöglicht, und das letzte Stück war, dass ich die geparsten Sätze grafisch darstellen wollte. Können Sie mir Ihre aktuellen Informationen per E-Mail zusenden, damit ich Sie als Autor für das Paket hinzufügen kann? –

+0

muss jetzt nicht effizient sein, nur arbeiten :-) Auch wenn langsam/ineffizient ist es besser als das, was R zur Zeit zur Verfügung hat. Ich werde Ihr SO-Handle verwenden und auf diese Frage Bezug nehmen, um die ethische Integrität zu wahren (d. H. Kredit geben, wo fällig). Wenn Sie Ihre Meinung jederzeit ändern, lassen Sie es mich wissen und ich werde Ihren tatsächlichen Namen verwenden. Danke noch einmal. –