Pyspark - 获取使用ParamGridBuilder创建的模型的所有参数

时间:2016-09-16 10:18:00

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

我正在使用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一样显示图形,条形图和工作。

2 个答案:

答案 0 :(得分:5)

Spark 2.4 +

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

默认情况下,此行为已停用,但可以使用CollectSubModels ParamsetCollectSubModels)进行控制。

valid = TrainValidationSplit(
    estimator=pipeline,
    estimatorParamMaps=paramGrid,
    evaluator=evaluator,            
    collectSubModels=True)

model = valid.fit(df)

model.subModels

Spark< 2.4

长话短说明,您无法获取所有模型的参数,因为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)

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

zip(models, params)

答案 1 :(得分:0)

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