文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

今天我们将探讨一下数据科学和图推荐:

视频链接

至今为止我使用 Neo4j 已经 2 年,但我和 Neo4j、 Cypher 打交道有三年了。我当初发现这个特别的图数据库时还在得克萨斯大学奥斯汀分校读研究生,那时我主攻方向是统计学的社交网络。

构建实时推荐引擎是 Neo4j最常见的用途之一,也是 Neo4j 强大而易用的用途之一。为了探讨这个问题,我将使用一些数据集样例来解释如何运用统计方法到推荐中去。

第 1 段(可获 1.41 积分)

第一个比较简单 —— 完全使用 Cypher 语言的社交推荐;之后我们探讨一个涉及可计算相似度度量的相似度推荐;最后是一个聚类推荐。

基本的图驱动推荐

下面的数据集包含达拉斯 - 沃斯堡国际机场提供的食物饮料,该机场是美国主要机场枢纽之一。

我们用黄色标注的场所节点对包括登机门、候机楼的位置进行建模。我们也用食物和饮料两大类对场所进行分类,其中包括墨西哥食物,三明治和酒吧烧烤。

第 2 段(可获 1.3 积分)

先做一个简单的推荐吧。我们想在机场内在特定位置里发现一种特定的食物类型,而大括号内的东西表示正在输入到我们假设应用程序的用户输入。

这句英语句子很好的映射到了一个 Cypher 查询:

上面中的 category、terminal 和 gate 都会使用用户的请求进行填充。然后我们将得到指定场所到用户所在登机门的绝对距离,并以正序排列。再强调一次,这是一个仅基于机场内用户所在位置的简单 Cypher 推荐。

第 3 段(可获 1.3 积分)

社交推荐

接下来讨论一下社交推荐。在我们假想的应用程序中,用户可以登陆并类似于脸书那样「喜欢」某个地方,并对这些地方进行筛选:

考虑基于我们探讨过的第一个模型上的这个数据模型,现在我们需要在如下分类中找到某个饮食场所,而这个地方最接近用户的朋友喜欢的候机楼的登机门。

MATCH 子句与我们在第一个 Cypher 查询中用到的 MATCH 子句类似,但不同的是我们现在是在匹配朋友和喜欢:

第 4 段(可获 1.44 积分)

前面三行是相同的,但对于问题中的用户 — 已经登录的用户 — 我们希望能通过 FRIENDS_WITH 关系找到他的朋友以便找到朋友们喜欢的饮食场所。添加少许行数到 Cypher 之后,我们的推荐引擎现在已考虑到社交方面了。

再次强调,我们仅显示用户明确要求是与用户同一候机楼的类型。当然,我们想通过已登录并正在发出请求的用户对这一结果进行筛选,并根据类型与位置返回这些场所的名字。我们也考虑了喜欢这个场所的朋友人数和这个场所到登机门的几何距离。返回都写在 RETURN 子句中。

第 5 段(可获 1.76 积分)

相似度推荐

现在我们再看一下一个相似度推荐引擎:

A data model for a similarity recommendation engine

类似于我们之前用户可以「喜欢」某些地方的数据模型,不过这次他们需要给这些地方打 0 至 10 分。对于 Neo4j 来说给这些关系添加一个属性十分简单。

这样我们可以寻找其他类似的用户,比如 Greta 和 Alice 的例子。我们已经知道他们都喜欢的地方和他们给每一个地方的分数。进而我们可以使用这些分数判定他们之间的相似度。

第 6 段(可获 1.4 积分)

现在我们有两组向量:

计算这两组向量的欧几里得几何距离:

The Euclidean distance between two user vectors

代入所有数之后,我们就能得到如下真正能说明两个用户相似度的度量:

A similarity metric for user vector distance

在 Cypher 中你可以计算两个特定用户的相似度,特别是他们共同喜欢的地方较少时。再次说明,我们在匹配 Greta 和 Alice 两个用户并试图找到他们共同喜欢的地方:

A Cypher query for user distance in a similarity recommendation engine

上述 Cypher 语句中将查询都有 :LIKES 关系连接某一个地方的两个用户,之后用各元素平方和的开根号计算他们的欧几里得几何距离:

第 7 段(可获 1.66 积分)

虽然在两个特殊用户的例子里这么做可能有用,但在实时推荐中,当你想通过在数据库中实时匹配其他用户来实时推测出与另一用户相似的用户时,其实也没必要这么做。说实话,这也没那么有效。

为了解决这个问题,我们先对这些计算做预处理并在实际关系中存储这一结果:

虽然在大数据集中我们可以成批做这种计算,但在小的样本数据集中,我们应该与所有用户匹配他们共同喜欢的地方的笛卡尔积。我们在 Cypher 语句中使用 WHERE id(u1) < id(u2) 以保证查找到只有左右关系不相同的结果。

第 8 段(可获 1.58 积分)

之后我们根据用户本身及其两者间的欧几里得几何距离创建一对 :DISTANCE 关系,并设置一个欧几里得属性 euclidean。理论上,我们也可以存储用户间关系的其他相似度量来描述不同的相似尺度,因为有一些相似尺度在确定的环境中是比其他的有用。

就是 Neo4j 这种能在关系上建模的能力让事情处理起来相当简单。但事实上你不会去存储每一个可能会存在的关系,因为你会只想返回与之相邻的顶层少部分人而已。

第 9 段(可获 1.29 积分)

所以你可以通过设置一些阈值保留少数关系从而抛弃全连接图。这将允许你进行如下实时查询图数据库,因为我们已预处理并存储在关系上,使用 Cypher 查询可以快速获取结果:

在这个查询里,我们匹配了地方和类别:

