Spark MLlib

Spark MLlib

Spark 机器学习

机器学习是人工智能的一个分支

注意:我们学习一个框架的时候一定要学会看官网

导入依赖

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-mllib_2.11</artifactId>
            <version>2.4.5</version>
        </dependency>

稠密向量和稀疏向量

稠密向量和稀疏向量的区别:

假如向量中的0很多的话,使用稀疏向量表示,所占空间更小

稠密向量和稀疏向量 -- 后面用来存特征X的

package com.shujia.mllib

import org.apache.spark.ml.feature.LabeledPoint
import org.apache.spark.ml.linalg
import org.apache.spark.ml.linalg.Vectors

object Demo1DataType {
  def main(args: Array[String]): Unit = {

    /**
      * 稠密向量 -- 有方向有大小
      * 向量中的元素类型必须是Double
      * 
      * 导入 import org.apache.spark.ml.linalg 包下的Vectors
      * spark.ml.linalg -- spark-sql 的
      * spark.ml.linalg -- spark RDD 的
      */

    val denseVector: linalg.Vector = Vectors.dense(Array(1.0, 2.0, 0.0, 0.0, 4.0, 0.0, 5.4))

    println(denseVector)

    /**
      * 稀疏向量 -- 只保存不为0的位置(数据)
      * 7 -- 向量的长度
      * Array(0, 1, 4, 6) -- 非0的位置(有值的数据的下标)
      * Array(1.0, 2.0, 4.0, 5.4) -- 有值的数据本身
      */

    val sparseVector: linalg.Vector = Vectors.sparse(7, Array(0, 1, 4, 6), Array(1.0, 2.0, 4.0, 5.4))

    println(sparseVector)

    /**
      * 稠密向量和稀疏向量可以相互换行
      * toSparse -- 稠密→稀疏
      */

    println(sparseVector.toDense)

    /**
      * 标记点 -- 由特征向量X和目标值Y组成
      *
      * 我们需要将原始数据转换成一个LabeledPoint数据带入到算法中
      *
      * LabeledPoint(1.0, Vectors.dense(1.0, 0.0, 3.0))
      * 1.0 -- 目标值Y
      * Vectors.dense(1.0, 0.0, 3.0) -- 特征向量X的稠密向量
      * 
      * LabeledPoint(0.0, Vectors.sparse(3, Array(0, 2), Array(1.0, 3.0))) -- 同理
      */

    // Create a labeled point with a positive label and a dense feature vector.
    val pos = LabeledPoint(1.0, Vectors.dense(1.0, 0.0, 3.0))

    // Create a labeled point with a negative label and a sparse feature vector.
    val neg = LabeledPoint(0.0, Vectors.sparse(3, Array(0, 2), Array(1.0, 3.0)))

  }
}

Spark MLlib 线性回归 程序示例

回归算法

数据:

目标值Y,特征X1|特征X2

4.0,1.0|1.0
5.0,1.5|1.0
6.0,2.0|1.0
7.0,2.5|1.0
4.0,1.0|1.0
5.0,1.5|1.0
6.0,2.0|1.0
7.0,2.5|1.0
4.0,1.0|1.0
5.0,1.5|1.0
6.0,2.0|1.0
7.0,2.5|1.0
4.0,1.0|1.0
5.0,1.5|1.0
6.0,2.0|1.0
7.0,2.5|1.0
4.0,1.0|1.0
5.0,1.5|1.0
6.0,2.0|1.0
7.0,2.5|1.0

package com.shujia.mllib

import org.apache.spark.ml.linalg
import org.apache.spark.ml.linalg.Vectors
import org.apache.spark.ml.regression.{LinearRegression, LinearRegressionModel}
import org.apache.spark.sql.{DataFrame, Dataset, Row, SparkSession}

