spark 1.6 MLlib

译者续:本文会持续更新。


MLlib 是spark 机器学习的库,它的目标是使机器学习算法能更容易上手。这个库包含通用学习算法和工具集,包括:分类,回归聚类协同过滤降维以及深层优化策略和上层管道API(pipeline).

 

分为两个包

1 spark.mllib 包含基于RDD的原始API

2 spark.ml 包含上层操作DataFrame 的API, 可以构造机器学习管道

 

推荐使用spark.ml 包,因为DataFrame API 在机器学习应用中更通用和灵活。但我们会持续支持spark.mllib 也配合spark.ml的开发。开发者可以提交新算法到spark.ml 包,但用户可以持续关注spark.mllib和使用spark.mllib中的特性。例如,特征抽取和特征变换。

 

一下列出机器学习包中主要的功能并讲解细节

spark.mllib: data types, algorithms, and utilities

·Data types

·Basic statistics

osummary statistics

ocorrelations

ostratified sampling

ohypothesis testing

ostreaming significance testing

orandom data generation

·Classification and regression

olinear models (SVMs, logistic regression, linear regression)

onaive Bayes

odecision trees

oensembles of trees (Random Forests and Gradient-Boosted Trees)

oisotonic regression

·Collaborative filtering

oalternating least squares (ALS)

·Clustering

ok-means

oGaussian mixture

opower iteration clustering (PIC)

olatent Dirichlet allocation (LDA)

obisecting k-means

ostreaming k-means

·Dimensionality reduction

osingular value decomposition (SVD)

oprincipal component analysis (PCA)

·Feature extraction and transformation

·Frequent pattern mining

oFP-growth

oassociation rules

oPrefixSpan

·Evaluation metrics

·PMML model export

·Optimization (developer)

ostochastic gradient descent

olimited-memory BFGS (L-BFGS)

一 数据类型 – MLlib

·Local vector

·Labeled point

·Local matrix

·Distributed matrix

oRowMatrix

oIndexedRowMatrix

oCoordinateMatrix

oBlockMatrix

