我正在使用 Spark (core/mlib) 和 Java,版本 2.3.1。
我正在对数据集应用三种转换 - StringIndexer、OneHotEncoderEstimator、VectorAssember - 这是为了将数据集中的分类变量转换为每个类别的 1 和 0 的单独列。在我的火车数据上,这种转换没有任何问题,一切都按预期进行,我正在将此模型保存到文件中。
当我尝试在新数据点上使用此模型时,我的问题出现了:
public static double loadModel(Obj newData) {
SparkSession spark = Shots.buildSession();
//Function which applies transformations
Dataset<Row> data = buildDataset(spark, Arrays.asList(newData));
LogisticRegressionModel lrModel = LogisticRegressionModel.load(modelPath);
//Error is thrown here as the model doesn't seem to understand the input
Dataset<Row> preds = lrModel.transform(data);
preds.show();
}
我认为,问题在于转换现在仅应用于一行数据,该数据仅输出分类特征的一个类别以及转换后仅包含一个元素的向量。当应用 LogisticRegressionModel 变换时,这会导致错误,该变换期望该特征的长度大于一的向量......我认为。
我知道我的错误是不知道如何将火车变换应用于新数据......但我不确定错误到底在哪里,因此,不知道在哪里找到答案(是保存的问题)模型,我是否需要保存其他东西,例如管道等)。
实际抛出的错误是-
java.lang.IllegalArgumentException: requirement failed: BLAS.dot(x: Vector, y:Vector) was given Vectors with non-matching sizes: x.size = 7, y.size = 2 - the reason why I have come to the conclusions above is a visual examination of the data.
一个例子可能有助于解释:我有一个具有 3 个值的分类特征 [是、否、也许]。我的训练数据包括所有三个值,我最终得到长度为 3 的向量特征来表示类别。
然后,我在单个数据点上使用相同的管道来预测一个值,但分类特征只能是“是”、“否”或“也许”,因为只有一个数据点。因此,当您应用与上面相同的转换时,您最终会得到一个包含一个元素的向量,而不是三个元素,从而导致模型转换抛出错误。
一般来说你没有正确使用API。正确的工作流程应包括保留在流程中训练的一整套
Models
(在您的情况下至少是 StringIndexerModel
,其他组件看起来像 Transformers
)并将其重新应用到新数据上。
最方便的方法是使用
Pipeline
:
val pipeline = new Pipeline().setStages(Arrray(indexer, encoder, assembler, lr))
val pipelineModel = pipeline.fit(data)
pipelineModel.transform(data)
PipelineModels
可以保存为任何其他组件,只要它的所有阶段都是可写的。
这里的问题是我在错误的位置保存了模型。
为了保留先前转换的效果,您需要使管道适合数据然后写入/保存模型。这意味着保存 PipelineModel 而不是 Pipeline。如果您在加载数据后适合,那么转换将完全重新应用,并且您将丢失转换工作所需的状态。
我也面临着同样的问题。 StringIndexer 对于测试中的新值或新数据将失败,因此我们可以选择跳过这些未知值。
new StringIndexer().setHandleInvalid("skip")
或者将训练数据和测试数据的并集传递到管道并在转换后将其拆分。
您有两个选择:
handle_data_PipelineModel ==> df ---> split_dataset ==> train_df/test_df--> arithmetic_PipelineModel----->test_model--->evaluate
df == > split_dataset ==> train_df/test_df--> PipelineModel(handle_data_stage and arithmetic_stage) ---> probably error
选项 1 是安全的:您需要保存
handle_data_PipelineModel
和 arithmetic_PipelineModel
。
选项2不好:无论你如何保存模型。当你先分割数据时,
train_df
和test_df
的分布会发生变化。
注意:划分后的数据集一定不能处理PipelineModel之前的数据。
我遇到了同样的问题,发现问题是您需要确保保存数据处理模型并加载这些模型来处理新数据。此外,应保存 LogisticRegressionModel,然后加载以应用于新数据。 例如:
确保使用与训练时使用 train_data 相同的拟合 oneHotEncoder 和 LogisticRegressionModel,将它们应用到新数据以确保结构一致