KDnuggets

3 NLTK Tricks for Advanced Text Preprocessing & Linguistic Analysis

8.5内容质量

TL;DR · AI 摘要

NLTK 提供了三种高级文本预处理技巧,可提升语义准确性,包括保留短语完整性、基于词性映射的上下文感知词形还原和使用关联度量提取共现词。

核心要点

  • 使用 MWETokenizer 保留多词表达的完整性,避免语义信息丢失。
  • 基于词性映射的上下文感知词形还原可提高词形还原的准确性。
  • 使用关联度量(如 PMI)提取统计共现词,提升语义分析效果。

结构提纲

按章节快速跳转。

  1. 文章介绍了 NLTK 在文本预处理和语言分析中的三个高级技巧。

  2. 使用 MWETokenizer 保留多词表达的完整性,避免语义信息丢失。

  3. 通过词性映射实现上下文感知的词形还原,提高准确性。

  4. 利用关联度量(如 PMI)提取共现词,提升语义分析效果。

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • NLTK 高级文本预处理技巧
    • 保留多词表达完整性
      • 使用 MWETokenizer
    • 上下文感知词形还原
      • 基于词性映射
    • 统计共现词提取
      • 使用关联度量(如 PMI)

金句 / Highlights

值得收藏与分享的关键句。

#NLP#NLTK#文本预处理#Python
打开原文

3 个 NLTK 技巧,用于高级文本预处理与语言分析 - KDnuggets

publ: 2026年6月22日

  • 博客热门文章
  • 主题 AI 职业建议 计算机视觉 数据工程 数据科学 语言模型 机器学习 MLOps NLP 编程 Python SQL
  • 数据集
  • 活动
  • 资源 快速参考指南 推荐 技术简报
  • 广告

加入新闻通讯

#header end

/ad_wrapper

3 个 NLTK 技巧,用于高级文本预处理与语言分析

在本文中,我们将介绍三个关键的 NLTK 技巧,以提升你的文本预处理能力:使用 MWETokenizer 保持短语完整性、使用词性(POS)映射进行上下文感知的词形还原,以及使用关联度量进行统计共现提取。

作者:

Matthew Mayo

,KDnuggets 主编,2026年6月22日发布于

自然语言处理

<div class="addthis_native_toolbox"></div>

# 引言

近年来,自然语言处理(NLP)经历了明显的范式转变,大型语言模型(LLMs)和变压器(transformers)负责处理复杂的端到端理解任务。然而,在任何实际的 NLP 工作流程中,原始文本在到达模型之前仍需进行分词、归一化和分析。虽然现代 NLP 库和生态系统,如 SpaCy 或 Hugging Face,非常适合构建通用的深度学习流水线或与 LLM 集成,但自然语言工具包(NLTK)仍然是一个可行且透明的选择,适用于细粒度结构语言学、自定义文本归一化和统计语料库分析。

不幸的是,许多开发者错误地认为 LLM 使传统的文本预处理变得过时,或者他们使用简单的方法编写文本预处理代码,丢弃了关键的语言结构。他们将像“机器学习”这样的多词表达式拆分为单独的、无意义的单词;他们进行无上下文的词形还原,导致基础形式不准确;或者他们依赖于简单的原始频率计数,忽略了有意义的词语关联。

为了构建强大且语义准确的 NLP 模型,你需要在预处理阶段保留结构和语言上下文。在本文中,我们将介绍三个关键的 NLTK 技巧,以提升你的文本预处理能力:

  • 使用 MWETokenizer 保持短语完整性
  • 使用词性(POS)映射进行上下文感知的词形还原
  • 使用关联度量进行统计共现提取

# 1. 使用多词表达式分词器保留领域术语

分词是任何 NLP 流水线的基础。然而,标准的分词器严格按照空格和标点符号来分割句子。这在处理特定领域的多词表达式时会变得有问题,例如“神经网络”、“决策树”或“旧金山”等,其中单个单词组合成一个单一的语义概念。

