spark学习之 GraphX—预测社交圈子

spark学习之 GraphX—预测社交圈子

一、计算连通分量

任务描述
连通分量是预测社交圈子的基础,使用连通分量算法能够快速找到一个图中的小圈子。
在这里插入图片描述
利用GraphX对图1进行创建并运用连通分量算法找出图中的连通分量:

import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.graphx._

object connectComponents{
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("connectComponents ").setMaster("local[4]")
    val sc = new SparkContext(conf) //屏蔽日志
    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
    //**************Begin*************************
    //1-->2
    // 4->5->6    4->5->7->6
    //4->6
    //3/
    //8
    val myVertices = sc.parallelize((1L to 8L).map((_,""))) //构造VertexRDD
    val myEdges = sc.parallelize(Array(Edge(1L,2L, ""),Edge(4L,5L, ""),Edge(4L,6L, ""),Edge(5L,6L, ""),Edge(5L,7L, ""),Edge(7L,6L, ""))) //构造EdgeRDD
    val myGraph=Graph(myVertices,myEdges) 
    val connectedcomponents = myGraph.connectedComponents.vertices.map(_.swap).groupByKey.map(_._2).collect
    println("")
    connectedcomponents.foreach(println)


  }
}


二、社交圈子预测1

任务描述
使用来自网络竞赛中的社交圈研究数据,这些数据来自少量的Facebook用户,这些用户在他们的朋友圈中分享信息。同时,每个用户被要求分配他们的朋友到一个或者多个社交圈。社交圈是一些用户朋友的分组,对这些用户是有意义的。本关将用一个简单的近似方法在每个用户有连接的图中找出连通组件。

在文件夹egonets数据集中,用户是匿名的,每个用户分配一个ID,每个用户一个egonet类型的文件,如 图:
在这里插入图片描述

import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.graphx._
object predict1_s{
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("predict1_s").setMaster("local[4]")
    val sc = new SparkContext(conf) //屏蔽日志
    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
    // 处理egonet文件的每行数据,返回元组形式的边数据
    def get_edges_from_line(line: String): Array[(Long, Long)] = {
      val ary = line.split(":")
      //划分源顶点和目标顶点
      val srcId = ary(0).toInt
      //根据分隔符把字符串切分为一个数组
      val dstIds = ary(1).split(" ")
      val edges = for {
        dstId <- dstIds
        if (dstId != "")
      } yield {
        //将源顶点和目标顶点组合成元组
        (srcId.toLong, dstId.toLong)
      }
      if (edges.size > 0) edges else Array((srcId, srcId))
    }
    //读取239.egonet文件内容
    val egonet_example = sc.textFile("/root/data/egonets/239.egonet")
    //**************Begin*************************
    //根据定义的get_edges_from_line函数构造由边数据组成的Array
    val edges_array = egonet_example.map(x => get_edges_from_line(x)).collect
    //但现在是一个二维数组,需要用flatten函数转化为一维数组
    val edges = edges_array.flatten
    //构造rawEdges:RDD[(VetexId,VertexId)]
    val g_edges = sc.makeRDD(edges)
    //使用fromEdgeTuples构造图
    val g = Graph.fromEdgeTuples(g_edges,1)
    //**************End**************************
    //**************Begin*************************
    //找出图中的连通分量
    val connectedcomponents = g.connectedComponents.vertices.map(_.swap).groupByKey.map(_._2).collect
    println("")
    //输出结果
    connectedcomponents.foreach(println)
    //**************End**************************
  }
}

程序输出:

CompactBuffer(312, 320, 276, 240, 336, 264, 316, 284, 256, 253, 277, 325, 337, 301, 293, 285, 313, 305, 241, 273, 309, 269, 338, 298, 310, 286, 294, 266, 302, 258, 242, 274, 334, 267, 283, 243, 263, 279, 295, 291, 335, 251, 339)
CompactBuffer(292, 288, 268)
CompactBuffer(296, 332, 324, 340, 280, 300, 260, 344, 272, 252, 304, 248, 308, 328, 244, 321, 297, 265, 261, 289, 281, 333, 245, 317, 249, 257, 341, 254, 326, 246, 262, 270, 250, 314, 322, 278, 318, 290, 342, 306, 282, 330, 315, 327, 331, 323, 319, 307, 311, 255, 275, 303, 259, 247, 271, 287, 299)
CompactBuffer(329)
CompactBuffer(343)

三、社交圈子预测2

