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)