我正在使用neo4j来设置推荐系统。我有以下设置:
节点
关系
__declspec(dllexport)
(m:Movie)-[w:WEIGHT {weight: 10}]->(a:Attribute)
以下是它的外观图表:
我现在正试图弄清楚如何应用协同过滤方案,其工作原理如下:
(u:User)-[r:RATED {rating: 5}]->(m:Movie)
喜欢哪些属性(隐含地喜欢看电影)user
other users
,但类似的user
已经看过。显然,每个属性对每部电影都有一定的权重。例如。类型other users
对于指环王而言可以具有adventure
的权重,但对于泰坦尼克号来说可以具有10
的权重。
此外,系统需要考虑每部电影的评分。例如。如果5
已经评定指环王other user
,那么他/她的范围之王的属性将按5
而不是5
进行缩放。对隐式属性进行评级的10
也接近user
应该推荐这部电影,而不是另一个评价相似属性的用户。
我首先只推荐其他用户评价的其他电影,但我不确定如何考虑关系评级和重量。它也没有用:
5
答案 0 :(得分:4)
从数学上讲,您所寻找的是两个用户之间的简化Jaccard index。也就是说,它们的相似之处在于它们有多少共同点。我说简化是因为我们没有考虑他们不同意的电影。基本上,按照您的订单,它将是:
1)获取每个用户的每个属性的总权重。例如:
MATCH (user:User{name:'user1'})
OPTIONAL MATCH (user)-[r:RATED]->(m:Movie)->[w:WEIGHT]->(a:Attribute)
WITH user, r.rating * w.weight AS totalWeight, a
WITH user, a, sum(totalWeight) AS totalWeight
我们需要最后一行,因为每个Movie-Attribute组合都有一行
2)然后,我们得到具有相似品味的用户。这是一个性能危险区域,有些过滤可能是必要的。但是粗暴强迫它,我们让用户喜欢10%错误中的每个属性(例如)
WITH user, a, totalWeight*0.9 AS minimum, totalWeight*1.10 AS maximum
MATCH (a)<-[w:WEIGHT]-(m:Movie)<-[r:RATES]-(otherUser:User)
WITH user, a, otherUser
WHERE w.weight * r.rating > minimum AND w.weight * r.rating < maximum
WITH user, otherUser
所以现在我们有一行(由于最后一行而是唯一的)与任何匹配的其他用户。在这里,说实话,我需要尝试确定是否包含只有1种类型匹配的其他用户..如果是,则需要额外的过滤器。但我认为应该在我们开始之后继续这样做。
3)现在很容易:
MATCH (otherUser)-[r:RATES]->(m:Movie)
WHERE NOT (user)-[:RATES]->(m)
RETURN m, sum(r.rating) AS totalRating ORDER BY totalRating DESC
如前所述,棘手的部分是2),但在我们知道如何进行数学运算之后,应该会更容易。哦,关于数学,为了使它正常工作,电影的总重量应该加1(normalizing)。在任何其他情况下,电影总重量之间的差异会导致不公平的比较。
我没有经过适当的研究(纸张,铅笔,方程式,统计数据)并在样本数据集中尝试代码。无论如何,我希望它可以帮到你!
如果你想要这个推荐而不考虑用户评级或属性权重,那么分别用r.rating或w.weight代替1)和2)中的数学就足够了。仍然会使用费率和权重关系,因此,冒险电影的狂热消费者将推荐冒险电影的消费者使用电影,但不会按照我们选择的等级或属性权重进行修改。
编辑:编辑代码以修复评论中讨论的语法错误。
答案 1 :(得分:1)
回答第一个问题:
检查用户喜欢哪些属性(隐含地喜欢看电影)
MATCH (user:User)
OPTIONAL MATCH (user)-[r:RATED]->(m:movie)
OPTIONAL MATCH (m)-[r:RATED]->(a:Attribute)
WHERE user.uid = "user4"
RETURN user, collect ({ a:a.title })
这是一个子查询构造,您可以在其中找到用户评分的电影,然后查找电影的属性,最后返回喜欢的属性列表
如果需要整个节点,可以将return语句修改为 收集(a)作为属性