如果一个分词器将“神经网络”拆分为“神经”和“网络”,下游的向量化器(如词袋或 TF-IDF)会将它们视为不相关的特征,从而稀释信号并引入噪声。开发者通常通过在分词前对原始文本编写搜索和替换的正则表达式来尝试解决这个问题。

使用字符级别的替换(例如:text.replace("neural network", "neural_network"))是脆弱的。它不尊重单词边界,处理标点符号效果不好,而且在处理大型数据集时执行速度非常慢。优化的方法是先对文本进行分词,然后使用 NLTK 本机的 MWETokenizer 来干净地合并这些分词。

使用正则表达式替换的简单方法依赖于字符级别的字符串操作,这种方法扩展性不好,还可能无意中修改不相关单词中的子字符串:

code
import re
import time

# 示例语料库
raw_texts = [
    "We are studying neural networks and deep learning.",
    "The decision tree is a popular model in machine learning.",
    "A neural network can have many layers."
] * 5000

cleaned_texts = []
for text in raw_texts:
    # 手动替换领域术语
    text = re.sub(r"\bneural networks?\b", "neural_network", text, flags=re.IGNORECASE)
    text = re.sub(r"\bdecision trees?\b", "decision_tree", text, flags=re.IGNORECASE)
    text = re.sub(r"\bmachine learnings?\b", "machine_learning", text, flags=re.IGNORECASE)
    
    # 分词处理后的字符串
    tokens = text.lower().split()
    cleaned_texts.append(tokens)

print("示例分词:", cleaned_texts[0])

输出:

code
示例分词: ['we', 'are', 'studying', 'neural_network', 'and', 'deep', 'learning.']

现在我们尝试使用 NLTK 的分词器。我们首先使用标准的 word_tokenize 方法进行分词,然后将分词流传递给一个初始化的 MWETokenizer,该分词器可以高效地在分词边界上进行合并:

code
import nltk
from nltk.tokenize import word_tokenize, MWETokenizer
import time

# 确保已下载 NLTK 资源
nltk.download('punkt', quiet=True)

raw_texts = [
    "We are studying neural networks and deep learning.",
    "The decision tree is a popular model in machine learning.",
    "A neural network can have many layers."
] * 5000

# 初始化分词器并注册 MWE 元组
mwe_tokenizer = MWETokenizer([
    ('neural', 'network'),
    ('neural', 'networks'),
    ('decision', 'tree'),
    ('decision', 'trees'),
    ('machine', 'learning')
], separator='_')

cleaned_texts_mwe = []
for text in raw_texts:
    # 使用 NLTK 标准分词器对单词进行分词
    tokens = word_tokenize(text.lower())
    # 合并指定的多词表达式
    merged_tokens = mwe_tokenizer.tokenize(tokens)
    cleaned_texts_mwe.append(merged_tokens)

print("示例分词:", cleaned_texts_mwe[0])

我们得到相同的输出,但采用了一种更优雅、语言学上更准确且可扩展的方法:

使用 MWETokenizer 将操作从缓慢的字符级别字符串匹配转移到了分词级别比较。

  • 我们将多词表达式定义为独立分词的元组:('neural', 'network')。通过设置 separator='_',分词器将匹配的序列合并为一个字符串分词:"neural_network"。因为它直接作用于分词数组,所以它不会受到边界匹配错误的影响,并且能正确处理尾随标点(例如,"neural networks." 首先被拆分为 "neural"、"networks"、".",然后安全地合并为 "neural_networks"、".")。它执行速度更快,并且可以干净地扩展到数百个领域术语。

# 2. 基于词性标注映射的上下文感知词形还原

词形还原(Lemmatization)是将一个词还原为其词典中的基本形式(即词元,lemma)的过程,例如“running”还原为“run”,“better”还原为“good”。这是一个重要的规范化步骤,因为它可以将同一个词的不同语法变化形式归为一组。

然而,NLTK 的 WordNetLemmatizer 默认将每个词都视为名词。如果你没有指定词性(POS)类别,直接传递动词或形容词,词形还原器将返回原词不变。例如:

  • lemmatizer.lemmatize("running") 返回 "running"(而不是 "run")
  • lemmatizer.lemmatize("better") 返回 "better"(而不是 "good")

