[ Spark mllib ] 聚类K-means案例——2021挖掘

目的与要求

  1. 筛选北京地区(“城市”字段为“北京市”)商家数据记录形成筛选数据集。
  2. 根据北京地区商家的经纬度属性,对商家进行 k-means 聚类,聚类数设为 5,迭代次数为 2000 次。
  3. 打印语句输出聚类中心、每个类的商家数,以及该类所包含的商圈。(打印格式:=cluster 0: 聚类中心为[],商家数为***个,包含商圈:【***,***,…】=)

数据格式

在这里插入图片描述

数据读取与清洗

读取、解析json文件。

val jsondata: RDD[JSONObject] = sc.textFile("D:\\task.json").map(line => JSON.parseObject(line.toString))

将解析的json文件数据进行数据的进行过滤,筛选得到城市名为北京的数据集。

val data: RDD[JSONObject] = jsondata.filter(line => {
      line.getString("city_name") == "北京市"
    })

将筛选得到的数据集进行清洗,将其向量化。

val vectors: RDD[linalg.Vector] = data.map(line => {
      //取得经纬度使得变为数组
      val features = Array[Double(line.getString("latitude").toDouble,line.getString("longitude").toDouble)
      //向量化
      Vectors.dense(features)
    })

聚合K-Means操作

第一参数为清洗后的向量化数据,第二参数为期望的聚类的个数,第三参数为迭代次数。

val model = KMeans.train(vectors, 5, 2000)

可通过遍历打印查看聚类中心点以及给定代表的索引,或聚类的个数。

var clusterIndex = 0;
model.clusterCenters.foreach(cen => {
      print(clusterIndex + ":")
      println(cen.toString)
      clusterIndex += 1
    })
println("Cluster Number:" + value1.clusterCenters.length)

数据的再次清洗和拼接

映射一个新的rdd,用来统计商家数量,假设这里的每一条数据代表每一个不同商家。
用(聚类中心的索引,1)通过聚类中心的索引统计商家数量。

val marketers_number = data.map(line => {
      val features = Array[Double](line.getString("latitude").toDouble, line.getString("longitude").toDouble)
      val i: Int = value1.predict(Vectors.dense(features))
      (i, 1)
    }).reduceByKey(_ + _)

用(聚类中心的索引,商圈)通过聚类中心的索引对其商圈进行分组(#注:商圈为location)。

val shopping = data.map(line => {
      val features = Array[Double](line.getString("latitude").toDouble, line.getString("longitude").toDouble)
      val i: Int = value1.predict(Vectors.dense(features))
      (i, line.getString("location"))
    }).groupByKey()

数据的输出打印

join通过相同key(聚类中心的索引)进行拼接,使得数据变为(聚类中心,(商家数量,商圈))。
sortby通过x._1(聚类中心的索引)升序排序,默认为升序,降序则添加参数false。
遍历打印,将我们得到的聚类中心通过索引进行匹配。

marketers_number.join(shopping).sortBy(x => x._1).collect().foreach(x => {
      var centre = ""
      if (x._1 == 0) {
        centre = "[39.963067343283576,116.34161625870645]"
      }
      if (x._1 == 1) {
        centre = "[39.824223999999994,116.67271499999998]"
      }
      if (x._1 == 2) {
        centre = "[40.03647706976744,116.27083911627908]"
      }
      if (x._1 == 3) {
        centre = "[40.00760493333333,116.57222786666668]"
      }
      if (x._1 == 4) {
        centre = "[40.044718465116276,116.40492395348836]"
      }
      println("=cluster " + x._1 + ": 聚类中心为" + centre + ",商家数为" + x._2._1 + "个,包含商圈:【" + x._2._2.toString().replace("CompactBuffer(", "").replace(")", "") + "】")
    })

完整代码

import com.alibaba.fastjson.{JSON, JSONObject}
import org.apache.spark.mllib.clustering.KMeans
import org.apache.spark.mllib.linalg
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object task9 {
  def main(args: Array[String]): Unit = {
    //环境配置
    val conf: SparkConf = new SparkConf().setMaster("local").setAppName("task")
    val sc = new SparkContext(conf)
    val jsondata: RDD[JSONObject] = sc.textFile("D:\\2021\\diliveryoutput1").map(line => JSON.parseObject(line.toString))
    //筛选出城市名为北京市的数据
    val data: RDD[JSONObject] = jsondata.filter(line => {
      line.getString("city_name") == "北京市" && line.getString("longitude") != "纬度"
    })
   
    val vectors: RDD[linalg.Vector] = data.map(line => {
      //取得经纬度使得变为数组
      val features = Array[Double](line.getString("latitude").toDouble, line.getString("longitude").toDouble)
      Vectors.dense(features)
    })
    // 第一参数为清洗后的向量化数据,第二参数为期望的聚类的个数,第三参数为迭代次数
    val value1 = KMeans.train(vectors, 5, 2000)
    
    //遍历打印查看聚类中心点以及给定代表的索引
    var clusterIndex = 0;
    value1.clusterCenters.foreach(c => {
      print(clusterIndex + ":")
      println(c.toString)
      clusterIndex += 1
    })
    val cost = value1.computeCost(vectors)
    println("Within Set Sum of Squared Errors=" + cost.toString)
   
    value1.clusterCenters.foreach(c => println(c))
   
    val marketers_number = data.map(line => {
      val features = Array[Double](line.getString("latitude").toDouble, line.getString("longitude").toDouble)
      val i: Int = value1.predict(Vectors.dense(features))
      (i, 1)
    }).reduceByKey(_ + _)

    val shopping = data.map(line => {
      val features = Array[Double](line.getString("latitude").toDouble, line.getString("longitude").toDouble)
      val i: Int = value1.predict(Vectors.dense(features))
      (i, line.getString("location"))
    }).groupByKey()
    marketers_number.join(shopping).sortBy(x => x._1).collect().foreach(x => {
      var centre = ""
      if (x._1 == 0) {
        centre = "[39.963067343283576,116.34161625870645]"
      }
      if (x._1 == 1) {
        centre = "[39.824223999999994,116.67271499999998]"
      }
      if (x._1 == 2) {
        centre = "[40.03647706976744,116.27083911627908]"
      }
      if (x._1 == 3) {
        centre = "[40.00760493333333,116.57222786666668]"
      }
      if (x._1 == 4) {
        centre = "[40.044718465116276,116.40492395348836]"
      }
      println("=cluster " + x._1 + ": 聚类中心为" + centre + ",商家数为" + x._2._1 + "个,包含商圈:【" + x._2._2.toString().replace("CompactBuffer(", "").replace(")", "") + "】")
    })
  }

}

最终结果

这里因为商圈数量居多,故取商圈的前两个,后以…代替输出作为结果。

=cluster 0: 聚类中心为[39.963067343283576,116.34161625870645],商家数为185个,包含商圈:【中关村南三街, 科学院南路, …】=
=cluster 1: 聚类中心为[39.824223999999994,116.67271499999998],商家数为5个,包含商圈:【燕昌路, 康复路, …】=
=cluster 2: 聚类中心为[40.03647706976744,116.27083911627908],商家数为26个,包含商圈:【泥洼路, 彰化路,…】=
=cluster 3: 聚类中心为[40.00760493333333,116.57222786666668],商家数为48个,包含商圈:【双营路, 来广营东路,…】=
=cluster 4: 聚类中心为[40.044718465116276,116.40492395348836],商家数为45个,包含商圈:【南花市大街, 大宏巷,…】=

用简单的思路做题。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值