如何交叉验证 RandomForest 模型?
Posted
技术标签:
【中文标题】如何交叉验证 RandomForest 模型?【英文标题】:How to cross validate RandomForest model? 【发布时间】:2015-12-22 13:00:30 【问题描述】:我想评估一个正在对一些数据进行训练的随机森林。 Apache Spark 中是否有任何实用程序可以执行相同操作,还是我必须手动执行交叉验证?
【问题讨论】:
【参考方案1】:ML 提供CrossValidator
类,可用于执行交叉验证和参数搜索。假设您的数据已经过预处理,您可以按如下方式添加交叉验证:
import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.tuning.ParamGridBuilder, CrossValidator
import org.apache.spark.ml.classification.RandomForestClassifier
import org.apache.spark.ml.evaluation.MulticlassClassificationEvaluator
// [label: double, features: vector]
trainingData org.apache.spark.sql.DataFrame = ???
val nFolds: Int = ???
val numTrees: Int = ???
val metric: String = ???
val rf = new RandomForestClassifier()
.setLabelCol("label")
.setFeaturesCol("features")
.setNumTrees(numTrees)
val pipeline = new Pipeline().setStages(Array(rf))
val paramGrid = new ParamGridBuilder().build() // No parameter search
val evaluator = new MulticlassClassificationEvaluator()
.setLabelCol("label")
.setPredictionCol("prediction")
// "f1" (default), "weightedPrecision", "weightedRecall", "accuracy"
.setMetricName(metric)
val cv = new CrossValidator()
// ml.Pipeline with ml.classification.RandomForestClassifier
.setEstimator(pipeline)
// ml.evaluation.MulticlassClassificationEvaluator
.setEvaluator(evaluator)
.setEstimatorParamMaps(paramGrid)
.setNumFolds(nFolds)
val model = cv.fit(trainingData) // trainingData: DataFrame
使用 PySpark:
from pyspark.ml import Pipeline
from pyspark.ml.classification import RandomForestClassifier
from pyspark.ml.tuning import CrossValidator, ParamGridBuilder
from pyspark.ml.evaluation import MulticlassClassificationEvaluator
trainingData = ... # DataFrame[label: double, features: vector]
numFolds = ... # Integer
rf = RandomForestClassifier(labelCol="label", featuresCol="features")
evaluator = MulticlassClassificationEvaluator() # + other params as in Scala
pipeline = Pipeline(stages=[rf])
paramGrid = (ParamGridBuilder.
.addGrid(rf.numTrees, [3, 10])
.addGrid(...) # Add other parameters
.build())
crossval = CrossValidator(
estimator=pipeline,
estimatorParamMaps=paramGrid,
evaluator=evaluator,
numFolds=numFolds)
model = crossval.fit(trainingData)
【讨论】:
您确定这适用于留一法吗?引擎盖下的 kFold() 调用似乎不能确定地返回两个折叠长度 N-1 和 1。当我使用 RegressionEvaluator 和 Lasso 模型运行上面的代码时,我得到:线程“main”中的异常 java.lang.IllegalArgumentException : 要求失败:此摘要器中未添加任何内容。 不,我很确定它不会。MLUtils.kFold
正在使用 BernoulliCellSampler
来确定拆分。另一方面,在 Spark 中执行 leave-one-out 交叉验证的成本可能太高,无法在实践中实现。
您好@zero323,当您在 Evaluator 对象中设置指标时,例如 .setMetricName("precision") 。我的问题是,如何在训练过程中计算出这些指标? (请参考这个问题:***.com/questions/37778532/…)
嘿@zero323,使用交叉验证时是否需要将数据拆分为训练/测试?当 CV 训练和测试多次折叠时,它应该给出五次折叠的准确性训练/测试的平均值吗?或者也许我已经走远了。
@zero323 根据issues.apache.org/jira/browse/SPARK-15771,我认为你应该用“准确度”来改变“精度”【参考方案2】:
要使用 Random Forest Classifier 在 zero323 的出色答案的基础上构建,这里有一个类似的 Random Forest Regressor 示例:
import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.tuning.ParamGridBuilder, CrossValidator
import org.apache.spark.ml.regression.RandomForestRegressor // CHANGED
import org.apache.spark.ml.evaluation.RegressionEvaluator // CHANGED
import org.apache.spark.ml.feature.VectorAssembler, VectorIndexer
val numFolds = ??? // Integer
val data = ??? // DataFrame
// Training (80%) and test data (20%)
val Array(train, test) = data.randomSplit(Array(0.8,0.2))
val featuresCols = data.columns
val va = new VectorAssembler()
va.setInputCols(featuresCols)
va.setOutputCol("rawFeatures")
val vi = new VectorIndexer()
vi.setInputCol("rawFeatures")
vi.setOutputCol("features")
vi.setMaxCategories(5)
val regressor = new RandomForestRegressor()
regressor.setLabelCol("events")
val metric = "rmse"
val evaluator = new RegressionEvaluator()
.setLabelCol("events")
.setPredictionCol("prediction")
// "rmse" (default): root mean squared error
// "mse": mean squared error
// "r2": R2 metric
// "mae": mean absolute error
.setMetricName(metric)
val paramGrid = new ParamGridBuilder().build()
val cv = new CrossValidator()
.setEstimator(regressor)
.setEvaluator(evaluator)
.setEstimatorParamMaps(paramGrid)
.setNumFolds(numFolds)
val model = cv.fit(train) // train: DataFrame
val predictions = model.transform(test)
predictions.show
val rmse = evaluator.evaluate(predictions)
println(rmse)
评估者指标来源: https://spark.apache.org/docs/latest/api/scala/#org.apache.spark.ml.evaluation.RegressionEvaluator
【讨论】:
以上是关于如何交叉验证 RandomForest 模型?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 GridSearchCV 测试回归交叉验证中的过度拟合?