ML中的一项重要任务是模型选择,或使用数据为给定任务找到最佳模型或参数。这也称为调整。调整可以在单个估计器(如LogisticRegression)上完成,也可以在包括多个算法、特征化和其他步骤的整个管道上完成。用户无需单独调整Pipeline中的每个元素,而是可以一次调整整个Pipeline。ML中的一项重要任务是模型选择,或使用数据为给定任务找到最佳模型或参数。这也称为调整。调优可以在单个Estimator(例如LogisticRegression)上完成,也可以在包括多个算法、特征化和其他步骤的整个管道上完成。用户无需单独调整Pipeline中的每个元素,而是可以一次调整整个Pipeline。MLlib支持使用CrossValidator和TrainValidationSplit等工具进行模型选择。这些工具需要以下内容:估计器:要调整的算法或管道一组参数:一组可选择的参数,有时称为搜索的“参数网格”评估器:衡量拟合模型对测试数据的执行情况这些模型选择工具是这样工作的:它们将输入数据分成单独的训练和测试数据集。对于每个(训练、测试)对,它们遍历ParamMap集合:对于每个ParamMap,使用这些参数来拟合Estimator,得到拟合的Model,并使用Evaluator来评估Model的性能。他们选择由性能最佳的一组参数生成的模型。为了帮助构建参数化网格,用户可以使用ParamGridBuilder。默认情况下,参数网格中的参数集是按顺序计算的。在使用CrossValidator或TrainValidationSplit运行模型选择之前,可以通过将并行度设置为2或更多(值1将是串行的)来并行完成参数评估。应谨慎选择并行度的值,以在不超出集群资源的情况下最大化并行度,较大的值不一定会提高性能。一般来说,10以上的值对于大多数集群来说应该足够了。交叉验证CrossValidator交叉验证器首先将数据集拆分为一组折叠数据集,用作单独的训练和测试数据集。例如,当k=3次时,CrossValidator会生成3对(训练、测试)数据集,每对数据集使用2/3的数据进行训练,1/3的数据进行测试。为了评估特定的ParamMap,CrossValidator通过在3个不同的(训练、测试)数据集对上拟合Estimator生成的3个模型来计算平均评估指标。在确定最佳ParamMap后,CrossValidator最后使用最佳ParamMap和整个数据集重新拟合Estimator。frompyspark.mlimportPipelinefrompyspark.ml.classificationimportLogisticRegressionfrompyspark.ml.evaluationimportBinaryClassificationEvaluatorfrompyspark.ml.featureimportHashingTF,Tokenizerfrompyspark.ml.tuningimportCrossValidator,ParamGridBuilder#准备训练文件并制作标签。training=spark.createDataFrame([(0,"abcdespark",1.0),(1,"bd",0.0),(2,"sparkfgh",1.0),(3,"hadoopmapreduce",0.0),(4,"bsparkwho",1.0),(5,"gday",0.0),(6,"sparkfly",1.0),(7,"wasmapreduce",0.0),(8,"esparkprogram",1.0),(9,"aecl",0.0),(10,"sparkcompile",1.0),(11,"hadoopsoftware",0.0)],["id","text","label"])#配置一个ML管道,它由树阶段组成:tokenizer、hashingTF和lr。tokenizer=Tokenizer(inputCol="text",outputCol="words")hashingTF=HashingTF(inputCol=tokenizer.getOutputCol(),outputCol="features")lr=LogisticRegression(maxIter=10)pipeline=Pipeline(阶段=[tokenizer,hashingTF,lr])#我们现在使用Pipeline作为Estimator并将其包装在CrossValidator实例中。#这将使我们能够为所有流水线阶段共同选择参数。#交叉验证器需要一个Estimator,一组EstimatorParamMaps和一个Evaluator。#我们使用ParamGridBuilder构造一个用于搜索的参数网格。#hashingTF.numFeatures的3个值,lr.regParam的2个值,#这个网格会有3x2=6个参数设置供CrossValidator选择。paramGrid=ParamGridBuilder()\.addGrid(hashingTF.numFeatures,[10,100,1000])\.addGrid(lr.regParam,[0.1,0.01])\.build()crossval=CrossValidator(estimator=pipeline,estimatorParamMaps=paramGrid,evaluator=BinaryClassificationEvaluator(),numFolds=2)#使用3+folds运行交叉验证#并选择最佳参数集。cvModel=crossval.fit(training)#准备测试无标签文件test=spark.createDataFrame([(4,"sparkijk"),(5,"lmn"),(6,"mapreducespark"),(7,"apachehadoop")],["id","text"])#预测测试文档,cvModel使用找到的最佳模型(lrModel)。prediction=cvModel.transform(test)selected=prediction.select("id","text","probability","prediction")forrowinselected.collect():print(row)trainingverificationsplitexceptCrossValidator此外,Spark还提供了TrainValidationSplit用于超参数调优。TrainValidationSplit只计算每个参数组合一次,而在CrossValidator的情况下是k次。因此,它的成本较低,但当训练数据集不够大时,它不会产生可靠的结果。与CrossValidator不同,TrainValidationSplit创建单个(训练、测试)数据集对。它使用trainRatio参数将数据集分成这两部分。例如,当trainRatio=0.75时,TrainValidationSplit将生成训练和测试数据集对,其中75%的数据用于训练,25%用于验证。与CrossValidator一样,TrainValidationSplit最终使用最好的ParamMap和整个数据集匹配Estimator。frompyspark.ml.evaluationimportRegressionEvaluatorfrompyspark.ml.regressionimportLinearRegressionfrompyspark.ml.tuningimportParamGridBuilder,TrainValidationSplit#准备训练和测试数据.data=spark.read.format("libsvm")\.load("data/mllib/sample_linear_regression_data.txt")train,test=data.randomSplit([0.9,0.1],seed=12345)lr=LinearRegression(maxIter=10)#我们使用ParamGridBuilder构建参数网格进行搜索。#TrainValidationSplit会尝试所有值的组合,并使用评估器来确定最佳模型。paramGrid=ParamGridBuilder()\.addGrid(lr.regParam,[0.1,0.01])\.addGrid(lr.fitIntercept,[False,True])\.addGrid(lr.elasticNetParam,[0.0,0.5,1.0])\.build()#在这种情况下,估计器是简单的线性回归。#TrainValidationSplit需要一个Estimator,一组EstimatorParamMaps和一个Evaluator。tvs=TrainValidationSplit(estimator=lr,estimatorParamMaps=paramGrid,evaluator=RegressionEvaluator(),#80%的数据将用于训练,20%用于验证。trainRatio=0.8)#运行TrainValidationSplit并选择最佳参数集。model=tvs.fit(train)#预测测试数据。该模型是参数组合后性能最好的模型。model.transform(测试)\.select(“特征”,“标签”,“预测”)\.show()
