Spark2.x 入门:高斯混合模型(GMM)聚类算法

模型的训练与分析

Spark的ML库提供的高斯混合模型都在org.apache.spark.ml.clustering包下,和其他的聚类方法类似,其具体实现分为两个类:用于抽象GMM的超参数并进行训练的GaussianMixture类(Estimator)和训练后的模型GaussianMixtureModel类(Transformer),在使用前,引入需要的包:

scala 复制代码
import org.apache.spark.ml.clustering.{GaussianMixture,GaussianMixtureModel}
import org.apache.spark.ml.linalg.{Vector,Vectors}

开启RDD的隐式转换:

scala 复制代码
import spark.implicits._

下文中,我们默认名为spark的SparkSession已经创建。与其他教程相同,本文亦使用模式识别领域广泛使用的UCI数据集中的鸢尾花数据Iris进行实验,它可以在iris获取,Iris数据的样本容量为150,有四个实数值的特征,分别代表花朵四个部位的尺寸,以及该样本对应鸢尾花的亚种类型(共有3种亚种类型),如下所示:

复制代码
5.1,3.5,1.4,0.2,setosa
...
5.4,3.0,4.5,1.5,versicolor
...
7.1,3.0,5.9,2.1,virginica
...

为了便于生成相应的DataFrame,这里定义一个名为model_instance的case class作为DataFrame每一行(一个数据样本)的数据类型。

注:因为是非监督学习,所以不需要数据中的label,只需要使用特征向量数据就可以。

scala 复制代码
scala> case class model_instance(features: org.apache.spark.ml.linalg.Vector)
defined class model_instance

在定义数据类型完成后,即可将数据读入RDD[model_instance]的结构中,并通过RDD的隐式转换.toDF()方法完成RDD到DataFrame的转换:

scala 复制代码
val rawData = sc.textFile("file:///root/data/iris.txt")
rawData: org.apache.spark.rdd.RDD[String] = file:///root/data/iris.txt MapPartitionsRDD[220] at textFile at <console>:56

scala> val df = rawData.map(line =>{ model_instance( Vectors.dense(line.split(",").filter(p => p.matches("\\d*(\\.?)\\d*")).map(_.toDouble)) )}).toDF()
df: org.apache.spark.sql.DataFrame = [features: vector]

与MLlib版的教程类似,我们使用了filter算子,过滤掉类标签,正则表达式\\d*(\\.?)\\d*可以用于匹配实数类型的数字,\\d*使用了*限定符,表示匹配0次或多次的数字字符,\\.?使用了?限定符,表示匹配0次或1次的小数点。

可以通过创建一个GaussianMixture类,设置相应的超参数,并调用fit(..)方法来训练一个GMM模型GaussianMixtureModel,在该方法调用前需要设置一系列超参数,如下表所示:

参数 含义
K 聚类数目,默认为2
maxIter 最大迭代次数,默认为100
seed 随机数种子,默认为随机Long值
Tol 对数似然函数收敛阈值,默认为0.01

其中,每一个超参数均可通过名为setXXX(...)(如maxIterations即为setMaxIterations())的方法进行设置。

这里,我们建立一个简单的GaussianMixture对象,设定其聚类数目为3,其他参数取默认值。

scala 复制代码
scala> val gm = new GaussianMixture().setK(3).setPredictionCol("Prediction").setProbabilityCol("Probability")
gm: org.apache.spark.ml.clustering.GaussianMixture = GaussianMixture_d8479eee2bdf

scala> val gmm = gm.fit(df)
17/09/07 17:10:07 WARN LAPACK: Failed to load implementation from: com.github.fommil.netlib.NativeSystemLAPACK
17/09/07 17:10:07 WARN LAPACK: Failed to load implementation from: com.github.fommil.netlib.NativeRefLAPACK
gmm: org.apache.spark.ml.clustering.GaussianMixtureModel = GaussianMixture_d8479eee2bdf

和KMeans等硬聚类方法不同的是,除了可以得到对样本的聚簇归属预测外,还可以得到样本属于各个聚簇的概率(这里我们存在"Probability"列中)。

调用transform()方法处理数据集之后,打印数据集,可以看到每一个样本的预测簇以及其概率分布向量(这里为了明晰起见,省略了大部分行,只选择三行):

scala 复制代码
scala> val result = gmm.transform(df)
result: org.apache.spark.sql.DataFrame = [features: vector, Prediction: int ... 1 more field]

