大数据(8x)机器学习库SparkML

本文详细介绍了Spark MLlib的使用,包括环境配置、内置样本、回归、分类、流水线、频繁模式挖掘、协同过滤和聚类等核心功能。通过实例展示了如何使用Spark进行机器学习,涵盖了从数据加载、模型训练到预测的全过程,并探讨了SparkMLlib与SparkML的区别。此外,还提供了关键参数的解释,如协同过滤中的秩(rank)和正则化参数(regParam)。

0、环境配置

  1. CentOS7安装Scala和Spark
  2. Win10安装Scala和Spark
  3. pom.xml额外配置
<!-- https://mvnrepository.com/artifact/org.apache.spark/spark-mllib -->
<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-mllib_2.12</artifactId>
    <version>3.0.2</version>
</dependency>
  1. 创建Hello.scala并写入外壳代码(复制用)
import org.apache.spark.sql.SparkSession

object Hello {
  def main(args: Array[String]): Unit = {
    //创建SparkSession对象
    val spark: SparkSession = SparkSession.builder()
      .master("local[*]").appName("a1").getOrCreate()
    //隐式转换支持
    import spark.implicits._
  }
}

1、SparkMLlib简介

  • 全称:Spark’s machine learning library
  • 译名:Spark的机器学习库
主要功能简述详细
ML Algorithms机器学习算法分类、回归、聚类、协同过滤
Featurization特征工程特征的 抽取、转换、选择、降维
Pipelines管道tools for constructing, evaluating, and tuning ML Pipelines
Persistence持久化保存和加载模型
Utilities实用工具线性代数、统计学

补充说明
本攻略Spark版本≥3,建议使用基于DataFrame的APIspark.ml,称作Spark ML

2、内置样本(Data sources)

  1. Spark内置样本在$SPARK_HOME/data
  2. 我们去到Linux服务器,把内置样本上传到HDFS,然后可以进入spark-shell来读数据
cd $SPARK_HOME/data/mllib/
hadoop fs -put sample_linear_regression_data.txt /
spark-shell
spark.read.format("libsvm").load("/sample_linear_regression_data.txt").show(5,99)

样本长相

3、回归(Regression)

数据续2

import org.apache.spark.ml.regression.LinearRegression
// 样本加载
val xy = spark.read.format("libsvm").load("/sample_linear_regression_data.txt")
// 建模
val lr = new LinearRegression().setMaxIter(9).setRegParam(.3).setElasticNetParam(.8)
// 训练
val lrModel = lr.fit(xy)
// 打印系数和截距
print(s"Coefficients: ${lrModel.coefficients} Intercept: ${lrModel.intercept}")

4、分类(Classification)

下面以文本分类为例

// 创建数据
val label2comment = Map(0 -> "好", 1 -> "中", 2 -> "差")
val sentenceDf = Seq(
  (0, "优秀 好味 精彩 软滑 白嫩 干货 超神 醍醐灌顶 不要不要的"),
  (1, "普通 一般般 无感 中规中矩 乏味 中立 还行 可以可以"),
  (2, "难吃 金玉其外 发货慢 无语 弱鸡 呵呵 水货 渣渣 超鬼"),
).toDF("label", "sentence")
// 特征工程
import org.apache.spark.ml.feature.{HashingTF, IDF, Tokenizer}
// 分词
val tokenizer = new Tokenizer().setInputCol("sentence").setOutputCol("words")
val wordsDf = tokenizer.transform(sentenceDf)
// 编码
val hashingTF = new HashingTF()
  .setInputCol("words").setOutputCol("rawFeatures").setNumFeatures(10)
val hashingDf = hashingTF.transform(wordsDf)
// TF-IDF训练+转换
val idf = new IDF().setInputCol("rawFeatures").setOutputCol("features")
val idfModel = idf.fit(hashingDf)
val tfidfDf = idfModel.transform(hashingDf)
tfidfDf.show(numRows = 9, truncate = false)
// 逻辑回归
import org.apache.spark.ml.classification.LogisticRegression
val lr = new LogisticRegression()
  .setFeaturesCol("features")
  .setLabelCol("label")
  .setPredictionCol("prediction")
  .setProbabilityCol("Probability")
// 逻辑回归拟合
val fittedLr = lr.fit(tfidfDf)
// 预测
val prediction = fittedLr.transform(
  idfModel.transform(
    hashingTF.transform(
      tokenizer.transform(
        Seq("无感 还行", "呵呵 渣渣", "干货 好味").toDF("sentence")
      )
    )
  )
)
prediction.show()

打印结果

5、流水线(Pipelines)

  • pipeline译作管道,其复数形式pipelines可译为流水线
  • 个人理解:把多道工序串成一条流水线
  • 代码示例,留意Pipeline(第26行)
import org.apache.spark.ml.{Pipeline, PipelineModel}
import org.apache.spark.ml.classification.LogisticRegression
import org.apache.spark.ml.feature.{HashingTF, Tokenizer}
import org.apache.spark.ml.linalg.Vector
import org.apache.spark.sql.Row