MLlib支持单个节点的本地向量和本地指标,同时也支持基于RDDs的分布式指标集。本地向量和本地指标可看做数据模型的对外接口,而底层的线性代数操作有Breeze 和 jblas提供。监督学习中的训练样本在MLlib中称为,“标签点”(本人注解即有类别信息的样本点数据

1.1本地向量

本地向量有两个关键数据:0开始在索引和双精度浮点型值。MLlib支持两类本地向量紧致向量和稀松向量。紧致向量是一个双精度浮点型向量元素组成的数组,稀松向量是两个同长度的数据,一个是非0向量指标数组,另一个是非0向量元素数组。如, 向量(1.0,0.0,3.0) 的紧致向量为[1.0,0.0,3.0] ,而对应的稀松向量为 (3, [0, 2], [1.0, 3.0])此处,3代表向量长度(本人注解:[0,2] 是向量中非0数据的指标集,[1.0,3.0] 是对应非0.0数据的值)

本地向量的基类是Vector,我们提供两个实现:DenseVector 和SparseVector ,建议用户使用Vectors的工厂方法创建本地向量。

Scala Vector API:http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.linalg.Vector

Scala Vectors API

http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.linalg.Vectors

 

importorg.apache.spark.mllib.linalg.{Vector,Vectors}

 

// Create a dense vector (1.0, 0.0, 3.0).

val dv:Vector=Vectors.dense(1.0,0.0,3.0)

// Create a sparse vector (1.0, 0.0, 3.0) by specifying its indices and values corresponding to nonzero entries.

val sv1:Vector=Vectors.sparse(3,Array(0,2),Array(1.0,3.0))

// Create a sparse vector (1.0, 0.0, 3.0) by specifying its nonzero entries.

val sv2:Vector=Vectors.sparse(3,Seq((0,1.0),(2,3.0)))

注意:

Scala默认import scala.collection.immutable.Vector , 在运行spark ML时,需要手动引入importorg.apache.spark.mllib.linalg.Vector.

1.2标签点

标签点是本地向量,可以使紧致向量,也可以使稀松向量。在MLlib中标签点用于监督学习算法但是绑定双精度浮点类别标签后也可以应用于回归和分类算法在两类分类中类别标签可选 0 或 1 , 对于多分类,类别标签  从0 到(总类别数- 1)。

标签类使用case classs LabeledPoint .

Scala LabdledPoint   APIhttp://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.regression.LabeledPoint

importorg.apache.spark.mllib.linalg.Vectors
importorg.apache.spark.mllib.regression.LabeledPoint
 
// Create a labeled point with a positive label and a dense feature vector.
valpos=LabeledPoint(1.0,Vectors.dense(1.0,0.0,3.0))
 
// Create a labeled point with a negative label and a sparse feature vector.
valneg=LabeledPoint(0.0,Vectors.sparse(3,Array(0,2),Array(1.0,3.0)))

1.2.1 稀松数据

实践中经常会碰到需要训练稀松数据集,MLLib支持从LIBSVN格式直接读取训练数据对于LIBSVN和LIBLINEAR的用户对这种格式并不陌生这种格式是文本文件每行是一个标签点这个点标识一个稀松特征向量

label index1:value1 index2:value2 ...

注意此处文件中向量的索引是从1开始,加载到spark 后自动转换为从0 开始。

MLUtils.loadLibSVMFile 读取按LIBSVN格式存储的训练测试数据

Scala MLUtils API : http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.util.MLUtils

importorg.apache.spark.mllib.regression.LabeledPoint
importorg.apache.spark.mllib.util.MLUtils
importorg.apache.spark.rdd.RDD
 
valexamples:RDD[LabeledPoint]=MLUtils.loadLibSVMFile(sc,"data/mllib/sample_libsvm_data.txt")

1.3本地矩阵

本地矩阵是单个主机上的矩阵具有特性:整数的矩阵索引和(双精度)浮点矩阵元素。MLLib支持紧致矩阵矩阵元素按列优先存储在数组中,稀松矩阵,矩阵非0元素按列优先存储在CSC格式(Compressed Sparse Column,压缩稀松列,如下面紧致矩阵

             

(3,2)的矩阵存储在数组中为 [1.0, 3.0, 5.0, 2.0, 4.0, 6.0] 

本地矩阵的基类是Matrix , 同时提供两种本地矩阵实现:DenseMatrix,和SparseMatrix 。 建议用户使用Matrices 类的工厂方法创建本地矩阵。再次提醒,矩阵是按列优先的数组存储。

Scala Matrix

http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.linalg.Matrix

 

Matrices API :

http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.linalg.Matrices

importorg.apache.spark.mllib.linalg.{Matrix,Matrices}
 
// Create a dense matrix ((1.0, 2.0), (3.0, 4.0), (5.0, 6.0))
valdm:Matrix=Matrices.dense(3,2,Array(1.0,3.0,5.0,2.0,4.0,6.0))
 
// Create a sparse matrix ((9.0, 0.0), (0.0, 8.0), (0.0, 6.0))
valsm:Matrix=Matrices.sparse(3,2,Array(0,1,3),Array(0,2,1),Array(9,6,8))

 

1.4 分布式矩阵

分布式矩阵是分布在一个或多个RDDs的矩阵具有特征长整型矩阵索引双精度浮点矩阵元素考虑到将分布式矩阵转换为其他形式需要全局shuffle, 这样很消耗时间,因此有必要仔细斟酌选择合适形式来存储分布式大矩阵。暂时支持三种类型的分布式矩阵。

第一类是RowMatrix .RowMatrix 是面向行存储的矩阵因此忽略行索引例如特征向量。这种矩阵每一行是一个本地向量(RDD)。假设每行的数据并不多,这样本地矩阵可以在单节点的driver间自由通信,也可以在单节点上存储和操作。

第二类是IndexedRowMatrix ,它比RowMatrix多了行索引,这个行索引可以标记行并用于关联操作。

第三类是CoordinateMatrix 这种举证按CCO链表(coordinate list, https://en.wikipedia.org/wiki/Sparse_matrix#Coordinate_list_.28COO.29 ) 格式存储, 链表每个元素是一个RDD。

注意

分布式矩阵的RDD的行和列在cache时必须是确定的,否则会出错。

 

1.4.1 RowMatrix

因为每行是一个本地向量因此矩阵的列数限制在integer的范围,在实际中不建议太大。

RowMatrix 可以由一个RDD[Vector]实例创建然后可以做列统计和分解QR分解的形式 A = QR , 此处Q是一个正交矩阵,而R是一个上三角矩阵。了解更多奇异值分解(SVD,https://en.wikipedia.org/wiki/Singular_value_decomposition)和主成分分析(PCA,https://en.wikipedia.org/wiki/Principal_component_analysis) ,请看降维章节, http://spark.apache.org/docs/latest/mllib-dimensionality-reduction.html

Scala RowMatrix API : http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.linalg.distributed.RowMatrix

importorg.apache.spark.mllib.linalg.Vector

importorg.apache.spark.mllib.linalg.distributed.RowMatrix

 

val rows:RDD[Vector]=...// an RDD of local vectors

// Create a RowMatrix from an RDD[Vector].

val mat:RowMatrix=newRowMatrix(rows)

 

// Get its size.

val m= mat.numRows()

val n= mat.numCols()

 

// QR decomposition

val qrResult= mat.tallSkinnyQR(true)

 

1.4.2 IndexedRowMatrix

IndexedRowMatrix 可由RDD[IndexedRow] 实例创建,此处IndexedRow 封装为(Long, Vector) . IndexedRowMatrix 去掉行索引就变成了RowMatrix

Scala IndexedRowMatrix API : http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.linalg.distributed.IndexedRowMatrix

importorg.apache.spark.mllib.linalg.distributed.{IndexedRow,IndexedRowMatrix,RowMatrix}

 

val rows:RDD[IndexedRow]=...// an RDD of indexed rows

// Create an IndexedRowMatrix from an RDD[IndexedRow].

val mat:IndexedRowMatrix=newIndexedRowMatrix(rows)

 

// Get its size.

val m= mat.numRows()

val n= mat.numCols()

 

// Drop its row indices.

val rowMat:RowMatrix= mat.toRowMatrix()

 

1.4.3 CoordinateMatrix ( 调和矩阵)

Coordinatematrix 是分布式矩阵,所有元素做成的RDD对象。其中Tuple3 形如( i : Long , j : Long, value : Double ) ,此处i 是行索引, j 是列索引, value 是元素的值。CoordinateMatrix 只在当矩阵行和列都很大时,同时矩阵非0 元素很稀松。

 

CoordinateMatrix 可以从RDD[MatrixEntry]实例创建,此处MatrixEntry 封装为(Long , Long, Double )。 CoordinateMatrix 调用toIndexeedRowMatrix 方法可以将CoordinateMatrix 矩阵转化为IndexedRowMatrix 矩阵,其他coordinateMatrix 的计算暂时还不支持。

Scala CoordinateMatrix API : http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.linalg.distributed.CoordinateMatrix

importorg.apache.spark.mllib.linalg.distributed.{CoordinateMatrix,MatrixEntry}

 

val entries:RDD[MatrixEntry]=...// an RDD of matrix entries

// Create a CoordinateMatrix from an RDD[MatrixEntry].

val mat:CoordinateMatrix=newCoordinateMatrix(entries)

 

// Get its size.

val m= mat.numRows()

val n= mat.numCols()

 

// Convert it to an IndexRowMatrix whose rows are sparse vectors.

val indexedRowMatrix= mat.toIndexedRowMatrix()

 

1.4.4 BlockMatrix (分块矩阵)

BlockMatrix是分布式矩阵RDD[MarixBlock],此处MatrixBlock是元组((Int, Int) , Matrix ), 其中(Int, Int) 是矩阵块的索引, Matrix 是给定矩阵块索引的子矩阵,矩阵维度(是数组的长度)rowsPerBlock* colsPerBlockBlockMatrix矩阵支持add 和 multiply 方法和另一个同维度的BlockMatrix 计算。Helper函数 validate可以校验 BlockMatrix 是否设置正确。

BlockMatrix 矩阵可以有IndexedRowMatrix 或 CoordinateMatrix  调用toBlockMatrix 方法得到, toBlockMatrix 方法默认创建 1024 * 1024 的块矩阵用户可以调用接口 toBlockMatrix(rowsPerBlock , colsPerBlock ) 修改矩阵维度。

 

Scala BlockMatrix API : http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.linalg.distributed.BlockMatrix

importorg.apache.spark.mllib.linalg.distributed.{BlockMatrix,CoordinateMatrix,MatrixEntry}

 

val entries:RDD[MatrixEntry]=...// an RDD of (i, j, v) matrix entries

// Create a CoordinateMatrix from an RDD[MatrixEntry].

val coordMat:CoordinateMatrix=newCoordinateMatrix(entries)

// Transform the CoordinateMatrix to a BlockMatrix

val matA:BlockMatrix= coordMat.toBlockMatrix().cache()

 

// Validate whether the BlockMatrix is set up properly. Throws an Exception when it is not valid.

// Nothing happens if it is valid.

matA.validate()

 

// Calculate A^T A.

val ata= matA.transpose.multiply(matA)

 

 

2 基本统计  spark.mllib

2.1 统计概览

Statistics类中提供基本列统计RDD[Vector]功能

colStats()返回MultivariateStatisticalSummary 的实例,这个实例可以按列计算最大,最小,均值,方差,非0个数统计,列的1范数。

Scala MultivariateStatisticalSummary API : http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.stat.MultivariateStatisticalSummary

import org.apache.spark.mllib.linalg.Vector

import org.apache.spark.mllib.stat.{MultivariateStatisticalSummary, Statistics}

 

val observations: RDD[Vector] = ... // an RDD of Vectors

 

// Compute column summary statistics.

val summary: MultivariateStatisticalSummary = Statistics.colStats(observations)

println(summary.mean) // a dense vector containing the mean value for each column

println(summary.variance) // column-wise variance

println(summary.numNonzeros) // number of nonzeros in each column

 

2.2 相关统计

计算两个数据序列可以使向量或矩阵)的相关系数。在spark.mllib中,我们提供成对计算相关系数,实现了Pearson’s相关和Spearman’s相关相关统计的结果依赖于计算对象如果是两个RDD[Double]的计算,结果是Double类型,如果是两个RDD[Vector]计算,结果是一个Matrix矩阵。

Scala Statistics API : http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.stat.Statistics

import org.apache.spark.SparkContext

import org.apache.spark.mllib.linalg._

import org.apache.spark.mllib.stat.Statistics

 

val sc: SparkContext = ...

 

val seriesX: RDD[Double] = ... // a series

val seriesY: RDD[Double] = ... // must have the same number of partitions and cardinality as seriesX

 

// compute the correlation using Pearson's method. Enter "spearman" for Spearman's method. If a 

// method is not specified, Pearson's method will be used by default. 

val correlation: Double = Statistics.corr(seriesX, seriesY, "pearson")

 

val data: RDD[Vector] = ... // note that each Vector is a row and not a column

 

// calculate the correlation matrix using Pearson's method. Use "spearman" for Spearman's method.

// If a method is not specified, Pearson's method will be used by default. 

val correlMatrix: Matrix = Statistics.corr(data, "pearson")

 

2.3 分层采样(Stratified sampling) 

spark.mllib中提供计算原始RDD 键值对的分层采样方法:sampleByKey 和 sampleByKeyExact 。在分层采样中,键可以看做标签类,相应的值可以看做属性。如,键可以使男人或女人,文档ID,相应的值可以使人的年龄或文档的单次。 sampleByKey 方法随机采样一系列观测值,过程就像逐个遍历所有样本点,通过抛银币决定取舍,因此只需要确定采样点个数。sampleByKeyExact 比分层随机采样方法sampleByKey需要更多地样本,才能保证采样点个数有99.99%的置信度,sampleByKeyExact暂不支持python.

 

sampleByKeyExact() 采样由[ f_k , n_k ] 完全决定, 对任意一个键属于 K 键集合f_k是预期键对应采样点值得占比分数),n_k 是这个键k在整个集合中值的个数。无放回采样(即采样的数据取走,不会出现重复) 方法需要一个参数(withReplacement默认是false , 而又放回采样方法需要两个参数

import org.apache.spark.SparkContext

import org.apache.spark.SparkContext._

import org.apache.spark.rdd.PairRDDFunctions

 

val sc: SparkContext = ...

 

val data = ... // an RDD[(K, V)] of any key value pairs

val fractions: Map[KDouble] = ... // specify the exact fraction desired from each key

 

// Get an exact sample from each stratum

val approxSample = data.sampleByKey(withReplacement = false, fractions)

val exactSample = data.sampleByKeyExact(withReplacement = false, fractions)

 

2.4 假设检验

假设检验在统计上用于判定统计结果又多大统计意义及统计结果有多大置信度Spark.mllib 暂支持Pearson’s chi-squared 检验检验结果的适用性和独立性输入数据需要验证适用性和独立性适用性检验需要输入Vector , 独立性需要数据Matrix 

Spark.mllib 支持输入RDD[LabledPoint] ,使用chi-squared独立性来决定特征的选择。

Statistics 提供方法运行Pearson’s chi-squared 检验下例用于假设检验

import org.apache.spark.SparkContext

import org.apache.spark.mllib.linalg._

import org.apache.spark.mllib.regression.LabeledPoint

import org.apache.spark.mllib.stat.Statistics._

 

val sc: SparkContext = ...

 

val vec: Vector = ... // a vector composed of the frequencies of events

 

// compute the goodness of fit. If a second vector to test against is not supplied as a parameter, 

// the test runs against a uniform distribution.  

val goodnessOfFitTestResult = Statistics.chiSqTest(vec)

println(goodnessOfFitTestResult) // summary of the test including the p-value, degrees of freedom, 

                                 // test statistic, the method used, and the null hypothesis.

 

val mat: Matrix = ... // a contingency matrix

 

// conduct Pearson's independence test on the input contingency matrix

val independenceTestResult = Statistics.chiSqTest(mat) 

println(independenceTestResult) // summary of the test including the p-value, degrees of freedom...

 

val obs: RDD[LabeledPoint] = ... // (feature, label) pairs.

 

// The contingency table is constructed from the raw (feature, label) pairs and used to conduct

// the independence test. Returns an array containing the ChiSquaredTestResult for every feature 

// against the label.

val featureTestResults: Array[ChiSqTestResult] = Statistics.chiSqTest(obs)

var i = 1

featureTestResults.foreach { result =>

    println(s"Column $i:\n$result")

    i += 1

} // summary of the test

 

Statistics 提供1-sample, 2-sided Kolmogorov-Smirnov检验概率分布是否相等。提供理论分布名称和理论分布参数,或者根据已知理论分布计算累计分布函数,用户可以检验样本点是否出自来验证概率分布。在特殊例子中,如正态分布,不用没有提供正态分布参数,则检验会使用标准正态分布参数。

Scala Statistics API : http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.stat.Statistics

import org.apache.spark.mllib.stat.Statistics

 

val data: RDD[Double] = ... // an RDD of sample data

 

// run a KS test for the sample versus a standard normal distribution

val testResult = Statistics.kolmogorovSmirnovTest(data, "norm", 0, 1)

println(testResult) // summary of the test including the p-value, test statistic,

                    // and null hypothesis

                    // if our p-value indicates significance, we can reject the null hypothesis

 

// perform a KS test using a cumulative distribution function of our making

val myCDF: Double => Double = ...

val testResult2 = Statistics.kolmogorovSmirnovTest(data, myCDF)

 

2.5 流式显著性测试

Spark.mllib 提供在线测试实现A/B在线测试。此测试需要在spark streaming DStream[(Boolean, Double)] 上使用每个流单元的第一个元素是逻辑真假假代表对照false),而真代表实验组(true) , 第二个元素是观测值

流式显著性检验支持这两个参数

peacePeriod  平稳周期), 默认最初启动后可以忽略的数据组数。

windowSize (窗尺寸, 每次假设检验使用的数据批次数,若设为, 则累计处理之前所有批次。

StreamingTest 支持流式假设检验

val data = ssc.textFileStream(dataDir).map(line => line.split(",") match {

  case Array(label, value) => BinarySample(label.toBoolean, value.toDouble)

})

 

val streamingTest = new StreamingTest()

  .setPeacePeriod(0)

  .setWindowSize(0)

  .setTestMethod("welch")

 

val out = streamingTest.registerStream(data)

out.print()

完整例子代码见examples/src/main/scala/org/apache/spark/examples/mllib/StreamingTestExample.scala

 

 

2.6 随机数发生器

随机数发生器在随机算法随机模板和性能测试中很有用Spark.mllib 的随机发生器RDD i.i.d. 随机数据来自给定分布:均匀分布, 标准正态, Possion (泊松分布)。

RandomRDDs 提供工厂方法来生成随机双精度浮点RDD 和 随机向量RDD。下例生辰随机双精度浮点RDD, 这些随机值来自标准正态分布N(0,1), 做平移和伸缩后映射到N(1,4)

 

Scala RandomRDD API : http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.random.RandomRDDs

import org.apache.spark.SparkContext

import org.apache.spark.mllib.random.RandomRDDs._

 

val sc: SparkContext = ...

 

// Generate a random double RDD that contains 1 million i.i.d. values drawn from the

// standard normal distribution `N(0, 1)`, evenly distributed in 10 partitions.

val u = normalRDD(sc, 1000000L, 10)

// Apply a transform to get a random double RDD following `N(1, 4)`.

val v = u.map(=> 1.0 + 2.0 * x)

 

2.6 核密度估计

核密度估计在经验概率分布图中用处很大,这种分布图不需要假设观测值来自特定的某个分布。通过给定点集,来计算随机变量的概率密度函数。通过计算经验分布在特定点的PDF(偏导数),作为标准正态分布在每个采样点附近的PDF

KernelDensity 提供方法计算RDD采样点集的核密度估计,见下例:

 

Scala KernelDensity API: http://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.stat.KernelDensity

import org.apache.spark.mllib.stat.KernelDensity

import org.apache.spark.rdd.RDD

 

val data: RDD[Double] = ... // an RDD of sample data

 

// Construct the density estimator with the sample data and a standard deviation for the Gaussian

// kernels

val kd = new KernelDensity()

  .setSample(data)

  .setBandwidth(3.0)

 

// Find density estimates for the given values

val densities = kd.estimate(Array(-1.0, 2.0, 5.0))

 

 

分类和回归spark.mllib

Spark.mllib 实现以下ML问题: 两个标签类的分类, 多个标签类的分类,和回归分析。

下表列出每类问题的支持算法

Problem Type

Supported Methods

Binary Classification

linear SVMs, logistic regression, decision trees, random forests,

 gradient-boosted trees, naive Bayes

线性支持向量机,逻辑回归,决策树,随机森林,梯度提升决策树,

朴素贝叶斯决策

Multiclass Classification

logistic regression, decision trees, random forests, naive Bayes

逻辑回归决策树,随机森林,朴素贝叶斯决策

Regression

linear least squares, Lasso, ridge regression, decision trees, 

random forests, gradient-boosted trees, isotonic regression

线性最小二乘法最小化的绝对收缩和选择算子,岭回归,

决策树,随机森林,梯度提升决策树,保序回归

 

3.1 线性模型 spark.mllib

 

· Mathematical formulation

Loss functions

Regularizers

Optimization

· Classification

Linear Support Vector Machines (SVMs)

Logistic regression

· Regression

Linear least squares, Lasso, and ridge regression

Streaming linear regression

· Implementation (developer)

3.1.1 数学公式

 许多标准机器学习问题可以转化为凸优化问题,如, 凸函数的最小值是依赖于d维向量w(称为权重向量),可以把问题转化为:

    \min_{w \in R^d }{ f(x) } 问题此处函数形如:

 

F(w) = \Lamda * R(w) + frac{1,n} * \Sum|_{i=1}|^{n} {L(w;x_i,y_i)|

此处向量   x_i \in R^d是训练测试数据,  1 <= I <= n , y_i \in R是相应的类标签,类标签在分类问题是需要预测的。如果方法是线性的,如果

L(w;x,y) 可以表示成w^{T} x 和 的函数, 下面会讲解不是凸优化问题的情况

 

目标函数有两个点:正规化决定模型的复杂程度,损失决定模型的误差,损失函数L(w; . , . ) 的凸函数,正规化参数 \Lamda >= 0 (名为regParam 来权衡两个目标错误最小 和模型复杂度最低 (为了防止过拟合)

 

3.1.1.1 损失函数 

下表总结损失函数集损失函数的梯度函数

 

3.1.1.2 正规化

正则化可以使模型处理相对简单,并且可以避免模型过拟合。支持以下正则化 spark.mllib

 

此处 sign(w) 是符号向量,每个元素是向量相应位置的符号函数 sign(x_i)

L2-正规化相对L1-正规化处理简单,是因为L2的正规函数是连续光滑函数L1的正规函数则不是。L1正规化可以使权向量中稀少的值变得不那么重要,使模型在特征选择上处理更容易理解。弹性网络(elastic netL1L2正规化的组合。不建议训练模型时不适用正则化,特别是训练向本数很少时。

 

3.1.1.3 最优化

线性方法使用凸最优化方法优化目标函数Spark.mllib使用两种方法SGD L-BFGS(见最优化章节)。当前,大多数算法API支持随机梯度下降SGD和大部分支持L-BFGS。 

 

3.1.2分类

分类算法的目标是把数据分门别类。最简单分类是两分类问题,即分成两类(正类和负类)。如果多余两类,一般称为多类别分类问题。Spark.mllib 支持两种线性分类线性支持向量机(SVM)和逻辑回归。 线性SVN 只支持两分类而逻辑回归支持两分类和多分类这两种算法都支持L1L2正规化。训练集为RDD[LabeledPoint] MLlib 而类标签为 0, 1,2,… 。 注意,数学公式中,两分类的类标签表示为: +正类) 和 -负类)。

 

3.1.2.1 线性支持向量机(SVM

线性SVN是处理大多数分类问题的首选线性方法描述见上面表达式(1),其中损失函数形如:

   L(w;x,y) :=  max{ 0,  1 – y w^t x }

默认,线性SVN训练集需要使用L2正规化同时支持L1正规化此情况下, 变成线性算法。

线性SVN算法输出SVN模型给定新数据点表示为x , 模型基于w^T x 的 预测。 默认, 如果 w^T x >= 0 , 则归为正类,否则归为负类。

例子

下例中展示如何加载测试数据执行算法训练,并预测结果与训练集的错误。

 

Scala SVMWithSGD API : https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.classification.SVMWithSGD

Scala SVMModel API : 

https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.classification.SVMModel

 

import org.apache.spark.mllib.classification.{SVMModel, SVMWithSGD}

import org.apache.spark.mllib.evaluation.BinaryClassificationMetrics

import org.apache.spark.mllib.util.MLUtils

 

// Load training data in LIBSVM format.

val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")

 

// Split data into training (60%) and test (40%).

val splits = data.randomSplit(Array(0.6, 0.4), seed = 11L)

val training = splits(0).cache()

val test = splits(1)

 

// Run training algorithm to build the model

val numIterations = 100

val model = SVMWithSGD.train(training, numIterations)

 

// Clear the default threshold.

model.clearThreshold()

 

// Compute raw scores on the test set.

val scoreAndLabels = test.map { point =>

  val score = model.predict(point.features)

  (score, point.label)

}

 

// Get evaluation metrics.

val metrics = new BinaryClassificationMetrics(scoreAndLabels)

val auROC = metrics.areaUnderROC()

 

println("Area under ROC = " + auROC)

 

// Save and load model

model.save(sc, "myModelPath")

val sameModel = SVMModel.load(sc, "myModelPath")

SVMWitSGD.train() 方法默认使用L2正规化且使用正规参数1.0 。如果想修改此默认,需要创建新的SVMWithSGD 实例,并用setter方法重新配置。其他spark.mllib算法也支持setter方法重新配置,例如,下例给出L1正规化 且SVM正规化参数位0.1 ,训练样本迭代200次。

import org.apache.spark.mllib.optimization.L1Updater

 

val svmAlg = new SVMWithSGD()

svmAlg.optimizer.

  setNumIterations(200).

  setRegParam(0.1).

  setUpdater(new L1Updater)

val modelL1 = svmAlg.run(training)

3.1.2.2 逻辑回归

逻辑回归广泛用于预测两类别分类问题它也符合等式(1) , 并且损失函数形如:

L(w;x,y)  := log( 1 + exp(-y w^T x) )

对于两类别分类问题算法输出两类别逻辑回归模型给定新的测试点记为x , 模型通过逻辑函数

F(z) = 1 / { 1 + e^(-z)} 

 此处 z = w^T x , 如果 f(w^T x) > 0.5 , 认为是正类, 否则认为是负类, 可以看到此分类方法分类和SVN不太一样,多了一个随机函数f( ) 

 

两类别分类逻辑回归可以推广到多类别逻辑回归,用来处理多类别分类问题。例如,假设有K可能的输出结果,选取其中一个作为对比值,剩下K-1个输出值分别去和对比值做两类别回归。在spark.mllib , 这个对比值就是类别,详见 统计学习基础:http://statweb.stanford.edu/~tibs/ElemStatLearn/

 

对于多类别分类问题算法会输出K-1个逻辑回归模型,给定一个新测试点,带入K-1个模型算出最大概率值得类别,记为预测结果。

 

我们实现两个算法解决逻辑回归小批梯队下降法mini-batch gradient descent)和L-BFGS , 我们建议优先选L-BFGS,它的收敛性更快一些。

例子

下面例子将如何加载多类别数据集将数据集分为训练和测试使用LogisticRegressionWithLBFGS 做逻辑回归模型再用测试数据集去评估优劣

 

Scala LogisticRegressionWithLBFGS API : https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.classification.LogisticRegressionWithLBFGS

Scala LogisticRegressionModel API : 

https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.classification.LogisticRegressionModel

import org.apache.spark.SparkContext

import org.apache.spark.mllib.classification.{LogisticRegressionWithLBFGS, LogisticRegressionModel}

import org.apache.spark.mllib.evaluation.MulticlassMetrics

import org.apache.spark.mllib.regression.LabeledPoint

import org.apache.spark.mllib.linalg.Vectors

import org.apache.spark.mllib.util.MLUtils

 

// Load training data in LIBSVM format.

val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")

 

// Split data into training (60%) and test (40%).

val splits = data.randomSplit(Array(0.6, 0.4), seed = 11L)

val training = splits(0).cache()

val test = splits(1)

 

// Run training algorithm to build the model

val model = new LogisticRegressionWithLBFGS()

  .setNumClasses(10)

  .run(training)

 

// Compute raw scores on the test set.

val predictionAndLabels = test.map { case LabeledPoint(label, features) =>

  val prediction = model.predict(features)

  (prediction, label)

}

 

// Get evaluation metrics.

val metrics = new MulticlassMetrics(predictionAndLabels)

val precision = metrics.precision

println("Precision = " + precision)

 

// Save and load model

model.save(sc, "myModelPath")

val sameModel = LogisticRegressionModel.load(sc, "myModelPath")

 

3.1.3 回归

3.1.3.1 线性最小二乘,Lasso , 岭回归

最小二乘在回归问题中经常使用同样是线性算法符合公式(1) , 损失函数形为:

 

使用不同的正规化方法得到不同最小二乘法: 正交最小二乘法或线性最小二乘法(不适用正规化);岭回归使用L2正规化Lasso使用L1正规化。对所有这些模型,平均损失(训练集错误率) 1/n  \SUM|_(i=1) ^n| ( w^T x_i – y_i )^2 , 称为均方误差

例子

下例展示如何加载训练数据转化成标签点的RDD例子使用LinearRegressionWithSGD 构建线性模型来预测类标签。最后计算均方差错误来评估拟合优度。

Scala LinearRegressionWithSGD API : https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.regression.LinearRegressionWithSGD

Scala LinearRegressionModel API : https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.mllib.regression.LinearRegressionModel

import org.apache.spark.mllib.regression.LabeledPoint

import org.apache.spark.mllib.regression.LinearRegressionModel

import org.apache.spark.mllib.regression.LinearRegressionWithSGD

import org.apache.spark.mllib.linalg.Vectors

 

// Load and parse the data

val data = sc.textFile("data/mllib/ridge-data/lpsa.data")

val parsedData = data.map { line =>

  val parts = line.split(',')

  LabeledPoint(parts(0).toDouble, Vectors.dense(parts(1).split(' ').map(_.toDouble)))

}.cache()

 

// Building the model

val numIterations = 100

val model = LinearRegressionWithSGD.train(parsedData, numIterations)

 

// Evaluate model on training examples and compute training error

val valuesAndPreds = parsedData.map { point =>

  val prediction = model.predict(point.features)

  (point.label, prediction)

}

val MSE = valuesAndPreds.map{case(v, p) => math.pow((- p), 2)}.mean()

println("training Mean Squared Error = " + MSE)

 

// Save and load model

model.save(sc, "myModelPath")

val sameModel = LinearRegressionModel.load(sc, "myModelPath")

RidgeRegressionWithSGD  LassoWithSGD 使用同LinearRegressionWithSGD 

为了运行上例代码需要查看spark 快速指南中 Self-Contained Applications 章节(https://spark.apache.org/docs/latest/quick-start.html#self-contained-applications

 

3.1.3.2 流线性回归

当数据是以流的形式进入模型最好选取在线回归模型更新数据每批生成的周期Spark.mllib  流线性回归暂支持正交最小二乘。除了拟合度是计算每批次数据的到,拟合度计算方法和离线是一样

例子

下例展示如何从文件生成训练数据流和测试数据流把流数据解释为标签点拟合在线线性回归模型预测下一个流的类标签

首先引入必须的输入数据和模型类

import org.apache.spark.mllib.linalg.Vectors

import org.apache.spark.mllib.regression.LabeledPoint

import org.apache.spark.mllib.regression.StreamingLinearRegressionWithSGD

然后生成训练数据流和测试数据流假设StreamingContext ssc 已经生成,详见Spark Streaming Programming Guide (https://spark.apache.org/docs/latest/streaming-programming-guide.html#initializing)

下例中我们使用标签点来代表训练和测试数据实际中建议测试数据使用无标签向量

val trainingData = ssc.textFileStream("/training/data/dir").map(LabeledPoint.parse).cache()

val testData = ssc.textFileStream("/testing/data/dir").map(LabeledPoint.parse)

初始化模型权重为0

val numFeatures = 3

val model = new StreamingLinearRegressionWithSGD()

    .setInitialWeights(Vectors.zeros(numFeatures))

注册训练数据流和测试数据流,将预测结果打印出来。

model.trainOn(trainingData)

model.predictOnValues(testData.map(lp => (lp.label, lp.features))).print()

 

ssc.start()

ssc.awaitTermination()

现在可以把训练和测试数据流保存在不同的文件夹下每行记录的数据点格式( y , [ x1,x2,x3]) ,此处是类标签, x1,x2,x3是特征向量。训练数据文件只要保存在/training/data/dir, 模型就会随时更新,测试数据文件保存在/testing/data/dir 下就会计算类标签预测注意训练数据越多预测结果越好

 

 

3.1.4 实现开发者

Spark.mllib实现了简单分布式版本的SGD(stochastic gradient descent),这个SGD是基于(underlying) 梯度下降法。所有提供的算法接受正规化参数作为输入(regParam) , 同时还有其他SGD的各种参数(stepSize , numIterations , miniBatchFraction ) 。 罪域每个参数,我们提供三种可能的正规化(none , L1 , L2 

逻辑回归L-BFGS版本的实现基于LogisticRegressionWithLBFGS类,这个实现支持两类别逻辑回归和多类别逻辑回归,而SGD只支持两类别逻辑回归。尽管,L-BFGS不支持L1正规化SGD只支持L1正规化L1正规化不是必选是, 强烈推荐L-BFGS算法, 因为它收敛更快,比SGD算法更精确的逼近逆 Hessian 矩阵,这个Hessian 矩阵通过拟牛顿法(quasi-Newton methond)

算法Scala 实现

· 
SVMWithSGD

· LogisticRegressionWithLBFGS

· LogisticRegressionWithSGD

· LinearRegressionWithSGD

· RidgeRegressionWithSGD

· LassoWithSGD

Python 调用scala 实现: PythonMLLibAPI.

 3.2 朴素贝叶斯














3.3 决策树

·  
Basic algorithm

· Node impurity and information gain

· Split candidates

· Stopping rule

·  Usage tips

· Problem specification parameters

· Stopping criteria

· Tunable parameters

· Caching and checkpointing

·  Scaling

·  Examples

· Classification

· Regression

决策树算法常用于机器学习中分类和回归问题,由于以下优点,决策树得到广泛使用:

处理特征分类时,对分类结果容易直观解释

容易扩展到多类情况

不去要对特征向量进行规整()

可以处理非线性问题

可以直观观察特征的比对交互过程

决策树算法族,诸如随机森林和随机深林的提升算法在处理分类和回归问题是效率最高。

Spark.mllib的决策树使用连续特征和归类特征,应用于两类别分类和多类别分类,以及回归问题。决策树实现按行分片处理,最多允许分布式训练百万行数据。

随机森林和梯度提升树详见 Ensembles guide (https://spark.apache.org/docs/latest/mllib-ensembles.html)

 

3.3.1 基本算法

决策树是贪婪算法它会按二分去遍历整个特征向量空间。算法预测相同标签类的叶节点集。每一种分片的结果都是在决策节点上,所有可能的划分方法中选取最优的方法,选取最优的依据是信息增益(information gain) 最大化。 换句话说在每个决策节点选取使 argmax(s)  IG(D,s) , 信息增益最大化的参数s  ,此处 , IG(D,s) 是在数据集上应用划分方法所得到的信息增益。

 

3.3.1.1 节点混杂度和信息增益

节点混杂度是测量节点上标签集均一性当前实现两种分类混杂度Gini 混杂度和熵一种回归混杂度。

 

信息增益不同于父节点的混杂度以及子节点的混杂度带权重之和假设划分将数据集划分为D1  D2 ,其中D1N1个元素,D2N2个元素。

信息增益

IG(D,s) = Impurity(D) – N1/N Impurity(D1) – N2/N Impurity(D2)

3.3.1.2 拆分可选集

3.3.1.2.1 连续特征

在单机上小数据集上,给定特征向量,对连续特征的划分备选集

 

 

 

 

 

spark.ml: high-level APIs for ML pipelines

·Overview: estimators, transformers and pipelines

·Extracting, transforming and selecting features

·Classification and regression

·Clustering

·Advanced topics

 

很多降维算法还没有完全在spark.ml中实现,用户可以自己把spark.mllib的实现和spark.ml中算法结合,构造自己的降维算法。

 

依赖
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值