scala> result.show(150, false)
+-----------------+----------+------------------------------------------------------------------+
|features         |Prediction|Probability                                                       |
+-----------------+----------+------------------------------------------------------------------+
|[5.1,3.5,1.4,0.2]|0         |[0.9999999999999951,4.682229962936943E-17,4.868372929925642E-15]  |
|[5.8,2.7,5.1,1.9]|1         |[5.443776218961163E-16,0.5809846403552363,0.41901535964476316]    |
|[5.1,2.5,3.0,1.1]|2         |[1.574811409348219E-14,1.646719617640849E-14,0.9999999999999678]  |

得到模型后,即可查看模型的相关参数,与KMeans方法不同,GMM不直接给出聚类中心,而是给出各个混合成分(多元高斯分布)的参数。在ML的实现中,GMM的每一个混合成分都使用一个MultivariateGaussian类(位于org.apache.spark.ml.stat.distribution包)来存储,我们可以使用GaussianMixtureModel类的weights成员获取到各个混合成分的权重,使用gaussians成员来获取到各个混合成分的参数(均值向量和协方差矩阵):

scala 复制代码
scala> for (i <- 0 until gmm.getK) {println("Component %d : weight is %f \n mu vector is %s \n sigma matrix is %s" format(i, gmm.weights(i), gmm.gaussians(i).mean, gmm.gaussians(i).cov))}
Component 0 : weight is 0.333333 
 mu vector is [5.006000336585284,3.41800074359835,1.4640001090120234,0.24399996278677907] 
 sigma matrix is 0.12176391071215485  0.098291689186003     0.01581595534223468   0.01033602571352466   
0.098291689186003    0.14227526345684152   0.011447885703674401  0.01120804907975396   
0.01581595534223468  0.011447885703674401  0.029504001732923526  0.005584009823879005  
0.01033602571352466  0.01120804907975396   0.005584009823879005  0.011264005407846419  
Component 1 : weight is 0.158358 
 mu vector is [6.683368733405749,2.869615454114306,5.6462886220107,2.0056734271362298] 
 sigma matrix is 0.4932801350542996    0.050374713498106384  0.3573203540815376    0.05001856939219663   
0.050374713498106384  0.04009423452906383   0.004169715059366357  0.020005237661706105  
0.3573203540815376    0.004169715059366357  0.33772537665484004   0.01700691760482919   
0.05001856939219663   0.020005237661706105  0.01700691760482919   0.06935869650451344   
Component 2 : weight is 0.508309 
 mu vector is [6.130726266791144,2.872742630634865,4.675369349848154,1.5732931362537985] 
 sigma matrix is 0.34423978263400257  0.1433295221383842   0.3498831855148469   0.1447023418962772   
0.1433295221383842   0.13127254135550323  0.18483272859443253  0.09799971374720756  
0.3498831855148469   0.18483272859443253  0.5558476131836453   0.26987975624410054  
0.1447023418962772   0.09799971374720756  0.26987975624410054  0.16825697031716608 
相关推荐
AiNightVision3 小时前
无人机夜视模块如何选择?——从参数指标到系统集成的完整选型指南
人工智能·算法·计算机视觉·车载系统·无人机·视频·智能硬件
牧羊人.3334 小时前
卷积神经网络之VGG
人工智能·深度学习·神经网络·算法·cnn
小郎君6584 小时前
Vue 多标签页的加载态设计:为什么我没有用 Suspense 实现 PageLoading
vue.js·算法
ManageEngineITSM5 小时前
工单分类怎么设计?类别、子类别与自动分派的实用方法
大数据·服务器·数据库·人工智能·分类·数据挖掘
JJJennie7775 小时前
MAI Gateway私有化部署全攻略:大模型网关如何接入?附架构图
算法·gateway·ai网关·魔芋ai
東隅已逝,桑榆非晚5 小时前
算法3.双指针法-快乐数
c++·笔记·学习·算法
专注仿真5 小时前
卷积神经网络(CNN)算法详解
人工智能·python·算法·代码·大模型训练
FII工业富联科技服务5 小时前
多智能体如何进入制造现场?从业务协同到数字孪生验证
大数据·人工智能·算法·机器人·制造·数字孪生
≮傷£≯√5 小时前
httpserver_QNetWorkClient
算法
kaiyou20265 小时前
商务数据分析与应用专业哪些证书企业比较认可?
数据挖掘·数据分析