Estoy jugando con algunos de la cruz-código de validación de la PySpark documentación, y tratando de conseguir PySpark para que me diga cuál es el modelo que se ha seleccionado:

from pyspark.ml.classification import LogisticRegression
from pyspark.ml.evaluation import BinaryClassificationEvaluator
from pyspark.mllib.linalg import Vectors
from pyspark.ml.tuning import ParamGridBuilder, CrossValidator

dataset = sqlContext.createDataFrame(
    [(Vectors.dense([0.0]), 0.0),
     (Vectors.dense([0.4]), 1.0),
     (Vectors.dense([0.5]), 0.0),
     (Vectors.dense([0.6]), 1.0),
     (Vectors.dense([1.0]), 1.0)] * 10,
    ["features", "label"])
lr = LogisticRegression()
grid = ParamGridBuilder().addGrid(lr.regParam, [0.1, 0.01, 0.001, 0.0001]).build()
evaluator = BinaryClassificationEvaluator()
cv = CrossValidator(estimator=lr, estimatorParamMaps=grid, evaluator=evaluator)
cvModel = cv.fit(dataset)

Ejecutando esto en PySpark shell, puede obtener el modelo de regresión lineal de los coeficientes, pero me parece que no puede encontrar el valor de lr.regParam seleccionado por la cruz procedimiento de validación. Alguna idea?

In [3]: cvModel.bestModel.coefficients
Out[3]: DenseVector([3.1573])

In [4]: cvModel.bestModel.explainParams()
Out[4]: ''

In [5]: cvModel.bestModel.extractParamMap()
Out[5]: {}

In [15]: cvModel.params
Out[15]: []

In [36]: cvModel.bestModel.params
Out[36]: []
InformationsquelleAutor Paul | 2016-04-18

