risposta

31

ML fornisce la classe CrossValidator che può essere utilizzata per eseguire la convalida incrociata e la ricerca di parametri. Supponendo che i dati sono già pre-elaborato è possibile aggiungere la convalida incrociata come segue:

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 

Utilizzando 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]) 

crossval = CrossValidator(
    estimator=pipeline, 
    estimatorParamMaps=paramGrid, 
    evaluator=evaluator, 
    numFolds=numFolds) 

model = crossval.fit(trainingData) 
+0

Sei sicuro che questo funzioni per leave-one-out? La chiamata kFold() sotto il cofano non sembra determinare in modo deterministico due lunghezze N-1 e 1. Quando eseguo il codice sopra con un modello RegressionEvaluator e Lazo ottengo: Eccezione nel thread "main" java.lang .IllegalArgumentException: requisito non riuscito: non è stato aggiunto nulla a questo riepilogo. – paradiso

+5

No, sono abbastanza sicuro che non sia così. 'MLUtils.kFold' sta usando' BernoulliCellSampler' per determinare la divisione. D'altra parte, il costo di esecuzione della convalida incrociata di permessi one-out in Spark è probabilmente troppo alto per essere reso praticabile nella pratica. – zero323

+0

Ciao @ zero323, quando si imposta una metrica nell'oggetto Evaluator come .setMetricName ("precisione"). La mia domanda è, come posso ottenere quelle metriche calulate durante il processo di allenamento? (Si prega di fare riferimento a questa domanda: http://stackoverflow.com/questions/37778532/how-to-get-precision-recall-using-crossvalidator-for-training-naivebayes-model-u) – dbustosp

1

Per costruire il grande risposta di zero323 usando a caso Foresta classificatore, ecco un esempio simile per Random Foresta 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) 

Evaluator fonte metrica: https://spark.apache.org/docs/latest/api/scala/#org.apache.spark.ml.evaluation.RegressionEvaluator

Problemi correlati