为了解决这个问题,我们必须使用 NLTK 的词性标注器(POS tagger)动态识别句子中每个词的语法角色,将这些标签映射到 WordNet 的简化类别(名词、动词、形容词、副词)中,然后将它们传递给词形还原器。

这种简单的方法直接将词传递给词形还原器,会遗漏动词和形容词的转换,导致词汇规范化效果不佳:

python
import nltk
from nltk.stem import WordNetLemmatizer
from nltk.tokenize import word_tokenize

nltk.download('punkt', quiet=True)
nltk.download('wordnet', quiet=True)

sentence = "The feet of the running runners are getting better and faster."
tokens = word_tokenize(sentence.lower())

lemmatizer = WordNetLemmatizer()

# 简单的词形还原:假设所有词都是名词
naive_lemmas = [lemmatizer.lemmatize(token) for token in tokens]
print("Tokens:      ", tokens)
print("Naive Lemmas:", naive_lemmas)
code
Tokens:       ['the', 'feet', 'of', 'the', 'running', 'runners', 'are', 'getting', 'better', 'and', 'faster', '.']
Naive Lemmas: ['the', 'foot', 'of', 'the', 'running', 'runner', 'are', 'getting', 'better', 'and', 'faster', '.']

让我们看看一个优化的版本:我们编写一个清晰的辅助字典,将 Penn Treebank 标签(由 NLTK 的 pos_tag 返回)映射到 WordNet 的词性常量,确保每种词类都能被准确地进行词形还原:

python
import nltk
from nltk.stem import WordNetLemmatizer
from nltk.tokenize import word_tokenize
from nltk.corpus import wordnet

# 下载词性标注器资源
nltk.download('punkt', quiet=True)
nltk.download('wordnet', quiet=True)
nltk.download('averaged_perceptron_tagger', quiet=True)

sentence = "The feet of the running runners are getting better and faster."
tokens = word_tokenize(sentence.lower())

# 为每个词生成词性标签
pos_tags = nltk.pos_tag(tokens)

# 将 Penn Treebank 标签映射到 WordNet 标签
def get_wordnet_pos(treebank_tag):
    if treebank_tag.startswith('J'):
        return wordnet.ADJ
    elif treebank_tag.startswith('V'):
        return wordnet.VERB
    elif treebank_tag.startswith('N'):
        return wordnet.NOUN
    elif treebank_tag.startswith('R'):
        return wordnet.ADV
    else:
        # 默认使用 WordNet 的名词处理方式
        return None

lemmatizer = WordNetLemmatizer()

# 使用映射的词性标签进行词形还原
context_lemmas = []
for token, tag in pos_tags:
    wn_tag = get_wordnet_pos(tag)
    if wn_tag:
        lemma = lemmatizer.lemmatize(token, pos=wn_tag)
    else:
        lemma = lemmatizer.lemmatize(token)
    context_lemmas.append(lemma)

print("POS Tagged:    ", pos_tags)
print("Context Lemmas:", context_lemmas)
code
POS 标注:     [('the', 'DT'), ('feet', 'NNS'), ('of', 'IN'), ('the', 'DT'), ('running', 'NN'), ('runners', 'NNS'), ('are', 'VBP'), ('getting', 'VBG'), ('better', 'RBR'), ('and', 'CC'), ('faster', 'RBR'), ('.', '.')]
上下文词形: ['the', 'foot', 'of', 'the', 'running', 'runner', 'be', 'get', 'well', 'and', 'faster', '.']

NLTK 的 pos_tag 使用 Penn Treebank 标签集对单词进行标注(例如,'VBG' 表示动名词,'JJR' 表示比较级形容词)。

  • 我们的辅助函数 get_wordnet_pos() 检查标签的第一个字符。根据 WordNet 的 POS 标准,如果以 'J' 开头,我们将其映射到 WordNet 的形容词标签(wordnet.ADJ);如果以 'V' 开头,映射到动词(wordnet.VERB),依此类推。
  • 通过将正确的 POS 标签传递给 lemmatizer.lemmatize(token, pos=wn_tag),词形还原器成功地将 "running" 还原为 "run","are" 还原为 "be","getting" 还原为 "get","better" 还原为 "good","faster" 还原为 "fast"。这保留了句子的语义核心,显著减少了下游 ML 模型的词汇稀疏性。

