Spark Mlib

sparkMLib

概述

mlib的设计很简单,吧数据以rdd的形式表示。然后再分布式数据集和散户个屌用各种算法。

需要注意的是,MLlib 中只包含能够在集群上运行良好的并行算法,这一点很重要。有些经典的机器学习算法没有包含在其中,就是因为它们不能并行执行。相反地,一些较新的研究得出的算法因为适用于集群,也被包含在 MLlib 中,例如分布式随机森林算法(distributed random forests)、K-means||聚类、交替最小二乘算法(alternating least squares)等。这样的选择使得 MLlib 中的每一个算法都适用于大规模数据集。如果你要在许多小规模数据集上训练各机器学习模型,最好还是在各节点上使用单节点的机器学习算法库

(例如 Weka,http://www.cs.waikato.ac.nz/ml/weka/,或 SciKit-Learn,http://scikit-learn.org/stable/)实现,比如可以用 Spark 的 map() 操作在各节点上并行使用。类似地,我们在机器学习流水线中也常常用同一算法的不同参数对小规模数据集分别训练,来选出最好的一组参数。在 Spark 中,你可以通过把参数列表传给 parallelize() 来在不同的节点上分别运行不同的参数,而在每个节点上则使用单节点的机器学习库来实现。只有当你需要在一个大规模分布式数据集上训练模型时,MLlib 的优势才能突显出来。

例子

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.mllib.classification.LogisticRegressionWithSGD
import org.apache.spark.mllib.feature.HashingTF
import org.apache.spark.mllib.regression.LabeledPoint

object MLlib {

  def main(args: Array[String]) {
    val conf = new SparkConf().setAppName(s"Book example: Scala")
    val sc = new SparkContext(conf)

    // Load 2 types of emails from text files: spam and ham (non-spam).
    // Each line has text from one email.
    val spam = sc.textFile("files/spam.txt")
    val ham = sc.textFile("files/ham.txt")

    // Create a HashingTF instance to map email text to vectors of 100 features.
    val tf = new HashingTF(numFeatures = 100)
    // Each email is split into words, and each word is mapped to one feature.
    val spamFeatures = spam.map(email => tf.transform(email.split(" ")))
    val hamFeatures = ham.map(email => tf.transform(email.split(" ")))

    // Create LabeledPoint datasets for positive (spam) and negative (ham) examples.
    val positiveExamples = spamFeatures.map(features => LabeledPoint(1, features))
    val negativeExamples = hamFeatures.map(features => LabeledPoint(0, features))
    val trainingData = positiveExamples ++ negativeExamples
    trainingData.cache() // Cache data since Logistic Regression is an iterative algorithm.

    // Create a Logistic Regression learner which uses the LBFGS optimizer.
    val lrLearner = new LogisticRegressionWithSGD()
    // Run the actual learning algorithm on the training data.
    val model = lrLearner.run(trainingData)

    // Test on a positive example (spam) and a negative one (ham).
    // First apply the same HashingTF feature transformation used on the training data.
    val posTestExample = tf.transform("O M G GET cheap stuff by sending money to ...".split(" "))
    val negTestExample = tf.transform("Hi Dad, I started studying Spark the other ...".split(" "))
    // Now use the learned model to predict spam/ham for new emails.
    println(s"Prediction for positive test example: ${model.predict(posTestExample)}")
    println(s"Prediction for negative test example: ${model.predict(negTestExample)}")

    sc.stop()
  }
}

数据类型

MLlib 包含一些特有的数据类型,它们位于 org.apache.spark.mllib 包(Java/Scala)或

pyspark.mllib(Python)内。主要的几个如下所列。

• Vector
一个数学向量。MLlib 既支持稠密向量也支持稀疏向量,前者表示向量的每一位都存储下来,后者则只存储非零位以节约空间。后面会简单讨论不同种类的向量。向量可以通过 mllib.linalg.Vectors 类创建出来。

分稠密和稀疏两种

// 创建稠密向量<1.0, 2.0, 3.0>;Vectors.dense接收一串值或一个数组 val denseVec1 = Vectors.dense(1.0, 2.0, 3.0)
val denseVec2 = Vectors.dense(Array(1.0, 2.0, 3.0))
// 创建稀疏向量<1.0, 0.0, 2.0, 0.0>;该方法只接收
// 向量的维度(这里是4)以及非零位的位置和对应的值
val sparseVec1 = Vectors.sparse(4, Array(0, 2), Array(1.0, 2.0))

• LabeledPoint
在诸如分类和回归这样的监督式学习(supervised learning)算法中,LabeledPoint用来表示带标签的数据点。它包含一个特征向量与一个标签(由一个浮点数表示),位置在mllib.regression 包中。

• Rating
用户对一个产品的评分,在 mllib.recommendation 包中,用于产品推荐。

• 各种Model类
每个 Model 都是训练算法的结果,一般有一个 predict() 方法可以用来对新的数据点或数据点组成的 RDD 应用该模型进行预测。

算法

特征提取:

  • TF-IDF:

词频—逆文档频率(简称 TF-IDF)是一种用来从文本文档(例如网页)中生成特征向量的简单方法。它为文档中的每个词计算两个统计值:一个是词频(TF),也就是每个词在文档中出现的次数,另一个是逆文档频率(IDF),用来衡量一个词在整个文档语料库中出现的(逆)频繁程度。这些值的积,也就是 TF × IDF,展示了一个词与特定文档的相关程度(比如这个词在某文档中很常见,但在整个语料库中却很少见)。

  • 统计

不论是在即时的探索中,还是在机器学习的数据理解中,基本的统计都是数据分析的重要部分。MLlib 通过 mllib.stat.Statistics 类中的方法提供了几种广泛使用的统计函数,这些函数可以直接在 RDD 上使用。一些常用的函数如下所列:

statistics.colstats

statistics.corr

  • 分类和回归

分类和回归都会使用 MLlib 中的 LabeledPoint 类。11.4 节中提过,这个类在 mllib.
regression 包中。一个 LabeledPoint 其实就是由一个 label(label 总是一个 Double 值,不过可以为分类算法设为离散整数)和一个 features 向量组成。

  • 聚类
  1. 聚类算法是一种无监督学习任务,用于将对象分到具有高度相似性的聚类中。前面提到的监督式任务中的数据都是带标签的,而聚类可以用于无标签的数据。该算法主要用于数据探索(查看一个新数据集是什么样子)以及异常检测(识别与任意聚类都相距较远的点)
  • 协同过滤和推荐

    协同过滤是一种根据用户对各种产品的交互与评分来推荐新产品的推荐系统技术。协同过滤吸引人的地方就在于它只需要输入一系列用户 / 产品的交互记录:无论是“显式”的交互(例如在购物网站上进行评分)还是“隐式”的(例如用户访问了一个产品的页面但是没有对产品评分)交互皆可。仅仅根据这些交互,协同过滤算法就能够知道哪些产品之间比较相似(因为相同的用户与它们发生了交互)以及哪些用户之间比较相似,然后就可以作出新的推荐。

    MLlib 中包含交替最小二乘(简称 ALS)的一个实现,这是一个协同过滤的常用算法.

    要使用 ALS 算法,你需要有一个由 mllib.recommendation.Rating 对象组成的 RDD,其中每个包含一个用户 ID、一个产品 ID 和一个评分(要么是显式的评分,要么是隐式反馈;参见接下来的讨论)。实现过程中的一个挑战是每个 ID 都需要是一个 32 位的整型值。如果你的 ID 是字符串或者更大的数字,我们推荐你直接在 ALS 中使用 ID 的哈希值;即使有两个用户或者两个产品映射到同一个 ID 上,总体结果依然会不错。还有一种办法是broadcast() 一张从产品 ID 到整型值的表,来赋给每个产品独特的 ID。

    ALS 返回一个 MatrixFactorizationModel 对象来表示结果,可以调用 predict() 来对一个由(userID, productID)对组成的RDD进行预测评分。8你也可以使用model.recommendProducts(userId, numProducts) 来为一个给定用户找到最值得推荐的前 numProduct 个产品。注意,和 MLlib 中的其他模型不同,MatrixFactorizationModel 对象很大,为每个用户和产品都存储了一个向量。这样我们就不能把它存到磁盘上,然后在另一个程序中读取回来。不过,你可以把模型中生成的特征向量 RDD,也就是 model.userFeatures 和 model.productFeatures 保存到分布式文件系统上。

    最后,ALS 有两个变种:显式评分(默认情况)和隐式反馈(通过调用 ALS.trainImplicit()

    而非 ALS.train() 来打开)。用于显式评分时,每个用户对于一个产品的评分需要是一个得分(例如 1 到 5 星),而预测出来的评分也是得分。而用于隐式反馈时,每个评分代表的是用户

    会和给定产品发生交互的置信度(比如随着用户访问一个网页次数的增加,评分也会提高),预测出来的也是置信度。关于对隐式反馈使用 ALS 算法,Hu 等人所撰写的“CollaborativeFiltering for Implicit Feedback Datasets,”ICDM 2008 中有更为详细的介绍。

  • 降纬

    机器学习社区中使用的主要的降维技术是主成分分析(简称 PCA,https://en.wikipedia.org/wiki/Principal_component_analysis)。在这种技术中,我们会把特征映射到低维空间,让数据在低维空间表示的方差最大化,从而忽略一些无用的维度。要计算出这种映射,我们要构建出正规化的相关矩阵,并使用这个矩阵的奇异向量和奇异值。与最大的一部分奇异值相对应的奇异向量可以用来重建原始数据的主要成分。

    import org.apache.spark.mllib.linalg.Matrix
         import org.apache.spark.mllib.linalg.distributed.RowMatrix
         val points: RDD[Vector] = // ...
         val mat: RowMatrix = new RowMatrix(points)
         val pc: Matrix = mat.computePrincipalComponents(2)
    // 将点投影到低维空间中
    val projected = mat.multiply(pc).rows
    // 在投影出的二维数据上训练k-means模型 val model = KMeans.train(projected, 10)
    

    奇异值分解

    MLlib 也提供了低层的奇异值分解(简称 SVD)原语。SVD 会把一个 m ×n 的矩阵 A 分解成三个矩阵 A ≈ T,其中:

    • U 是一个正交矩阵,它的列被称为左奇异向量;

    • 是一个对角线上的值均为非负数并降序排列的对角矩阵,它的对角线上的值被称为奇

    异值;

    • 是一个正交矩阵,它的列被称为右奇异向量。

    对于大型矩阵,通常不需要进行完全分解,只需要分解出靠前的奇异值和与之对应的奇异向量即可。这样可以节省存储空间、降噪,并有利于恢复低秩矩阵。如果保留前 k 个奇异值,那么结果矩阵就会是U : m×k, : k×k以及 :n×k

    // 计算RowMatrix矩阵的前20个奇异值及其对应的奇异向量 val svd: SingularValueDecomposition[RowMatrix, Matrix] =
           mat.computeSVD(20, computeU=true)
    val U: RowMatrix = svd.U // U是一个分布式RowMatrix
    val s: Vector = svd.s // 奇异值用一个局部稠密向量表示 val V: Matrix = svd.V // V是一个局部稠密矩阵
    
  • 模型评估

    在 mllib.evaluation中又一些评估参数和方法

  • 流水线api









你可能感兴趣的:(Spark Mlib)