【问题标题】:Pyspark - Get all parameters of models created with ParamGridBuilderPyspark - 获取使用 ParamGridBuilder 创建的模型的所有参数
【发布时间】:2017-01-24 12:52:49
【问题描述】:

我正在使用 PySpark 2.0 进行 Kaggle 比赛。我想知道模型(RandomForest)的行为取决于不同的参数。 ParamGridBuilder() 允许为单个参数指定不同的值,然后执行(我猜)整个参数集的笛卡尔积。假设我的DataFrame 已经定义:

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)

好的,现在我可以使用手工制作的功能检索简单的信息:

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

现在我想要几样东西:

  • 最佳模型的参数是什么?这篇文章部分回答了这个问题:How to extract model hyper-parameters from spark.ml in PySpark?
  • 所有型号的参数是多少?
  • 每个模型的结果(也称为召回率、准确率等)是什么?我只发现print(model.validationMetrics) 显示(似乎)包含每个模型的准确性的列表,但我无法知道指的是哪个模型。

如果我可以检索所有这些信息,我应该能够显示图表、条形图,并像使用 Panda 和 sklearn 一样工作。

【问题讨论】:

    标签: python machine-learning pyspark apache-spark-ml hyperparameters


    【解决方案1】:

    Spark 2.4+

    SPARK-21088 CrossValidator, TrainValidationSplit 应该在拟合时收集所有模型 - 添加对收集子模型的支持。

    默认情况下,此行为被禁用,但可以使用 CollectSubModels Param (setCollectSubModels) 进行控制。

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

    火花

    长话短说,您根本无法获得所有模型的参数,因为similarly to CrossValidatorTrainValidationSplitModel 仅保留最佳模型。这些类是为半自动模型选择而不是探索或实验而设计的。

    所有模型的参数是什么?

    虽然您无法检索实际模型 validationMetrics 对应于输入 Params,但您应该能够简单地 zip 两者:

    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()))
    

    了解指标和参数之间的关系。

    如果您需要更多信息,请使用Pipeline Params。它将保留所有可用于进一步处理的模型:

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

    它将生成与params参数对应的PipelineModels列表:

    zip(models, params)
    

    【讨论】:

    • 谢谢,我现在可以获得每个模型的评估指标。不幸的是,zip(model.validationMetrics, model.getEstimatorParamMaps()) 不适用于模型。当我打印 model.params 时,它什么也没显示(我确信我的 paramGrid 工作)
    • 是的,这个建议只是关于TrainValidationSplitModel。我添加了输入提示以避免混淆。
    【解决方案2】:

    我想我已经找到了一种方法来做到这一点。我编写了一个函数,专门为逻辑回归提取超参数,该函数具有两个参数,使用 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
    

    【讨论】:

    • 这看起来不必要的复杂,这真的是最好的方法吗?
    猜你喜欢
    • 1970-01-01
    • 2018-04-10
    • 1970-01-01
    • 2017-07-21
    • 2019-07-11
    • 2019-03-17
    • 2020-02-05
    • 1970-01-01
    • 2017-12-15
    相关资源
    最近更新 更多