# 3. 使用搭配查找器进行统计短语提取

从文本中提取关键词短语或多词概念对于主题建模、搜索索引和情感分析非常有价值。这些短语被称为搭配,它们是比随机出现更频繁共现的词序列。

寻找搭配的简单方法是统计所有原始二元组(两个词的序列)并按频率排序。然而,这种方法会产生大量信息量低的短语。由于原始频率分布,像 "of the"、"in the" 和 "on a" 这样的组合总是会占据排名靠前的结果。即使过滤掉停用词,原始计数也可能偏向于随机、偶然重复几次的组合。

优化的解决方案是使用 NLTK 的 BigramCollocationFinder 结合统计关联度量。我们不再统计原始频率,而是使用如点互信息(PMI)或卡方统计等关联度量。这些度量评估两个词是否比纯粹随机出现更频繁地一起出现。

首先,我们简单的做法只是统计原始二元组并截取排名靠前的匹配项,这会捕捉到噪音和常见功能词:

code
from collections import Counter
import nltk
from nltk.tokenize import word_tokenize
from nltk.util import bigrams

# 示例语料库
corpus = """
Natural language processing is an active field of AI. Machine learning plays a key role 
in natural language processing. Deep learning architectures have revolutionized natural 
language processing. We need machine learning models to solve these natural language tasks.
"""
tokens = word_tokenize(corpus.lower())

# 提取并统计原始二元组
raw_bigrams = list(bigrams(tokens))
bigram_counts = Counter(raw_bigrams)

print("Top 5 Raw Bigrams:")
for bigram, freq in bigram_counts.most_common(5):
    print(f"{bigram}: {freq}")
code
Top 5 Raw Bigrams:
('natural', 'language'): 4
('language', 'processing'): 3
('machine', 'learning'): 2
('processing', '.'): 2
('processing', 'is'): 1

在这里,我们初始化 NLTK 的搭配查找器,应用过滤约束,并使用 BigramAssocMeasures 类通过点互信息(PMI)对短语关联进行评分:

code
import nltk
from nltk.collocations import BigramCollocationFinder
from nltk.metrics.association import BigramAssocMeasures
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize

nltk.download('punkt', quiet=True)
nltk.download('stopwords', quiet=True)

corpus = """
Natural language processing is an active field of AI. Machine learning plays a key role 
in natural language processing. Deep learning architectures have revolutionized natural 
language processing. We need machine learning models to solve these natural language tasks.
"""
tokens = word_tokenize(corpus.lower())

# Initialize the collocation finder
finder = BigramCollocationFinder.from_words(tokens)

# Filter out punctuation and stop words
stop_words = set(stopwords.words('english'))
filter_stops = lambda w: w in stop_words or not w.isalnum()
finder.apply_word_filter(filter_stops)

# Filter out bigrams that occur less than N times
finder.apply_freq_filter(2)

# Score bigrams using pointwise mutual information
pmi_measures = BigramAssocMeasures()
top_collocations = finder.score_ngrams(pmi_measures.pmi)

print("Top Collocations by PMI:")
for bigram, pmi_score in top_collocations[:5]:
    # Formulate a clean print representation
    phrase = " ".join(bigram)
    print(f"Phrase: {phrase:<30} | PMI Score: {pmi_score:.4f}")
code
Top Collocations by PMI:
Phrase: machine learning               | PMI Score: 3.8074
Phrase: language processing            | PMI Score: 3.3923
Phrase: natural language               | PMI Score: 3.3923
  • BigramCollocationFinder.from_words() 提取所有双词组,同时保持其结构位置。我们使用 finder.apply_word_filter() 清理候选词,该方法动态排除包含停用词或标点符号的双词组,而不会修改原始词间距上下文。通过设置 apply_freq_filter(2),我们忽略只出现一次的随机组合,从而减少统计噪声。最后,使用点互信息进行评分,数学上衡量两个词同时出现的概率除以它们独立出现的概率。这突出了像“machine learning”和“natural language”这样的高度耦合术语,同时忽略常见的松散组合。

