python对数据相似度分析算法库_相似度算法在知识图谱中的实现

随着知识图谱的火爆从美国一路烧到了国内,近几年知识图谱技术在国内已经得到了飞速的发展,我们对知识图谱的概念及应用都不再陌生。你可以看到知识图谱技术的应用出现在越来越多的垂直领域中。从最早大家最为熟悉的在搜索引擎中的应用,逐渐地扩充到金融领域、医药领域等等。今天我们已经在各行各业中,都能够看到知识图谱的身影,更多的技术人员也加入了我们知识图谱工程的大家庭。

那么今天我们来就知识图谱的技术问题进行更深层的探讨。今天我将和大家分享一个,我在知识图谱搭建中遇到的棘手问题,相信有不少小伙伴也会遇到这样的问题。希望今天我分享的解决方案可以给大家一些帮助!

我遇到的问题:

在构建知识图谱的图关系时,基础数据来自很多不同的数据源。比如金融风控领域中,我们要构建的知识图谱中,包含地址、公司等出现频率比较高,并且名称一模一样的可能性很低的词汇。

比如:北京市国贸中心写字楼和北京朝阳区建外大街1号国贸中心是同一个地址么?

那在图关系的构建中,如果把上地址作为两个地址进行处理的话,那么就会创建两个实体,并且这两个实体之间并没有什么关联关系,这种处理方法,肯定是错误的。这个时候,需要进行的工作就是地址消歧,把两个地址经过处理后,变成同一个地址。

这个时候我们需要做的是进行相似度计算。

我的解决方案:

在Neo4j中的余弦相似度计算如何满足这种应用场景。

那么什么是余弦相似度呢?余弦相似度是n维空间中两个n维向量之间角度的余弦。它是两个向量的点积除以两个向量的长度(或幅度)的乘积。

余弦相似度公式:

那么计算的值介于-1和1之间,其中-1完全不同,1完全相似。

那么在neo4j中怎么使用余弦相似度计算呢?

非常幸运,neo4j的一个插件可以提供这样一个功能,让我们能够直接在其上实现相似度计算。

环境安装:

这里你只需要一个jar包,就可以将其搞定。

下载链接:https://github.com/neo4j-contrib/neo4j-graph-algorithms/releases

将下载的graph-algorithms-algo-3.5.0.1.jar包拷贝到$NEO4J_HOME/plugins目录中

注意:要修改neo4j的配置将

dbms.security.procedures.unrestricted=algo.*

添加到neo4j.conf文件当中,一定要做,要不然后边的试验会失败

重启neo4j数据库就可以了。

第一个例子:

打开你的neo4j数据库,输入 :RETURN algo.similarity.cosine([3,8,7,5,2,9], [10,8,6,6,4,5]) AS similarity

这个语句的意思就是调用neo4j提供的算法计算库中的函数,并且计算[3,8,7,5,2,9]和 [10,8,6,6,4,5]两组数据的余弦相似度,那么返回的结果是:

那么这个值已经非常的接近1了。这就是这两个数字列表的余弦相似度值。

此时你应该感觉到,使用Neo4j库中的插件来实现,非常的简单。

那么下面,我们可以自己来根据公式进行推理一下。

首先,我们创建一个图关系:

具体Cypher如下:

MERGE (french:Cuisine {name:'French'})MERGE (italian:Cuisine {name:'Italian'})MERGE (indian:Cuisine {name:'Indian'})MERGE (lebanese:Cuisine {name:'Lebanese'})MERGE (portuguese:Cuisine {name:'Portuguese'})MERGE (zhen:Person {name: "Zhen"})MERGE (praveena:Person {name: "Praveena"})MERGE (michael:Person {name: "Michael"})MERGE (arya:Person {name: "Arya"})MERGE (karin:Person {name: "Karin"})MERGE (praveena)-[:LIKES {score: 9}]->(indian)MERGE (praveena)-[:LIKES {score: 7}]->(portuguese)MERGE (zhen)-[:LIKES {score: 10}]->(french)MERGE (zhen)-[:LIKES {score: 6}]->(indian)MERGE (michael)-[:LIKES {score: 8}]->(french)MERGE (michael)-[:LIKES {score: 7}]->(italian)MERGE (michael)-[:LIKES {score: 9}]->(indian)MERGE (arya)-[:LIKES {score: 10}]->(lebanese)MERGE (arya)-[:LIKES {score: 10}]->(italian)MERGE (arya)-[:LIKES {score: 7}]->(portuguese)MERGE (karin)-[:LIKES {score: 9}]->(lebanese)MERGE (karin)-[:LIKES {score: 7}]->(italian)

