标签传播

词汇表

有向

有向特征。该算法在有向图上定义良好。

有向

有向特征。该算法忽略了图的方向。

有向

有向特征。该算法不在有向图上运行。

无向

无向特征。该算法在无向图上定义良好。

无向

无向特征。该算法忽略了图的无向性。

异构节点

异构节点 全面支持。该算法能够区分不同类型的节点。

异构节点

异构节点 允许。该算法以相同的方式处理所有选定节点,无论其标签如何。

异构关系

异构关系 全面支持。该算法能够区分不同类型的关系。

异构关系

异构关系 允许。该算法以相同的方式处理所有选定关系,无论其类型如何。

加权关系

加权特征。该算法支持使用关系属性作为权重,通过 relationshipWeightProperty 配置参数指定。

加权关系

加权特征。该算法将每个关系视为同等重要,丢弃任何关系权重的值。

介绍

标签传播算法(LPA)是一种快速查找图中社区的算法。它仅使用网络结构作为引导来检测这些社区,不需要预定义的目标函数或关于社区的先验信息。

LPA 通过在整个网络中传播标签并基于此标签传播过程形成社区来工作。

该算法背后的直觉是,单个标签可以在密集连接的节点组中快速变得占主导地位,但难以穿越稀疏连接的区域。标签将被困在密集连接的节点组中,当算法完成时,最终具有相同标签的那些节点可以被认为是同一个社区的一部分。

该算法的工作原理如下

  • 每个节点都初始化为一个唯一的社区标签(一个标识符)。

  • 这些标签通过网络传播。

  • 在每次传播迭代中,每个节点都将其标签更新为其大多数邻居所属的标签。平局是任意地但确定性地解决的。

  • 当每个节点都具有其邻居的多数标签时,LPA 达到收敛。

  • 如果达到收敛或用户定义的最大迭代次数,LPA 就会停止。

随着标签的传播,密集连接的节点组会快速达成关于唯一标签的共识。在传播结束时,只会剩下几个标签——大多数标签会消失。在收敛时具有相同社区标签的节点被认为属于同一个社区。

LPA 的一个有趣特性是,可以为节点分配初步标签来缩小生成解决方案的范围。这意味着它可以用作一种半监督方式来查找社区,我们可以在其中手动选择一些初始社区。

有关该算法的更多信息,请参见

运行此算法需要足够的内存可用性。在运行此算法之前,建议您阅读 内存估计

语法

本节介绍在每种执行模式下执行标签传播算法时使用的语法。我们正在描述命名的图变体的语法。要了解有关通用语法变体的更多信息,请参见 语法概述

每个模式的标签传播语法
在命名的图上以流模式运行标签传播。
CALL gds.labelPropagation.stream(
  graphName: String,
  configuration: Map
)
YIELD
    nodeId: Integer,
    communityId: Integer
表 1. 参数
名称 类型 默认值 可选 描述

graphName

字符串

n/a

存储在目录中的图的名称。

configuration

映射

{}

特定于算法和/或图过滤的配置。

表 2. 配置
名称 类型 默认值 可选 描述

nodeLabels

字符串列表

['*']

使用给定的节点标签过滤命名的图。将包含具有任何给定标签的节点。

relationshipTypes

字符串列表

['*']

使用给定的关系类型过滤命名的图。将包含具有任何给定类型的关系。

concurrency

整数

4

用于运行算法的并发线程数。

jobId

字符串

内部生成

可以提供的 ID,以便更容易跟踪算法的进度。

logProgress

布尔值

如果禁用,则不会记录进度百分比。

maxIterations

整数

10

要运行的最大迭代次数。

nodeWeightProperty

字符串

包含节点权重的节点属性的名称。

relationshipWeightProperty

字符串

用作权重的关系属性的名称。如果未指定,则算法将以未加权的方式运行。

seedProperty

字符串

n/a

定义初始数字标签的节点属性的名称。

consecutiveIds

布尔值

标志,用于决定是否将组件标识符映射到连续的 ID 空间(需要额外的内存)。

minCommunitySize

整数

0