# 总结

自定义文本预处理是提取原始文本中更清晰信号的关键,NLTK 提供了定制这些操作所需的结构工具。

通过结合这三种 NLTK 技术,你可以构建更稳健的 NLP 工作流程:

  • 使用 MWETokenizer 保留领域术语,可以在标记级别合并复合词,防止关键概念在向量化过程中被拆分。
  • 基于上下文的词形还原将词性标注生成与 WordNet 映射相结合,以获取语言上准确的基础形式,显著减少词汇维度。
  • 统计共现提取使用如 PMI 等数学关联度量,从原始语料库数据中提取真正的语义短语,绕过简单频率计数的噪声。

在特征工程过程中使用这些结构模式,可以确保下游分类、搜索和聚类算法接收到高质量且语义完整的标记。

Matthew Mayo(@mattmayo13)拥有计算机科学硕士学位和数据挖掘研究生文凭。作为 KDnuggets & Statology 的主编,以及 Machine Learning Mastery 的特约编辑,Matthew 致力于让复杂的数据科学概念变得易于理解。他的职业兴趣包括自然语言处理、语言模型、机器学习算法以及探索新兴的人工智能技术。他致力于推动数据科学社区知识的普及。Matthew 从六岁起就开始编程了。

更多相关内容

  • 从杂乱到整洁:8 个 Python 技巧,轻松实现数据预处理
  • 使用 Pandas 清理和预处理文本数据以进行自然语言处理任务
  • 数据科学家必备的 10 个高级 Python 技巧
  • 高级 NotebookLM 技巧与技巧,专为高级用户设计
  • 3 个 SpaCy 技巧,实现高效的文本处理与实体识别
  • 数据预处理中 10 个必不可少的 Pandas 命令

<hr class="grey-line"><br> <div><h3>我们推荐的 5 门免费课程</h3><br> </div>

Mailchimp for WordPress v4.13.0 - https://wordpress.org/plugins/mailchimp-for-wp/

/ Mailchimp for WordPress 插件

你可以从这里开始编辑。

如果评论已关闭。

<= 上一篇

下一篇 =>

#content end

<script type="text/javascript">kda_sid_write(kda_sid_n);</script>

最新文章

  • Abacus AI 的 ChatLLM 评测:一个为日常工作打造的多模型 AI 工作空间
  • 关于代理 AI,大家普遍误解的三个地方
  • 高级文本预处理与语言分析的 3 个 NLTK 技巧
  • 为新手解释损失函数(模型如何知道它们是错误的)
  • 每个数据科学家都应该知道的实用 SQL 技巧
  • Python 字典技巧和技巧,你应该永远记住

热门文章

  • 2026 年成为 LLM 工程师的路线图
  • 将 Claude Code 与本地模型配对
  • 我是如何(以及为什么)构建一个 AI 助手的
  • 使用 OpenAI Codex 的 5 个有趣项目
  • 使用 Python 中的 sktime 构建时间序列机器学习模型
  • 停止在 Pandas 中编写循环:尝试 7 个更快的替代方法
  • 3 个 Pandas 技巧,用于数据清洗与准备
  • 为你的创业点子获取资金的 7 个最佳方式
  • 廉价本地代理编程:Claude Code + Ollama + Gemma4
  • Python 字典技巧和技巧,你应该永远记住

#content_wrapper end

© 2026

Guiding Tech Media

|

关于

联系

广告

隐私

服务条款

发布于 2026 年 6 月 22 日

blank

不,谢谢!

/.main_wrapper

<script defer type="text/javascript" src="https://s7.addthis.com/js/300/addthis_widget.js#pubid=gpsaddthis"></script>

noptimize

/noptimize