Louvain 社区发现算法---scala 实现

关系对象类:

class RelationBean {

  //起始节点
  private var _fromNode: String = "null"

  def fromNode: String = _fromNode

  def fromNode_=(value: String): Unit = {
    _fromNode = value
  }

  //指向节点
  private var _toNode: String = "null"

  def toNode: String = _toNode

  def toNode_=(value: String): Unit = {
    _toNode = value
  }


  def canEqual(other: Any): Boolean = other.isInstanceOf[RelationBean]

  override def equals(other: Any): Boolean = other match {
    case that: RelationBean =>
      (that canEqual this) && (_fromNode == that._fromNode && _toNode == that._toNode)
    case _ => false
  }


  override def toString: String = "{fromNode:" + fromNode + ",toNode:" + toNode + ",info:" + info.toString() + "}"
}

object RelationBean {
  def apply: RelationBean = new RelationBean()

}


louvain 实现类:

import scala.collection.mutable

/**
  * 该算法 默认所有的边的权重为1 
 * 关系为无向关系
  * @param communityId 社区id
  */

class LouvainCommunity(val communityId: String) {
 //社区所包含的节点
  var nodes: mutable.HashSet[String] = new mutable.HashSet[String]()

  override def equals(obj: scala.Any): Boolean = obj.isInstanceOf[LouvainCommunity] && obj.asInstanceOf[LouvainCommunity].communityId == communityId

  override def toString: String = "{communityId:" + communityId + ",nodes:" + nodes.toString() + "}"
}


object LouvainCommunity {

  var global_1_m: Double = 0.0 //全局的 1/m
  var graph: mutable.HashMap[String, LouvainCommunity] = new mutable.HashMap[String, LouvainCommunity]()

  //某个节点的关系节点
  var nodeMap: mutable.HashMap[String, mutable.HashSet[String]] = new mutable.HashMap[String, mutable.HashSet[String]]()

  //节点所在的社区
  var nodecom: mutable.HashMap[String, String] = new mutable.HashMap[String, String]()

  //初始化louvain图
  def initGraph(edgeSet: Set[RelationBean]): Unit = {
    graph = new mutable.HashMap[String, LouvainCommunity]()
    nodeMap = new mutable.HashMap[String, mutable.HashSet[String]]()
    nodecom = new mutable.HashMap[String, String]()

    global_1_m = 1.0 / edgeSet.size
    for (edge: RelationBean <- edgeSet) {
      val fn: String = edge.fromNode
      val tn: String = edge.toNode
      nodeMap.put(fn, {
        val s: mutable.HashSet[String] = nodeMap.getOrElse(fn, new mutable.HashSet[String]())
        s.add(tn)
        s
      })
      nodeMap.put(tn, {
        val s: mutable.HashSet[String] = nodeMap.getOrElse(tn, new mutable.HashSet[String]())
        s.add(fn)
        s
      })
    }

    for (comid: String <- nodeMap.keySet.toSet) {
      graph.put(comid, {
        val c = new LouvainCommunity(comid)
        c.nodes.add(comid)
        c
      })
    }

    nodeMap.keySet.foreach(a => {
      nodecom.put(a, a)
    })
  }

  //入射 社区 的边的权重之和
  def getSigma_tot(comid: String): Int = {
    val comnodes = graph(comid).nodes
    val set = new mutable.HashSet[String]()
    comnodes.foreach(a => {
      nodeMap(a).foreach(b => {
        if (!comnodes.contains(b)) set.add(b)
      })
    })
    set.size
  }

  //入射 节点i 的权重之和
  def getK_i(nodeid: String): Int = nodeMap(nodeid).size

  //节点i 入射 社区 的权重之和
  def getK_i_in(nodeid: String, comid: String): Int = graph(comid).nodes.intersect(nodeMap(nodeid)).size

  //计算模块度 node为入射节点
  private def getDeltaModularity(node: String): (String, String, Double) = {
    val k_i = getK_i(node)
    val relanodes: mutable.HashSet[String] = nodeMap(node)
    val oldcomset = new mutable.HashSet[String]()
    var deltamax = ("flag", "0", 0.0)
    relanodes.foreach(node2 => {
      val comid = nodecom(node2)
      if (!oldcomset.contains(node2)) {
        oldcomset.add(node2)
        val k_i_in = getK_i_in(node, comid)
        val sigma_tot = getSigma_tot(comid)
        val deltatmp = k_i_in - sigma_tot * k_i * global_1_m
        if (deltatmp > 0 && deltatmp > deltamax._3) deltamax = (node, comid, deltatmp)
      }
    })
    deltamax
  }


  //重构louvain图
  def rebuildgraph(fromnode: String, tocom: String): String = {
    var re = " "
    graph(nodecom(fromnode)).nodes.remove(fromnode)
    if (graph(nodecom(fromnode)).nodes.isEmpty) {
      graph.remove(nodecom(fromnode))
      re = nodecom(fromnode)
    }
    graph(tocom).nodes.add(fromnode)
    nodecom.update(fromnode, tocom)
    re
  }

  def caculate(): Unit = {
    val deltaSet = new mutable.HashSet[(String, String, Double)]()
    val changenodeset = new mutable.HashSet[String]()
    nodeMap.keySet.foreach(com => {
      val delta = getDeltaModularity(com)
      if (delta._1 != "flag") deltaSet.add(delta)
    })

    if (deltaSet.nonEmpty) {
      deltaSet.foreach(a => {
        if (!changenodeset.contains(a._2) && !changenodeset.contains(a._1) && a._2 != nodecom(a._1)) {
          val re = rebuildgraph(a._1, a._2)
          changenodeset.add(a._1)
          changenodeset.add(a._2)
          changenodeset.add(re)
        }
      })
    }
  }


  def run(edgeSet: Set[RelationBean]): Set[LouvainCommunity] = {
    println("init")
    initGraph(edgeSet)
    println("caculate")
    var flag = 1
    while (flag < 10) {
      println("---- 第" + (flag + 1) + "次迭代 ----")
      caculate()
      flag += 1
    }
    graph.foreach(println(_))
    val re = graph
    graph.clear()
    nodecom.clear()
    nodeMap.clear()
    re.valuesIterator.toSet
  }

自用,待优化

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值