MLlib之KNN算法实例

MLlib之KNN算法实例

knn算法的思想:
邻近算法,或者最近邻(kNN,k-NearestNeighbor)分类算法是数据挖掘分类技术中最简单的方法之一。所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表(近朱者赤近墨者黑)。
程序的思想
1.设置两个容器用来存放已知的数据,和未知的数据
2.将双方数据搞成向量
3.自定义一个欧式距离计算表
4.利用udf的表算双方向量的距离
5.两套数据,同行数之间的像向量距离

求距离公式:
曼哈顿距离
欧几里得距离

需求:
样本数据,
label,f1,f2,f3,f4,f5
0,10,20,30,40,30
0,12,22,29,42,35
0,11,21,31,40,34
0,13,22,30,42,32
0,12,22,32,41,33
0,10,21,33,45,35
1,30,11,21,40,34
1,33,10,20,43,30
1,30,12,23,40,33
1,32,10,20,42,33
1,30,13,20,42,30
1,30,09,22,41,32

– 用spark编程,对下列类别未知的向量,标注预测的类别
id,b1,b2,b3,b4,b5
1,11,21,31,44,32
2,14,26,32,39,30
3,32,14,21,42,32
4,34,12,22,42,34

代码实现:
object suanfa {
def main(args: Array[String]): Unit = {
//创建一个spark环境

val spark: SparkSession = SparkSession.builder()
  .appName(this.getClass.getSimpleName)
  .master("local[*]")
  .getOrCreate()

利用new StructType()自定义导入的数据类型

    //自定义样本的数据类型
val schemal: StructType = new StructType()
  .add("label", DataTypes.DoubleType)
  .add("f1", DataTypes.DoubleType)
  .add("f2", DataTypes.DoubleType)
  .add("f3", DataTypes.DoubleType)
  .add("f4", DataTypes.DoubleType)
  .add("f5", DataTypes.DoubleType)

  //自定义未知数据的数据类型
val schema2: StructType = new StructType()
  .add("id", DataTypes.DoubleType)
  .add("b1", DataTypes.DoubleType)
  .add("b2", DataTypes.DoubleType)
  .add("b3", DataTypes.DoubleType)
  .add("b4", DataTypes.DoubleType)
  .add("b5", DataTypes.DoubleType)

两个数据做crossjoin笛卡尔积的join,一对多的放在一起形成zhb(综合表)

//导入样本数据导入
val yb: DataFrame = spark.read.option("header","true").schema(schemal).csv("data/demo/yangben")
//导入为知数据
val wz: DataFrame = spark.read.schema(schema2).option("header","true").csv("data/demo/weizhi")
    //将样本数据和为主数据连接crossjion(交叉join  笛卡尔积join)
    val zhb: DataFrame = wz.crossJoin(yb)

利用 vectors.sqdist自己先用 udf() 弄一个两个空数据的欧式距离计算表
运行时会报Failed to execute user defined function(数据执行异常,数据不匹配)的错
解决办法:将自己写的普通Array改成mutable.WrappedArray,在dense的时候在改回来

        //自定义一个计算欧式距离的函数  
   import org.apache.spark.sql.functions._
    val osjl: UserDefinedFunction = udf((arr1:mutable.WrappedArray[Double], arr2:mutable.WrappedArray[Double]) =>{
       val v1: linalg.Vector = Vectors.dense(arr1.toArray)
       val v2: linalg.Vector = Vectors.dense(arr2.toArray)
        Vectors.sqdist(v1,v2)//sq(平方)dist(距离)只不过得到的最后的结果的平方不影响计算结果
    })

利用综合表.select()的方法将两个数据传入上方设定的欧式距离计算表

//计算样本和未知之间的距离
    import spark.implicits._
val fra: DataFrame = zhb.select(
  $"label", //如果想用符号就必须用隐式转换(import spark.implicits._),
  //col("label")如果想用这个就必须用(import org.apache.spark.sql.functions._)
  $"id",
  //这个数据不是普通数组是WrappedArray会报错
  osjl(array("f1", "f2", "f3", "f4", "f5"), array("b1", "b2", "b3", "b4", "b5"))as "dist"
)

创建sparksql处理表格

//处理表格找出距离最小的5名
fra.createTempView("top")
    val top5 = spark.sql(
      """
        |
        |select
        |*
        |from
        |(
        |    select
        |    id,
        |    label,
        |    dist,
        |    row_number() over(partition by id order by dist)as rn
        |    from
        |    top
        |)t
        |where rn<6
        |order by id
        |
      """.stripMargin)

    //在距离最小的5名里找出次数最多的label
    //离他最近的5个人中,其中1多,这个人就是1,离他最近的5个人中0多,他就是0

top5.createTempView("top5")
spark.sql(
  """
    |
    |select
    |id,
    |label
    |from
    |top5
    |group by id,label
    |having count(1)> 2
    |
  """.stripMargin)

      .show(100,false)

    //关流
      spark.stop()
  }
}
//代码实现(未知的四个人都有了自己的label):
+---+-----+
|id |label|
+---+-----+
|1.0|0.0  |
|2.0|0.0  |
|3.0|1.0  |
|4.0|1.0  |
+---+-----+

你可能感兴趣的:(大数据,算法)