// 训练集
val training = spark.createDataFrame(Seq(
  (0L, "a b c d e spark", 1.0),
  (1L, "b d", 0.0),
  (2L, "spark f g h", 1.0),
  (3L, "hadoop mapreduce", 0.0)
)).toDF("id", "text", "label")

// 安装一个由【tokenizer hashingTF lr】串成的流水线
val tokenizer = new Tokenizer()
  .setInputCol("text")
  .setOutputCol("words")
val hashingTF = new HashingTF()
  .setNumFeatures(1000)
  .setInputCol(tokenizer.getOutputCol)
  .setOutputCol("features")
val lr = new LogisticRegression()
  .setMaxIter(10)
  .setRegParam(0.001)
val pipeline = new Pipeline()
  .setStages(Array(tokenizer, hashingTF, lr))

// 输入训练数据来拟合pipeline
val model = pipeline.fit(training)

// 保存拟合好的pipeline到磁盘
model.write.overwrite().save("/tmp/spark-logistic-regression-model")

// 保存还没拟合的pipeline到磁盘
pipeline.write.overwrite().save("/tmp/unfit-lr-model")

// 加载拟合好的pipeline
val sameModel = PipelineModel.load("/tmp/spark-logistic-regression-model")

// 测试集
val test = spark.createDataFrame(Seq(
  (4L, "spark i j k"),
  (5L, "l m n"),
  (6L, "spark hadoop spark"),
  (7L, "apache hadoop")
)).toDF("id", "text")

// 预测
model.transform(test)
  .select("id", "text", "probability", "prediction")
  .collect()
  .foreach { case Row(id: Long, text: String, prob: Vector, prediction: Double) =>
    println(s"($id, $text) --> prob=$prob, prediction=$prediction")
  }

6、Frequent Pattern Mining

例如:
a b c
b c d
↓↓↓
ab共现1次
bc共现2次
ad共现0次

// 创建数据
val df = Seq(
"1 2 5",
"1 2 3 5",
"1 2"
).map(_.split(" ")).toDF("items")
// Frequent Pattern Growth 建模训练
import org.apache.spark.ml.fpm.FPGrowth
val fpGrowth = new FPGrowth().setItemsCol("items").setMinSupport(0.5).setMinConfidence(0.6)
val model = fpGrowth.fit(df)

// 共现频数
model.freqItemsets.show()
/*
+---------+----+
|    items|freq|
+---------+----+
|      [1]|   3|
|      [2]|   3|
|   [2, 1]|   3|
|      [5]|   2|
|   [5, 2]|   2|
|[5, 2, 1]|   2|
|   [5, 1]|   2|
+---------+----+
*/

// 关联规则
model.associationRules.show()
/*
+----------+----------+------------------+----+
|antecedent|consequent|        confidence|lift|
+----------+----------+------------------+----+
|    [2, 1]|       [5]|0.6666666666666666| 1.0|
|    [5, 1]|       [2]|               1.0| 1.0|
|       [2]|       [1]|               1.0| 1.0|
|       [2]|       [5]|0.6666666666666666| 1.0|
|       [5]|       [2]|               1.0| 1.0|
|       [5]|       [1]|               1.0| 1.0|
|       [1]|       [2]|               1.0| 1.0|
|       [1]|       [5]|0.6666666666666666| 1.0|
|    [5, 2]|       [1]|               1.0| 1.0|
+----------+----------+------------------+----+
*/


// 预测
model.transform(Seq(
  "1 2",
  "1 5",
  "1 2 3 5",
  "1 2 3",
  "5 2"
).map(_.split(" ")).toDF("items")).show()
/*
+------------+----------+
|       items|prediction|
+------------+----------+
|      [1, 2]|       [5]|
|      [1, 5]|       [2]|
|[1, 2, 3, 5]|        []|
|   [1, 2, 3]|       [5]|
|      [5, 2]|       [1]|
+------------+----------+
*/
方法说明默认值
setItemsCol设置 输入列的名称items
setMinSupport过滤低频;最低门槛=minSupport × \times ×size-of-the-dataset0.3
setMinConfidence设定置信度门槛,低于该值将被过滤;定义域[0,1]0.8

7、协同过滤(Collaborative Filtering)

  • 思想:想看电影,但不造看啥,此时可以问兴趣相近的朋友,有什么好电影推荐。

以 Alternating Least Squares 交替最小二乘 矩阵分解 为例

