我们不使用Pipeline,所以我们只需要保存OneHotEncoder状态以在不同的过程中使用。 pickle由于安全性和向后兼容性问题而joblib被皱眉,因此也被皱眉。更准确地说,我们希望找到一种更好/不同的方法来从训练中保存编码器状态,并在以后的评分中使用它。我们最终做了以下事情:
- 像往常一样在训练期间适应/变换
- 从训练时编码器中获取有序类别并将其保存为 json/yaml。
- 在生产运行期间,阅读有序类别并使用这些类别来补充新的编码。它需要一点动力才能开始(见下面的例子)。
- 更重要的是,它允许我们在生产过程中改变编码器的行为,例如使其适应迄今为止未知的类别。
以下是演示该方法的示例代码:
import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder
ds = pd.DataFrame(
{
"colors": ["red", "red", "white", "blue"],
"fruits": ["apple", "orange", "apple", "orange"],
}
)
这是我们的示例数据集
colors fruits
0 red apple
1 red orange
2 white apple
3 blue orange
让我们对数据进行编码:
encoder_training = OneHotEncoder(sparse=False)
encoded_colors = encoder_training.fit_transform(np.array(ds.colors).reshape(-1, 1))
encoded_colors
编码如下:
array([[0., 1., 0.],
[0., 1., 0.],
[0., 0., 1.],
[1., 0., 0.]])
正如预期的那样,这个不能容忍未知类别。
encoder_training.transform(np.array("black").reshape(-1, 1))
这将给出以下错误。
ValueError: Found unknown categories ['black'] in column 0 during transform
然而,在拟合之后,编码器包含已编码用于生成编码的类别的有序列表(因此模型正在使用这些类别)
color_categories = encoder_training.categories_
这是它的内容
color_categories
[array(['blue', 'red', 'white'], dtype=object)]
现在让我们为生产/评分创建另一个编码。但是请注意,这需要有不同的行为来处理unknown值。为什么?因为通常对生产的需求(有时甚至是负责人)可能与培训的需求不同。例如,如果编码器在包括测试/保留集在内的整个训练数据集上运行,那么它永远不必处理未知类别。
encoder_production = OneHotEncoder(
handle_unknown="ignore", sparse=False, categories=color_categories
)
我们为它提供了从训练编码器中获取的有序类别数组。在实践中,这将在训练期间序列化为 json/yaml,并在生产 python 过程中加载回。注意:我sparse=False只是为了方便查看示例中的编码。
奇怪的是,我们不能直接使用它,首先我们需要引导它!这可以是任何东西。为避免任何类型不匹配问题,我们只需使用类别列表中的第一项
encoder_production.fit(np.array(color_categories[0][0]).reshape(-1, 1))
现在我们的编码器已经准备好迎接黄金时段了!
encoder_production.transform(np.array("red").reshape(-1, 1))
这打印:
array([[0., 1., 0.]])
与训练实例不同,这个实例可以容忍未知值
encoder_production.transform(np.array("black").reshape(-1, 1))
这打印:
array([[0., 0., 0.]])