#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. Спасибо! Я попробую. Если это сработает, я приму этот ответ как решение.