object Demo2LineReg {
  def main(args: Array[String]): Unit = {
    val spark: SparkSession = SparkSession
      .builder()
      .master("local")
      .appName("line")
      .getOrCreate()

    import spark.implicits._

    /**
      * 1、读取原始数据
      * 
      */

    val dataDF: DataFrame = spark
      .read
      .format("csv")
      .option("sep", ",")
      .schema("label DOUBLE,features STRING")
      .load("data/line.txt")

    /**
      * 特征工程
      *
      */

    //将原始数据转换成算法可以识别的数据
    val trainData: DataFrame = dataDF.map {
      // Row -- org.apache.spark.sql.Row
      case Row(label: Double, features: String) =>
        //将多个x转换特征向量  | -- 需要转义
        val xs: Array[Double] = features.split("\\|").map(_.toDouble)
        //转换成稠密向量
        val featuresVector: linalg.Vector = Vectors.dense(xs)
        
        (label, featuresVector)
        
    }.toDF("label", "features")

    /**
      * 选择算法训练模型
      * 
      */

    //线性回归算法
    val linearRegression = new LinearRegression()

    //将数据带入算法训练模型
    /**
      * 训练模型底层是rdd的计算,循环迭代让误差函数最小化
      *
      * 模型:由特征权重和截距组成
      */
    val model: LinearRegressionModel = linearRegression.fit(trainData)

    //模型的截距
    val intercept: Double = model.intercept

    println(s"intercept:$intercept")

    //特征的权重
    println(model.coefficients)

    /**
      * 新的特征x
      *
      */
    val xs: linalg.Vector = Vectors.dense(Array(0.85, 100))

    //将新的特征x带入模型计算得出y
    val y: Double = model.predict(xs)

    println(y)

  }
}

Spark MLlib 逻辑回归 程序示例

分类算法

svm 格式的数据 --- 是一种专门应用在机器学习上的格式

# 人体指标数据

目标值 特征向量……
0 1:5.3 2:3.5 3:2.5 4:106.4 5:67.5 6:69.1 7:83
1 1:5.9 2:3.9 3:3.0 4:135.0 5:82.8 6:79.5 7:64
1 1:6.5 2:4.2 3:3.3 4:140.4 5:85.0 6:79.8 7:69
1 1:5.4 2:4.0 3:3.0 4:135.6 5:88.6 6:70.1 7:72
0 1:4.5 2:3.6 3:2.4 4:101.1 5:77.1 6:65.1 7:87
0 1:4.7 2:3.8 3:2.8 4:98.7 5:69.3 6:65.5 7:77
0 1:4.6 2:3.4 3:2.2 4:104.7 5:69.4 6:52.3 7:90
0 1:4.5 2:3.7 3:3.0 4:113.9 5:73.5 6:71.2 7:79
0 1:5.7 2:4.3 3:2.7 4:120.5 5:79.1 6:72.4 7:75
1 1:5.8 2:5.0 3:3.7 4:148.7 5:90.1 6:76.2 7:65
0 1:4.0 2:2.9 3:2.3 4:94.3 5:65.0 6:50.7 7:98
1 1:5.7 2:4.3 3:3.5 4:130.1 5:85.9 6:84.0 7:65
1 1:4.9 2:3.9 3:3.0 4:131.0 5:79.8 6:63.7 7:77
0 1:4.2 2:3.0 3:2.4 4:97.3 5:57.7 6:58.5 7:89
0 1:4.9 2:3.9 3:2.8 4:109.7 5:68.0 6:59.3 7:77
0 1:5.0 2:3.8 3:2.6 4:116.7 5:69.9 6:61.3 7:71
0 1:5.2 2:3.8 3:2.8 4:116.8 5:69.2 6:63.0 7:88
1 1:5.8 2:4.2 3:2.8 4:134.5 5:89.7 6:79.8 7:77
0 1:4.5 2:3.4 3:2.5 4:98.7 5:63.7 6:59.3 7:97
1 1:6.0 2:4.7 3:3.2 4:140.1 5:94.8 6:84.2 7:66
0 1:3.9 2:3.5 3:2.4 4:103.4 5:67.4 6:53.2 7:95
1 1:6.4 2:4.7 3:3.2 4:136.3 5:99.8 6:85.0 7:58
0 1:4.7 2:3.6 3:2.5 4:118.2 5:73.8 6:65.8 7:76
1 1:5.8 2:3.6 3:2.8 4:117.0 5:75.2 6:70.6 7:75
1 1:6.3 2:4.4 3:2.9 4:145.2 5:86.1 6:75.3 7:68
1 1:5.6 2:4.6 3:2.9 4:136.7 5:97.8 6:77.7 7:63
1 1:5.8 2:4.4 3:3.1 4:136.1 5:76.5 6:75.2 7:70
…………
package com.shujia.mllib

import org.apache.spark.ml.classification.{LogisticRegression, LogisticRegressionModel}
import org.apache.spark.sql.{DataFrame, Dataset, Row, SparkSession}