任务描述:
在文件夹egonets数据集中,用户是匿名的,每个用户分配一个ID,每个用户一个egonet类型的文件。本关的任务是根据egonets文件夹下的所有文件内容,根据朋友间的连接创建一个图,找出图中的连通分量,输出社交圈子的结果。

根据读取的目录内容使用map和自定义的ext\fract函数提取用户ID,接着利用map和自定义的make_edges函数构造边元组,将得到的结果转化为List后,根据get_circles函数构造图,并计算连通分量;再次用zip函数将用户ID与预测的社交圈子组合,最后输出结果。
根据提示,补全代码中的内容,以使得程序运行结果如预期输出,最终的输出因为太大,所以我们减少了egonet的文件数据量,如果想获得完整数据,可从Kaggle上下载,链接为:https://www.kaggle.com/c/learning-social-circles/data。

import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.graphx._
object predict2_s{
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("predict2_s").setMaster("local[4]")
    val sc = new SparkContext(conf) //屏蔽日志
    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
    // 从path/userId.egonet格式的文件路径中解析出用户ID
    def extract(s: String) = {
      val Pattern = """^.*?(\d+).egonet""".r
      val Pattern(num) = s
      num
    }
    // 处理egonet文件的每行数据,返回元组形式的边数据
    def get_edges_from_line(line: String): Array[(Long, Long)] = {
      val ary = line.split(":")
      val srcId = ary(0).toInt
      val dstIds = ary(1).split(" ")
      val edges = for {
        dstId <- dstIds
        if (dstId != "")
      } yield {
        (srcId.toLong, dstId.toLong)
      }
      if (edges.size > 0) edges else Array((srcId, srcId))
    }
    // 根据文件内容构造边元组
    def make_edges(contents: String) = {
      val lines = contents.split("\n")
      // 根据get_edges_from_line构造元组类型的数组,此时unflat为二维数组
      val unflat = for {
        line <- lines
      } yield {
        get_edges_from_line(line)
      }
      //使用flatten函数降维,并返回值
      val flat = unflat.flatten
      flat
    }
    // 构建图对象,执行connectedComponents()操作,返回结果
    def get_circles(flat: Array[(Long, Long)]) = {
      val edges = sc.makeRDD(flat)
      val g = Graph.fromEdgeTuples(edges,1)
      val cc = g.connectedComponents()
      cc.vertices.map(x => (x._2, Array(x._1))).
        reduceByKey( (a,b) => a ++ b).
        values.map(_.mkString(" ")).collect.mkString(";")
    }
    //读取目录内容
    val egonets = sc.wholeTextFiles("/root/data/egonets")
    //**************Begin*************************
    //获取用户ID
    val egonet_numbers = egonets.map(x => extract(x._1)).collect
    //构造边元组
    val egonet_edges = egonets.map(x => make_edges(x._2)).collect
    //根据get_circles函数构造图,并计算连通分量
    val egonet_circles = egonet_edges.toList.map(x => get_circles(x))
    //**************End**************************
    //**************Begin*************************
    //将用户ID与预测的社交圈子组合,需要使用zip函数
    val result = egonet_numbers.zip(egonet_circles).map(x => x._1 + "," + x._2)
    println("")
    println("UserId,Predicted social circles(Every social circle is used ';' separated.)")
    //换行输出最终结果
    println(result.mkString("\n"))
    //**************End**************************
  }
}

输出内容:

UserId,Predicted social circles(Every social circle is used ‘;’ separated.)
0,29;196 96 52 4 180 16 156 216 28 80 104 92 24 152 36 188 140 204 212 236 132 72 64 20 12 108 228 144 148 192 100 160 84 56 224 112 76 120 184 232 200 116 48 128 32 220 172 124 164 40 8 60 44 88 136 176 68 168 177 13 189 137 101 81 229 193 153 129 105 125 121 65 157 161 57 149 37 185 133 205 201 45 1 89 17 173 9 49 109 145 41 61 217 21 77 169 53 97 25 117 73 213 93 233 33 181 113 237 221 141 69 165 85 209 197 5 225 34 230 150 134 158 82 66 54 138 98 170 222 30 14 50 110 214 146 202 154 106 74 226 90 238 70 18 38 78 218 178 10 162 94 122 22 182 166 46 142 194 62 42 210 126 118 206 186 6 190 86 58 198 114 174 234 2 39 19 151 119 71 55 231 79 171 11 127
注:部分结果省略

最后,本文如有帮助,望一键三连哈

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值