2012-12-30 36 views
29

Tôi đang sử dụng NLTK để phân tích một vài văn bản cổ điển và tôi đang gặp sự cố khi mã hóa văn bản theo câu. Ví dụ, đây là những gì tôi nhận được cho một đoạn từ Moby Dick:Cách tinh chỉnh mã thông báo câu hỏi NLTK

import nltk 
sent_tokenize = nltk.data.load('tokenizers/punkt/english.pickle') 

''' 
(Chapter 16) 
A clam for supper? a cold clam; is THAT what you mean, Mrs. Hussey?" says I, "but 
that's a rather cold and clammy reception in the winter time, ain't it, Mrs. Hussey?" 
''' 
sample = 'A clam for supper? a cold clam; is THAT what you mean, Mrs. Hussey?" says I, "but that\'s a rather cold and clammy reception in the winter time, ain\'t it, Mrs. Hussey?"' 

print "\n-----\n".join(sent_tokenize.tokenize(sample)) 
''' 
OUTPUT 
"A clam for supper? 
----- 
a cold clam; is THAT what you mean, Mrs. 
----- 
Hussey? 
----- 
" says I, "but that\'s a rather cold and clammy reception in the winter time, ain\'t it, Mrs. 
----- 
Hussey? 
----- 
" 
''' 

Tôi không mong đợi sự hoàn hảo ở đây, xem xét rằng cú pháp Melville là một chút ngày, nhưng NLTK nên để có thể xử lý các dấu ngoặc kép thiết bị đầu cuối và các tựa đề như "Mrs." Vì tokenizer là kết quả của một algo đào tạo không giám sát, tuy nhiên, tôi không thể tìm ra cách để tinker với nó.

Bất kỳ ai cũng có đề xuất cho trình thông báo câu tốt hơn? Tôi muốn một heuristic đơn giản mà tôi có thể hack hơn là phải đào tạo phân tích cú pháp của riêng tôi.

Trả lời

40

Bạn cần cung cấp một danh sách các từ viết tắt cho tokenizer, như vậy:

from nltk.tokenize.punkt import PunktSentenceTokenizer, PunktParameters 
punkt_param = PunktParameters() 
punkt_param.abbrev_types = set(['dr', 'vs', 'mr', 'mrs', 'prof', 'inc']) 
sentence_splitter = PunktSentenceTokenizer(punkt_param) 
text = "is THAT what you mean, Mrs. Hussey?" 
sentences = sentence_splitter.tokenize(text) 

câu bây giờ là:

['is THAT what you mean, Mrs. Hussey?'] 
Cập nhật

: Điều này không hoạt động nếu từ cuối cùng của câu có dấu nháy đơn hoặc dấu ngoặc kép gắn liền với nó (như Hussey? '). Vì vậy, một cách nhanh chóng-và-bẩn xung quanh này là để đặt chỗ trước dấu nháy và dấu ngoặc kép mà làm theo những biểu tượng câu-end (.!?):

text = text.replace('?"', '? "').replace('!"', '! "').replace('."', '. "') 
+0

Ah, rất hữu ích. Kỳ lạ thay, điều này không hiệu quả nếu tôi chạy câu hoàn chỉnh trong câu hỏi của tôi thông qua giải pháp của bạn. Bất kỳ ý tưởng tại sao? –

+0

Chỉ cần thêm một số thông tin khác vào câu trả lời. – vpekar

+3

Tôi thường tránh nhận xét 'cảm ơn', nhưng ở đây nó thực sự là tại chỗ: cảm ơn! – Private

7

Bạn có thể nói phương thức PunktSentenceTokenizer.tokenize để bao gồm dấu ngoặc kép "đầu cuối" với phần còn lại của câu bằng cách đặt tham số realign_boundaries thành True. Xem mã bên dưới để biết ví dụ.

Tôi không biết cách nào để ngăn văn bản như Mrs. Hussey bị tách thành hai câu. Tuy nhiên, đây là một hack mà

  • mangles tất cả các lần xuất hiện của Mrs. Hussey-Mrs._Hussey,
  • sau đó chia tách các đoạn text vào câu với sent_tokenize.tokenize,
  • sau đó cho mỗi câu, unmangles Mrs._Hussey trở lại Mrs. Hussey

Tôi ước tôi biết một cách tốt hơn, nhưng điều này có thể làm việc trong một nhúm.


import nltk 
import re 
import functools 

mangle = functools.partial(re.sub, r'([MD]rs?[.]) ([A-Z])', r'\1_\2') 
unmangle = functools.partial(re.sub, r'([MD]rs?[.])_([A-Z])', r'\1 \2') 

sent_tokenize = nltk.data.load('tokenizers/punkt/english.pickle') 

sample = '''"A clam for supper? a cold clam; is THAT what you mean, Mrs. Hussey?" says I, "but that\'s a rather cold and clammy reception in the winter time, ain\'t it, Mrs. Hussey?"'''  

sample = mangle(sample) 
sentences = [unmangle(sent) for sent in sent_tokenize.tokenize(
    sample, realign_boundaries = True)]  

print u"\n-----\n".join(sentences) 

sản lượng

"A clam for supper? 
----- 
a cold clam; is THAT what you mean, Mrs. Hussey?" 
----- 
says I, "but that's a rather cold and clammy reception in the winter time, ain't it, Mrs. Hussey?" 
+0

Chỉ cần những gì tôi cần - cảm ơn bạn! –

+0

Cập nhật: Hợp nhất một phần câu trả lời này với câu trả lời ở trên –

2

Vì vậy, tôi đã có một vấn đề tương tự và cố gắng ra giải pháp vpekar của ở trên.

Có lẽ tôi là một loại trường hợp cạnh nhưng tôi quan sát hành vi tương tự sau khi áp dụng thay thế, tuy nhiên, khi tôi cố gắng thay thế dấu câu với các trích dẫn được đặt trước chúng, tôi nhận được kết quả mà tôi đang tìm kiếm. Có lẽ việc thiếu tuân thủ MLA ít quan trọng hơn việc giữ lại báo giá ban đầu như một câu duy nhất.

Để được rõ ràng hơn:

text = text.replace('?"', '"?').replace('!"', '"!').replace('."', '".') 

Nếu MLA là quan trọng mặc dù bạn luôn có thể quay trở lại và đảo ngược những thay đổi bất cứ nơi nào nó đếm.

24

Bạn có thể sửa đổi mã thông báo câu tiếng Anh được đào tạo trước của NLTK để nhận biết thêm các từ viết tắt bằng cách thêm chúng vào tập hợp _params.abbrev_types. Ví dụ:

extra_abbreviations = ['dr', 'vs', 'mr', 'mrs', 'prof', 'inc', 'i.e'] 
sentence_tokenizer = nltk.data.load('tokenizers/punkt/english.pickle') 
sentence_tokenizer._params.abbrev_types.update(extra_abbreviations) 

Lưu ý rằng chữ viết tắt phải được xác định mà không cần giai đoạn cuối cùng, nhưng đừng bao gồm bất kỳ thời gian nội bộ, như trong 'i.e' trên. Để biết chi tiết về các thông số mã thông báo khác, hãy tham khảo the relevant documentation.

+1

Đây phải là câu trả lời hàng đầu. Nếu bạn chỉ cần tạo một tokenizer mới, bạn sẽ không nhận được tất cả các tính năng hiện có của tokenizer tiếng Anh. –

+0

Nó dường như không làm việc cho tôi, trong khi câu trả lời hàng đầu đã làm. – Alter