2014-12-23 22 views
10

Tôi đang sử dụng NER trong NLTK để tìm người, địa điểm và tổ chức trong câu. Tôi có thể tạo ra kết quả như sau:Chunking Đầu ra nhận dạng đối tượng được đặt tên Stanford (NER) từ định dạng NLTK

[(u'Remaking', u'O'), (u'The', u'O'), (u'Republican', u'ORGANIZATION'), (u'Party', u'ORGANIZATION')] 

Có thể kết hợp mọi thứ lại với nhau bằng cách sử dụng không? Điều tôi muốn là như sau:

u'Remaking'/ u'O', u'The'/u'O', (u'Republican', u'Party')/u'ORGANIZATION' 

Cảm ơn!

Trả lời

1

Bạn có thể sử dụng cách NLTK tiêu chuẩn của đại diện cho khối sử dụng nltk.Tree. Điều này có nghĩa là bạn phải thay đổi biểu diễn của mình một chút.

Những gì tôi thường làm là đại diện NER-tagged câu như danh sách ba:

sentence = [('Andrew', 'NNP', 'PERSON'), ('is', 'VBZ', 'O'), ('part', 'NN', 'O'), ('of', 'IN', 'O'), ('the', 'DT', 'O'), ('Republican', 'NNP', 'ORGANIZATION'), ('Party', 'NNP', 'ORGANIZATION'), ('in', 'IN', 'O'), ('Dallas', 'NNP', 'LOCATION')] 

Tôi làm điều này khi tôi sử dụng một công cụ bên ngoài cho NER gắn thẻ một câu. Bây giờ bạn có thể chuyển đổi câu này đại diện NLTK:

from nltk import Tree 


def IOB_to_tree(iob_tagged): 
    root = Tree('S', []) 
    for token in iob_tagged: 
     if token[2] == 'O': 
      root.append((token[0], token[1])) 
     else: 
      try: 
       if root[-1].label() == token[2]: 
        root[-1].append((token[0], token[1])) 
       else: 
        root.append(Tree(token[2], [(token[0], token[1])])) 
      except: 
       root.append(Tree(token[2], [(token[0], token[1])])) 

    return root 


sentence = [('Andrew', 'NNP', 'PERSON'), ('is', 'VBZ', 'O'), ('part', 'NN', 'O'), ('of', 'IN', 'O'), ('the', 'DT', 'O'), ('Republican', 'NNP', 'ORGANIZATION'), ('Party', 'NNP', 'ORGANIZATION'), ('in', 'IN', 'O'), ('Dallas', 'NNP', 'LOCATION')] 
print IOB_to_tree(sentence) 

Thay đổi loại đại diện có ý nghĩa bởi vì bạn chắc chắn cần thẻ POS để gắn thẻ NER.

Kết quả cuối cùng sẽ giống như thế:

(S 
    (PERSON Andrew/NNP) 
    is/VBZ 
    part/NN 
    of/IN 
    the/DT 
    (ORGANIZATION Republican/NNP Party/NNP) 
    in/IN 
    (LOCATION Dallas/NNP)) 
3

Điều này thực sự đến trong bản phát hành tiếp theo của CoreNLP, dưới tên MentionsAnnotator. Nó có thể sẽ không có sẵn trực tiếp từ NLTK, tuy nhiên, trừ khi NLTK muốn hỗ trợ nó cùng với giao diện chuẩn Stanford NER.

Trong mọi trường hợp, tại thời điểm này, bạn sẽ phải sao chép mã tôi đã liên kết tới (sử dụng LabeledChunkIdentifier cho công việc bẩn) hoặc viết trình xử lý sau của riêng bạn bằng Python.

+0

Chỉ cần bắt đầu học java ... – Cosmozhang

8

Có vẻ dài nhưng nó công trình:

ner_output = [(u'Remaking', u'O'), (u'The', u'O'), (u'Republican', u'ORGANIZATION'), (u'Party', u'ORGANIZATION')] 
chunked, pos = [], "" 
for i, word_pos in enumerate(ner_output): 
    word, pos = word_pos 
    if pos in ['PERSON', 'ORGANIZATION', 'LOCATION'] and pos == prev_tag: 
     chunked[-1]+=word_pos 
    else: 
     chunked.append(word_pos) 
    prev_tag = pos 