neo4j插入结果:

那么我们用这个数据再进行一次计算

Cypher如下:

MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, 0))} as userData WITH collect(userData) as data CALL algo.similarity.cosine.stream(data) YIELD item1, item2, count1, count2, similarity RETURN algo.getNodeById(item1).name AS from, algo.getNodeById(item2).name AS to, similarity ORDER BY similarity DESC

相似度计算结果:

以上,我们可以看到Arya和Karin的食物口味最相似,得分为0.889。最高分为1,因此它们非常接近最大相似度

下边还有很多相似度为0的,原因是我数据库中原本有一些数据导致,那么现在我们要把这些数据过滤掉

Cypher如下:

MATCH (p:Person), (c:Cuisine)

OPTIONAL MATCH (p)-[likes:LIKES]->(c)

WITH {item:id(p), weights: collect(coalesce(likes.score, 0))} as userData

WITH collect(userData) as data

CALL algo.similarity.cosine.stream(data, {similarityCutoff: 0.0})

YIELD item1, item2, count1, count2, similarity

RETURN algo.getNodeById(item1).name AS from, algo.getNodeById(item2).name AS to, similarity

ORDER BY similarity DESC

运行结果:

我们可以看到那些没有相似性的用户已被过滤掉了。如果我们正在实现k-Nearest Neighbors类型查询,我们可能希望k为给定用户找到最相似的用户。我们可以通过传入topK参数来做到这一点。

以下将返回用户流以及最相似的用户(即k=1):

Cypher如下:

MATCH (p:Person), (c:Cuisine)

OPTIONAL MATCH (p)-[likes:LIKES]->(c)

WITH {item:id(p), weights: collect(coalesce(likes.score, 0))} as userData

WITH collect(userData) as data

CALL algo.similarity.cosine.stream(data, {topK:1, similarityCutoff: 0.0})

YIELD item1, item2, count1, count2, similarity

RETURN algo.getNodeById(item1).name AS from, algo.getNodeById(item2).name AS to, similarity

ORDER BY from

执行结果:

细心的同学会发现,以上的结果有一点问题,第一行的结果和第二行的结果其实是相同的。

那么我们现在要做的是为每个用户找到最相似的用户,并存储这些用户之间的关系:

Cypher如下

MATCH (p:Person), (c:Cuisine)

OPTIONAL MATCH (p)-[likes:LIKES]->(c)

WITH {item:id(p), weights: collect(coalesce(likes.score, 0))} as userData

WITH collect(userData) as data

CALL algo.similarity.cosine(data, {topK: 1, similarityCutoff: 0.1, write:true})

YIELD nodes, similarityPairs, write, writeRelationshipType, writeProperty, min, max, mean, stdDev, p25, p50, p75, p90, p95, p99, p999, p100

RETURN nodes, similarityPairs, write, writeRelationshipType, writeProperty, min, max, mean, p95

执行结果如下:

然后,我们可以写一个查询,以找出与我们相似的其他人可能喜欢的美食类型。

以下将找到与Praveena最相似的用户

Cypher:

MATCH (p:Person {name: "Praveena"})-[:SIMILAR]->(other),

(other)-[:LIKES]->(cuisine)

WHERE not((p)-[:LIKES]->(cuisine))

RETURN cuisine.name AS cuisine

执行结果:

以上就是整个的计算过程。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值