仅返回大于或等于给定值的社区内的节点。

表 3. 结果
名称 类型 描述

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
表 4. 参数
名称 类型 默认值 可选 描述

graphName

字符串

n/a

存储在目录中的图的名称。

configuration

映射

{}

特定于算法和/或图过滤的配置。

表 5. 配置
名称 类型 默认值 可选 描述

nodeLabels

字符串列表

['*']

使用给定的节点标签过滤命名的图。将包含具有任何给定标签的节点。

relationshipTypes

字符串列表

['*']

使用给定的关系类型过滤命名的图。将包含具有任何给定类型的关系。

concurrency

整数

4

用于运行算法的并发线程数。

jobId

字符串

内部生成

可以提供的 ID,以便更容易跟踪算法的进度。

logProgress

布尔值

如果禁用,则不会记录进度百分比。

maxIterations

整数

10

要运行的最大迭代次数。

nodeWeightProperty

字符串

包含节点权重的节点属性的名称。

relationshipWeightProperty

字符串

用作权重的关系属性的名称。如果未指定,则算法将以未加权的方式运行。

seedProperty

字符串

n/a

定义初始数字标签的节点属性的名称。

consecutiveIds

布尔值

标志,用于决定是否将组件标识符映射到连续的 ID 空间(需要额外的内存)。

表 6. 结果
名称 类型 描述

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
表 7. 参数
名称 类型 默认值 可选 描述

graphName

字符串

n/a

存储在目录中的图的名称。

configuration

映射

{}

特定于算法和/或图过滤的配置。

表 8. 配置
名称 类型 默认值 可选 描述

mutateProperty

字符串

n/a

GDS 图中将社区 ID 写入的节点属性。

nodeLabels

字符串列表

['*']

使用给定的节点标签过滤命名的图。

relationshipTypes

字符串列表

['*']

使用给定的关系类型过滤命名的图。

concurrency

整数

4

用于运行算法的并发线程数。

jobId

字符串

内部生成

可以提供的 ID,以便更容易跟踪算法的进度。

maxIterations

整数

10

要运行的最大迭代次数。

nodeWeightProperty

字符串

包含节点权重的节点属性的名称。

relationshipWeightProperty

字符串

用作权重的关系属性的名称。如果未指定,则算法将以未加权的方式运行。

seedProperty

字符串

n/a

定义初始数字标签的节点属性的名称。

consecutiveIds

布尔值

标志,用于决定是否将组件标识符映射到连续的 ID 空间(需要额外的内存)。

表 9. 结果
名称 类型 描述

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
表 10. 参数
名称 类型 默认值 可选 描述

graphName

字符串

n/a

存储在目录中的图的名称。

configuration

映射

{}

特定于算法和/或图过滤的配置。

表 11. 配置
名称 类型 默认值 可选 描述

nodeLabels

字符串列表

['*']

使用给定的节点标签过滤命名的图。将包含具有任何给定标签的节点。

relationshipTypes

字符串列表

['*']

使用给定的关系类型过滤命名的图。将包含具有任何给定类型的关系。

concurrency

整数

4

用于运行算法的并发线程数。

jobId

字符串

内部生成

可以提供的 ID,以便更容易跟踪算法的进度。

logProgress

布尔值

如果禁用,则不会记录进度百分比。

writeConcurrency

整数

'concurrency' 的值

用于将结果写入 Neo4j 的并发线程数。

writeProperty

字符串

n/a

Neo4j 数据库中将社区 ID 写入的节点属性。

maxIterations

整数

10

要运行的最大迭代次数。

nodeWeightProperty

字符串

包含节点权重的节点属性的名称。

relationshipWeightProperty

字符串

用作权重的关系属性的名称。如果未指定,则算法将以未加权的方式运行。

seedProperty

字符串

n/a

定义初始数字标签的节点属性的名称。

consecutiveIds

布尔值

标志,用于决定是否将组件标识符映射到连续的 ID 空间(需要额外的内存)。

minCommunitySize

整数

0

仅将大小大于或等于给定值的社区的社区 ID 写入 Neo4j。

