You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用NLTK Naive Bayes实现命名实体识别?附自有语料示例

嘿,我来帮你搞定用NLTK朴素贝叶斯做命名实体识别(NER)的事儿,结合你给的那种带标签的自有语料,咱们一步步来:

步骤1:先把你的标注语料转成NLTK能处理的格式

你给的语料是带XML风格标签的,首先得把每个词和对应的实体类型提取出来,还要给非实体词打上O(表示Outside Entity,不属于任何实体)的标签。我用正则来做解析,简单直接:

import re

def parse_enamex_corpus(text):
    # 匹配<ENAMEX TYPE="XXX">内容</ENAMEX>的正则表达式
    enamex_pattern = r'<ENAMEX TYPE="([^"]+)">([^<]+)</ENAMEX>'
    processed_tokens = []
    last_position = 0

    # 遍历所有匹配的实体标签
    for match in re.finditer(enamex_pattern, text):
        # 先处理标签前的普通文本
        if match.start() > last_position:
            ordinary_words = text[last_position:match.start()].split()
            processed_tokens.extend([(word, 'O') for word in ordinary_words])
        # 处理实体内部的词,每个词打上对应的实体类型标签
        entity_words = match.group(2).split()
        entity_type = match.group(1)
        processed_tokens.extend([(word, entity_type) for word in entity_words])
        last_position = match.end()

    # 处理最后一段普通文本
    if last_position < len(text):
        remaining_words = text[last_position:].split()
        processed_tokens.extend([(word, 'O') for word in remaining_words])
    
    return processed_tokens

# 用你的示例文本测试一下
sample_text = 'Sementara itu Pengamat Pasar Modal <ENAMEX TYPE="PERSON">Dandossi Matram</ENAMEX> mengatakan, sulit bagi sebuah <ENAMEX TYPE="ORGANIZATION">kantor akuntan publik</ENAMEX> (<ENAMEX TYPE="ORGANIZATION">KAP</ENAMEX>) untuk dapat menyelesaikan audit perusahaan sebesar <ENAMEX TYPE="ORGANIZATION">Telkom</ENAMEX> dalam waktu 3 b...'
print(parse_enamex_corpus(sample_text))

运行这段代码后,你会得到一个类似[('Sementara', 'O'), ('itu', 'O'), ('Dandossi', 'PERSON'), ...]的列表,每个词都对应了正确的标签。

步骤2:定义NER的特征函数

朴素贝叶斯分类器需要基于词的特征来判断它的实体类型,除了词本身,我们还可以加入上下文、大小写、前缀后缀这些常用的NER特征,比如:

def word_features(word, prev_word, next_word):
    return {
        'word_lower': word.lower(),
        'is_capitalized': word[0].isupper(),
        'is_title_case': word.istitle(),
        'is_digit': word.isdigit(),
        'prefix_1': word[:1],
        'prefix_2': word[:2],
        'suffix_1': word[-1:],
        'suffix_2': word[-2:],
        'prev_word_lower': prev_word.lower(),
        'next_word_lower': next_word.lower()
    }

这些特征能帮分类器更好地区分实体(比如人名通常首字母大写,机构名可能有特定后缀)。

步骤3:准备训练数据

我们需要把预处理后的语料转换成「特征集+标签」的格式,还要处理句子首尾的边界情况(比如第一个词没有前一个词,就用<START>代替,最后一个词用<END>):

def prepare_training_data(processed_corpus):
    training_examples = []
    total_tokens = len(processed_corpus)
    
    for idx in range(total_tokens):
        word, label = processed_corpus[idx]
        # 获取前一个词,边界用特殊标记
        prev_word = processed_corpus[idx-1][0] if idx > 0 else '<START>'
        # 获取后一个词,边界用特殊标记
        next_word = processed_corpus[idx+1][0] if idx < total_tokens - 1 else '<END>'
        # 提取特征
        features = word_features(word, prev_word, next_word)
        training_examples.append((features, label))
    
    return training_examples

# 把你的全部语料都处理成训练集
# 这里只是示例,实际要替换成你所有的标注语料
all_processed_data = parse_enamex_corpus(sample_text)
training_set = prepare_training_data(all_processed_data)
步骤4:训练Naive Bayes分类器

现在就可以用NLTK自带的朴素贝叶斯分类器来训练了,还能查看分类准确率和最有信息量的特征:

from nltk.classify import NaiveBayesClassifier
from nltk.classify.util import accuracy

# 训练分类器
classifier = NaiveBayesClassifier.train(training_set)

# 如果有测试集,可以看准确率(把测试集也用同样方法处理成(test_features, label)格式)
# test_accuracy = accuracy(classifier, test_set)
# print(f"分类器准确率: {test_accuracy:.2f}")

# 查看最有信息量的特征,帮你调试模型
classifier.show_most_informative_features(10)
步骤5:用训练好的分类器做NER预测

写个简单的函数,输入句子就能返回每个词的实体标签:

def ner_predict(sentence, classifier):
    words = sentence.split()
    tagged_result = []
    total_words = len(words)
    
    for idx in range(total_words):
        word = words[idx]
        prev_word = words[idx-1] if idx > 0 else '<START>'
        next_word = words[idx+1] if idx < total_words - 1 else '<END>'
        features = word_features(word, prev_word, next_word)
        predicted_label = classifier.classify(features)
        tagged_result.append((word, predicted_label))
    
    return tagged_result

# 测试一下
test_sentence = "Dandossi Matram bekerja di Telkom"
print(ner_predict(test_sentence, classifier))
一些小提示
  • 语料规模很重要:朴素贝叶斯是统计模型,语料越多效果越好,如果你的标注数据少,可以考虑做些数据增强(比如同义词替换、句子改写)
  • 针对印尼语优化:你的示例是印尼语,可以加入印尼语词干提取(NLTK有印尼语词干器nltk.stem.snowball.IndonesianStemmer)来优化特征
  • 标签细化:如果你的实体有更细的分类(比如地点、时间),只要语料里有对应的<ENAMEX TYPE>,代码不用改就能支持

内容的提问来源于stack exchange,提问作者Irfan HP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:46:02