从零到精通的完整指南
目录导读
为什么需要文本去重脚本?
在大数据时代,重复文本无处不在:爬虫采集的新闻、用户评论、论文查重、知识库清理……如果手动处理,不仅效率低下,还容易遗漏,一个高效的文本去重脚本能自动识别并剔除重复项,节省存储空间、提升数据质量。

核心问题:什么是“重复”?
- 完全重复:两段文本字符完全一致。
- 近似重复:仅有个别字符差异(如标点、空格、同义词替换),但语义相同。
我们的脚本需要应对这两种情况。
核心去重算法原理解析
哈希法(最快速)
将每一行文本通过哈希函数(如MD5、SHA1)生成唯一指纹,如果指纹相同,则判定为重复。
import hashlib
def md5(text):
return hashlib.md5(text.encode()).hexdigest()
优点:速度极快。
缺点:无法识别近似重复(比如仅多一个空格的两句话)。
SimHash(适合长文本近似去重)
Google提出的算法:将文本转为64位指纹,通过汉明距离(Hamming Distance)判断相似度,如果两个指纹差异小于等于3位,则视为相似。
MinHash + Jaccard相似度(通用方案)
将句子拆分为Shingle(如2-gram),计算集合的Jaccard系数,当相似度超过阈值(如0.8)时,判定为重复。
Python实战:编写一个基础去重脚本
完整代码示例(支持文件与命令行参数)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import os
from collections import OrderedDict
def remove_duplicates(input_file, output_file):
seen = set()
unique_lines = []
with open(input_file, 'r', encoding='utf-8') as f:
for line in f:
line_stripped = line.strip()
if line_stripped and line_stripped not in seen:
seen.add(line_stripped)
unique_lines.append(line_stripped)
with open(output_file, 'w', encoding='utf-8') as f:
f.write('\n'.join(unique_lines))
print(f"去重完成!原始行数:{len(seen)+len(unique_lines)-1},去重后行数:{len(unique_lines)}")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("用法:python dedup.py 输入文件.txt 输出文件.txt")
sys.exit(1)
remove_duplicates(sys.argv[1], sys.argv[2])
运行方法
python dedup.py input.txt output.txt
局限性:该脚本仅处理精确重复,如果需要处理“近似重复”,请看下一节。
进阶:基于相似度的高效去重方案
1 使用fuzzywuzzy库识别近似重复
from fuzzywuzzy import fuzz
from collections import deque
def fuzzy_dedup(lines, threshold=80):
unique = []
for line in lines:
is_dup = False
for existing in unique:
if fuzz.ratio(line, existing) >= threshold:
is_dup = True
break
if not is_dup:
unique.append(line)
return unique
性能提示:对于大数据量,逐对比较是O(n²)复杂度,建议先按长度分组,或使用SimHash预过滤。
2 集成SimHash的工业级方案
from simhash import Simhash, SimhashIndex
def build_simhash_index(lines):
data = [(str(i), Simhash(line)) for i, line in enumerate(lines)]
index = SimhashIndex(data, k=3) # k为汉明距离阈值
return index
该方案能快速定位与给定文本相似的候选,适用于百万级数据。
常见问题与优化技巧(问答篇)
Q1:我的数据量极大(几千万行),内存不够怎么办?
A:采用分片+外排序策略。
- 将文件按首字母或哈希值分成多个小文件(如每个100万行)。
- 分别对每个小文件去重。
- 最后合并结果,再对合并后的文件跨片去重(因为可能跨片重复)。
Q2:如何区分“标题重复”和“内容重复”?
A:在脚本中添加优先级策略。
- 第一遍:按标题哈希去重(保留最完整版本)。
- 第二遍:对去重后的集合做内容相似度过滤。
示例代码片段:def dedup_by_title(articles): seen_titles = set() result = [] for art in articles: title_hash = md5(art['title']) if title_hash not in seen_titles: seen_titles.add(title_hash) result.append(art) return result
Q3:脚本运行很慢,如何优化?
A:从以下三方面入手。
- 使用生成器:避免一次性读入所有数据到内存。
- 多进程并行:按行分割后使用
multiprocessing分片处理。 - 选择合适算法:精确去重用哈希法,近似去重用SimHash(速度是fuzzywuzzy的百倍以上)。
Q4:如何处理中文停用词和符号?
A:在计算哈希或相似度前,先对文本做预处理:
import re
def clean_text(text):
# 移除标点符号、空格、换行
text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9]', '', text)
# 可选:移除停用词(如“的”、“是”、“在”)
return text
总结与最佳实践
编写文本去重脚本的核心步骤:
- 明确需求:精确去重还是近似去重?
- 选择算法:小数据用哈希,大数据用SimHash或MinHash。
- 考虑扩展性:脚本应支持管道操作、文件格式多样化(如JSON、CSV)。
- 性能调优:先做数据清洗(去除空行、特殊字符),再跑去重。
推荐逻辑顺序:
- 第一层:精确哈希去重(移除完全相同的行)。
- 第二层:长度分组 + 相似度阈值(移除近似重复)。
- 第三层:人工抽检(针对特殊场景,如法规文档)。
将脚本封装为函数,方便集成到更大规模的数据清洗流水线中,反复测试不同阈值(如SimHash的k值从3到6),找到最适合你数据集的平衡点。
本文参考了Python官方文档、fuzzywuzzy库手册以及SimHash论文的中文解读,结合搜索引擎中常见去重方案的精髓进行重构编写,确保技术细节准确且易于理解。