【问题标题】:How to cross validate RandomForest model?如何交叉验证 RandomForest 模型?
【发布时间】:2015-12-22 13:00:30
【问题描述】:

我想评估一个正在对一些数据进行训练的随机森林。 Apache Spark 中是否有任何实用程序可以执行相同操作,还是我必须手动执行交叉验证?

【问题讨论】:

    标签: apache-spark random-forest cross-validation apache-spark-ml apache-spark-mllib


    【解决方案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") 。我的问题是,如何在训练过程中计算出这些指标? (请参考这个问题:stackoverflow.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

    【讨论】:

      猜你喜欢
      • 2019-09-17
      • 2013-05-19
      • 2014-08-13
      • 2020-02-06
      • 2014-02-18
      • 2013-12-08
      • 2016-05-26
      • 2020-03-26
      • 2015-05-01
      相关资源
      最近更新 更多