相似文本搜索
介绍
相似文本搜索是一种特殊的文本搜索,它的目的是找到与指定文本最相似的文档。这种技术通常通过计算文本间的相似度来实现,相似度可以通过各种方法,如余弦相似度,Jaccard相似度等,来计算。相似文本搜索在很多领域,如文档推荐,抄袭检测,文本生成等有广泛的应用。
应用场景
相似文本搜索的应用场景非常广泛,一些常见的场景如下:
1.文档推荐:根据用户的阅读历史,推荐与其最相关的文档
2.抄袭检测:检测文档中是否存在抄袭或抄袭的内容
3.文本生成:生成与指定文本相似的文本
4.文档分类:根据文档的相似度对文档进行分类
5.文档摘要:根据文档的相似度生成文档摘要
6.语言翻译:使用相似文本搜索技术来帮助翻译
7.相似问题搜索:在问答系统中,查找与指定问题最相似的问题
这些应用场景只是相似文本搜索的一部分,实际上它的应用非常广泛,并且还在不断的拓展。
常见算法
1.text2vec
流程
使用text2vec进行相似文本搜索的流程如下:
1.数据预处理:将文本数据进行预处理,包括删除停用词,词形还原,分词等。
2.生成词向量:使用text2vec工具生成每个词的词向量,词向量表示文本中每个词的语义信息。
3.计算文档向量:将每个文档的词向量平均得到文档向量,文档向量表示整个文档的语义信息。
4.计算文档相似度:根据文档向量的余弦相似度或者欧几里得距离等其他相似度指标计算文档之间的相似度。
5.查询:将用户的查询语句同样处理成向量,并与文档向量进行相似度比较,得到与查询语句最相似的文档。
这是text2vec进行相似文本搜索的大致流程,实际的实现过程中可能有一些细节的差异。
代码
import sys sys.path.append('..') from text2vec import SentenceModel, cos_sim, semantic_search embedder = SentenceModel() # Corpus with example sentences corpus = [ '花呗更改绑定银行卡', '我什么时候开通了花呗', 'A man is eating food.', 'A man is eating a piece of bread.', 'The girl is carrying a baby.', 'A man is riding a horse.', 'A woman is playing violin.', 'Two men pushed carts through the woods.', 'A man is riding a white horse on an enclosed ground.', 'A monkey is playing drums.', 'A cheetah is running behind its prey.' ] corpus_embeddings = embedder.encode(corpus) # Query sentences: queries = [ '如何更换花呗绑定银行卡', 'A man is eating pasta.', 'Someone in a gorilla costume is playing a set of drums.', 'A cheetah chases prey on across a field.'] for query in queries: query_embedding = embedder.encode(query) hits = semantic_search(query_embedding, corpus_embeddings, top_k=5) print("\n\n======================\n\n") print("Query:", query) print("\nTop 5 most similar sentences in corpus:") hits = hits[0] # Get the hits for the first query for hit in hits: print(corpus[hit['corpus_id']], "(Score: {:.4f})".format(hit['score']))
2.gensim
流程
- 加载文本库、停用词
- 文本预处理:中文分词,去除停用词
- 计算词频,选择频率大于1的词
- 创建字典(单词与编号之间的映射)
- 文档转换为向量
- 初始化一个tfidf模型,可以用它来转换向量
- 创建索引
- 相似度计算并返回相似度topN的文本
代码
from gensim import corpora, models, similarities from collections import defaultdict import jieba import time s1 = time.time() documents = [] with open('doc_search/data.txt','r') as file: for line in file: documents.append(line.replace('\n',"")) new_doc = "五年级的学生应该布置更多作业" # 1.文本预处理:中文分词,去除停用词 print('1.文本预处理:中文分词,去除停用词') # 获取停用词 stopwords = set() file = open("doc_search/stopwords.txt", 'r', encoding='UTF-8') for line in file: stopwords.add(line.strip()) file.close() # 将分词、去停用词后的文本数据存储在list类型的texts中 texts = [] for line in documents: words = ' '.join(jieba.cut(line)).split(' ') # 利用jieba工具进行中文分词 text = [] # 过滤停用词,只保留不属于停用词的词语 for word in words: if word not in stopwords: text.append(word) texts.append(text) for line in texts: print(line) # 待比较的文档也进行预处理(同上) words = ' '.join(jieba.cut(new_doc)).split(' ') new_text = [] for word in words: if word not in stopwords: new_text.append(word) print(new_text) # 2.计算词频 print('2.计算词频') frequency = defaultdict(int) # 构建一个字典对象 # 遍历分词后的结果集,计算每个词出现的频率 for text in texts: for word in text: frequency[word] += 1 # 选择频率大于1的词(根据实际需求确定) texts = [[word for word in text if frequency[word] > 1] for text in texts] for line in texts: print(line) # 3.创建字典(单词与编号之间的映射) print('3.创建字典(单词与编号之间的映射)') dictionary = corpora.Dictionary(texts) print(dictionary) # 打印字典,key为单词,value为单词的编号 print(dictionary.token2id) s2 = time.time() # 4.将待比较的文档转换为向量(词袋表示方法) print('4.将待比较的文档转换为向量(词袋表示方法)') # 使用doc2bow方法对每个不同单词的词频进行了统计,并将单词转换为其编号,然后以稀疏向量的形式返回结果 new_vec = dictionary.doc2bow(new_text) print(new_vec) # 5.建立语料库 print('5.建立语料库') # 将每一篇文档转换为向量 corpus = [dictionary.doc2bow(text) for text in texts] print(corpus) # 6.初始化模型 print('6.初始化模型') # 初始化一个tfidf模型,可以用它来转换向量(词袋整数计数),表示方法为新的表示方法(Tfidf 实数权重) tfidf = models.TfidfModel(corpus) # 将整个语料库转为tfidf表示方法 corpus_tfidf = tfidf[corpus] for doc in corpus_tfidf: print(doc) # 7.创建索引 print('7.创建索引') # 使用上一步得到的带有tfidf值的语料库建立索引 index = similarities.MatrixSimilarity(corpus_tfidf) # 8.相似度计算并返回相似度最大的文本 print('# 8.相似度计算并返回相似度最大的文本') new_vec_tfidf = tfidf[new_vec] # 将待比较文档转换为tfidf表示方法 print(new_vec_tfidf) # 计算要比较的文档与语料库中每篇文档的相似度 sims = index[new_vec_tfidf] print(sims) sims_list = sims.tolist() result = {key:value for key, value in enumerate(sims_list) if value > 0.4} result = dict(sorted(result.items(), key=lambda item: item[1],reverse = True)) res_doc = {} for k,v in result.items(): text = documents[k] res_doc[text] = v print(res_doc) # print(sims_list.index(max(sims_list))) # 返回最大值 # print("最相似的文本为:", documents[sims_list.index(max(sims_list))]) # 返回相似度最大的文本 s3 = time.time() print("词典建立的时间为:",s2-s1) print("比较的时间为:",s3-s2) if __name__ == "__main__": pass