表 12. 结果
名称 类型 描述

preProcessingMillis

整数

预处理数据的毫秒数。

computeMillis

整数

运行算法的毫秒数。

writeMillis

整数

将结果数据写回的毫秒数。

postProcessingMillis

整数

计算百分位数和社区数量的毫秒数。

nodePropertiesWritten

整数

写入的节点属性数。

communityCount

整数

找到的社区数量。

ranIterations

整数

执行的迭代次数。

didConverge

布尔值

如果算法在提供的最大迭代次数内收敛到稳定的标记,则为真。

communityDistribution

映射

包含社区规模的最小值、最大值、平均值以及 p1、p5、p10、p25、p50、p75、p90、p95、p99 和 p999 百分位数的映射。

configuration

映射

用于运行算法的配置。

示例

以下所有示例都应在空数据库中运行。

这些示例使用 Cypher 投影 作为规范。原生投影将在将来的版本中弃用。

在本节中,我们将展示在具体图上运行标签传播算法的示例。目的是说明结果是什么样子,并提供如何在实际环境中使用该算法的指南。我们将在少量节点以特定模式连接的小型社交网络图上进行此操作。示例图如下所示

Visualization of the example graph
以下 Cypher 语句将在 Neo4j 数据库中创建示例图
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 属性表示图中用于用标签播种节点的值。例如,这可以是先前运行标签传播算法的结果。此外,每个关系都具有一个权重属性。

以下语句将使用 Cypher 投影投影图,并将该图存储在图目录中,名称为“myGraph”。
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
表 13. 结果
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
表 14. 结果
名称 社区

"Alice"

0

"Bridget"

0

"Michael"

0

"Charles"

4

"Doug"

4

"Mark"

4

在上面的示例中,我们可以看到我们的图有两个社区,每个社区包含三个节点。算法的默认行为是运行 unweighted,例如,不使用 noderelationship 权重。weighted 选项将在 加权 中演示

统计

stats 执行模式下,算法会返回包含算法结果摘要的单行。此执行模式没有任何副作用。通过检查 computeMillis 返回项,它可以用于评估算法性能。在以下示例中,我们将省略返回计时。可以在 语法部分 中找到该过程的完整签名。

有关 stats 模式的更多详细信息,请参见 统计

以下将以 stats 模式运行算法
CALL gds.labelPropagation.stats('myGraph')
YIELD communityCount, ranIterations, didConverge
表 15. 结果
communityCount ranIterations didConverge

2

3

从上面的示例中我们可以看到,算法找到了两个社区,并在三次迭代中收敛。请注意,我们以 unweighted 方式运行了算法。

变异

mutate 执行模式扩展了 stats 模式,并具有一个重要的副作用:使用一个包含该节点的社区 ID 的新节点属性更新命名的图。新属性的名称使用强制配置参数 mutateProperty 指定。结果是单行摘要,类似于 stats,但具有一些额外的指标。mutate 模式在多个算法联合使用时尤其有用。

有关 mutate 模式的更多详细信息,请参见 变异

以下将运行算法并写回结果
CALL gds.labelPropagation.mutate('myGraph', { mutateProperty: 'community' })
YIELD communityCount, ranIterations, didConverge
表 16. 结果
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
表 17. 结果
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
表 18. 结果
名称 社区

"Bridget"

0

"Michael"

0

"Alice"

4

"Charles"

4

"Doug"

4

"Mark"

4

与算法的 无权运行 相比,我们仍然有两个社区,但它们分别包含两个和四个节点。使用加权关系,节点 AliceCharles 现在位于同一个社区中,因为它们之间存在强链接。

加权节点

通过使用 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
表 19. 结果
名称 社区

"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
表 20. 结果
名称 社区

"Charles"

19

"Doug"

19

"Mark"

19

"Alice"

52

"Bridget"

52

"Michael"

52

正如我们所见,社区是基于 seed_label 属性的,具体来说,19 来自节点 Mark52 来自 Alice

我们使用 stream 模式来演示使用 seedProperty 运行算法,此配置参数可用于算法的所有模式。