4、数据清洗实战:处理缺失值、去重、去除HTML标签、统一文本编码(Unicode)、正则表达式入门。
各位同学,欢迎来到数据清洗实战环节。
说实话,在新闻情绪分析这个领域,我踩过最大的坑不是模型选型,也不是调参,而是——数据太脏。你想想看,从网上爬下来的新闻文本,什么乱七八糟的东西都有。缺失值、重复内容、HTML标签乱飞、编码错乱……如果不把这些处理好,模型学出来的东西,说白了就是垃圾进垃圾出。
我个人习惯,拿到数据的第一件事,不是看分布,不是画图,而是先做清洗。今天这一章,我就带你把这几个核心操作过一遍。
4.1 处理缺失值
新闻数据里,缺失值很常见。比如某条新闻的正文字段是空的,或者发布时间缺失。怎么办?
我一般分三步走:
- 检测缺失:用
df.isnull().sum()快速定位 - 判断策略:如果缺失比例超过 50%,直接删掉整行;如果只是少量缺失,看情况填充
- 执行操作:用
df.dropna()或df.fillna()
举个例子:
import pandas as pd
# 假设 df 是新闻数据集
print(df.isnull().sum())
# 删除正文为空的新闻
df = df.dropna(subset=['content'])
# 用空字符串填充标题缺失
df['title'] = df['title'].fillna('')
嗯,这里要注意:千万别一股脑全删。我在项目中遇到过,某次删了太多行,导致样本量不够,模型直接崩了。所以,先看比例,再动手。
4.2 去重
新闻数据里重复很常见。同一篇新闻被多个网站转载,或者爬虫重复抓取。去重是必须的。
我常用的方法:
- 完全去重:
df.drop_duplicates() - 按关键列去重:比如按标题去重
df.drop_duplicates(subset=['title'])
但这里有个坑:有些新闻标题一样,内容却不同(比如更新版)。所以,我建议你按「标题+发布时间」联合去重,更稳妥。
# 按标题和发布时间联合去重
df = df.drop_duplicates(subset=['title', 'publish_time'])
我曾经因为只按标题去重,结果把同一事件的不同报道版本删掉了,导致模型学到的信息不完整。后来改了策略,效果好了很多。
4.3 去除HTML标签
爬虫抓下来的新闻,经常带着一堆HTML标签。比如 <p>内容</p>、<br> 这些。模型可看不懂这些,必须去掉。
我推荐用 BeautifulSoup 或者正则表达式。BeautifulSoup 更安全,正则更快。看你的场景。
from bs4 import BeautifulSoup
def clean_html(text):
soup = BeautifulSoup(text, 'html.parser')
return soup.get_text()
df['content'] = df['content'].apply(clean_html)
如果你不想引入第三方库,也可以用正则:
import re
def clean_html_re(text):
return re.sub(r'<[^>]+>', '', text)
我个人习惯用 BeautifulSoup,因为它还能处理一些不规范的标签。正则虽然快,但遇到嵌套标签容易出错。
4.4 统一文本编码(Unicode)
编码问题,是数据清洗里最让人头疼的。你想想看,有的新闻是UTF-8,有的是GBK,还有的是Latin-1。如果不统一,后面分词、建模全乱套。
我的做法是:
- 先检测编码:用
chardet库 - 再统一转为 UTF-8
import chardet
def detect_and_fix_encoding(text_bytes):
result = chardet.detect(text_bytes)
encoding = result['encoding']
return text_bytes.decode(encoding, errors='ignore')
# 假设你读取的是字节数据
with open('news.txt', 'rb') as f:
raw = f.read()
text = detect_and_fix_encoding(raw)
嗯,这里有个小技巧:如果数据量很大,别一条条检测,太慢了。可以抽样检测,然后统一用检测到的编码去解码。
我曾经在做一个多语言新闻项目时,因为编码没处理好,模型训练到一半直接报错。排查了半天,才发现是某条俄语新闻的编码不对。从那以后,我每次清洗数据都会先过一遍编码检测。
4.5 正则表达式入门
正则表达式,说白了就是文本匹配的瑞士军刀。在数据清洗里,它无处不在。
我常用的几个场景:
- 去除特殊字符(如标点、emoji)
- 提取特定模式(如邮箱、电话号码)
- 替换不规范写法
先看几个基础语法:
| 模式 | 含义 | 示例 |
|---|---|---|
. | 匹配任意字符(除换行) | a.b 匹配 "acb" |
* | 匹配前一个字符0次或多次 | ab*c 匹配 "ac", "abc" |
+ | 匹配前一个字符1次或多次 | ab+c 匹配 "abc", "abbc" |
? | 匹配前一个字符0次或1次 | ab?c 匹配 "ac", "abc" |
\d | 匹配数字 | \d+ 匹配 "123" |
\w | 匹配字母、数字、下划线 | \w+ 匹配 "hello_123" |
[] | 字符集 | [aeiou] 匹配元音字母 |
实战例子:去除新闻正文里的所有非中文字符(保留中文、数字、标点)
import re
def clean_text(text):
# 只保留中文、英文、数字、常见标点
pattern = r'[^\u4e00-\u9fa5a-zA-Z0-9,。!?、;:""''()【】《》\s]'
return re.sub(pattern, '', text)
df['content'] = df['content'].apply(clean_text)
你可能会问:为什么要保留中文?因为新闻情绪分析,中文是核心。去掉中文,那还分析什么?
正则表达式入门不难,但想精通需要大量练习。我建议你每次遇到新的清洗需求,先想想能不能用正则解决。久而久之,你就熟练了。
核心要点总结
- 缺失值:先检测比例,再决定删除还是填充
- 去重:按关键列联合去重,避免误删
- HTML标签:BeautifulSoup 或正则,推荐前者
- 编码统一:用 chardet 检测,转 UTF-8
- 正则:从基础语法开始,逐步应用到实际场景
我的小建议
数据清洗没有标准答案。每个项目的数据都不一样,你需要根据实际情况灵活调整。但记住一点:清洗得越干净,模型效果越好。别嫌麻烦。
注意
正则表达式虽然强大,但不要滥用。有些复杂的文本处理,用专门的NLP库(如jieba、spaCy)会更高效。正则适合做「规则明确」的清洗任务。
好了,这一章的内容就到这里。数据清洗虽然琐碎,但它是整个新闻情绪分析项目的基石。你想想看,如果数据本身就有问题,后面再好的模型也白搭。所以,别嫌麻烦,一步步来。
下一章,我们会进入文本预处理环节,包括分词、去停用词、词性标注等。到时候见。