标签传播
词汇表
- 有向
-
有向特征。该算法在有向图上定义良好。
- 有向
-
有向特征。该算法忽略了图的方向。
- 有向
-
有向特征。该算法不在有向图上运行。
- 无向
-
无向特征。该算法在无向图上定义良好。
- 无向
-
无向特征。该算法忽略了图的无向性。
- 异构节点
-
异构节点 全面支持。该算法能够区分不同类型的节点。
- 异构节点
-
异构节点 允许。该算法以相同的方式处理所有选定节点,无论其标签如何。
- 异构关系
-
异构关系 全面支持。该算法能够区分不同类型的关系。
- 异构关系
-
异构关系 允许。该算法以相同的方式处理所有选定关系,无论其类型如何。
- 加权关系
-
加权特征。该算法支持使用关系属性作为权重,通过 relationshipWeightProperty 配置参数指定。
- 加权关系
-
加权特征。该算法将每个关系视为同等重要,丢弃任何关系权重的值。
介绍
标签传播算法(LPA)是一种快速查找图中社区的算法。它仅使用网络结构作为引导来检测这些社区,不需要预定义的目标函数或关于社区的先验信息。
LPA 通过在整个网络中传播标签并基于此标签传播过程形成社区来工作。
该算法背后的直觉是,单个标签可以在密集连接的节点组中快速变得占主导地位,但难以穿越稀疏连接的区域。标签将被困在密集连接的节点组中,当算法完成时,最终具有相同标签的那些节点可以被认为是同一个社区的一部分。
该算法的工作原理如下
-
每个节点都初始化为一个唯一的社区标签(一个标识符)。
-
这些标签通过网络传播。
-
在每次传播迭代中,每个节点都将其标签更新为其大多数邻居所属的标签。平局是任意地但确定性地解决的。
-
当每个节点都具有其邻居的多数标签时,LPA 达到收敛。
-
如果达到收敛或用户定义的最大迭代次数,LPA 就会停止。
随着标签的传播,密集连接的节点组会快速达成关于唯一标签的共识。在传播结束时,只会剩下几个标签——大多数标签会消失。在收敛时具有相同社区标签的节点被认为属于同一个社区。
LPA 的一个有趣特性是,可以为节点分配初步标签来缩小生成解决方案的范围。这意味着它可以用作一种半监督方式来查找社区,我们可以在其中手动选择一些初始社区。
有关该算法的更多信息,请参见
运行此算法需要足够的内存可用性。在运行此算法之前,建议您阅读 内存估计。 |
语法
本节介绍在每种执行模式下执行标签传播算法时使用的语法。我们正在描述命名的图变体的语法。要了解有关通用语法变体的更多信息,请参见 语法概述。
CALL gds.labelPropagation.stream(
graphName: String,
configuration: Map
)
YIELD
nodeId: Integer,
communityId: Integer
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
graphName |
字符串 |
|
否 |
存储在目录中的图的名称。 |
configuration |
映射 |
|
是 |
特定于算法和/或图过滤的配置。 |
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
字符串列表 |
|
是 |
使用给定的节点标签过滤命名的图。将包含具有任何给定标签的节点。 |
|
字符串列表 |
|
是 |
使用给定的关系类型过滤命名的图。将包含具有任何给定类型的关系。 |
|
整数 |
|
是 |
用于运行算法的并发线程数。 |
|
字符串 |
|
是 |
可以提供的 ID,以便更容易跟踪算法的进度。 |
|
布尔值 |
|
是 |
如果禁用,则不会记录进度百分比。 |
|
整数 |
|
是 |
要运行的最大迭代次数。 |
|
字符串 |
|
是 |
包含节点权重的节点属性的名称。 |
|
字符串 |
|
是 |
用作权重的关系属性的名称。如果未指定,则算法将以未加权的方式运行。 |
|
字符串 |
|
是 |
定义初始数字标签的节点属性的名称。 |
|
consecutiveIds |
布尔值 |
|
是 |
标志,用于决定是否将组件标识符映射到连续的 ID 空间(需要额外的内存)。 |
minCommunitySize |
整数 |
|
是 |
仅返回大于或等于给定值的社区内的节点。 |
名称 | 类型 | 描述 |
---|---|---|
nodeId |
整数 |
节点 ID。 |
communityId |
整数 |
社区 ID。 |
CALL gds.labelPropagation.stats(
graphName: String,
configuration: Map
)
YIELD
preProcessingMillis: Integer,
computeMillis: Integer,
postProcessingMillis: Integer,
communityCount: Integer,
ranIterations: Integer,
didConverge: Boolean,
communityDistribution: Map,
configuration: Map
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
graphName |
字符串 |
|
否 |
存储在目录中的图的名称。 |
configuration |
映射 |
|
是 |
特定于算法和/或图过滤的配置。 |
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
字符串列表 |
|
是 |
使用给定的节点标签过滤命名的图。将包含具有任何给定标签的节点。 |
|
字符串列表 |
|
是 |
使用给定的关系类型过滤命名的图。将包含具有任何给定类型的关系。 |
|
整数 |
|
是 |
用于运行算法的并发线程数。 |
|
字符串 |
|
是 |
可以提供的 ID,以便更容易跟踪算法的进度。 |
|
布尔值 |
|
是 |
如果禁用,则不会记录进度百分比。 |
|
整数 |
|
是 |
要运行的最大迭代次数。 |
|
字符串 |
|
是 |
包含节点权重的节点属性的名称。 |
|
字符串 |
|
是 |
用作权重的关系属性的名称。如果未指定,则算法将以未加权的方式运行。 |
|
字符串 |
|
是 |
定义初始数字标签的节点属性的名称。 |
|
consecutiveIds |
布尔值 |
|
是 |
标志,用于决定是否将组件标识符映射到连续的 ID 空间(需要额外的内存)。 |
名称 | 类型 | 描述 |
---|---|---|
preProcessingMillis |
整数 |
预处理数据的毫秒数。 |
computeMillis |
整数 |
运行算法的毫秒数。 |
postProcessingMillis |
整数 |
计算百分位数和社区数量的毫秒数。 |
communityCount |
整数 |
找到的社区数量。 |
ranIterations |
整数 |
执行的迭代次数。 |
didConverge |
布尔值 |
如果算法在提供的最大迭代次数内收敛到稳定的标记,则为真。 |
communityDistribution |
映射 |
包含社区规模的最小值、最大值、平均值以及 p1、p5、p10、p25、p50、p75、p90、p95、p99 和 p999 百分位数的映射。 |
configuration |
映射 |
用于运行算法的配置。 |
CALL gds.labelPropagation.mutate(
graphName: String,
configuration: Map
)
YIELD
preProcessingMillis: Integer,
computeMillis: Integer,
mutateMillis: Integer,
postProcessingMillis: Integer,
nodePropertiesWritten: Integer,
communityCount: Integer,
ranIterations: Integer,
didConverge: Boolean,
communityDistribution: Map,
configuration: Map
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
graphName |
字符串 |
|
否 |
存储在目录中的图的名称。 |
configuration |
映射 |
|
是 |
特定于算法和/或图过滤的配置。 |
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
mutateProperty |
字符串 |
|
否 |
GDS 图中将社区 ID 写入的节点属性。 |
字符串列表 |
|
是 |
使用给定的节点标签过滤命名的图。 |
|
字符串列表 |
|
是 |
使用给定的关系类型过滤命名的图。 |
|
整数 |
|
是 |
用于运行算法的并发线程数。 |
|
字符串 |
|
是 |
可以提供的 ID,以便更容易跟踪算法的进度。 |
|
整数 |
|
是 |
要运行的最大迭代次数。 |
|
字符串 |
|
是 |
包含节点权重的节点属性的名称。 |
|
字符串 |
|
是 |
用作权重的关系属性的名称。如果未指定,则算法将以未加权的方式运行。 |
|
字符串 |
|
是 |
定义初始数字标签的节点属性的名称。 |
|
consecutiveIds |
布尔值 |
|
是 |
标志,用于决定是否将组件标识符映射到连续的 ID 空间(需要额外的内存)。 |
名称 | 类型 | 描述 |
---|---|---|
preProcessingMillis |
整数 |
预处理数据的毫秒数。 |
computeMillis |
整数 |
运行算法的毫秒数。 |
mutateMillis |
整数 |
将属性添加到内存中图的毫秒数。 |
postProcessingMillis |
整数 |
计算百分位数和社区数量的毫秒数。 |
nodePropertiesWritten |
整数 |
写入的节点属性数。 |
communityCount |
整数 |
找到的社区数量。 |
ranIterations |
整数 |
执行的迭代次数。 |
didConverge |
布尔值 |
如果算法在提供的最大迭代次数内收敛到稳定的标记,则为真。 |
communityDistribution |
映射 |
包含社区规模的最小值、最大值、平均值以及 p1、p5、p10、p25、p50、p75、p90、p95、p99 和 p999 百分位数的映射。 |
configuration |
映射 |
用于运行算法的配置。 |
CALL gds.labelPropagation.write(
graphName: String,
configuration: Map
)
YIELD
preProcessingMillis: Integer,
computeMillis: Integer,
writeMillis: Integer,
postProcessingMillis: Integer,
nodePropertiesWritten: Integer,
communityCount: Integer,
ranIterations: Integer,
didConverge: Boolean,
communityDistribution: Map,
configuration: Map
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
graphName |
字符串 |
|
否 |
存储在目录中的图的名称。 |
configuration |
映射 |
|
是 |
特定于算法和/或图过滤的配置。 |
名称 | 类型 | 默认值 | 可选 | 描述 |
---|---|---|---|---|
字符串列表 |
|
是 |
使用给定的节点标签过滤命名的图。将包含具有任何给定标签的节点。 |
|
字符串列表 |
|
是 |
使用给定的关系类型过滤命名的图。将包含具有任何给定类型的关系。 |
|
整数 |
|
是 |
用于运行算法的并发线程数。 |
|
字符串 |
|
是 |
可以提供的 ID,以便更容易跟踪算法的进度。 |
|
布尔值 |
|
是 |
如果禁用,则不会记录进度百分比。 |
|
整数 |
|
是 |
用于将结果写入 Neo4j 的并发线程数。 |
|
字符串 |
|
否 |
Neo4j 数据库中将社区 ID 写入的节点属性。 |
|
整数 |
|
是 |
要运行的最大迭代次数。 |
|
字符串 |
|
是 |
包含节点权重的节点属性的名称。 |
|
字符串 |
|
是 |
用作权重的关系属性的名称。如果未指定,则算法将以未加权的方式运行。 |
|
字符串 |
|
是 |
定义初始数字标签的节点属性的名称。 |
|
consecutiveIds |
布尔值 |
|
是 |
标志,用于决定是否将组件标识符映射到连续的 ID 空间(需要额外的内存)。 |
minCommunitySize |
整数 |
|
是 |
仅将大小大于或等于给定值的社区的社区 ID 写入 Neo4j。 |
名称 | 类型 | 描述 |
---|---|---|
preProcessingMillis |
整数 |
预处理数据的毫秒数。 |
computeMillis |
整数 |
运行算法的毫秒数。 |
writeMillis |
整数 |
将结果数据写回的毫秒数。 |
postProcessingMillis |
整数 |
计算百分位数和社区数量的毫秒数。 |
nodePropertiesWritten |
整数 |
写入的节点属性数。 |
communityCount |
整数 |
找到的社区数量。 |
ranIterations |
整数 |
执行的迭代次数。 |
didConverge |
布尔值 |
如果算法在提供的最大迭代次数内收敛到稳定的标记,则为真。 |
communityDistribution |
映射 |
包含社区规模的最小值、最大值、平均值以及 p1、p5、p10、p25、p50、p75、p90、p95、p99 和 p999 百分位数的映射。 |
configuration |
映射 |
用于运行算法的配置。 |
示例
以下所有示例都应在空数据库中运行。 这些示例使用 Cypher 投影 作为规范。原生投影将在将来的版本中弃用。 |
在本节中,我们将展示在具体图上运行标签传播算法的示例。目的是说明结果是什么样子,并提供如何在实际环境中使用该算法的指南。我们将在少量节点以特定模式连接的小型社交网络图上进行此操作。示例图如下所示
CREATE
(alice:User {name: 'Alice', posts: 4, seed_label: 52}),
(bridget:User {name: 'Bridget', posts: 13, seed_label: 21}),
(charles:User {name: 'Charles', posts: 55, seed_label: 43}),
(doug:User {name: 'Doug', posts: 5, seed_label: 21}),
(mark:User {name: 'Mark', posts: 7, seed_label: 19}),
(michael:User {name: 'Michael', posts: 15, seed_label: 52}),
(alice)-[:FOLLOW {weight: 1}]->(bridget),
(alice)-[:FOLLOW {weight: 10}]->(charles),
(mark)-[:FOLLOW {weight: 1}]->(doug),
(bridget)-[:FOLLOW {weight: 1}]->(michael),
(doug)-[:FOLLOW {weight: 1}]->(mark),
(michael)-[:FOLLOW {weight: 1}]->(alice),
(alice)-[:FOLLOW {weight: 1}]->(michael),
(bridget)-[:FOLLOW {weight: 1}]->(alice),
(michael)-[:FOLLOW {weight: 1}]->(bridget),
(charles)-[:FOLLOW {weight: 1}]->(doug)
该图代表六个用户,其中一些用户相互关注。除了 name
属性外,每个用户还具有 seed_label
属性。seed_label
属性表示图中用于用标签播种节点的值。例如,这可以是先前运行标签传播算法的结果。此外,每个关系都具有一个权重属性。
MATCH (source:User)-[r:FOLLOW]->(target:User)
RETURN gds.graph.project(
'myGraph',
source,
target,
{
sourceNodeProperties: source { .posts, .seed_label },
targetNodeProperties: target { .posts, .seed_label },
relationshipProperties: r { .weight }
}
)
在以下示例中,我们将演示在该图上使用标签传播算法。
内存估计
首先,我们将使用 estimate
过程估计运行算法的成本。这可以在任何执行模式下完成。在本示例中,我们将使用 write
模式。估计算法有助于了解在图上运行算法将产生的内存影响。当您稍后在其中一种执行模式下实际运行算法时,系统将执行估计。如果估计表明执行很有可能超过其内存限制,则会禁止执行。要了解有关此内容的更多信息,请参见 自动估计和执行阻止。
有关 estimate
的更多详细信息,请参见 内存估计。
CALL gds.labelPropagation.write.estimate('myGraph', { writeProperty: 'community' })
YIELD nodeCount, relationshipCount, bytesMin, bytesMax, requiredMemory
nodeCount | relationshipCount | bytesMin | bytesMax | requiredMemory |
---|---|---|---|---|
6 |
10 |
1592 |
1592 |
"1592 字节" |
流
在 stream
执行模式下,算法会返回每个节点的社区 ID。这使我们可以直接检查结果,或者在 Cypher 中对结果进行后处理,而不会产生任何副作用。例如,我们可以对结果进行排序,以查看属于同一个社区的节点彼此相邻显示。
有关 stream
模式的更多详细信息,请参见 流。
CALL gds.labelPropagation.stream('myGraph')
YIELD nodeId, communityId AS Community
RETURN gds.util.asNode(nodeId).name AS Name, Community
ORDER BY Community, Name
名称 | 社区 |
---|---|
"Alice" |
0 |
"Bridget" |
0 |
"Michael" |
0 |
"Charles" |
4 |
"Doug" |
4 |
"Mark" |
4 |
在上面的示例中,我们可以看到我们的图有两个社区,每个社区包含三个节点。算法的默认行为是运行 unweighted
,例如,不使用 node
或 relationship
权重。weighted
选项将在 加权 中演示
统计
在 stats
执行模式下,算法会返回包含算法结果摘要的单行。此执行模式没有任何副作用。通过检查 computeMillis
返回项,它可以用于评估算法性能。在以下示例中,我们将省略返回计时。可以在 语法部分 中找到该过程的完整签名。
有关 stats
模式的更多详细信息,请参见 统计。
stats
模式运行算法CALL gds.labelPropagation.stats('myGraph')
YIELD communityCount, ranIterations, didConverge
communityCount | ranIterations | didConverge |
---|---|---|
2 |
3 |
真 |
从上面的示例中我们可以看到,算法找到了两个社区,并在三次迭代中收敛。请注意,我们以 unweighted
方式运行了算法。
变异
mutate
执行模式扩展了 stats
模式,并具有一个重要的副作用:使用一个包含该节点的社区 ID 的新节点属性更新命名的图。新属性的名称使用强制配置参数 mutateProperty
指定。结果是单行摘要,类似于 stats
,但具有一些额外的指标。mutate
模式在多个算法联合使用时尤其有用。
有关 mutate
模式的更多详细信息,请参见 变异。
CALL gds.labelPropagation.mutate('myGraph', { mutateProperty: 'community' })
YIELD communityCount, ranIterations, didConverge
communityCount | ranIterations | didConverge |
---|---|---|
2 |
3 |
真 |
返回的结果与 stats
示例中的结果相同。此外,图“myGraph”现在具有一个节点属性 community
,用于存储每个节点的社区 ID。要了解如何检查内存中图的新架构,请参见 列出图。
写入
write
执行模式扩展了 stats
模式,并具有一个重要的副作用:将每个节点的社区 ID 作为属性写入 Neo4j 数据库。新属性的名称使用必需的配置参数 writeProperty
指定。结果是一行与 stats
类似的汇总行,但包含一些额外的指标。write
模式支持将结果直接持久化到数据库中。
有关 write
模式的更多详细信息,请参阅 写入。
CALL gds.labelPropagation.write('myGraph', { writeProperty: 'community' })
YIELD communityCount, ranIterations, didConverge
communityCount | ranIterations | didConverge |
---|---|---|
2 |
3 |
真 |
返回的结果与 stats
示例中的相同。此外,六个节点中的每一个现在在 Neo4j 数据库中都有一个新的属性 community
,其中包含该节点的社区 ID。
加权
当我们投影 myGraph
时,我们也投影了关系属性 weight
。为了告诉算法将此属性视为关系权重,我们必须将 relationshipWeightProperty
配置参数设置为 weight
。
CALL gds.labelPropagation.stream('myGraph', { relationshipWeightProperty: 'weight' })
YIELD nodeId, communityId AS Community
RETURN gds.util.asNode(nodeId).name AS Name, Community
ORDER BY Community, Name
名称 | 社区 |
---|---|
"Bridget" |
0 |
"Michael" |
0 |
"Alice" |
4 |
"Charles" |
4 |
"Doug" |
4 |
"Mark" |
4 |
与算法的 无权运行 相比,我们仍然有两个社区,但它们分别包含两个和四个节点。使用加权关系,节点 Alice
和 Charles
现在位于同一个社区中,因为它们之间存在强链接。
加权节点
通过使用 nodeWeightProperty
键指定节点权重,我们还可以控制节点社区对其邻居的影响。在计算特定社区的权重期间,节点属性将乘以该节点关系的权重。
CALL gds.labelPropagation.stream('myGraph', { nodeWeightProperty: 'posts' })
YIELD nodeId, communityId AS Community
RETURN gds.util.asNode(nodeId).name AS Name, Community
ORDER BY Community, Name
名称 | 社区 |
---|---|
"Alice" |
4 |
"Charles" |
4 |
"Doug" |
4 |
"Mark" |
4 |
"Bridget" |
5 |
"Michael" |
5 |
我们使用 stream 模式来演示使用权重运行算法,这些配置参数可用于算法的所有模式。 |
种子社区
在算法计算开始时,每个节点都使用唯一标签进行初始化,并且标签通过网络传播。
可以通过设置 seedProperty
配置参数来提供一组初始标签。当我们投影 myGraph
时,我们也投影了节点属性 seed_label
。我们可以使用此节点属性作为 seedProperty
。
算法首先检查节点是否分配了种子标签。如果不存在种子标签,则算法会为该节点分配新的唯一标签。使用此初步标签集,它随后会按顺序将每个节点的标签更新为一个新的标签,该标签在标签传播的每次迭代中都是其邻居中最频繁的标签。
consecutiveIds 配置选项不能与 seedProperty 结合使用以保留种子值。 |
CALL gds.labelPropagation.stream('myGraph', { seedProperty: 'seed_label' })
YIELD nodeId, communityId AS Community
RETURN gds.util.asNode(nodeId).name AS Name, Community
ORDER BY Community, Name
名称 | 社区 |
---|---|
"Charles" |
19 |
"Doug" |
19 |
"Mark" |
19 |
"Alice" |
52 |
"Bridget" |
52 |
"Michael" |
52 |
正如我们所见,社区是基于 seed_label
属性的,具体来说,19
来自节点 Mark
,52
来自 Alice
。
我们使用 stream 模式来演示使用 seedProperty 运行算法,此配置参数可用于算法的所有模式。 |