【大数据分析】ML:分类和聚类

目录Spark ML库Estimators、transformers和evaluatorsML参数Spark有两个机器学习库:MLlib和ML。它们都在积极发展,但是目前的发展重点更多的是ML库。Spark ML库ML相对于MLlib是比较新的机器学习库。创建新的机器学习库的原因是因为MLlib没有足够的伸缩和扩展性,也不足以在实际的机器学习项目中使用。ML的目标是概括机器学习操作和简化机器学习过程。受scikit-learn影响,它引入了可以组合形成管道的新的抽象概念——估计器、转换器和评估器。M
摘要由CSDN通过智能技术生成


Spark有两个机器学习库:MLlib和ML。它们都在积极发展,但是目前的发展重点更多的是ML库。

Spark ML库

ML相对于MLlib是比较新的机器学习库。创建新的机器学习库的原因是因为MLlib没有足够的伸缩和扩展性,也不足以在实际的机器学习项目中使用。ML的目标是概括机器学习操作和简化机器学习过程。受scikit-learn影响,它引入了可以组合形成管道的新的抽象概念——估计器、转换器和评估器。
ML经常会使用DataFrame对象来呈现数据集,这就是不能简单地升级旧的MLlib算法的原因。

Estimators、transformers和evaluators

在spark中,可以通过使用transformers来实现一个机器学习组件,这个组件可以将一个数据集transform为另一个数据集。Spark ML中的所谓“模型”实际上是一个transformer,只是它需要添加predictions来实现。
Estimators通过拟合数据集创建transformers。
评估器根据单一度量来评估模型的性能。例如回归评估器可以使用RMSE和R2作为度量。
在这里插入图片描述

ML参数

在Spark ML中为估计器和转换器指定参数是非常常见的,可以使用Param、ParamPair和ParamMap类来指定它们的参数。
Param包含的参数类型包括:参数名称、类的类型、参数描述、用于验证参数的函数以及可选的默认值。ParamPair包含参数类型(Param对象)以及它的值。ParamMap包含一组ParamPair对象。
将ParamPair或ParamMap对象传递给Estimators的fit或transformers的transform方法,或者可以使用特定的setter方法设置参数。

ML管道

在机器学习中,相同的步骤通常使用稍微不同的参数以相同的顺序重复,从而找到产生最佳结果的参数。例如在《Spark大数据分析-MLlib——线性回归实例》中,每次都会使用不同的参数组合,或者是添加高阶多项式,然后再次进行训练。Spark ML可以创建具有两个阶段的Pipeline对象,第一阶段通过添加高阶多项式来转换数据集,ML中的PolynomialExpansion transformer使用多项式的次数来作为参数。第二阶段进行线性回归分析,将整个管道视为单个估计器,产生一个PipelineModel模型。
PipelineModel模型也有两个阶段:多项式展开和拟合线性回归模型。每次拟合管道时,都会给它一组不同的参数(包括两个阶段的参数ParamMap),然后选择一个可以获得最佳结果的参数集合。

逻辑回归

在《Spark大数据分析-MLlib——线性回归实例》中,有一个例子是预测波士顿郊区的房价。这是一个回归分析的例子,因为这个过程是基于一组输入变量查找一个值。另一方面,分类的目标是将输入示例分类为两个或更多个类。如果想预测房价是否大于某个固定值,可以轻松将房价问题转化为分类问题。

二元逻辑回归模型

在逻辑回归中,不是使用线性方程建模概率p(x),而是用逻辑函数。
在这里插入图片描述
对于两个不同的权重集合w绘制函数的结果如下。
在这里插入图片描述
如果进一步操作逻辑函数,可以得到以下等式:
在这里插入图片描述
这个方程左边的表达式称为赔率。取等式的自然对数后,可以得出以下表达式。
在这里插入图片描述
方程左侧的表达式变成了逻辑函数的对数,它线性地取决于x。
p(x)实际上是输入例子x属于1类的概率,所以1-p(x)等于相反情况的概率。使用条件概率表示法来写如下:
在这里插入图片描述
第一个方程的右侧可以解读为:给定了示例x和权重w,类别为1的概率。
可以通过最大化似然函数来确定逻辑回归中的权重参数的最优值。似然函数给出了“正确预测所有数据”的联合概率公式。并且希望这个概率值能尽可能的接近1。这得到以下等式:
在这里插入图片描述
对表达式作自然对数可以得到对数似然函数,它经常被用作逻辑回归的cost function。
在这里插入图片描述
但依然可以进一步计算得到如下所示:
在这里插入图片描述
有了cost function后就可以使用gradient descent方法(这里可以翻译成梯度上升,原资料里翻译成了梯度下降)来找到这个cost function的最大值。还可以使用L1和L2正则化,或者是LBFGS优化等方法来应用到逻辑回归当中。
在这里插入图片描述

