GraphX【算法实现】同配性算法:平均连通性算法

平均连通性算法

算法描述:

具有K度节点的平均最近邻度,用作考察度值相近的节点是否倾向于相互连接,在社交网络中,节点更倾向于于度数相近的节点连接;

计算思路

  1. 计算图中每个顶点的sourceDegree,targetDegree(根据指定的source|target的方向);
  2. 根据指定的sourceDirection方向,计算每个节点的领点集合;
  3. 根据是否指定待计算的节点列,从sourceDegree中过滤指定的节点:sourceNode;
  4. 对sourceNodes每个节点进行转换;
    4.1 计算每个节点的邻点度数之和;
    4.2 计算后数据格式为:(节点数据,(节点度数,节点的邻点的度数之和))
  5. 聚合计算:计算相同度数的节点的度数之和,相同度数的节点的邻点的度数之和;
  6. 计算平均最近邻度;

GraphX实现逻辑

def averageDegreeConnectivity[VD: ClassTag, ED: ClassTag](g: Graph[VD, ED],
                                                            sourceDirection: EdgeDirection = EdgeDirection.Either,
                                                            targetDirection: EdgeDirection = EdgeDirection.Either,
                                                            nodeList: List[VertexId]): RDD[(Long, Double)] = {
    val graph = g.cache()
    //根据边的方向,计算该点对应的度数,出度|入度|总度数
    val sourceDegree: VertexRDD[Int] = degreesRDD(graph, sourceDirection)
    val targetDegree: Array[(VertexId, Int)] = degreesRDD(graph, targetDirection).collect()

    val sparkSession = SparkSession.builder().getOrCreate()

    val sc = sparkSession.sparkContext

    val broadcast = sc.broadcast(targetDegree)
    //计算每个顶点的原点方向的邻点
    val neighbor: VertexRDD[Set[VertexId]] = neighbors(graph, sourceDirection)

    //如果指定了节点列表,则过滤指定的节点列
    val sourceNodes: VertexRDD[Int] = if (nodeList != null) {
      sourceDegree.filter(item => nodeList.contains(item._1))
    } else {
      sourceDegree
    }

    val vertexNeighborsRdd: RDD[(VertexId, (Int, Option[Set[VertexId]]))] = sourceNodes.leftOuterJoin(neighbor)

    //遍历顶点,转换每个顶点,并将每个顶点的度数作为key,该顶点的度数以及该顶点的邻点的度数之和组成二元组作为value(Int,(Int,Double))
    val resultRdd: RDD[(Long, Double)] = vertexNeighborsRdd.map(item => {
      val itemNeighbors = item._2._2.getOrElse(Set())
      if (itemNeighbors.nonEmpty) {
        val neighborSet = itemNeighbors
        val neighborDegree: Double = broadcast.value.filter(itemV2 => neighborSet.contains(itemV2._1)).map(_._2).sum
        (item._2._1, (item._2._1, neighborDegree))
      } else {
        (item._2._1, (item._2._1, 0.0))
      }
      //根据key做聚合,计算度数相同的顶点的度数之和以及,度数相同的顶点的邻点的度数之和
    }).reduceByKey((x, y) => (x._1 + y._1, x._2 + y._2))
      .filter(item => {
        item._2._1 > 0 && item._2._2 > 0
        //做转换,计算具有k度的节点的平均最近邻度
        //分子为:具有K度节点的度数之和
        //分母为:具有K度节点的邻点的度数之和
      }).map(item => {
      val avg = item._2._2 / item._2._1
      (item._1.toLong, avg)
    })

    resultRdd
  }
 /**
   * 计算图中每个顶点的邻点集
   */
  def neighbors[VD, ED: ClassTag](graph: Graph[VD, ED],
                                  edgeDirection: EdgeDirection = EdgeDirection.Either): VertexRDD[Set[VertexId]] = {
    if (edgeDirection == EdgeDirection.In) {
      graph.aggregateMessages(ctx => {
        ctx.sendToDst(Set(ctx.srcId))
      }, _ ++ _, TripletFields.None)
    } else if (edgeDirection == EdgeDirection.Out) {
      graph.aggregateMessages(ctx => {
        ctx.sendToSrc(Set(ctx.dstId))
      }, _ ++ _, TripletFields.None)
    }
    else {
      graph.aggregateMessages(ctx => {
        ctx.sendToDst(Set(ctx.srcId))
        ctx.sendToSrc(Set(ctx.dstId))
      }, _ ++ _, TripletFields.None)
    }
  }


  def degreesRDD[VD: ClassTag, ED: ClassTag](g: Graph[VD, ED],
                                             direction: EdgeDirection = EdgeDirection.Either): VertexRDD[Int] = {
    val vertexRdd: VertexRDD[Int] = direction match {
      case EdgeDirection.In => g.inDegrees
      case EdgeDirection.Out => g.outDegrees
      case EdgeDirection.Either => g.degrees
      case EdgeDirection.Both =>
        throw new SparkException("collectEdges does not support EdgeDirection.Both.Use EdgeDirection.Either instead")
    }
    vertexRdd
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是一个完整的程序,用于使用深度优先算法和广度优先算法遍历一个 5x5 的布尔二维数组表示的图形的连通性。程序还考虑了根据图的连通性合理选择遍历的起始位置的问题。 ```python import queue # 定义5x5的布尔二维数组表示需要遍历的图形的连通性 graph = [[True, True, False, False, False], [True, True, True, False, False], [False, True, True, True, False], [False, False, True, True, True], [False, False, False, True, True]] # 定义深度优先算法函数 def dfs(graph, visited, x, y): # 标记当前位置为已访问 visited[x][y] = True print("当前位置:(", x, ",", y, ")") # 检查当前位置四周的位置是否需要访问 if x > 0 and graph[x-1][y] and not visited[x-1][y]: dfs(graph, visited, x-1, y) if x < 4 and graph[x+1][y] and not visited[x+1][y]: dfs(graph, visited, x+1, y) if y > 0 and graph[x][y-1] and not visited[x][y-1]: dfs(graph, visited, x, y-1) if y < 4 and graph[x][y+1] and not visited[x][y+1]: dfs(graph, visited, x, y+1) # 定义广度优先算法函数 def bfs(graph, visited, x, y): # 创建队列并将起始位置入队 q = queue.Queue() q.put((x, y)) visited[x][y] = True while not q.empty(): # 取出队头位置并输出 cur_x, cur_y = q.get() print("当前位置:(", cur_x, ",", cur_y, ")") # 检查队头位置四周的位置是否需要访问 if cur_x > 0 and graph[cur_x-1][cur_y] and not visited[cur_x-1][cur_y]: q.put((cur_x-1, cur_y)) visited[cur_x-1][cur_y] = True if cur_x < 4 and graph[cur_x+1][cur_y] and not visited[cur_x+1][cur_y]: q.put((cur_x+1, cur_y)) visited[cur_x+1][cur_y] = True if cur_y > 0 and graph[cur_x][cur_y-1] and not visited[cur_x][cur_y-1]: q.put((cur_x, cur_y-1)) visited[cur_x][cur_y-1] = True if cur_y < 4 and graph[cur_x][cur_y+1] and not visited[cur_x][cur_y+1]: q.put((cur_x, cur_y+1)) visited[cur_x][cur_y+1] = True # 根据图的连通性合理选择遍历的起始位置 # 从左上角开始搜索,如果该位置是 False,则向右移动一位,继续搜索 # 直到找到一个 True 位置作为起始位置 start_x = 0 start_y = 0 while not graph[start_x][start_y]: start_y += 1 if start_y >= 5: start_x += 1 start_y = 0 # 创建 visited 数组用于记录每个位置是否已被访问 visited = [[False for i in range(5)] for j in range(5)] # 使用深度优先算法遍历图形 dfs(graph, visited, start_x, start_y) # 重置 visited 数组 visited = [[False for i in range(5)] for j in range(5)] # 使用广度优先算法遍历图形 bfs(graph, visited, start_x, start_y) ``` 这个程序首先定义了一个 5x5 的布尔二维数组表示需要遍历的图形的连通性。然后,它定义了一个深度优先算法函数和一个广度优先算法函数,用于遍历图形。函数的输入参数包括图形的连通性,visited 数组用于记录每个位置是否已被访问,以及起始位置的坐标。其中,深度优先算法使用递归实现,而广度优先算法使用队列实现。在遍历过程中,程序输出当前位置的坐标。 程序还考虑了根据图的连通性合理选择遍历的起始位置的问题。在这里,程序从左上角开始搜索,如果该位置是 False,则向右移动一位,继续搜索,直到找到一个 True 位置作为起始位置。 最后,程序调用深度优先算法函数和广度优先算法函数,使用不同的算法遍历图形。每次遍历前,程序都会重置 visited 数组,以确保每个位置都可以被访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stay_running

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值