• 2.1 句子分割

    2.1 句子分割

    句子分割可以看作是一个标点符号的分类任务:每当我们遇到一个可能会结束一个句子的符号,如句号或问号,我们必须决定它是否终止了当前句子。

    第一步是获得一些已被分割成句子的数据,将它转换成一种适合提取特征的形式:

    1. >>> sents = nltk.corpus.treebank_raw.sents()
    2. >>> tokens = []
    3. >>> boundaries = set()
    4. >>> offset = 0
    5. >>> for sent in sents:
    6. ... tokens.extend(sent)
    7. ... offset += len(sent)
    8. ... boundaries.add(offset-1)

    在这里,tokens是单独句子标识符的合并列表,boundaries是一个包含所有句子边界词符索引的集合。下一步,我们需要指定用于决定标点是否表示句子边界的数据特征:

    1. >>> def punct_features(tokens, i):
    2. ... return {'next-word-capitalized': tokens[i+1][0].isupper(),
    3. ... 'prev-word': tokens[i-1].lower(),
    4. ... 'punct': tokens[i],
    5. ... 'prev-word-is-one-char': len(tokens[i-1]) == 1}

    基于这一特征提取器,我们可以通过选择所有的标点符号创建一个加标签的特征集的列表,然后标注它们是否是边界标识符:

    1. >>> featuresets = [(punct_features(tokens, i), (i in boundaries))
    2. ... for i in range(1, len(tokens)-1)
    3. ... if tokens[i] in '.?!']

    使用这些特征集,我们可以训练和评估一个标点符号分类器:

    1. >>> size = int(len(featuresets) * 0.1)
    2. >>> train_set, test_set = featuresets[size:], featuresets[:size]
    3. >>> classifier = nltk.NaiveBayesClassifier.train(train_set)
    4. >>> nltk.classify.accuracy(classifier, test_set)
    5. 0.936026936026936

    使用这种分类器进行断句,我们只需检查每个标点符号,看它是否是作为一个边界标识符;在边界标识符处分割词列表。在2.1中的清单显示了如何可以做到这一点。

    1. def segment_sentences(words):
    2. start = 0
    3. sents = []
    4. for i, word in enumerate(words):
    5. if word in '.?!' and classifier.classify(punct_features(words, i)) == True:
    6. sents.append(words[start:i+1])
    7. start = i+1
    8. if start < len(words):
    9. sents.append(words[start:])
    10. return sents