object Demo3Person {
  def main(args: Array[String]): Unit = {
    val spark: SparkSession = SparkSession
      .builder()
      .master("local")
      .appName("line")
      .getOrCreate()

    import spark.implicits._
    import org.apache.spark.sql.functions._

    /**
      * 读取svm格式的数据
      * svm 格式是一种专门用于机器学习的数据格式,包含两部分,目标值,特征向量
      *
      */

    val data: DataFrame = spark
      .read
      .format("libsvm")
      .load("data/人体指标.txt")

    /**
      * 将数据拆分成训练数据和测试数据
      * randomSplit(Array(0.8, 0.2)) -- 指定切分比例,二八分
      */

    val split: Array[Dataset[Row]] = data.randomSplit(Array(0.8, 0.2))
    //训练数据
    val trainData: Dataset[Row] = split(0)
    //测试数据
    val testData: Dataset[Row] = split(1)

    //构建算法,训练模型
    //逻辑回归
    val logisticRegression = new LogisticRegression()

    //将训练集带入算法训练模型
    val model: LogisticRegressionModel = logisticRegression.fit(trainData)

    /**
      * 将测试集带入模型测试模型的准确率
      * 
      */

    val testDF: DataFrame = model.transform(testData)

    /**
      * 计算准确率
      *
      */
    val p: Double = testDF.where($"prediction" === $"label").count().toDouble / testDF.count()

    println(s"准确率:$p")

    /**
      * 保存模型
      * 将模型保存到hdfs
      */

    model.write.overwrite().save("data/model")

  }
}

使用已经训练好的模型

package com.shujia.mllib

import org.apache.spark.ml.classification.LogisticRegressionModel
import org.apache.spark.ml.linalg
import org.apache.spark.ml.linalg.Vectors
import org.apache.spark.sql.SparkSession

object Demo4UseModel {
  def main(args: Array[String]): Unit = {
    val spark: SparkSession = SparkSession
      .builder()
      .master("local")
      .appName("line")
      .getOrCreate()

    import spark.implicits._
    import org.apache.spark.sql.functions._

    /**
      * 加载已经保存好的模型
      *
      */

    val model: LogisticRegressionModel = LogisticRegressionModel.load("data/model")

    /**
      * 使用模型预测未知的数据
      * 0 1:4.7 2:3.1 3:2.3 4:101.4 5:66.6 6:55.1 7:80
      */
    val vector: linalg.Vector = Vectors.dense(Array(4.7, 3.1, 2.3, 101.4, 66.6, 55.1, 80.0))

    val y: Double = model.predict(vector)

    println(y)

  }
}

image(图片) 训练模型

图片由很多像素点组成,每一个像素点可以看做一个特征

特征工程

package com.shujia.mllib

import org.apache.spark.ml.linalg
import org.apache.spark.sql.{DataFrame, SaveMode, SparkSession}
import org.apache.spark.ml.linalg.{SparseVector, Vectors}

object Demo4ReadImage {
  def main(args: Array[String]): Unit = {

    /**
      * 特征工程
      *
      */

    val spark: SparkSession = SparkSession.builder()
      .master("local[8]")
      .appName("image")
      .config("spark.sql.shuffle.partitions", 2)
      .getOrCreate()

    /**
      * 读取图片数据
      *
      */
      
    val images: DataFrame = spark
      .read
      .format("image")
      .load("D:\\课件\\机器学习数据\\手写数字\\train")

    //查看DataFrame结构
    images.printSchema()
    
    import spark.implicits._

    val data: DataFrame = images
      .select($"image.origin", $"image.data")
      .as[(String, Array[Byte])]
      .map {
        case (name: String, data: Array[Byte]) => {
          val ints: Array[Int] = data.map(b => b.toInt)
          //将数据进行标准化,黑像素点使用0代替,白的像素点使用1代替
          //去除噪声点
          val result: Array[Double] = ints.map(i => {
            if (i < 0) {
              1.0
            } else {
              0.0
            }
          })

          //将特征转换成向量
          val fea: linalg.Vector = Vectors.dense(result)
          //获取图片名
          val filename: String = name.split("/").last

          (filename, fea)
        }
      }.toDF("name", "features")

    /**
      * 读取标签数据
      *
      */
    //读取图片对应的目标值
    val labelDF: DataFrame = spark
      .read.format("csv")
      .option("sep", " ")
      .schema("name STRING, label DOUBLE")
      .load("D:\\课件\\机器学习数据\\手写数字\\train.txt")
      
    //关联标签,取出标签和特征
    val trainDF: DataFrame = data
      .join(labelDF, "name")
      .select("label", "features")
      
    /**
      * 将处理好的数据保存为SVM
      *
      */
      
    trainDF
      .write
      .format("libsvm")
      .mode(SaveMode.Overwrite)
      .save("spark/data/images")

  }
}

