注:此为项目之前所作利用Python实现文档的分词及词频统计的后续工作,主要做推荐所用。该代码相比普适性不强,只是针对项目所需编写。下面是链接:python3.6实现文档词频统计 - CSDN博客
https://blog.csdn.net/yanjiaxin1996/article/details/80629597
摘要:每个文章对应一个list,里面包含着[文件名,分词1,分词2,。。。。,分词15],。要进行文章的最佳匹配与推荐,思路是以15个分词作为特征,进行list与list之间的交集运算。我们认为交集元素数目最多的最匹配,一样多的情况下,分词的序号(例如分词1、分词3、分词10的1、3、10)代表着其重要性,计算他们的和,越小则优先级最高。
难点的详细解释放在代码后面。
环境:win10+pycharm2018.1+Python3.6
第三方库:无
输入:python3.6实现文档词频统计 - CSDN博客 最后生成的 分词结果汇总.txt
输入文件示例(不必一致,只是为了运行结果说明):
PTA.docx,节点,题目,存储,输出,算法,做法,路径,循环,集合,时间,数据,元素,最小,数组,两个
高级程序设计语言.docx,方法,对象,类型,变量,语句,数组,int,Java,执行,String,实例,数据,循环,声明,引用
计算机组成原理复习纲要.docx,中断,方式,地址,CPU,周期,指令,程序,执行,设备,寄存器,寻址,DMA,数据,主存,接口
离散数学合子童.docx,运算,关系,元素,系统,生成,代数,同态,函数,排列,单位,映射,盒子,原理,递推,an
软件工程内部终版.docx,系统,测试,需求,设计,过程,开发,软件,功能,模型,描述,故障,活动,对象,关系,时间
山软智库_计算机网络_1-41.txt,发送,数据,网络,协议,接收,传输,连接,信号,服务,智库,山软,地址,信道,TCP,主机
数据库_可编辑.docx,属性,事务,关系,数据,索引,元组,记录,查询,连接,实体,函数,Ti,依赖,搜索,数据库
智库内部编辑版_操作系统概念.docx,进程,系统,文件,内存,磁盘,线程,程序,调度,资源,用户,执行,访问,等待,时间,地址1
面向对象开发技术(1).doc,对象,方法,public,继承,接口,模式,子类,定义,抽象,实例,void,类型,父类,属性,new
数据结构复习纲要见解.doc,元素,节点,链表,数组,操作,插入,搜索,描述,路径,删除,二叉树,时间,排序,遍历,位置
Alpha_1_操作系统概念_16-20.txt,进程,调度,程序,PCB,系统,CPU,状态,执行,内存,fork,创建,3.1,信息,上下文,切换
Alpha_1_操作系统概念_61-70.txt,内存,页表,地址,进程,逻辑,空间,分配,分页,碎片,大小,偏移量,长度,寄存器,作业,吉鹏
代码:
fr = open("分词结果汇总.txt")
data = []
for line in fr:
line = line.replace("\n", "")
data.append(line.split(","))
fr.close()
#把标签list转化合并为string,并加在每篇文章的最后一列
def list2String():
for i in range(len(data)):
string = ""
for j in range(1,len(data)-1):
string=string+data[i][j]
data[i].append(string)
print (data)
#python 两个list 求交集,并集,差集 - CSDN博客 https://blog.csdn.net/bitcarmanlee/article/details/51622263
#获取两个list的交集 返回值是list
def intersection(listA,listB):
#求交集的两种方式
retA = [i for i in listA if i in listB]
# retB = list(set(listA).intersection(set(listB)))
return retA
#获取两个list的并集 返回值是list
def union(listA,listB):
#求并集
retC = list(set(listA).union(set(listB)))
return retC
#获取两个list的补集 返回值是list
def complement(listA,listB):
#求差集,在B中但不在A中
retD = list(set(listB).difference(set(listA)))
return retD
#获取权重最小的序号index
def getMinIndex(list):
min=100
if(len(list)==1):
index=0
else:
for i in range(len(list)):
if (list[i] < min):
min = list[i]
index = i
return index
#寻找与其最相似的文章
def findSimilarity(singleDataAsList):
# 生成包含匹配数目最多的文章的列表。如[[7, '进程', '内存'], [10, '进程', '内存']]
allresult = [["初始值"]]
max = -1
for i in range(len(data)):
if (data[i]!=singleDataAsList): #不能与自身比较
a = data[i]
intersectionResult = intersection(a,singleDataAsList)
print (intersectionResult)
if (len(intersectionResult) > max and len(intersectionResult) != 0): # and len(intersectionResult)!=0
max = len(intersectionResult)
allresult.pop()
intersectionResult.insert(0, i)
allresult.append(intersectionResult)
elif (len(intersectionResult) == max):
intersectionResult.insert(0, i)
allresult.append(intersectionResult)
# 生成相应的列表的权重 如[5, 10]
allweight = [0] * len(allresult)
for i in range(len(allresult)):
for j in range(1, len(allresult[i])):
for k in range(len(data[allresult[i][0]])):
if (data[allresult[i][0]][k] == allresult[i][j]):
allweight[i] = allweight[i] + k
print (allresult)
print (allweight)
minIndex = getMinIndex(allweight)
title = data[allresult[minIndex][0]][0]
print ("最匹配的文章是:" + title)
b=data[-1] #以最后一篇文章示例
findSimilarity(b)
运行结果不生成文件,只打印信息,如图所示:
因为我们是拿最后一篇文章来做例子的,最后一篇文章是截取的操作系统内存部分章节的内容。那么理应我们得到的最匹配的文字是操作系统的文档。结果证明与预想的符合,该推荐还是有一定意义的。
评价总结:
推荐效果:所做测试不是很多,但效果尚可接受,均与预想符合。
耗时:非常短,大约一秒就可完成。采用列表匹配后大大节省了时间。
重点解释:
1.为什么用列表匹配,而不用建立稀疏矩阵,计算cos等常规方法?
因为文档对于实际项目是未知的,所以无法确定的文档的分词会产生什么结果,所以无法建立一些预定的分词。其次由于分词的多样行,即使我们预先定义好一些同义词和近义词,仍然是一个巨大的分词库。这样势必会导致产生的文档*分词的矩阵极其稀疏,当文档数目达到一定量时,运算耗时会成指数增长。考虑到时间因素,不得已放弃常规方法。
采用list匹配,优化的部分在于省去一些本不必要的计算,比如两篇文档的交集本就为0或者为1(代指很少),这种根本无需进行cos计算,因为根本不可能是最优结果。所以用list匹配先求出交集,在交集最多的几个候选集里再次计算。这样虽然比计算cos相似度在精确度方面有不足,但是大大节约了运算时间和资源,性价比较高。
2.如何进行列表匹配?
一开始想到的是最基础的设置几个for循环,但对于for循环要慎重考虑。毕竟当文档数目很多后,for循环是指数增长的罪魁祸首。后来查阅一些资料,在一篇博客里发现不错的解决方案。
python 两个list 求交集,并集,差集 - CSDN博客 https://blog.csdn.net/bitcarmanlee/article/details/51622263
里面提供了两种方法,选用其中一种即可。(代码注释里有解释,可看代码)
3.对于交集数目同样的文档怎么进一步划分?
首先要明确,有同样数目的交集,并不代表相似程度就一样。回过头来捋一捋,我们假定分词代表着文章的内容,词频越高代表性越强。我们的list里面也是按词频的大小排序的。所以有同样元素数目的交集,元素的代表性(词频)也是不一样的,这就是我们二次筛选的依据。即利用分词的序号(例如分词1、分词3、分词10的1、3、10)来模拟词频,模拟重要性。
如上图所示,这三篇文章的分词的交集的重要度的和分别是13,5,10。前面的2,7,10是文章序号。数目越小,重要性越高。故第7篇文章最符合,根据前面的序号(7)匹配到文章名,输出最后的结果。