利用Python过滤相似文本的简单方法示例
本文介绍如何使用Python和SpaCy库,通过预处理标题、生成文本对并计算余弦相似度,递归地过滤掉内容相似的重复文档。该方法适用于归档清理、歌词去重等场景,能有效保留唯一性文档并释放存储空间。
问题
假设你管理的存档中包含成千上万份文档,其中存在大量彼此重复的内容,即便标题不同,核心内容也可能完全一致。此时,若上级要求你通过移除冗余的重复文档来释放存储空间,该如何操作?
核心挑战在于:如何识别并过滤掉那些标题高度相似、从而推测内容可能相同的文本?同时,在实现这一目标时,需确保不会误删过多文档,而是保留下一组具有唯一性的文档集合。下面通过具体代码示例来阐明这一过程:
titles = [
"End of Year Review 2020",
"2020 End of Year",
"January Sales Projections",
"Accounts 2017-2018",
"Jan Sales Predictions"
]
# Desired output
filtered_titles = [
"End of Year Review 2020",
"January Sales Projections",
"Accounts 2017-2018",
]
鉴于上述问题,本文适合那些希望快速掌握解决此类问题的实用方法,并广泛了解其背后原理的读者!
接下来,我将详细介绍为解决该问题所采取的具体步骤。以下是整体控制流的概要:
对所有标题文本进行预处理
生成所有标题的组合配对
测试所有配对的相似程度
若某对文本未能通过相似性测试,则删除其中一份文本,并生成一个新的文本列表
继续对新列表中的相似文本进行测试,直到列表中不再存在相似的文本为止
在Python中,这一逻辑可以很好地映射到递归函数上!
代码
以下是Python中实现此功能的两个关键函数。
import spacy
from itertools import combinations
# Set globals
nlp = spacy.load("en_core_web_md")
def pre_process(titles):
"""
Pre-processes titles by removing stopwords and lemmatizing text.
:param titles: list of strings, contains target titles,.
:return: preprocessed_title_docs, list containing pre-processed titles.
"""
# Preprocess all the titles
title_docs = [nlp(x) for x in titles]
preprocessed_title_docs = []
lemmatized_tokens = []
for title_doc in title_docs:
for token in title_doc:
if not token.is_stop:
lemmatized_tokens.append(token.lemma_)
preprocessed_title_docs.append(" ".join(lemmatized_tokens))
del lemmatized_tokens[
:
] # empty the lemmatized tokens list as the code moves onto a new title
return preprocessed_title_docs
def similarity_filter(titles):
"""
Recursively check if titles pass a similarity filter.
:param titles: list of strings, contains titles.
If the function finds titles that fail the similarity test, the above param will be the function output.
:return: this method upon itself unless there are no similar titles; in that case the feed that was passed
in is returned.
"""
# Preprocess titles
preprocessed_title_docs = pre_process(titles)
# Remove similar titles
all_summary_pairs = list(combinations(preprocessed_title_docs, 2))
similar_titles = []
for pair in all_summary_pairs:
title1 = nlp(pair[0])
title2 = nlp(pair[1])
similarity = title1.similarity(title2)
if similarity > 0.8:
similar_titles.append(pair)
titles_to_remove = []
for a_title in similar_titles:
# Get the index of the first title in the pair
index_for_removal = preprocessed_title_docs.index(a_title[0])
titles_to_remove.append(index_for_removal)
# Get indices of similar titles and remove them
similar_title_counts = set(titles_to_remove)
similar_titles = [
x[1] for x in enumerate(titles) if x[0] in similar_title_counts
]
# Exit the recursion if there are no longer any similar titles
if len(similar_title_counts) == 0:
return titles
# Continue the recursion if there are still titles to remove
else:
# Remove similar titles from the next input
for title in similar_titles:
idx = titles.index(title)
titles.pop(idx)
return similarity_filter(titles)
if __name__ == "__main__":
your_title_list = ['title1', 'title2']
similarty_filter(your_title_list)
第一个函数用于预处理标题文本;它的作用是移除“the”、“a”、“and”等停用词,并仅返回标题中单词的词形还原(lemma)形式。
若向该函数输入“End of Year Review 2020”,输出将为“end year review 2020”;若输入“January Sales Projections”,输出则为“january sale projection”。
该实现主要利用了Python中易于使用的SpaCy库。
第二个函数(位于代码第30行)负责为所有标题创建配对,并判断它们是否通过余弦相似度测试。如果未找到任何相似标题,则直接输出不相似标题的列表;如果找到了相似标题,在移除未通过相似度测试的配对后,它会将这些过滤后的标题再次传入自身,以检查是否仍存在相似标题。
这就是递归机制的作用所在!其逻辑简单明了:函数将持续检查输出结果,以确保在返回“最终”输出之前,列表中确实不再包含相似标题。
什么是余弦相似度?
简而言之,这就是SpaCy在后台执行的操作……
首先,回顾之前预处理过的文本。SpaCy首先将输入的单词转化为一个数字矩阵。
完成这一步后,你可以将这些数字转换为向量,也就是说,可以在坐标系中绘制出这些向量。
一旦完成上述转换,计算两条直线夹角的余弦值,即可判断它们是否指向相同的方向。

因此,在上图中,假设A线代表“闪亮的橙色水果”,B线代表“闪亮的红苹果是一种水果”。
在此情况下,A线和B线均对应于由空格分隔这两个句子所生成的数字矩阵。这两条线之间的夹角——在上面的图表中由希腊字母theta表示——具有极高的实用价值!你可以计算余弦值来判断这两条线是否指向同一方向。
这听起来似乎显而易见且难以计算,但关键在于,这种方法为我们提供了一种自动化整个处理流程的手段。
总结
回顾全文,我已解释了递归Python函数如何结合余弦相似度与SpaCy自然语言处理库,接收相似文本输入,并返回彼此差异较大的文本。
此类用例可能非常广泛……类似于我在本文开头提到的归档场景,你还可以利用此方法在数据集中过滤具有唯一歌词的歌曲,甚至筛选内容类型独特的社交媒体帖子。
到此这篇关于利用Python过滤相似文本的简单方法的文章就介绍到这了,更多相关Python过滤相似文本内容请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













