基于jaccard计算论文对的reference相似度的算法(2)

    技术2022-07-10  139

    基本实现思路:每次输入两个论文的名字,然后通过查询node.list找到相应的id,或者直接输入论文id进行查询,然后在link.json中找到他引用的所有论文集合,然后计算jaccard相似度。模型中会遇到大量的查询两个论文引用的jaccard相似度,这样查询速度比较慢。由于样本数据量较大,后续使用时,每次读取所有的数据(一对一的引用关系),然后计算相似度速度比较慢,所以把数据集进行了整理,以每篇论文的id为key,以引用的论文的id列表为value进行保存,保存到link.json没有把所有的论文对的相似度计算完保存起来,是因为维度比较高,且数据比较稀疏。(注:对称且稀疏矩阵,可以采用压缩存储。) 算法:十分简单的杰卡德系数(Jaccard Index),也称Jaccard相似系数(Jaccard similarity coefficient),用于比较有限样本集之间的相似性与差异性。如集合间的相似性、字符串相似性、目标检测的相似性、文档查重等 Jaccard系数的计算方式为:交集个数和并集个数的比值

    数据来源:计算所使用的数据来自已经给出的ACM数据集,其中的inlinks.list和outlinks.list的数据是两列论文id,都是前面的id所对应的论文引用后面的id所对应的论文。 有待改进的地方: 1.所给数据集只是在一定范围内的引用关系,并不全面,不能较为准确的反应论文对引用的相似度,可以爬取所有的引用关系,然后再计算。 2.可以把所有的论文对引用相似度计算出来,自己尝试进行计算时,还是使用了大量的时间,若是直接带入模型,进行计算,会耗费大量的时间。至于占用空间比较大。可以采用矩阵的压缩存储。 3.在论文所引用的集合中,不同的论文所占有权重也应该是不同的。有的论文对相似度贡献比较大,有的比较小。可以加入惩罚因子。但是究竟是引用量高的被引论文对相似度的贡献更大,还是较少出现的偏僻的被引论文对相似度的贡献更大呢?

    直接计算:

    def node_id(name): fp=open("C:\\Users\\asus\\Desktop\\实训\\资料整理\\code+data\\ACM数据集\\nodes.list",'r') while(fp.readline()): id,node=fp.readline().rstrip().split("\t") if node==name: return id #若是引用关系不在变化,需不需建立一个表直接把信息存起来 def jaccard2id(a,b): links1=set() links2=set() fp=open("C:\\Users\\asus\\Desktop\\实训\\资料整理\\code+data\\ACM数据集\\inlinks.list",'r') while(fp.readline()): links_from,links_to=fp.readline().rstrip().split("\t") if links_from==a: links1.add(links_to) if links_from==b: links2.add(links_to) if links1.intersection(links2)==None or links1.intersection_update(links2)==None: return 0 else: common=len(links1.intersection(links2)) all2=len(links1.intersection_update(links2)) jaccard=common/(all2+1) return jaccard if __name__ == '__main__': name1=input("请输入第一篇论文的名字:") name2=input("请输入第二篇论文的名字:") id1=node_id(name1) id2=node_id(name2) samilarity=jaccard2id(id1,id2) print(samilarity)

    保存到文件中:

    import json def essay_link(): link=dict() fp=open("C:\\Users\\asus\\Desktop\\实训\\资料整理\\code+data\\ACM数据集\\inlinks.list",'r') while(fp.readline()): link_from,link_to=fp.readline().rstrip().split("\t") if link_from in link: link[link_from].append(link_to)#link['link_from']那么key就是link_from else: link[link_from]=[link_to] #value用list保存,用set()不能保存为json json_str = json.dumps(link, indent=4) with open('link.json', 'w') as json_file: json_file.write(json_str) def jaccard(id1,id2): with open('link.json', 'r') as json_file: link=json.load(json_file) if id1 in link and id2 in link: links1=set(link[id1]) links2=set(link[id2]) if links1.intersection(links2)==None or links1.intersection_update(links2)==None: return 0 else: # common=len(links1.intersection(links2)) # all2=len(links1.intersection_update(links2)) # jaccard=common/(all2+1) #已经不为0了,感觉不加1平滑也可以了 jaccard=len(links1.intersection(links2))/(len(links1.intersection_update(links2))+1)#借鉴推荐系统上惩罚热门的做法??? return jaccard else: return -1 def name_query(): name1=input("请输入第一篇论文的名字:") name2=input("请输入第二篇论文的名字:") fp=open("C:\\Users\\asus\\Desktop\\实训\\资料整理\\code+data\\ACM数据集\\nodes.list",'r') while(fp.readline()): id,node=fp.readline().rstrip().split("\t") if node==name1: id1=id if node==name2: id2=id return jaccard(id1,id2) def id_query(): id1=input("请输入第一篇论文的编号:") id2=input("请输入第二篇论文的编号:") return jaccard(id1,id2) #计算所有论文对的jaccard相似度 def jall(): fp=open("C:\\Users\\asus\\Desktop\\实训\\资料整理\\code+data\\ACM数据集\\nodes.list",'r') id=[] while(fp.readline()): iid,name=fp.readline().rstrip().split("\t") id.append(iid) #print(id) fp.close() f=open('jaccard.txt', 'w') for i in range(len(id)): for j in range(i+1,len(id)): jac=jaccard(id[i], id[j]) f.writelines([str(id[i])+'\t'+str(id[j])+'\t'+str(jac)+'\n']) f.close() if __name__ == '__main__': #essay_link() #name_query() #print(id_query()) jall()

    运行结果: 下图为link.json里面的内容,很多仅有两三篇引用文献,所以大部分的引用关系不是特别全面。 下图是计算出的相似度,-1表示没有引用关系(没有引用其他文献和被其他文献引用),直接保存相似度还是比较稀疏和占用空间的。

    Processed: 0.011, SQL: 9