Pyspark: obtenga todos los parámetros de los modelos creados con ParamGridBuilder

Estoy usando PySpark 2.0 para una competencia de Kaggle. Me gustaría saber el comportamiento de un modelo ( RandomForest ) dependiendo de diferentes parámetros. ParamGridBuilder() permite especificar diferentes valores para un solo parámetro y luego realizar (supongo) un producto cartesiano de todo el conjunto de parámetros. Suponiendo que mi DataFrame ya está definido:

 rdc = RandomForestClassifier() pipeline = Pipeline(stages=STAGES + [rdc]) paramGrid = ParamGridBuilder().addGrid(rdc.maxDepth, [3, 10, 20]) .addGrid(rdc.minInfoGain, [0.01, 0.001]) .addGrid(rdc.numTrees, [5, 10, 20, 30]) .build() evaluator = MulticlassClassificationEvaluator() valid = TrainValidationSplit(estimator=pipeline, estimatorParamMaps=paramGrid, evaluator=evaluator, trainRatio=0.50) model = valid.fit(df) result = model.bestModel.transform(df) 

OK, ahora puedo recuperar información simple con una función hecha a mano:

 def evaluate(result): predictionAndLabels = result.select("prediction", "label") metrics = ["f1","weightedPrecision","weightedRecall","accuracy"] for m in metrics: evaluator = MulticlassClassificationEvaluator(metricName=m) print(str(m) + ": " + str(evaluator.evaluate(predictionAndLabels))) 

Ahora quiero varias cosas:

  • ¿Cuáles son los parámetros del mejor modelo? Esta publicación responde parcialmente a la pregunta: ¿Cómo extraer los hiperv parámetros del modelo de spark.ml en PySpark?
  • ¿Cuáles son los parámetros de todos los modelos?
  • ¿Cuáles son los resultados (también conocido como memoria, precisión, etc.) de cada modelo? Solo encontré print(model.validationMetrics) que muestra (parece) una lista que contiene la precisión de cada modelo, pero no puedo saber qué modelo referir.

Si puedo recuperar toda esa información, debería poder mostrar gráficos, gráficos de barras y trabajar como lo hago con Panda y sklearn .

Spark 2.4+

SPARK-21088 CrossValidator, TrainValidationSplit debe recostackr todos los modelos al momento de la instalación : agrega soporte para la recolección de submodelos.

De forma predeterminada, este comportamiento está deshabilitado, pero se puede controlar mediante CollectSubModels Param ( setCollectSubModels ).

 valid = TrainValidationSplit( estimator=pipeline, estimatorParamMaps=paramGrid, evaluator=evaluator, collectSubModels=True) model = valid.fit(df) model.subModels 

Chispa <2.4

En pocas palabras, simplemente no puede obtener parámetros para todos los modelos porque, al igual que CrossValidator , TrainValidationSplitModel solo conserva el mejor modelo. Estas clases están diseñadas para la selección semiautomática de modelos, no para exploración o experimentos.

¿Cuáles son los parámetros de todos los modelos?

Si bien no puede recuperar los modelos reales, validationMetrics corresponde con los Params entrada, por lo que debería poder simplemente zip ambos:

 from typing import Dict, Tuple, List, Any from pyspark.ml.param import Param from pyspark.ml.tuning import TrainValidationSplitModel EvalParam = List[Tuple[float, Dict[Param, Any]]] def get_metrics_and_params(model: TrainValidationSplitModel) -> EvalParam: return list(zip(model.validationMetrics, model.getEstimatorParamMaps())) 

para obtener algo sobre la relación entre las métricas y los parámetros

Si necesita más información, debe utilizar Pipeline Params . Conservará todos los modelos que pueden utilizarse para el procesamiento posterior:

 models = pipeline.fit(df, params=paramGrid) 

Generará una lista de los PipelineModels correspondientes al argumento params :

 zip(models, params) 

Creo que he encontrado una manera de hacer esto. Escribí una función que específicamente extrae hiperparámetros para una regresión logística que tiene dos parámetros, creados con un CrossValidator:

 def hyperparameter_getter(model_obj,cv_fold = 5.0): enet_list = [] reg_list = [] ## Get metrics metrics = model_obj.avgMetrics assert type(metrics) is list assert len(metrics) > 0 ## Get the paramMap element for x in range(len(model_obj._paramMap.keys())): if model_obj._paramMap.keys()[x].name=='estimatorParamMaps': param_map_key = model_obj._paramMap.keys()[x] params = model_obj._paramMap[param_map_key] for i in range(len(params)): for k in params[i].keys(): if k.name =='elasticNetParam': enet_list.append(params[i][k]) if k.name =='regParam': reg_list.append(params[i][k]) results_df = pd.DataFrame({'metrics':metrics, 'elasticNetParam': enet_list, 'regParam':reg_list}) # Because of [SPARK-16831][PYTHON] # It only sums across folds, doesn't average spark_version = [int(x) for x in sc.version.split('.')] if spark_version[0] <= 2: if spark_version[1] < 1: results_df.metrics = 1.0*results_df['metrics'] / cv_fold return results_df