4、数据预处理实战:数据清洗、文本分词、停用词过滤
说实话,很多做舆情分析的朋友,一上来就急着跑模型、画热力图。结果呢?数据里一堆垃圾,出来的图根本没法看。我踩过这个坑,所以今天咱们老老实实把数据预处理这块啃下来。
数据预处理,说白了就是给原始数据「洗澡」。洗得干净,后面的分析才靠谱。咱们分三步走:清洗、分词、过滤停用词。
4.1 数据清洗:去重、去噪、处理缺失值
原始数据长什么样?我举个例子你就明白了。从微博、论坛扒下来的评论,经常是这种画风:
# 原始数据样例
"这个产品太棒了!!!"
"这个产品太棒了!!!" # 重复
"点击链接" # 广告噪音
"😊😊😊😊😊" # 纯表情
" " # 空白
"我觉的很好" # 错别字
嗯,看着就头疼。咱们一个一个解决。
4.1.1 去重
重复数据是最常见的。用户刷屏、爬虫重复抓取,都会导致重复。我个人习惯用 pandas 的 drop_duplicates(),简单粗暴:
import pandas as pd
df = pd.read_csv('weibo_comments.csv')
print(f"去重前数据量: {len(df)}")
# 基于文本内容去重
df_clean = df.drop_duplicates(subset=['content'])
print(f"去重后数据量: {len(df_clean)}")
我在项目中遇到过一种情况:两条评论内容一模一样,但发布时间不同。这时候要不要去重?我的建议是——看场景。如果是做情绪趋势分析,保留时间戳,只去重内容;如果是做词频统计,直接全量去重就行。
4.1.2 去噪
去噪是门手艺活。常见的噪音包括:
- HTML标签:比如
<br>、<a>这些 - URL链接:http、https 开头的
- 特殊符号:@某人、#话题#、表情符号
- 纯数字或纯标点:比如 "123456"、"!!!"
我一般用正则表达式来处理:
import re
def clean_text(text):
# 去除HTML标签
text = re.sub(r'<[^>]+>', '', text)
# 去除URL
text = re.sub(r'http\S+|www\S+', '', text)
# 去除@和#内容
text = re.sub(r'@\w+|#\w+#', '', text)
# 保留中英文、数字、基本标点
text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9,。!?、]', '', text)
return text.strip()
df_clean['content'] = df_clean['content'].apply(clean_text)
4.1.3 处理缺失值
缺失值怎么处理?三种策略:
| 策略 | 适用场景 | 代码示例 |
|---|---|---|
| 直接删除 | 缺失比例 < 5% | df.dropna(subset=['content']) |
| 填充默认值 | 缺失比例 5%-20% | df.fillna({'content': '无内容'}) |
| 模型预测填充 | 缺失比例 > 20% | 用其他字段预测(不常用) |
我个人习惯:先看看缺失值长什么样。如果是整行空白,直接删;如果是部分字段缺失,看情况填充。别一上来就全删,数据来之不易啊。
4.2 文本分词:jieba vs NLTK
分词是中文NLP的第一步。英文有空格天然分隔,中文可没有。你想想看,「武汉市长江大桥」该怎么切?
- 武汉 / 市长江 / 大桥 ❌
- 武汉市 / 长江大桥 ✅
这就是分词的难点。咱们用 jieba 来处理中文,用 NLTK 处理英文(如果有的话)。
4.2.1 jieba 分词实战
import jieba
text = "这个产品真的太棒了,我强烈推荐给所有人!"
# 精确模式(推荐)
words = jieba.lcut(text)
print(words)
# 输出: ['这个', '产品', '真的', '太棒了', ',', '我', '强烈推荐', '给', '所有人', '!']
# 添加自定义词典
jieba.add_word('太棒了')
jieba.add_word('强烈推荐')
# 去掉标点符号
words_clean = [w for w in words if w not in ',。!?、']
print(words_clean)
4.2.2 NLTK 分词(处理英文)
如果你的数据里混了英文,可以用 NLTK:
import nltk
from nltk.tokenize import word_tokenize
text_en = "This product is amazing! I highly recommend it."
tokens = word_tokenize(text_en)
print(tokens)
# 输出: ['This', 'product', 'is', 'amazing', '!', 'I', 'highly', 'recommend', 'it', '.']
嗯,英文分词简单多了。但要注意大小写统一,一般转小写处理。
4.3 停用词过滤
停用词是什么?就是那些高频但没实际意义的词。比如「的」「了」「是」「在」「我」「你」等等。这些词在情绪分析里是噪音,得去掉。
我一般用现成的停用词表,再根据项目情况手动补充。网上有哈工大停用词表、百度停用词表,都挺好用。
# 加载停用词表
def load_stopwords(filepath='stopwords.txt'):
with open(filepath, 'r', encoding='utf-8') as f:
stopwords = set([line.strip() for line in f])
return stopwords
stopwords = load_stopwords()
# 过滤停用词
def filter_stopwords(words, stopwords):
return [w for w in words if w not in stopwords and len(w) > 1]
# 完整流程
text = "这个产品真的太棒了,我强烈推荐给所有人!"
words = jieba.lcut(text)
words_clean = [w for w in words if w not in ',。!?、']
words_filtered = filter_stopwords(words_clean, stopwords)
print(words_filtered)
# 输出: ['产品', '太棒了', '强烈推荐', '所有人']
4.4 本章知识体系
下面这张图,是我梳理的数据预处理全流程。你跟着走一遍,基本不会出大问题。
4.5 避坑指南
最后,分享几个我踩过的坑:
- 分词粒度问题:太细了丢失语义,太粗了信息不够。我一般先用精确模式,再根据结果调整词典。
- 停用词表别乱用:通用停用词表可能把「不」「没」这种否定词也删了。情绪分析里,「不好」「不喜欢」可是关键信息。建议保留否定词。
- 编码问题:中文数据经常遇到
UnicodeDecodeError。我习惯用encoding='utf-8',遇到特殊字符加errors='ignore'。 - 性能问题:几十万条数据分词,jieba 会有点慢。可以试试
jieba.enable_parallel()开启并行,或者用pkuseg替代。
好了,数据预处理这块就讲到这里。你跟着代码走一遍,把原始数据洗得干干净净,后面做热力图就顺手多了。