4、NLP基础:分词技术(Jieba分词)、停用词过滤、词性标注、命名实体识别
好,咱们进入NLP实战的第一站。说实话,很多初学者一上来就搞深度学习模型,结果数据预处理那一步就翻车了。我当年也是这样,觉得分词嘛,不就是按空格切一切?后来被中文的「南京市长江大桥」狠狠教育了一顿。
这一章,咱们把NLP最基础的四个工具练扎实:分词、停用词过滤、词性标注、命名实体识别。你想想看,这些就是情感分析的「地基」,地基不稳,后面全白搭。
4.1 分词技术:Jieba分词实战
中文分词和英文不一样。英文单词自带空格,中文词与词之间没有天然分隔符。我习惯用 Jieba,它轻量、速度快,而且支持自定义词典,非常适合做情感分析的预处理。
4.1.1 安装与基本用法
pip install jieba
安装完直接上手。Jieba 提供三种模式:精确模式、全模式、搜索引擎模式。我个人最常用精确模式,它最精准,不会把词切得稀碎。
import jieba
text = "我今天心情不太好,感觉特别糟糕"
words = jieba.lcut(text) # 精确模式
print(words)
# 输出:['我', '今天', '心情', '不太', '好', ',', '感觉', '特别', '糟糕']
你看,「心情不太好」被切成了「心情」「不太」「好」,这个粒度对情感分析来说刚刚好。全模式会把所有可能的词都列出来,比如「北京大学」会切成「北京」「大学」「北京大学」,太冗余了。
4.1.2 自定义词典
我在项目中遇到过一个问题:用户评论里有很多产品名,比如「小爱同学」「天猫精灵」,Jieba 默认会切成「小爱」「同学」。这显然不对。解决办法就是加自定义词典。
# 创建一个 user_dict.txt 文件,每行一个词
# 小爱同学 5 n
# 天猫精灵 5 n
jieba.load_userdict("user_dict.txt")
text = "小爱同学今天播放了一首悲伤的歌"
words = jieba.lcut(text)
print(words)
# 输出:['小爱同学', '今天', '播放', '了', '一首', '悲伤', '的', '歌']
嗯,这里要注意:词典里可以指定词频和词性,但如果你不确定,只写词也行,Jieba 会自动调整。
4.2 停用词过滤
分词之后,你会发现一堆「的」「了」「在」「是」这种词。它们对情感分析几乎没有贡献,反而会引入噪声。我习惯在预处理阶段就把它们干掉。
4.2.1 什么是停用词?
说白了,就是那些高频但无实际意义的词。比如:
- 助词:的、地、得
- 介词:在、从、到
- 连词:和、与、但是
- 语气词:啊、呢、吗
你想想看,如果一条评论是「这个产品真的太好了」,去掉停用词后变成「产品 真的 好」,情感倾向依然保留,但特征维度降低了。
4.2.2 实战:加载停用词表
网上有很多现成的停用词表,比如哈工大停用词表、百度停用词表。我一般用哈工大的,比较全。
def load_stopwords(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
stopwords = set([line.strip() for line in f])
return stopwords
stopwords = load_stopwords('stopwords.txt')
def filter_stopwords(words, stopwords):
return [w for w in words if w not in stopwords and w.strip()]
text = "我今天心情不太好"
words = jieba.lcut(text)
filtered = filter_stopwords(words, stopwords)
print(filtered)
# 输出:['今天', '心情', '不太好']
4.3 词性标注
词性标注就是给每个词打上标签:名词、动词、形容词、副词……为什么需要这个?因为情感词大多是形容词和副词。比如「开心」「难过」是形容词,「非常」「极其」是副词。通过词性标注,我们可以精准定位情感词。
4.3.1 Jieba 词性标注
Jieba 自带词性标注功能,用 jieba.posseg 模块就行。
import jieba.posseg as pseg
text = "这部电影真的非常感人"
words = pseg.lcut(text)
for word, flag in words:
print(f"{word}: {flag}")
# 输出:
# 这: r
# 部: q
# 电影: n
# 真的: d
# 非常: d
# 感人: a
你看,「感人」是形容词(a),「非常」是副词(d)。我习惯把形容词和副词单独提取出来,作为情感特征。
4.3.2 常见词性标签
| 标签 | 含义 | 示例 |
|---|---|---|
| a | 形容词 | 好、坏、开心 |
| d | 副词 | 非常、很、极其 |
| n | 名词 | 电影、产品、服务 |
| v | 动词 | 喜欢、讨厌、推荐 |
| r | 代词 | 我、你、这 |
4.4 命名实体识别(NER)
命名实体识别,听起来高大上,其实就是从文本中找出人名、地名、机构名、时间等专有名词。在情感分析里,NER 可以帮助我们定位情感对象。比如「我对华为的售后服务很不满意」,NER 能识别出「华为」是机构名,「售后服务」是产品相关实体。
4.4.1 使用 Jieba 做简单 NER
Jieba 的 NER 能力比较基础,主要靠词性标注和自定义词典。比如人名、地名可以通过词性标签识别。
import jieba.posseg as pseg
text = "张三昨天去了北京,对小米的客服非常失望"
words = pseg.lcut(text)
for word, flag in words:
if flag in ['nr', 'ns', 'nt']: # nr:人名, ns:地名, nt:机构名
print(f"实体: {word}, 类型: {flag}")
# 输出:
# 实体: 张三, 类型: nr
# 实体: 北京, 类型: ns
# 实体: 小米, 类型: nt
嗯,这里要注意:Jieba 的 NER 准确率一般,尤其是对长尾实体。如果你需要高精度的 NER,建议用 HanLP 或 LAC。但在情感分析入门阶段,Jieba 完全够用。
4.4.2 实战:提取情感对象
我做过一个项目,分析用户对手机品牌的评论。通过 NER 提取出品牌名(如「华为」「小米」「苹果」),然后结合情感词,就能知道用户对哪个品牌满意、对哪个品牌不满。
def extract_entities_and_sentiment(text):
words = pseg.lcut(text)
entities = []
sentiments = []
for word, flag in words:
if flag in ['nt']: # 机构名
entities.append(word)
if flag in ['a']: # 形容词
sentiments.append(word)
return entities, sentiments
text = "华为的拍照效果很好,但小米的电池续航太差了"
entities, sentiments = extract_entities_and_sentiment(text)
print(f"实体: {entities}") # ['华为', '小米']
print(f"情感词: {sentiments}") # ['好', '差']
4.5 整合:一个完整的预处理流水线
好了,咱们把上面四个步骤串起来,形成一个可复用的预处理函数。我习惯把它封装成一个类,方便后续调用。
import jieba
import jieba.posseg as pseg
class TextPreprocessor:
def __init__(self, stopwords_path, user_dict_path=None):
self.stopwords = self._load_stopwords(stopwords_path)
if user_dict_path:
jieba.load_userdict(user_dict_path)
def _load_stopwords(self, path):
with open(path, 'r', encoding='utf-8') as f:
return set([line.strip() for line in f])
def process(self, text):
# 1. 分词
words = jieba.lcut(text)
# 2. 停用词过滤
words = [w for w in words if w not in self.stopwords and w.strip()]
# 3. 词性标注
pos_tags = pseg.lcut(text)
pos_dict = {word: flag for word, flag in pos_tags}
# 4. 命名实体识别
entities = [(word, flag) for word, flag in pos_tags if flag in ['nr', 'ns', 'nt']]
return {
'words': words,
'pos_tags': pos_dict,
'entities': entities
}
# 使用示例
preprocessor = TextPreprocessor('stopwords.txt', 'user_dict.txt')
result = preprocessor.process("我今天对小米的售后服务非常不满意")
print(result['words']) # ['今天', '小米', '售后服务', '非常', '不满意']
print(result['entities']) # [('小米', 'nt')]
这一章的内容就到这里。你想想看,分词、停用词过滤、词性标注、NER,这四个工具就像厨师手里的刀、砧板、锅、铲。单独看都不难,但组合起来就能做出一桌好菜。下一章咱们就用这些工具,开始搭建情感分析的第一个模型。