基于python语言使用余弦相似性算法进行文本相似度分析
编写此脚本的目的:
本人从事软件测试工作,近两年发现项目成员总会提出一些内容相似的问题,导致开发抱怨。一开始想搜索一下是否有此类工具能支持查重的工作,但并没找到,因此写了这个工具。通过从纸上谈兵到着手实践,还是发现很多大大小小的问题(一定要动手去做喔!),总结起来就是理解清楚参考资料、按需设计、多角度去解决问题。
脚本进行相似度分析的基本过程:
1、获取Bug数据。读取excel表,获取到“BugID”和“Bug内容”
2、获取指定格式的Bug关键字集合。使用“jieba包”,采用“搜索模式”,对Bug内容进行分词,获取到分词表后,使用“正则表达式”过滤,拿到词语(词语长度>=2),提出掉单个字、符号、数字等非关键字
3、计算词频(TF)。在步骤2中获取到关键字总量,在本步骤,则对筛选后的关键字进行频率统计,最后得出“TF值(关键字出现频率/总词数)”
4、获取词逆文档频率(IDF)(也可以理解为权重)。在本步骤,有个重要的前提就是“语料库”,这里我没有使用开放、通用的语料库,而是使用本项目的“测试用例步骤、约束条件”等内容,唯一的原因就是“很适应Bug内容的语言场景”,在此模块,也是采用分词,然后利用参考资料中的计算公式,获取到每个“关键词”的IDF值,并存至名称为“get_IDF_value.txt”的文件中(一开始没放到这里,导致出现重复、多次进行本步骤计算,几kb的文本内容还能接受,几百kb的就......当时跑了一夜都没完!)
5、获取TF_IDF值,并据此对Bug关键字进行倒序排列,然后硬性截取所有Bug排位前50%的关键字,并形成集合,然后以冒泡的形式,从第一个Bug开始,进行“相似度计算”(公式见参考资料),最终将相似度大于阀值的Bug,以形式“Bug编号_1(被比对对象)-Bug编号_2(比对对象)”打印到名称为“bug_compare_result.xls”的Excel表中
过程中一些特殊点的处理:
1、“所有Bug排位前50%的关键字,并形成集合”之所以创建该列表是为减少单个列表或字典在多个函数使用的频率,肯定是可以减少脚本问题频率的。
2、语料库的选择是为适应使用需求
3、得到TF_IDF值的目的只是为了获取到“排位前50%的Bug关键字”
4、逆文档频率(IDF)值会存储至“get_IDF_value.txt”文件中,每次运行脚本时会提醒是否更改语料库
说明:
1、代码友好性差,技术能力有限。当然可塑性很高 ~ ~
2、出于练习的目的,独立编写“IDF计算”的脚本,并放到另一路径下
源码:(纯生肉,通过代码注释还是能看到本人设计过程的心态)
sameText.py
--------------------sameText.py--------------------------
#-*- coding:utf-8 -*-
import jieba
import re
import CorpusDatabase.getIDF as getIDF
import math
import xlrd
import xlwt
import time
#######获取原始bug数据
re_rule_getTF = re.compile(r"^([\u4e00-\u9fa5]){2,20}")#选择中文开头,且文字长度为2-20,一定要记住哇
Top_List = []#将分词的列表和TF_IDF值前50%的列表合于此处
Compare_CosResult = []#相似度大于??(可调整)的问题号
BugID_List = []#用于存放BugID
getIDF_get_IDF_value = {}#存储语料库中各关键词的权重
xiangsidu = 0.8
###########
def read_Originalbase(filename):
Original_Bug_Dict = {}
book = xlrd.open_workbook(filename)
sheet_name = book.sheet_by_index(0)
nrows = sheet_name.nrows
for i in range(nrows):
Original_Bug_Dict[sheet_name.row_values(i)[0]] = sheet_name.row_values(i)[1]
return Original_Bug_Dict ###########词频统计###################
def get_TF_value(test_String_one):
word_counts = 0#统计除空、单字、符号以外的总词数
counts = {}
counts_two = {}
words_re_TF = []
words = jieba.lcut_for_search(test_String_one)
#这边得加段正则表达式的,筛除掉words非中文且单字的内容,并构建words_re_TF
for i in words:
if re.match(re_rule_getTF,i):
words_re_TF.append(i)
#统计每个分词的出现次数,即总词数量counts
Top_List.append(words_re_TF)#全局的作用列表,很关键
for word in words_re_TF:
word_counts = word_counts + 1
counts[word] = counts.get(word,0) + 1#为关键字出现次数进行统计,从0开始,get中第一个为key,0为赋给其对应的value
#获取每个关键字在整句话中出现的频率,即最终词频
for count in counts:
counts_two[count] = counts_two.get(count,(counts[count]/float(word_counts)))
return counts_two
###########获取TF_TDF值,并向量化#############
def get_TF_IDF_Key(test_String_two):
global getIDF_get_IDF_value
TestString_TF_value = {}
TF_IDF_value = {}
The_Last_TF_IDF_List = []
Corpus_weight_value = getIDF_get_IDF_value#此部分直接定义一个存储语料库权重的全局变量吧
TestString_TF_value = get_TF_value(test_String_two)
for i in TestString_TF_value:
balance_value = 1
for j in Corpus_weight_value:
if i == j:
TF_IDF_value[i] = float(TestString_TF_value[i]) * float(Corpus_weight_value[j])
elif i != j and balance_value != len(Corpus_weight_value):#遍历列表过程中,判断是否与TF的值一样,且是否遍历到最后一个元素了
balance_value = balance_value + 1#计算遍历次数
continue
else:
TF_IDF_value[i] = float(TestString_TF_value[i]) * 1#对于语料库中不存在的词,权重默认为1
The_Last_TF_IDF_List = sorted(TF_IDF_value,key = TF_IDF_value.__getitem__,reverse=True)
The_Last_TF_IDF_List = The_Last_TF_IDF_List[0:int((len(The_Last_TF_IDF_List)/2) + 0.5)]#默认取一半关键字
Top_List.append(The_Last_TF_IDF_List)#全局的作用列表,很关键
return The_Last_TF_IDF_List
def cosine_result(the_Top_List):#计算余弦相似度
global Compare_CosResult
global BugID_List
global xiangsidu
cos_result = 0.0
keymix = []
compare_one = []
compare_two = []
control_i = 0
for i in range(0,len(the_Top_List) - 1,2):
control_j = control_i + 1
for j in range(i + 2,len(the_Top_List) - 1,2):
keymix = list(set(the_Top_List[i+1] + the_Top_List[j+1]))#去掉重复的关键字
compare_one = the_Top_List[i]
compare_two = the_Top_List[j]
compare_one_dict = {}
compare_two_dict = {}
fenzi_value = 0.0
fenmu_value = 1.0
fenmu_value_1 = 0.0
fenmu_value_2 = 0.0
for word_one in compare_one:
for unit_keymix_one in keymix:
if unit_keymix_one == word_one:
compare_one_dict[unit_keymix_one] = compare_one_dict.get(unit_keymix_one,0) + 1
else:
compare_one_dict[unit_keymix_one] = compare_one_dict.get(unit_keymix_one,0) + 0
for word_two in compare_two:
for unit_keymix_two in keymix:
if unit_keymix_two == word_two:
compare_two_dict[unit_keymix_two] = compare_two_dict.get(unit_keymix_two,0) + 1
else:
compare_two_dict[unit_keymix_two] = compare_two_dict.get(unit_keymix_two,0) + 0
###########计算余弦相似度##################
for k in compare_one_dict:
fenzi_value = fenzi_value + compare_one_dict[k] * compare_two_dict[k]
fenmu_value_1 = fenmu_value_1 + math.pow(compare_one_dict[k],2)
fenmu_value_2 = fenmu_value_2 + math.pow(compare_two_dict[k],2)
fenmu_value = math.sqrt(fenmu_value_1) * math.sqrt(fenmu_value_2)
cos_result = fenzi_value / fenmu_value
if cos_result >= xiangsidu:#调控值
Compare_CosResult.append(str(int(BugID_List[control_i])) + '-' + str(int(BugID_List[control_j])))#浮点数转整数再转字符串
control_j = control_j + 1
control_i = control_i + 1
return 0
#########将最终结果写入到新的xls文件中#########
def write_BugBase(bug_base,CosResult_list):
global xiangsidu
key_list = list(bug_base.keys())
value_list = list(bug_base.values())
newbook = xlwt.Workbook(encoding = "utf-8", style_compression = 0)
sheet_name = newbook.add_sheet('sheet1',cell_overwrite_ok = True)
for i in range(0,len(key_list)):
bug_com_key_list = []
if i == 0:
sheet_name.write(i,0,key_list[i])
sheet_name.write(i,1,value_list[i])
sheet_name.write(i,2,u"相似问题(相似度大于%.1f)"%(xiangsidu))
else:
re_CosResult = re.compile(r"^((%s)-\d{0,3}$)"%str(int(key_list[i])))
sheet_name.write(i,0,key_list[i])
sheet_name.write(i,1,value_list[i])
for bug_com_key in CosResult_list:
if re.match(re_CosResult,bug_com_key):########
bug_com_key_list.append(bug_com_key)########
else:
continue
for j in range(len(bug_com_key_list)):
sheet_name.write(i,j + 2,bug_com_key_list[j] + "\n")#重复写入
newbook.save("bug_compare_result.xls") def main():
global getIDF_get_IDF_value
user_message = input("是否更改了语料库,请输入 Y or N:")
starttime = time.time()
if str(user_message) == "Y" or str(user_message) == "y":
getIDF_get_IDF_value = getIDF.get_IDF_value()
getIDF_file = open('get_IDF_value.txt','w')
getIDF_file.write(str(getIDF_get_IDF_value))
getIDF_file.close()
else:
getIDF_file = open('get_IDF_value.txt','r')
getIDF_get_IDF_value = eval(getIDF_file.read())
getIDF_file.close()
##########
Bug_base = read_Originalbase('bug.xls')
for main_key_value_1 in Bug_base.keys():
if main_key_value_1 == "Bug编号":
continue
else:
BugID_List.append(main_key_value_1)
for main_key_value_2 in Bug_base.values():
if main_key_value_2 == "Bug标题":
continue
else:
get_TF_IDF_Key(main_key_value_2)#字符串
cosine_result(Top_List)
write_BugBase(Bug_base,Compare_CosResult)
endtime = time.time()
print("共用时:%d秒!"%(endtime - starttime)) if __name__ == '__main__':
main()
-----------------------------------------------------------------
getIDF.py
---------------------getIDF.py-------------------------------
#-*- coding:utf-8 -*-
import os
import re
import jieba
import math
import re
######正则表达式规则######
re_rule_getIDF = re.compile(r"^([\u4e00-\u9fa5]){2,20}")#选择中文开头,且文字长度为2-20,一定要记住哇
#读取语料库,并计算出语料库中所有关键词的权重
def get_IDF_value():
Corpus_file_list = []#获取所有语料库文件,以列表形式保存
Corpus_text_list = []
words_re_IDF = []
Corpus_word_counts = 0
Corpus_counts = {}
Corpus_counts_two = {}
for root,dirs,files in os.walk('.',topdown=False):
for name in files:
str_value = ""
str_value = os.path.join(root,name)
Corpus_file_list.append(str_value)
for i in Corpus_file_list:
if i == '.\\CorpusDatabase\\__pycache__\\getIDF.cpython-36.pyc' or i == '.\\CorpusDatabase\\__pycache__\\__init__.cpython-36.pyc' or i == '.\\CorpusDatabase\\getIDF.py' or i == '.\\CorpusDatabase\\getIDF.pyc' or i == '.\\CorpusDatabase\\__init__.py' or i == '.\\CorpusDatabase\\__init__.pyc' or i == '.\\sameText.py' or i == '.\\bug.xls' or i == '.\\bug_compare_result.xls' or i == '.\\get_IDF_value.txt':
continue
else:
file_object = open(i,'r',encoding = 'UTF-8')#避免出现编码问题,open文件时使用UTF-8编码
file_content = file_object.readlines()
for j in file_content:
Corpus_text_list.append(j)
#对语料库进行分词,统计总词数和每个词出现频率,最终计算出权重
for split_words in Corpus_text_list:
words = jieba.lcut_for_search(split_words)
#这边得加段正则表达式的,筛除掉words非中文、单个汉字的内容,并构建words_re_IDF
for k in words:
if re.match(re_rule_getIDF,k):
words_re_IDF.append(k)
for word in words_re_IDF:
Corpus_word_counts = Corpus_word_counts + 1
Corpus_counts[word] = Corpus_counts.get(word,0) + 1
for count in Corpus_counts:
Corpus_counts_two[count] = Corpus_counts_two.get(count,(math.log(Corpus_word_counts / (float(Corpus_counts[count] + 1)))))
return Corpus_counts_two
-------------------------------------------------------
文档结构:
NLP为主文件名,文件中包括:
——bug.xls(存有BugID和Bug内容的原始文件)
——bug_compare_result.xls(存储比对结果的文件,由程序生成)
——get_IDF_value.txt(存储IDF值的文件)
——sameText.py(主脚本文件)
——CorpusDatabase
——__init__.py(空脚本文件)
——getIDF.py(计算IDF值的文件)
——OAcase.txt(语料库)
——__pycache__(程序自动生成,不用关注)
Bug原文件样式:
最终结果:
相似的问题会从第3列开始写入
参考资料:
http://www.ruanyifeng.com/blog/2013/03/tf-idf.html
http://www.ruanyifeng.com/blog/2013/03/cosine_similarity.html
基于python语言使用余弦相似性算法进行文本相似度分析的更多相关文章
- 关于《selenium2自动测试实战--基于Python语言》
关于本书的类型: 首先在我看来技术书分为两类,一类是“思想”,一类是“操作手册”. 对于思想类的书,一般作者有很多年经验积累,这类书需要细读与品位.高手读了会深有体会,豁然开朗.新手读了不止所云,甚至 ...
- 《Selenium2自动化测试实战--基于Python语言》 --即将面市
发展历程: <selenium_webdriver(python)第一版> 将本博客中的这个系列整理为pdf文档,免费. <selenium_webdriver(python)第 ...
- 基于python语言的tensorflow的‘端到端’的字符型验证码识别源码整理(github源码分享)
基于python语言的tensorflow的‘端到端’的字符型验证码识别 1 Abstract 验证码(CAPTCHA)的诞生本身是为了自动区分 自然人 和 机器人 的一套公开方法, 但是近几年的 ...
- 关于《Selenium3自动化测试实战--基于python语言》
2016年1月,机缘巧合下我出版了<Selenium2自动化测试实战--基于python语言>这本书,当时写书的原因是,大部分讲Selenium的书并不讲编程语言和单元测试框,如果想在项目 ...
- selenium2自动化测试实战--基于Python语言
自动化测试基础 一. 软件测试分类 1.1 根据项目流程阶段划分软件测试 1.1.1 单元测试 单元测试(或模块测试)是对程序中的单个子程序或具有独立功能的代码段进行测试的过程. 1.1.2 集成测试 ...
- selenium2环境搭建----基于python语言
selenium支持多种语言如java.c#.Python.PHP等,这里基于python语言,所以这里搭建环境时需做俩步操作: ----1.Python环境的搭建 ----2.selenium的安装 ...
- 《Selenium 2自动化测试实战 基于Python语言》中发送最新邮件无内容问题的解决方法
虫师的<Selenium 2自动化测试实战 基于Python语言>是我自动化测试的启蒙书 也是我推荐的自动化测试入门必备书,但是书中有一处明显的错误,会误导很多读者,这处错误就是第8章自动 ...
- Python实现的选择排序算法原理与用法实例分析
Python实现的选择排序算法原理与用法实例分析 这篇文章主要介绍了Python实现的选择排序算法,简单描述了选择排序的原理,并结合实例形式分析了Python实现与应用选择排序的具体操作技巧,需要的朋 ...
- 文本相似度分析(基于jieba和gensim)
基础概念 本文在进行文本相似度分析过程分为以下几个部分进行, 文本分词 语料库制作 算法训练 结果预测 分析过程主要用两个包来实现jieba,gensim jieba:主要实现分词过程 gensim: ...
随机推荐
- Windows 应用容器化
背景 在这个时间点,我们可能已经对 Linux 容器使用已经达到熟练掌握的程度,因为 Docker 与 Kubernetes 都是最早为 Linux 平台设计.当我们从容器这项技术中体会到种种收益,对 ...
- 2.秋招复习简单整理之String、StringBuffer、StringBuilder的区别和联系
String特点: 1.String是不可变对象,一旦赋值创建就不变,这意味着对String的一切修改将产生一个新的字符串,比如String的subString,replace.toUpperCase ...
- 浅入深出Vue:注册
基本布局已经有了, 现在我们来开始做我们的注册页面~ 当然需要注册才能发表文章啊(糟老头子坏得很, 我可以只有我一个人能发啊). 这里我们设定只有注册才能发表文章,也就淡化了管理员这个概念.在开发中先 ...
- [NOIP2016]换教室 题解(奇怪的三种状态)
2558. [NOIP2016]换教室 [题目描述] 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有2n节课程安排在n个时间段上.在第i(1< ...
- Element-ui DatePicker显示周数
1.场景描述 我们公司是做电商的,运营的工作指标都是按周来定的,所以他们对周特别敏感,希望我们能在日期选择器上显示周数.刚接到这个需求时,心中很不乐意,因为Element-ui的日期选择器根本不支持显 ...
- Java面试题汇总---整理版(附答案)
今天继续为大家整理Java面试题,并涉及数据库和网络等相关知识,希望能帮助到各位开发者. 1,为什么要用spring,Spring主要使用了什么模式? spring能够很好的和各大框架整合,它通过IO ...
- 摄像头驱动的使能配置、V4L2编程接口的设计应用
摄像头采集子系统 一.摄像头驱动的使能配置 摄像头软件驱动构架 摄像头采集系统由上图所示,硬件(摄像头) -> 驱动(Linux内核配置中,选择支持V4L2的驱动选项) -> V4L2接口 ...
- c++小游戏——五子棋
#include<iostream> #include<iomanip> #include<cstring> using namespace std; const ...
- 小白开学Asp.Net Core 《一》
在开篇中介绍了项目的搭建以及项目中所用到的第三方工具 本篇介绍SqlSugar和Dapper在本项目的实现 一.SqlSugar SqlSuagr的介绍就直接浏览官方网站,官网地址将在底部给出. 在本 ...
- C#写进程守护程序
最近写了好多次进程守护程序,今天在这里总结一下. 用到的知识点: 1.在程序中启动进程, 2.写Windows服务, 3.以及在Windows服务中启动带界面的程序 关于第三点的问题,我在我的上一篇博 ...