Python实现列表匹配

注:此为项目之前所作利用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)

运行结果不生成文件,只打印信息,如图所示:

Python实现列表匹配_第1张图片

因为我们是拿最后一篇文章来做例子的,最后一篇文章是截取的操作系统内存部分章节的内容。那么理应我们得到的最匹配的文字是操作系统的文档。结果证明与预想的符合,该推荐还是有一定意义的。

评价总结:

推荐效果:所做测试不是很多,但效果尚可接受,均与预想符合。

耗时:非常短,大约一秒就可完成。采用列表匹配后大大节省了时间。

重点解释:

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)来模拟词频,模拟重要性。

Python实现列表匹配_第2张图片

如上图所示,这三篇文章的分词的交集的重要度的和分别是13,5,10。前面的2,7,10是文章序号。数目越小,重要性越高。故第7篇文章最符合,根据前面的序号(7)匹配到文章名,输出最后的结果。


你可能感兴趣的:(项目实训)