PySpark: несоответствие между CrossValidator.avgMetrics и средним значением, вычисленным по collectSubModels - PullRequest
0 голосов
/ 09 апреля 2020

Я настроил объект CrossValidator в сочетании с конвейером линейной регрессии и сеткой гиперпараметров для выбора. В частности, я запускаю 5-кратную перекрестную проверку на 9 различных настройках, полученных в результате сочетания двух гиперпараметров (каждый из которых принимает 3 значения), и отслеживаю все 45 полученных моделей, устанавливая collectSubModels флаг True:

...

lr = LinearRegression(featuresCol="features", labelCol="label")

pipeline = Pipeline(stages=indexers + [encoder] + [assembler] + [lr])

param_grid = ParamGridBuilder()\
        .addGrid(lr.regParam, [0.0, 0.05, 0.1]) \
        .addGrid(lr.elasticNetParam, [0.0, 0.5, 1.0])\
        .build()

cross_val = CrossValidator(estimator=pipeline, 
                           estimatorParamMaps=param_grid,
                           evaluator=RegressionEvaluator(metricName="rmse"),
                           numFolds=5,
                           collectSubModels=True
                           )

# Run cross-validation, and choose the best set of parameters
cv_model = cross_val.fit(train)

return cv_model

Кажется, что все идет гладко, за исключением того факта, что когда я печатаю производительность (т. Е. Среднеквадратичное значение) каждой модели (т. Е. 9 моделей для каждый раз), и я пытаюсь «вручную» вычислить среднее значение для каждого раза, полученные в результате 9 средних значений не вообще совпадают со значениями, которые я получаю, когда использую внутреннее свойство avgMetrics CrossValidator. Просто в качестве примера приведем следующие 5 значений RMSE, которые я получил, используя первую комбинацию двух гиперпараметров (т. Е. Оба установлены в 0):

*************** Fold #1 ***************
--- Model #1 out of 9 ---
    Parameters: lambda=[0.000]; alpha=[0.000] 
    RMSE: 149354.656

*************** Fold #2 ***************
--- Model #1 out of 9 ---
    Parameters: lambda=[0.000]; alpha=[0.000] 
    RMSE: 146038.521

*************** Fold #3 ***************
--- Model #1 out of 9 ---
    Parameters: lambda=[0.000]; alpha=[0.000] 
    RMSE: 148739.919

*************** Fold #4 ***************
--- Model #1 out of 9 ---
    Parameters: lambda=[0.000]; alpha=[0.000] 
    RMSE: 146816.473

*************** Fold #5 ***************
--- Model #1 out of 9 ---
    Parameters: lambda=[0.000]; alpha=[0.000] 
    RMSE: 149868.621

Как видите, все значения RMSE ниже 150000. Я ожидал, что если бы я взял среднее из этих значений выше, я бы получил первый элемент списка avgMetrics (который, действительно, предположительно содержит среднее значение перекрестной проверки для каждой комбинации гиперпараметров, вычисленной по сгибам). Вместо этого, если я использую cv_model.avgMetrics, я получу следующее:

[150091.7372030353, 150091.7372030353, 150091.7372030353, 150091.7345116686, 150093.66131828527, 150090.52769066638, 150091.7338301999, 150090.52716106002, 150091.59829053417]

Ожидается 9 элементов, но ни один из них не выглядит правильно! На самом деле, все они превышают 150 000, хотя ни одна из моих 45 моделей (не только те 5, которые я перечислил выше) достигает этих цифр.

Похоже, что заполнение avgMetrics неверно. Я знаю, что была проблема еще в 2016 году, когда это значение по ошибке содержало сумму показателей перекрестной проверки, а не среднее значение, но, по-видимому, это было исправлено .

Я также пытался проверить текущая реализация метода _fit объекта CrossValidator и - хотя я не слишком много времени уделял этому - по-видимому, все выглядит хорошо:

for i in range(nFolds):
    validateLB = i * h
    validateUB = (i + 1) * h
    condition = (df[randCol] >= validateLB) & (df[randCol] < validateUB)
    validation = df.filter(condition).cache()
    train = df.filter(~condition).cache()

    tasks = _parallelFitTasks(est, train, eva, validation, epm, collectSubModelsParam)
    for j, metric, subModel in pool.imap_unordered(lambda f: f(), tasks):
        metrics[j] += (metric / nFolds)
        if collectSubModelsParam:
            subModels[i][j] = subModel

Имеет кто-нибудь еще сталкивался с такой же проблемой?

РЕДАКТИРОВАТЬ: Я слепо предположил, что проблема (если таковая имеется) в avgMetrics свойство; однако, возможно, что эти средние значения на самом деле верны, в то время как отдельные показатели, которые я напечатал выше, вызывая .summary.rootMeanSquaredError для каждой подмодели, вычисляются неправильно. В любом случае, между ними есть явное несоответствие.

1 Ответ

0 голосов
/ 23 апреля 2020

Я отправил этот вопрос непосредственно на Apache Spark github , и мне сказали, что я делаю не так.

Я публикую ответ здесь, если кто-то та же проблема.

По сути, я думал, что распечатываю отдельные среднеквадратичные среднеквадратичные среднеквадратичные значения, измеренные в задержанной (т.е. проверочной) части каждого (k) прогона перекрестной проверки. На самом деле я вместо этого распечатывал среднеквадратическое среднеквадратичное значение, вычисленное для части обучающего набора (каждого сгиба).

Очевидно, что нет простого способа вспомнить, что я пытался получить, так как эта информация, похоже, не хранится в любом случае. Хорошей новостью является то, что среднее значение перекрестной проверки имеет смысл.

Надеюсь, это поможет.

...