4. 数据清洗与预处理:文本去噪、去重、标准化、处理表情符号与特殊字符
数据清洗,说白了就是给原始文本「洗澡」。
我做了这么多年量化分析,见过太多人拿着脏数据硬跑模型。结果呢?模型精度上不去,回测曲线漂亮得像假的一样。嗯,其实不是模型不行,是数据本身就有问题。
社交媒体情绪指数的基础是文本。但社交文本有多脏?你想想看——错别字、表情符号、@用户、URL链接、重复转发、广告水军……这些东西不清理干净,后面的分析全是白费功夫。
4.1 文本去噪:把垃圾信息筛出去
去噪,就是去掉那些对情绪分析没用的东西。
我个人习惯把噪声分成三类:
| 噪声类型 | 例子 | 处理方式 |
|---|---|---|
| 格式噪声 | HTML标签、URL、@用户、#话题# | 正则表达式直接剔除 |
| 内容噪声 | 广告、刷屏、无意义重复 | 规则过滤 + 模型判别 |
| 语言噪声 | 错别字、火星文、拼音缩写 | 词典映射 + 纠错模型 |
举个例子。我在做某电商平台的舆情监控时,发现大量「加V信xxxxx领红包」的垃圾评论。这些内容对情绪分析毫无价值,反而会拉偏模型。
核心原则:去噪不是越狠越好。过度清洗会丢失情感信息。比如「这手机真TMD垃圾」里的「TMD」虽然是脏话,但恰恰是强烈的负面情绪信号。
import re
def text_denoise(text):
# 去掉URL
text = re.sub(r'http\S+', '', text)
# 去掉@用户
text = re.sub(r'@\w+', '', text)
# 去掉#话题#,但保留话题文字
text = re.sub(r'#', '', text)
# 去掉多余空格
text = re.sub(r'\s+', ' ', text).strip()
return text
4.2 文本去重:别让重复数据骗了你
社交媒体的重复数据有多严重?我见过一个极端案例——某条负面新闻下面,同一个ID发了37遍一模一样的评论。如果不做去重,这条负面情绪会被放大37倍。
去重分两个层次:
- 完全去重:一模一样的内容,只保留一条
- 近似去重:内容相似度超过阈值(比如95%),合并处理
我的经验:完全去重用哈希就够了。近似去重我推荐MinHash或SimHash,处理千万级数据也不慢。
from simhash import Simhash
def dedup_by_simhash(texts, threshold=0.95):
seen = []
unique = []
for t in texts:
h = Simhash(t)
if not any(h.distance(s) < threshold for s in seen):
seen.append(h)
unique.append(t)
return unique
4.3 文本标准化:把「方言」翻译成「普通话」
标准化,就是把各种不规范的表达统一起来。
我曾经处理过一批微博数据,发现「哈哈哈」「哈哈哈哈」「哈哈哈哈哈」出现了几十种变体。如果不标准化,模型会认为它们是不同的词。
标准化的几个关键点:
- 统一大小写:英文全部转小写
- 全角半角转换:中文用全角,英文数字用半角
- 表情符号映射:😊 → [微笑] 或直接保留
- 重复字符压缩:「好棒棒棒棒」→「好棒」
注意:重复字符压缩要谨慎。「哈哈哈」压缩成「哈」会丢失情感强度。我一般保留2-3个重复字符作为情感增强信号。
import unicodedata
def normalize_text(text):
# 全角转半角(字母数字部分)
text = unicodedata.normalize('NFKC', text)
# 压缩重复字符(保留2个)
import re
text = re.sub(r'(.)\1{2,}', r'\1\1', text)
return text
4.4 表情符号与特殊字符处理
表情符号是社交媒体情绪分析的金矿。一个😡比一百字吐槽都管用。
我的处理策略是:
- 保留表情符号:直接作为特征输入模型
- 或者映射为文本:😊 → happy, 😢 → sad
- 特殊字符:比如「!!!」,表示强烈情绪,保留但压缩
为什么会这样?因为很多情绪模型在纯文本上表现一般,加上表情符号后准确率能提升5-10%。
import emoji
def process_emojis(text):
# 方案一:保留原样
# return text
# 方案二:映射为文本
return emoji.demojize(text, delimiters=("", ""))
4.5 完整清洗流水线
在实际项目中,我习惯把清洗步骤串成一条流水线。每一步都是可配置的,方便调试。
class TextCleaner:
def __init__(self):
self.pipeline = []
def add_step(self, func, name):
self.pipeline.append((func, name))
def clean(self, text):
for func, name in self.pipeline:
text = func(text)
return text
# 使用示例
cleaner = TextCleaner()
cleaner.add_step(text_denoise, '去噪')
cleaner.add_step(normalize_text, '标准化')
cleaner.add_step(process_emojis, '表情处理')
raw_text = "😡这手机太垃圾了!!!@小明 http://xxx.com"
clean_text = cleaner.clean(raw_text)
print(clean_text) # 输出: 这手机太垃圾了!!!
避坑指南:我曾经在清洗时把「不」字误删了,结果「我不喜欢」变成了「我喜欢」,情绪完全反转。从那以后,我每次清洗完都会抽样检查,确保语义没变。
4.6 本章知识体系
下面这张图,是我自己总结的数据清洗核心流程。你照着这个框架走,基本不会漏掉关键步骤。
嗯,数据清洗这一步确实枯燥,但它是整个情绪指数编制的基石。我见过太多团队在模型上花大功夫,结果数据源没洗干净,最后全白干。
记住一句话:垃圾进,垃圾出。你清洗得越仔细,后面的分析就越靠谱。