2015-11-02 34 views
6

Tôi muốn hiển thị phân tích cú pháp (gắn thẻ POS) từ openNLP làm hiển thị cấu trúc cây. Bên dưới, tôi cung cấp cây phân tích cú pháp từ openNLP nhưng tôi không thể vẽ dưới dạng cây trực quan chung cho Python's parsing.Trực quan hóa cấu trúc cây phân tích cú pháp

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

Cấu trúc cây sẽ trông giống như thế này:

enter image description here

Có cách nào để hiển thị cây trực quan này?

Tôi đã tìm thấy this related tree viz câu hỏi để vẽ biểu đồ các biểu thức số có thể được sử dụng nhưng tôi không thể khái quát hóa để hiển thị phân tích cú pháp câu.

+0

Được rồi, nhưng sau đó thì sao? – Indi

+2

Có thể qua https://en.wikibooks.org/wiki/LaTeX/Linguistics#tikz-qtree? – Reactormonk

Trả lời

8

Đây là phiên bản igraph. Hàm này lấy kết quả từ Parse_annotator làm đầu vào của nó, do đó, ptext trong ví dụ của bạn. NLP::Tree_parse đã tạo ra một cấu trúc cây đẹp, vì vậy ý ​​tưởng ở đây là duyệt qua nó một cách đệ quy và tạo ra một edgelist để cắm vào igraph. Các edgelist chỉ là một ma trận 2 cột của head-> tail giá trị.

Để cho igraph để tạo các cạnh giữa các nút thích hợp, chúng cần phải có số nhận dạng duy nhất. Tôi đã làm điều này bằng cách thêm một dãy số nguyên (sử dụng regmatches<-) vào các từ trong văn bản trước khi sử dụng Tree_parse.

Chức năng nội bộ edgemaker đi ngang qua cây, điền edgelist khi di chuyển. Có các tùy chọn để tô màu các lá riêng biệt với phần còn lại của các nút, nhưng nếu bạn vượt qua tùy chọn vertex.label.color, nó sẽ tô màu chúng giống nhau.

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

Vì vậy, sử dụng ví dụ của bạn, chuỗi x và phiên bản chú thích của nó ptext, trông giống như

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

Tạo đồ thị bằng cách gọi

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

Tôi đã khóc :-) Tôi đánh giá cao công việc về +500 –

+0

này cũng đáng để tôi có thể làm điều này trong R trong 3 năm. Chỉ cần quay trở lại một gói cho phép phân tích cú pháp dễ dàng và phần cuối cùng là tôi muốn có cách vẽ các câu được phân tích cú pháp. Bạn có thể gửi email cho tôi thông tin thực tế của bạn để tôi có thể đưa bạn làm tác giả trên gói không? –

+0

không cần phải có hiệu quả cho bây giờ, chỉ cần làm việc :-) Ngay cả khi chậm/không hiệu quả nó tốt hơn so với những gì R đã có sẵn hiện nay. Tôi sẽ sử dụng SO xử lý của bạn và tham khảo câu hỏi này để duy trì tính toàn vẹn đạo đức (tức là, cho tín dụng khi đến hạn). Nếu bạn thay đổi ý định bất cứ lúc nào, hãy cho tôi biết và tôi sẽ sử dụng tên thật của bạn. Cảm ơn một lần nữa. –

Các vấn đề liên quan