An example Cypher query for a similarity real-time recommendation engine

还是老样子,前面三行与之前相同,但对于已经登录的用户而言,我们将获取与之有 :DISTANCE 关系用户而已。我们之前做的努力就在这里体现出来了 — 实际上你只需要存储与之相似的少数用户的 :DISTANCE 关系便无需在 MATCH 子句中操作大量的用户。相反,我们只获取与之有 :DISTANCE 关系用户,且这些用户喜欢这个地方。

第 10 段(可获 1.9 积分)

由此我们仅需几行便可以表达复杂的模式。我们同时也获取 :LIKES 关系并保存在变量里,因为我们之后应用到比值时会使用这些权重。

更重要的是我们使用距离正序排列这些用户,因为我们可以使用这种距离度量让最短距离表示最相似。

用欧几里得距离排列完这些用户之后,获得距离最小的三个用户的评分,并使用三个评分作为推荐场所的的平均分数。换句话说,我们假定一个在线用户,根据共同喜欢的地方发现跟他们相似的潜在用户,然后计算这些用户给这些地方打的平均分数并作为一个结果集。

第 11 段(可获 1.84 积分)

我们本质上是通过计算集合中元素的总和并除以其个数值来得到平均数,之后便可使用这些平均数正序排列。其次我们再使用到登机门的距离值排列。我假定之后你会通过排列登机门距离返回 name,category,gate 和 terminal 等结果。

聚类推荐

最后的例子是一个聚类推荐,这种推荐可以看成离线计算的工作流,也就是 Cypher 中比较变通的做法。由于 GraphConnect Europe 公布了一些新特性,所以这种变通可能会有些过时。

第 12 段(可获 1.26 积分)

但有时你也不得不实现一些 Cypher 2.3 版本没有公开的算法。

这时你可以使用一些统计软件,如 Apache Spark, R 或 Python,将 Neo4j 的数据导出。下面是使用 R 代码导出数据的例子,运行程序,然后在合适时机,将程序结果作为属性、节点、关系或标签写回 Neo4j。

将程序结果写回图之后,你将会在实时系统中用到类似如下我们刚刚看到的查询:

第 13 段(可获 1.44 积分)

An R algorithm code example for Neo4j in a cluster recommendation engine

下面是一些 R 语言实现的代码例程,当然你也可以用其他你习惯的软件来写,比如 Python 或 Spark。你要做的就是登陆和连接到这个图。

在下面的例子中,我根据相似度将用户进行聚类操作。每一个用户都表示一个单独对象,并统计他们对每一种分类的打分:

An R code example for a cluster recommendation engine

可能对酒吧分类的打分相似的用户在其他方面也相似。这里我将喜欢同一地方分类的用户名、分类名、「喜欢」关系的平均权值列出一张类似如下图的表格:

第 14 段(可获 1.68 积分)

因为我们将每个用户都单独列出,所以我们不得不去计算用户的评分数据,这些数据每一个特征都是他们给每一个分类的平均评分。我们之后会使用这个来度量他们之间的相似程度,并用一个聚类算法决定将用户分配到哪个聚类中。

在 R 里,这实现起来很简单:

在这个演示里,我们使用了比较容易进行聚类分配的 K-均值法。总的来说,就是我运行了一个聚类算法并对每个用户进行聚类分配。

第 15 段(可获 1.23 积分)

Bob 和 David 都在二号类里 —— 现在我可以实时看到哪些用户被分配到同一个聚类里。

之后我们将结果写入一个 CSV 文件中,用来转入图中:

我们只需要用户和聚类分配结果,所以 CSV 文件只需要两个字段就可以了。Cypher 里有一个内建的 LOAD CSV 语法,能让我们从某些文件路径、URL 或别名中调用 CSV 文件。之后我们会通过已存在图里的数据匹配用户,提取 CSV 文件中用户字段合并用户聚类到图里面去。

第 16 段(可获 1.44 积分)

这里,我们在图中创建了一个新的节点,命名为 Cluster ID。之后在用户和聚类之间建立关系,这些关系可以让我们在同一聚类中获取实际推荐用户时简化查询。

现在我们有标记簇,其中同一簇的用户都会有到该簇的关系连接。我们的数据模型看起来像下面那样,不过这只是我们已建立模型中的局部:

现在看下这个查询:

在这个 Cypher 查询中,我们使用同簇用户而不是相似用户,这时我们也该删除距离关系了:

第 17 段(可获 1.51 积分)

A Cypher query example for a cluster recommendation engine

在这个查询中,我们抓取已经登录的用户,在用户簇关系的基础上找到他们的簇,并在同一个簇中找到他们的邻居。
我们给变量cl 赋值,在同一个簇中,我们得到那些拥有用户簇关系的其他用户,我将它们放在别名为neighbor的变量中,然后我们得到了那个邻居喜欢的地方。再次,我们把“likes”放在变量r中,因为我们想要从关系中提取出权重,用来排序我们的结果。
我们在查询中改变的是,没有使用相似距离,取而代之的是我们抓取在同一个簇中的用户,声明categories,声明terminal 以及声明我们只抓取登陆的用户。我们从他们的邻居喜欢的地方收集所有“likes”的关系权重,得到类别,距离的绝对值,以降序排序,并返回这些结果。

第 18 段(可获 2.13 积分)

在这些例子中,我们已经能够使用比较复杂处理并用图存储结果,之后可以实时使用这些算法结果 — 即聚类算法结果和聚类分配。

我们更倾向于可以在合适周期 — 比如说,每天或每个小时 — 更新这些聚类分配的工作方式。当然,你也可以靠直觉决定合适的更新周期。

第 19 段(可获 0.99 积分)

文章评论