6 Comentarios

  1. 27

    Encontré con este problema. Me enteré de que usted necesita llamar a la propiedad java, por alguna razón, no sé por qué. Tan solo hacer esto:

    from pyspark.ml.tuning import TrainValidationSplit, ParamGridBuilder, CrossValidator
    from pyspark.ml.regression import LinearRegression
    from pyspark.ml.evaluation import RegressionEvaluator
    
    evaluator = RegressionEvaluator(metricName="mae")
    lr = LinearRegression()
    grid = ParamGridBuilder().addGrid(lr.maxIter, [500]) \
                                    .addGrid(lr.regParam, [0]) \
                                    .addGrid(lr.elasticNetParam, [1]) \
                                    .build()
    lr_cv = CrossValidator(estimator=lr, estimatorParamMaps=grid, \
                            evaluator=evaluator, numFolds=3)
    lrModel = lr_cv.fit(your_training_set_here)
    bestModel = lrModel.bestModel

    La impresión de los parámetros que desee:

    >>> print 'Best Param (regParam): ', bestModel._java_obj.getRegParam()
    0
    >>> print 'Best Param (MaxIter): ', bestModel._java_obj.getMaxIter()
    500
    >>> print 'Best Param (elasticNetParam): ', bestModel._java_obj.getElasticNetParam()
    1

    Esto se aplica a otros métodos como el de extractParamMap() así. Deberían arreglar esto pronto.

    • Buena captura. Incluso mejor que una solución sería una característica como cvModel.getAllTheBestModelsParametersPlease()
    • La respuesta no funcionó para mí. El correcto es: modelOnly.bestModel.stages[-1]._java_obj.parent().getRegParam(). O si no usa la tubería, sólo quita el stages[-1].
  2. 3

    Suponiendo cvModel3Day es su nombres de los modelos, parámetros pueden ser extraídos como se muestra a continuación en la Chispa de la Scala

    val params = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].extractParamMap()
    
    val depth = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getMaxDepth
    
    val iter = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getMaxIter
    
    val bins = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getMaxBins
    
    val features  = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getFeaturesCol
    
    val step = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getStepSize
    
    val samplingRate  = cvModel3Day.bestModel.asInstanceOf[PipelineModel].stages(2).asInstanceOf[GBTClassificationModel].getSubsamplingRate
  3. 2

    Yo también rebotó en mi cabeza en este muro, por desgracia solo se puede obtener específicos parámetros para específicos modelos. Felizmente para la regresión logística puede acceder a la intersección y pesos, lamentablemente no se puede recuperar la regParam.
    Esto se puede hacer de la siguiente manera:

    best_lr = cv.bestModel
    
    #get weigths
    best_lr.weights
    >>>DenseVector([3.1573])
    
    #or better
    best_lr.coefficients
    >>>DenseVector([3.1573])
    
    #get intercept
    best_lr.intercept
    >>>-1.0829958115287153

    Como escribí antes, cada modelo tiene pocos parámetros que se pueden extraer.
    En general obtener los modelos pertinentes de una Tubería (por ejemplo, cv.bestModel cuando la Cruz Validador se ejecuta a través de una Tubería) se puede hacer con:

    best_pipeline = cv.bestModel
    best_pipeline.stages
    >>>[Tokenizer_4bc8884ad68b4297fd3c,CountVectorizer_411fbdeb4100c2bfe8ef, PCA_4c538d67e7b8f29ff8d0,LogisticRegression_4db49954edc7033edc76]

    Cada modelo se obtiene por simple lista de indexación

    best_lr = best_pipeline.stages[3]

    Ahora los anteriores pueden ser aplicadas.

  4. 2

    Esto podría no ser tan buena como la de wernerchao respuesta (porque no es conveniente para almacenar hyperparameters en variables), pero puede buscar rápidamente en el mejor de hyper-los parámetros de la validación cruzada del modelo de esta manera :

    cvModel.getEstimatorParamMaps()[ np.argmax(cvModel.avgMetrics) ]
  5. 1

    Hay dos preguntas realidad:

    • ¿cuáles son los aspectos del modelo ajustado (como los coeficientes y las intersecciones)
    • lo que se la meta parámetros mediante los cuales el bestModel estaba equipado.

    Lamentablemente la api de python de el conjunto de los estimadores (los modelos) no permite (fácil) acceso directo a los parámetros del estimador, lo que hace difícil responder a la última pregunta.

    Sin embargo hay una solución utilizando la api de java. La integridad, la primera de una instalación completa de una cruz validado el modelo de

    %pyspark
    from pyspark.ml import Pipeline
    from pyspark.ml.classification import LogisticRegression
    from pyspark.ml.evaluation import BinaryClassificationEvaluator
    from pyspark.ml.tuning import CrossValidator, ParamGridBuilder
    logit = LogisticRegression(maxIter=10)
    pipeline = Pipeline(stages=[logit])
    paramGrid = ParamGridBuilder() \
        .addGrid(logit.regParam, [0, 0.01, 0.05, 0.1, 0.5, 1]) \
        .addGrid(logit.elasticNetParam, [0.0, 0.1, 0.5, 0.8, 1]) \
        .build()
    evaluator = BinaryClassificationEvaluator(metricName = 'areaUnderPR')
    crossval = CrossValidator(estimator=pipeline,
                              estimatorParamMaps=paramGrid,
                              evaluator=evaluator,
                              numFolds=5)
    tuned_model = crossval.fit(train)
    model = tuned_model.bestModel

    Uno podría entonces utilizar los métodos genéricos en el objeto de java para obtener los valores de los parámetros, sin explícita referencia a métodos como getRegParam() :

    java_model = model.stages[-1]._java_obj
    {param.name: java_model.getOrDefault(java_model.getParam(param.name)) 
        for param in paramGrid[0]}

    Este ejecuta los siguientes pasos:

    1. Obtener el amueblada modelo logit como la creada por el estimador de la última etapa de la mejor modelo: crossval.fit(..).bestModel.stages[-1]
    2. Obtener la interna de objetos java a partir de _java_obj
    3. Conseguir todo configurado nombres de la paramGrid (que es una lista de diccionarios). Sólo la primera fila se usa, suponiendo que es la misma red, ya que en cada fila contiene las mismas claves. De lo contrario, usted necesita recoger todos los nombres que jamás utilizado en cualquier fila.
    4. Obtener la correspondiente Param<T> parámetro identificador del objeto java.
    5. Pasar el Param<T> instancia a la getOrDefault() función para obtener el valor real
  6. 0

    Esto tomó un par de minutos para descifrar, pero me lo imaginé.

    from pyspark.ml.tuning import CrossValidator, ParamGridBuilder
    
        # prenotation: I've built out my model already and I am calling the validator ParamGridBuilder
    paramGrid = ParamGridBuilder() \
                              .addGrid(hashingTF.numFeatures, [1000]) \
                              .addGrid(linearSVC.regParam, [0.1, 0.01]) \
                              .addGrid(linearSVC.maxIter, [10, 20, 30]) \
                              .build()
    crossval = CrossValidator(estimator=pipeline,\
                              estimatorParamMaps=paramGrid,\
                              evaluator=MulticlassClassificationEvaluator(),\
                              numFolds=2)
    
    cvModel = crossval.fit(train)
    
    prediction = cvModel.transform(test)
    
    
    bestModel = cvModel.bestModel
    
        #applicable to your model to pull list of all stages
    for x in range(len(bestModel.stages)):
    print bestModel.stages[x]
    
    
        #get stage feature by calling correct Transformer then .get<parameter>()
    print bestModel.stages[3].getNumFeatures()

Dejar respuesta

Please enter your comment!
Please enter your name here