1. 交叉验证
1.1 方法介绍
CrossValidator将数据集划分为若干子集分别地训练和测试。 如当k=3时, CrossValidator产生3个训练数据与测试数据对, 每个数据对使用2/3 的数据来训练, 1/3的数据来测试。 对于一组特定的参数表, CrossValidator 计算基于三组不同训练数据与测试数据对训练得到的模型的评估准则的平均值。 确定最佳参数后, CrossValidator最后使用最佳参数表基于全部数据来重新拟合评估器。
示例:
注意: 对参数网格进行交叉验证的成本是很高的。 如下面例子中, 参数网格 hashingTF.numFeatures 有3个值, lr.regParam有2个值, CrossValidator使用2折交叉验证。 这样就会产生(3\2)2=12 种不同的模型需要进行训练。 在实际的设置中, 通常有更多的参数需要设置, 且我们可能会使用更多的交叉验证折数(3折或10折都是经常使用的)。所以CrossValidator的成本是很高的, 尽管如此, 比起启发式的手工验证, 交叉验证仍然是目前存在的参数选择方法中非常有用有用的一种。
1.2 调用示例
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql.SparkSession
/**
* 交叉验证
*/
object CrossValidator extends App{
val conf = new SparkConf().setAppName("GaussianMixture")
//设置master local[4] 指定本地模式开启模拟worker线程数
conf.setMaster("local[4]")
//创建sparkContext文件
val sc = new SparkContext(conf)
val spark = SparkSession.builder().getOrCreate()
sc.setLogLevel("Error")
import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.classification.LogisticRegression
import org.apache.spark.ml.evaluation.BinaryClassificationEvaluator
import org.apache.spark.ml.feature.{HashingTF, Tokenizer}
import org.apache.spark.ml.linalg.Vector
import org.apache.spark.ml.tuning.{CrossValidator, ParamGridBuilder}
import org.apache.spark.sql.Row
// 从(id,text,label)元组列表中准备训练数据。
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),
(4L, "b spark who", 1.0),
(5L, "g d a y", 0.0),
(6L, "spark fly", 1.0),
(7L, "was mapreduce", 0.0),
(8L, "e spark program", 1.0),
(9L, "a e c l", 0.0),
(10L, "spark compile", 1.0),
(11L, "hadoop software", 0.0)
)).toDF("id", "text", "label")
// 配置一个ML流水线,它由三个阶段组成:标记器,哈希TF和lr。
val tokenizer = new Tokenizer()
.setInputCol("text")
.setOutputCol("words")
val hashingTF = new HashingTF()
.setInputCol(tokenizer.getOutputCol)
.setOutputCol("features")
val lr = new LogisticRegression()
.setMaxIter(10)
val pipeline = new Pipeline()
.setStages(Array(tokenizer, hashingTF, lr))
//我们使用ParamGridBuilder构造一个参数网格来搜索。
//有3个值为hashingTF.numFeatures和2个值为lr.regParam,
//这个网格将有3 x 2 = 6参数设置供CrossValidator选择。
val paramGrid = new ParamGridBuilder()
.addGrid(hashingTF.numFeatures, Array(10, 100, 1000))
.addGrid(lr.regParam, Array(0.1, 0.01))
.build()
//我们现在将Pipeline作为Estimator对待,并将其封装在CrossValidator实例中。
//这将允许我们共同为所有管道阶段选择参数。
// CrossValidator需要一个估计器,一组估计器参数映射和一个评估器。
//请注意,此处的评估程序是BinaryClassificationEvaluator及其默认度量标准
//是areaUnderROC。
val cv = new CrossValidator()
.setEstimator(pipeline)
.setEvaluator(new BinaryClassificationEvaluator)
.setEstimatorParamMaps(paramGrid)
.setNumFolds(2) // Use 3+ in practice
// 运行交叉验证,并选择最佳参数集。
val cvModel = cv.fit(training)
// 准备测试文档,这是未标记的(id,文本)元组。
val test = spark.createDataFrame(Seq(
(4L, "spark i j k"),
(5L, "l m n"),
(6L, "mapreduce spark"),
(7L, "apache hadoop")
)).toDF("id", "text")
// 对测试文档进行预测。 cvModel使用找到的最佳模型(lrModel)。
cvModel.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")
}
/**
(4, spark i j k) --> prob=[0.1256626071135734,0.8743373928864266], prediction=1.0
(5, l m n) --> prob=[0.995215441016286,0.004784558983714063], prediction=0.0
(6, mapreduce spark) --> prob=[0.30696895232626553,0.6930310476737345], prediction=1.0
(7, apache hadoop) --> prob=[0.804027944240141,0.195972055759859], prediction=0.0
*/
}
2. 模型选择
2.1 模型选择介绍
模型选择(又名超参数调整)
在机器学习中非常重要的任务就是模型选择, 或者使用数据来倒找具体问题的最佳的模型和参数, 这个过程叫调试。 调试可以在独立的逻辑回归等评估器中完成, 也可以在包含多样算法、特征工程和其他步骤的管线中完成。 用户应该一次性调试整个关心, 而不是独立的调整管线中的每个组成部分。
MLlib支持交叉验证和训练验证分裂联众模型选择工具。 使用这两个工具要求包含如下对象:
1、估计器: 待调试的算法或管线。
2、一系列参数表:可选参数, 也叫做“参数网格”
3、评估器:评估模型拟合程度的准则或方法。
2.2 工作方式
模型选择工具工作原理如下:
1、将输入数据划分为训练数据和测试数据。
2、对每组训练数据与测试数据对、对参数表集合, 用响应的拟合估计其,得到训练后的模型, 在使用评估器来评估模型表现。
2、选择性能表现最优模型对应参数表。
其中, 对于回归问题评估器可选在 RegressionEvaluator , 二值数据问题可选择 BinaryClassificationEvaluator, 多分类问题可选择 MulticlassClassificationEvaluator 。 评估器里默认的评估准则可通过setMetricName 方法重写。
用户可通过ParamGridBuilder 构建参数网格。
2.3 方法思想
CrossValidator将数据集划分为若干子集分别地训练和测试。 如当k=3时, CrossValidator产生3个训练数据与测试数据对, 每个数据对使用2/3 的数据来训练, 1/3的数据来测试。 对于一组特定的参数表, CrossValidator 计算基于三组不同训练数据与测试数据对训练得到的模型的评估准则的平均值。 确定最佳参数后, CrossValidator最后使用最佳参数表基于全部数据来重新拟合评估器。
注意: 对参数网格进行交叉验证的成本是很高的。 如下面例子中, 参数网格 hashingTF.numFeatures 有3个值, lr.regParam有2个值, CrossValidator使用2折交叉验证。 这样就会产生(3\2)2=12 种不同的模型需要进行训练。 在实际的设置中, 通常有更多的参数需要设置, 且我们可能会使用更多的交叉验证折数(3折或10折都是经常使用的)。所以CrossValidator的成本是很高的, 尽管如此, 比起启发式的手工验证, 交叉验证仍然是目前存在的参数选择方法中非常有用有用的一种。
3. 线性模型的优化
3.1 有限记忆BFGS
L-BFGS 是拟牛顿方法家族里的一个优化算法, 解决 $min_{weR^df(x)}$ 形式的优化问题。
L-BFGS方法以二次方程来逼近目标函数来构造黑塞矩阵, 不考虑目标函数的二街偏导数。
黑塞矩阵由先前的迭代评估逼近, 所以不像直接使用牛顿方法一样可垂直扩展(训练特征的数目)。
所以L-BFGS 通常比其他一阶优化方法能更快收敛。
象限有限记忆拟牛顿(OWL-QN) 算法是L-BFGS的扩展, 它可以有效处理L1和弹性网格正则化。
L-BFGS 在Spark MLlib中用于线性回归、逻辑回归、AFT生存回归和多层感知器的求解。
3.2 加权最小二乘法的正规方程求解器
MLlib通过 WeightedLeastSquares 提供加权最小二乘法的正规方程求解器。
给定n 个加权观察值,$(w_i,a_i,b_i)$
$(w_i)$ 是第 i 个观察值的权重
$(a_i)$ 是第i个观察值的特征向量
$(b_i)$ 是第i个观察值的标签
每个观察值有m个特征。 我们使用下面的最小二乘法公式:
其中 是正则化参数, 是标签的总体标准偏差, 是第j 列特征的总体标准偏差。
其中 $\tau$ 是正则化参数,$\delta$ 是标签的总体标准偏差,$\sigma_j$ 是第 j 列特征的总体标准偏差。
这个目标数有一个解析器, 它只需要一个收集数据的必要统计量。 与原始数据护具需要被存储在分布式系统中不同, 如果特征数量叫嚣, 统计信息可以存储在单机中, 然后我们可以通过Cholesky 分解来解决目标函数。
加权最小二乘仅支持L2正则化, 提供选项启用或禁用正则化和标准化。 为了使正则方程逼近是有效的, 加权最小二乘要求特征数量不超过4096个。 对于规模更大的问题, 是有L-BFGS。
3.3 迭代加权最小二乘法(IRLS)
迭代加权最小二乘法可以用来找到广义线性模型的极大似然估计,找到鲁棒回归和其他优化问题中的M 估计。
它通过下面的步骤迭代地解决具体的优化问题。
1、线性化目标并更新响应的权重
2、解决加权最小二乘问题
3、重复上述步骤直至收敛
因为在第二步中使用了加权最小二乘方法在每个迭代中, 所以它同样要求特征数量不超过4096个。现在IRLS是广义线性回归的默认方法。