训练模型

package com.shujia.mllib

import org.apache.spark.ml.classification.{LogisticRegression, LogisticRegressionModel}
import org.apache.spark.sql.functions.{count, sum, when}
import org.apache.spark.sql.{DataFrame, Dataset, Row, SparkSession}

object DEmo5TrainModel {

  def main(args: Array[String]): Unit = {

    val spark: SparkSession = SparkSession.builder()
      .master("local[8]")
      .appName("image")
      .config("spark.sql.shuffle.partitions", 2)
      .getOrCreate()

    /**
      * 1、读取数据
      */

    val data: DataFrame = spark
      .read
      .format("libsvm")
      .load("spark/data/images")

    /**
      * 2、切分训练集和测试集
      *
      */

    val split: Array[Dataset[Row]] = data.randomSplit(Array(0.7, 0.3))

    val train: Dataset[Row] = split(0)
    val test: Dataset[Row] = split(1)

    //构建算法 执行参数
    //逻辑回归
    val logisticRegression: LogisticRegression = new LogisticRegression()
      .setMaxIter(10) //最大迭代次数
      .setFitIntercept(true) //是否有截距

    /**
      * 训练模型
      *
      * 通过spark进行分布式迭代计算
      *
      */

    val model: LogisticRegressionModel = logisticRegression.fit(train)

    /**
      * 4、模型评估
      * 使用模型预测测试集的数据,判断和原始标记是否一致,计算准确率
      *
      */
    val frame: DataFrame = model.transform(test)

    /**
      *
      * 计算准确率
      */

    import spark.implicits._
    import org.apache.spark.sql.functions._

    val result: DataFrame = frame.select(sum(when($"label" === $"prediction", 1).otherwise(0)) / count($"label"))

    result.show()

    /**
      * 保存模型
      *
      */

    model.save("spark/data/image_model")

  }
}

使用上面训练好的模型判断图片中的数字

package com.shujia.mllib

import org.apache.spark.ml.classification.LogisticRegressionModel
import org.apache.spark.ml.linalg
import org.apache.spark.ml.linalg.Vectors
import org.apache.spark.sql.{DataFrame, Row, SparkSession}

object Demo7UseImageModel {
  def main(args: Array[String]): Unit = {
    val spark: SparkSession = SparkSession
      .builder()
      .master("local[6]")
      .appName("image")
      .getOrCreate()
    import spark.implicits._
    import org.apache.spark.sql.functions._

    val imageData: DataFrame = spark.read
      .format("image")
      .load("data/image_test")

    val nameAndFeatures: DataFrame = imageData
      .select($"image.origin" as "origin", $"image.data" as "data")
      .map {
        case Row(origin: String, data: Array[Byte]) =>

          //将数据进行标准化,黑像素点使用0代替,白的像素点使用1代替
          val point: Array[Double] = data.map(i => {
            if (i.toInt >= 0) {
              0.0
            } else {
              1.0
            }
          })

          //将特征转换成向量
          val features: linalg.Vector = Vectors.dense(point)

          //获取图片名
          val name: String = origin.split("/").last

          (name, features)
      }
      .toDF("name", "features")

    /**
      * 加载图片模型
      *
      */

    val model: LogisticRegressionModel = LogisticRegressionModel.load("data/image_model")

    //使用模型判断图片中的数字
    val testDF: DataFrame = model.transform(nameAndFeatures)

    testDF.show(1000)
  }
}

现在有一个比较好的开源的算法库 -- alink

alink是基于Flink的一个算法的库

[GitHub - alibaba/Alink: Alink is the Machine Learning algorithm platform based on Flink, developed by the PAI team of Alibaba computing platform.](https://github.com/alibaba/Alink)

posted @ 2022-03-15 11:38  赤兔胭脂小吕布  阅读(78)  评论(0编辑  收藏  举报