一个稀疏矩阵,可以使用Alternating Least Squares分解成两个小矩阵相乘
然后两个小矩阵相乘,就可以估算出稀疏矩阵缺失的值
所谓交替,就是交替训练两个矩阵(固定I训练U,固定U训练I

// 创建SparkSession对象
import org.apache.spark.sql.SparkSession
val spark: SparkSession = SparkSession.builder()
  .master("local[*]").appName("a0").getOrCreate()
// 隐式转换支持
import spark.implicits._
// 创建数据
val df = Seq(
  (1, 1, 5), (1, 2, 3), (1, 3, 1), (1, 4, 5), (1, 6, 2),
  (2, 1, 5), (2, 2, 3), (2, 5, 4), (2, 6, 2), (2, 7, 1),
  (3, 2, 3), (3, 3, 1), (3, 4, 4), (3, 5, 5), (3, 7, 1),
  (4, 2, 3), (4, 4, 5), (4, 7, 1),
  (5, 1, 5), (5, 4, 4), (5, 5, 4), (5, 6, 2),
  (6, 1, 5), (6, 3, 1), (6, 6, 4), (6, 7, 4),
  (7, 1, 5), (7, 4, 1), (7, 5, 1), (7, 7, 5),
  (8, 1, 5), (8, 2, 3), (8, 5, 2), (8, 6, 5),
).toDF("user", "item", "rating")
// Alternating Least Squares (ALS) matrix factorization
import org.apache.spark.ml.recommendation.ALS
val als = new ALS().setRank(5) //rank:矩阵分解的秩
val model = als.fit(df)
// 物品特征
model.itemFactors.sort("id").show(false)
// 用户特征
model.userFactors.sort("id").show(false)
// 为每个用户推荐物品
model.recommendForAllUsers(7).sort("user").show(false)
// 为每个物品推荐用户
model.recommendForAllItems(8).sort("item").show(false)
常用参数原文译文默认值
rankParam for rank of the matrix factorization (positive)矩阵分解的秩,该参数是正数10
implicitPrefsParam to decide whether to use implicit preference是否使用隐含偏好false
ratingColParam for the column name for ratings评价列名称rating
userColParam for the column name for user ids用户列名称,该输入列的数据要求数字类型user
itemColParam for the column name for item ids.物品列名称,该输入列的数据要求数字类型item
regParamParam for regularization parameter正则化参数,要求≥00.1
maxIterParam for maximum number of iterations训练的最大迭代次数,要求≥010

8、聚类(Clustering)

// 创建SparkSession对象
import org.apache.spark.sql.SparkSession
val spark: SparkSession = SparkSession.builder()
  .master("local[*]").appName("a0").getOrCreate()
// 创建数据
val dataset = spark.read.format("libsvm").load(
  "D:\\coding\\scala\\lib\\spark-3.0.2\\data\\mllib\\sample_kmeans_data.txt")
dataset.show(false)
/*
+-----+-------------------------+
|label|features                 |
+-----+-------------------------+
|0.0  |(3,[],[])                |
|1.0  |(3,[0,1,2],[0.1,0.1,0.1])|
|2.0  |(3,[0,1,2],[0.2,0.2,0.2])|
|3.0  |(3,[0,1,2],[9.0,9.0,9.0])|
|4.0  |(3,[0,1,2],[9.1,9.1,9.1])|
|5.0  |(3,[0,1,2],[9.2,9.2,9.2])|
+-----+-------------------------+
*/
// 建模、训练
import org.apache.spark.ml.clustering.KMeans
val kmeans = new KMeans().setK(2)
val model = kmeans.fit(dataset)
// 预测
val predictions = model.transform(dataset)
predictions.show(false)
/*
+-----+-------------------------+----------+
|label|features                 |prediction|
+-----+-------------------------+----------+
|0.0  |(3,[],[])                |0         |
|1.0  |(3,[0,1,2],[0.1,0.1,0.1])|0         |
|2.0  |(3,[0,1,2],[0.2,0.2,0.2])|0         |
|3.0  |(3,[0,1,2],[9.0,9.0,9.0])|1         |
|4.0  |(3,[0,1,2],[9.1,9.1,9.1])|1         |
|5.0  |(3,[0,1,2],[9.2,9.2,9.2])|1         |
+-----+-------------------------+----------+
*/
// 聚类中心
println("Cluster Centers: ")
model.clusterCenters.foreach(println)
/*
[0.1,0.1,0.1]
[9.1,9.1,9.1]
*/
// 聚类评价:轮廓系数
import org.apache.spark.ml.evaluation.ClusteringEvaluator
val evaluator = new ClusteringEvaluator()
val silhouette = evaluator.evaluate(predictions)
println(s"Silhouette with squared euclidean distance = $silhouette")
/* Silhouette with squared euclidean distance = 0.9997530305375207 */

Appendix

en🔉cn
antecedentˌæntɪˈsiːdntn. 前情;祖先;(语法)先行词;adj. 先前的;(语法)先行的
consequentˈkɑːnsɪkwentadj. 随之发生的,作为结果的;合乎逻辑的;n. (逻辑)后件,推断;分母
confidenceˈkɑːnfɪdənsn. 信心;置信度
liftlɪft(价格)上涨;(音量)提高
collaborativekəˈlæbəreɪtɪvadj. 合作的,协作的
ALSAlternating Least Squares交替最小二乘法
通过最小化误差的平方和寻找数据的最佳函数匹配
alternateˈɔːltərnətv. (使)交替,(使)轮流
factorizationˌfæktərəˈzeɪʃənn. [数] 因子分解;[数] 因式分解
preferenceˈprefrənsn. 偏爱;优先权
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小基基o_O

您的鼓励是我创作的巨大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值