Сохраненная модель случайного леса выдает разные результаты для одного и того же набора данных

#apache-spark #pyspark #random-forest #apache-spark-ml #one-hot-encodin&

#apache-spark #pyspark #случайный лес #apache-spark-ml #one-hot-encodin&

Вопрос:

У меня возникли проблемы с воспроизведением результатов с моделью случайного леса, сохраненной на диске, и использованием точно такого же набора данных для прогнозирования. Другими словами, я обучаю модель с набором данных A и сохраняю ее на своем локальном компьютере, затем загружаю ее и использую для прогнозирования набора данных B, каждый раз, когда я прогнозирую набор данных B, я получаю разные результаты.

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

Обучающий скрипт имеет следующую структуру:

 df_train = spark.read.format("csv") 
      .option('header', 'true') 
      .option('inferSchema', 'true') 
      .option('delimiter', ';') 
      .load("C:2020_05.csv") 

#The problem seems to be related to the Strin&Indexer/One-Hot Encodin&
#If I remove all cate&orical variables the results can be reproduced
cate&orical_variables = []
for variable in df_train.dtypes:
    if variable[1] == 'strin&' :
       cate&orical_variables.append(variable[0])

indexers = [Strin&Indexer(inputCol=col, outputCol=col "_indexed") for col in cate&orical_variables]

for indexer in indexers:
    df_train =indexer.fit(df_train).transform(df_train)
    df_train = df_train.drop(indexer.&etInputCol())
      
indexed_cols = []
for variable in df_train.columns:
    if variable.endswith("_indexed"):
        indexed_cols.append(variable)

encoders = []
for variable in indexed_cols:
    inputCol = variable
    outputCol = variable.replace("_indexed", "_encoded")
    one_hot_encoder_estimator_train = OneHotEncoderEstimator(inputCols=[inputCol], outputCols=[outputCol])

    encoder_model_train = one_hot_encoder_estimator_train.fit(df_train)
    df_train = encoder_model_train.transform(df_train)
    df_train = df_train.drop(inputCol)


inputCols = [x for x in df_train.columns if x != "id" and x != "churn"]

vector_assembler_train = VectorAssembler(
      inputCols=inputCols,
      outputCol='features',
      handleInvalid='keep'
)

df_train = vector_assembler_train.transform(df_train)

df_train = df_train.select('churn', 'features', 'id')

df_train_1 = df_train.filter(df_train['churn'] == 0).sample(withReplacement=False, fraction=0.3, seed=7)
df_train_2 = df_train.filter(df_train['churn'] == 1).sample(withReplacement=True, fraction=20.0, seed=7)
df_train = df_train_1.unionAll(df_train_2) 

rf = RandomForestClassifier(labelCol="churn", featuresCol="features")
  paramGrid = ParamGridBuilder() 
      .addGrid(rf.numTrees, [100]) 
      .addGrid(rf.maxDepth, [15]) 
      .addGrid(rf.maxBins, [32]) 
      .addGrid(rf.featureSubsetStrate&y, ['onethird']) 
      .addGrid(rf.subsamplin&Rate, [1.0])
      .addGrid(rf.minInfoGain, [0.0])
      .addGrid(rf.impurity, ['&ini']) 
      .addGrid(rf.minInstancesPerNode, [1]) 
      .addGrid(rf.seed, [10]) 
  .build()



  evaluator = BinaryClassificationEvaluator(
      labelCol="churn")

  crossval = CrossValidator(estimator=rf,
                            estimatorParamMaps=paramGrid,
                            evaluator=evaluator,
                            numFolds=3)
  model = crossval.fit(df_train)
  model.save("C:/myModel")

  

Сценарий тестирования выглядит следующим образом:

 df_test = spark.read.format("csv") 
      .option('header', 'true') 
      .option('inferSchema', 'true') 
      .option('delimiter', ';') 
      .load("C:2020_06.csv")
  
#The problem seems to be related to the Strin&Indexer/One-Hot Encodin&
#If I remove all cate&orical variables the results can be reproduced
cate&orical_variables = []
for variable in df_test.dtypes:
    if variable[1] == 'strin&' :
       cate&orical_variables.append(variable[0])

indexers = [Strin&Indexer(inputCol=col, outputCol=col "_indexed") for col in cate&orical_variables]

for indexer in indexers:
    df_test =indexer.fit(df_test).transform(df_test)
    df_test = df_test.drop(indexer.&etInputCol())
      
indexed_cols = []
for variable in df_test.columns:
    if variable.endswith("_indexed"):
        indexed_cols.append(variable)

encoders = []
for variable in indexed_cols:
    inputCol = variable
    outputCol = variable.replace("_indexed", "_encoded")
    one_hot_encoder_estimator_test = OneHotEncoderEstimator(inputCols=[inputCol], outputCols=[outputCol])

    encoder_model_test= one_hot_encoder_estimator_test.fit(df_test)
    df_test= encoder_model_test.transform(df_test)
    df_test= df_test.drop(inputCol)


inputCols = [x for x in df_test.columns if x != "id" and x != "churn"]

vector_assembler_test = VectorAssembler(
      inputCols=inputCols,
      outputCol='features',
      handleInvalid='keep'
)

df_test = vector_assembler_test.transform(df_test)

df_test = df_test.select('churn', 'features', 'id')


model = CrossValidatorModel.load("C:/myModel")

result = model.transform(df_test)

areaUnderROC = evaluator.evaluate(result)

tp = result.filter("prediction == 1.0 AND churn == 1").count()
tn = result.filter("prediction == 0.0 AND churn == 0").count()
fp = result.filter("prediction == 1.0 AND churn == 0").count()
fn = result.filter("prediction == 0.0 AND churn == 1").count()
  

Каждый раз, когда я запускаю сценарий тестирования, AUC и матрица путаницы всегда разные.
Я использую Spark 2.4.5 и Python 3.7 на компьютере с Windows 10.
Мы высоко ценим любое предложение или идею.

Редактировать: проблема связана с этапами кодирования Strin&Indexer / One-Hot. Когда я использую только числовые переменные, я могу воспроизвести результаты. Вопрос все еще открыт, поскольку я не могу объяснить, почему это происходит.

Комментарии:

1. Каждый раз, когда вы получаете другой результат, вы проверяли, что ваши обучающие / тестовые данные остаются неизменными?

2. @AhmetTavli в каждом выполнении одинаковое количество строк и столбцов

Ответ №1:

По моему опыту, эта проблема связана с тем, что вы повторно оцениваете OneHotEncoder в test.

Вот как работает OneHotEncodin&, из документов:

Одноразовый кодировщик, который сопоставляет столбец индексов категорий со столбцом двоичных векторов, причем в строке не более одного значения, указывающего индекс входной категории. Например, при использовании 5 категорий входное значение 2.0 будет соответствовать выходному вектору [0.0, 0.0, 1.0, 0.0]. Последняя категория не включена по умолчанию (настраивается через dropLast), поскольку она приводит к суммированию векторных записей до единицы и, следовательно, к линейной зависимости. Таким образом, входное значение 4.0 соответствует [0.0, 0.0, 0.0, 0.0].

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

Вам следует добавить OneHotEncoder в конвейер вместе с вашей обученной моделью, подогнать ее и затем сохранить, а затем снова загрузить в тест. Таким образом, значения в кодировке One Hot гарантированно совпадают с одними и теми же значениями при каждом запуске данных по конвейеру.

Более подробную информацию о конвейерах сохранения и загрузки можно найти в документации.

Комментарии:

1. Спасибо! Я попробую. Если это сработает, я приму этот ответ как решение.