准备数据以使用Spark中的逻辑回归

用于逻辑回归的示例数据是从1994年美国人口普查数据中提取的成人数据集。它包含13个属性,性别、年龄、教育程度、婚姻状况、民族、原籍,以及Label是收入。

import spark.implicits._

val census_raw = sc.textFile("first-edition/ch08/adult.raw", 4).map(x => x.split(",").map(_.trim)).
    map(row => row.map(x => try {
    x.toDouble } catch {
    case _ : Throwable => x }))

import org.apache.spark.sql.types.{
   StructType,StructField,StringType,DoubleType}
val adultschema = StructType(Array(
    StructField("age",DoubleType,true),
    StructField("workclass",StringType,true),
    StructField("fnlwgt",DoubleType,true),
    StructField("education",StringType,true),
    StructField("marital_status",StringType,true),
    StructField("occupation",StringType,true),
    StructField("relationship",StringType,true),
    StructField("race",StringType,true),
    StructField("sex",StringType,true),
    StructField("capital_gain",DoubleType,true),
    StructField("capital_loss",DoubleType,true),
    StructField("hours_per_week",DoubleType,true),
    StructField("native_country",StringType,true),
    StructField("income",StringType,true)
))
import org.apache.spark.sql.Row
val dfraw = spark.createDataFrame(census_raw.map(Row.fromSeq(_)), adultschema)
dfraw.show()

处理缺失值

dfraw.show列出了前20行的数据,这些数据具有缺失值(标记为?)。有几个处理缺失值的方法。
(1)如果列中缺少大量数据,则可以从数据集中删除整个列,因为该列可能会有不好的影响(如计算速度等等)。
(2)如果单个数据(行)中包含太多缺失值,则可以将其从数据集中删除。
(3)可以将缺失值设置为列中最常见的值。
(4)可以训练单独的分类或回归模型,并使用它来预测缺失值。
一般会选择第(3)条来处理缺失数据。
缺失值都出现在workclass、occupation和native_country。下面来研究workclass列中各个值的计数。

dfraw.groupBy(dfraw("workclass")).count().rdd.foreach(println)
[?,2799]
[Self-emp-not-inc,3862]
[Never-worked,10]
[Self-emp-inc,1695]
[Federal-gov,1432]
[State-gov,1981]
[Local-gov,3136]
[Private,33906]
[Without-pay,21]

可以看到,Private在workclass列是最多的。此外通过类似的代码可以发现,在occupation列,Prof-specialty值最常见。在native-country列最常用的值是United-States。现在可以使用DataFrame的na字段来估算缺失值。

//Missing data imputation
val dfrawrp = dfraw.na.replace(Array("workclass"), Map("?" -> "Private"))
val dfrawrpl = dfrawrp.na.replace(Array("occupation"), Map("?" -> "Prof-specialty"))
val dfrawnona = dfrawrpl.na.replace(Array("native_country"), Map("?" -> "United-States"))

处理类别值

dfrawnona中的大多数值都是字符串,分类算法并不能处理它们,需要将数据转换为数值。但是这个过程并不能单纯地使用0,1,2,3…来区别同个特征下的不同字符值。比如将marital_status字段的值(separated、divorced、never married、widowed、married)编码为0~4的整数值,这并不是一种具有现实意义的解释。因为这看上去never married会比separaed“大”,但其实不是,所以目前最常用的是一种称为“one hot encoding”的编码方式。如下图所示:
在这里插入图片描述
ML库中的3个类可以处理分类值,StringIndexer,OneHotEncoder,VectorAssembler。

使用StringIndexer

StringIndexer可以将String分类值转换为这些值的整数索引。

//converting strings to numeric values
import org.apache.spark.sql.DataFrame
def indexStringColumns(df:DataFrame, cols:Array[String]):DataFrame = {
   
    import org.apache.spark.ml.feature.StringIndexer
    import org.apache.spark.ml.feature.StringIndexerModel
    //variable newdf will be updated several times
    var newdf = df
    for(c <- cols) {
   
        //对cols中的每个列都fit一个StringIndexerModel,相当于生产了分类值。
        val si = new StringIndexer().setInputCol(c).setOutputCol(c+"-num")
        val sm:StringIndexerModel = si.fit(newdf)
        //将转换的值放在带有扩展名“-num”的新列上,并删除旧列
        newdf = sm.transform(newdf).drop(c
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值