clean_chunked = [tuple([" ".join(wordpos[::2]), wordpos[-1]]) if len(wordpos)!=2 else wordpos for wordpos in chunked] 

print clean_chunked 

[ra]:

[(u'Remaking', u'O'), (u'The', u'O'), (u'Republican Party', u'ORGANIZATION')] 

Để biết thêm chi tiết:

Đầu tiên cho vòng lặp "với bộ nhớ "đạt được điều gì đó như thế này:

[(u'Remaking', u'O'), (u'The', u'O'), (u'Republican', u'ORGANIZATION', u'Party', u'ORGANIZATION')] 

Bạn sẽ nhận thấy rằng tất cả các tên Enitties sẽ có nhiều hơn 2 mục trong một bộ và những gì bạn muốn là các từ như các phần tử trong danh sách, tức là 'Republican Party' trong (u'Republican', u'ORGANIZATION', u'Party', u'ORGANIZATION'), vì vậy bạn sẽ làm một cái gì đó như thế này để có được thậm chí yếu tố:

>>> x = [0,1,2,3,4,5,6] 
>>> x[::2] 
[0, 2, 4, 6] 
>>> x[1::2] 
[1, 3, 5] 

Sau đó, bạn cũng nhận ra rằng yếu tố cuối cùng trong tuple NE là thẻ mà bạn muốn, do đó bạn sẽ làm `

>>> x = (u'Republican', u'ORGANIZATION', u'Party', u'ORGANIZATION') 
>>> x[::2] 
(u'Republican', u'Party') 
>>> x[-1] 
u'ORGANIZATION' 

đó là một chút ad-hoc và vebose nhưng Tôi hy vọng nó sẽ giúp. Và ở đây nó là một chức năng, Phúc cho Giáng sinh:

ner_output = [(u'Remaking', u'O'), (u'The', u'O'), (u'Republican', u'ORGANIZATION'), (u'Party', u'ORGANIZATION')] 


def rechunk(ner_output): 
    chunked, pos = [], "" 
    for i, word_pos in enumerate(ner_output): 
     word, pos = word_pos 
     if pos in ['PERSON', 'ORGANIZATION', 'LOCATION'] and pos == prev_tag: 
      chunked[-1]+=word_pos 
     else: 
      chunked.append(word_pos) 
     prev_tag = pos 


    clean_chunked = [tuple([" ".join(wordpos[::2]), wordpos[-1]]) 
        if len(wordpos)!=2 else wordpos for wordpos in chunked] 

    return clean_chunked 


print rechunk(ner_output) 
+1

tôi đã thay đổi chunked, pos = [] "" để chửi rủa, pos, prev_tag = [], "", Không có, mà tôi nghĩ làm sence hơn. :) Nhưng vẫn còn đây là một chút khó xử trong việc đối phó với hai thực thể liên tiếp, ví dụ: Person Person O. Cảm ơn rất nhiều. – Cosmozhang

+0

NE liên tiếp rất hiếm và tôi đang tìm kiếm chúng cho một số công việc khác, nếu bạn tìm thấy chúng, bạn có thể giúp đăng một hoặc hai ví dụ không? =) – alvas

+0

@alvas nói rằng bạn có hai tên được phân tách bằng dấu phẩy .. "PER1_NAME, PER2_NAME và một người khác là bạn tốt" ..? – KillBill

1

Dưới đây là một thực hiện viết tắt của nhóm các kết quả Stanford NER sử dụng groupby iterator của itertools:

def grouptags(tags, ignore="O", join=" "): 
    from itertools import groupby 
    for c,g in groupby(tags, lambda t: t[1]): 
     if ignore is None or c != ignore: 
      if join is None: 
       entity = [e for e,_ in g] 
      else: 
       entity = join.join(e for e,_ in g) 
      yield(c, entity) 

Chức năng grouptags có hai tùy chọn:

  • bỏ qua: chỉ định lớp bị bỏ qua và bỏ qua khỏi đầu ra (mặc định: "O"). Nếu Không, tất cả các thực thể được trả về.
  • tham gia: chỉ định ký tự được sử dụng để tham gia các phần (mặc định: ""). Nếu Không có, các bộ phận được trả lại không được đính kèm dưới dạng danh sách.
Các vấn đề liên quan