处理标签编码的未知值

Posted

技术标签:

【中文标题】处理标签编码的未知值【英文标题】:Handling unknown values for label encoding 【发布时间】:2017-03-12 07:11:31 【问题描述】:

如何处理 sk-learn 中标签编码的未知值? 标签编码器只会在检测到新标签的情况下崩溃。

我想要的是通过 one-hot-encoder 对分类变量进行编码。但是,sk-learn 不支持字符串。所以我在每一列上都使用了一个标签编码器。

我的问题是在管道的交叉验证步骤中出现了未知标签。 基本的 one-hot-encoder 可以选择忽略这种情况。 apriori pandas.getDummies /cat.codes 是不够的,因为管道应该处理现实生活中可能包含未知标签的新传入数据。

是否可以为此使用CountVectorizer

【问题讨论】:

您有用于此目的的示例插图吗? 你能捕捉到异常,记录它(或其他),然后继续吗?还是直接忽略它们? 如果将预测模型部署为 API,它很可能会遇到未知的特征标签。我该如何在sklearn中处理?您是否建议将错误传播到 API? @GeorgHeiler,您是否尝试过查看DictVectorizer,它对字符串特征进行二进制一热编码?但是,您需要输入字典列表。因此,选择存在分类值的子集并执行df[cat_cols].to_dict(orient='records') 之类的操作来创建字典列表的映射,然后将其馈送到DictVectorizer。这些也可以包含在管道中,供 scikit-learn 估计器使用。 @NickilMaveli 我用它做了一些试验,但还没有让它工作。 【参考方案1】:

编辑:

最近使用 scikit-learn 处理这个问题的更简单/更好的方法是使用类 sklearn.preprocessing.OneHotEncoder

from sklearn.preprocessing import OneHotEncoder

enc = OneHotEncoder(handle_unknown='ignore')
enc.fit(train)

enc.transform(train).toarray()

旧答案:

有几个答案提到pandas.get_dummies 作为一种方法,但我觉得labelEncoder 方法对于实现模型更干净。 其他类似的答案提到为此使用DictVectorizer,但再次将整个DataFrame 转换为dict 可能不是一个好主意。

让我们假设以下有问题的列:

from sklearn import preprocessing
import numpy as np
import pandas as pd

train = 'city': ['Buenos Aires', 'New York', 'Istambul', 'Buenos Aires', 'Paris', 'Paris'],
        'letters': ['a', 'b', 'c', 'd', 'a', 'b']
train = pd.DataFrame(train)

test = 'city': ['Buenos Aires', 'New York', 'Istambul', 'Buenos Aires', 'Paris', 'Utila'],
        'letters': ['a', 'b', 'c', 'a', 'b', 'b']
test = pd.DataFrame(test)

Utila 是一个比较稀有的城市,它不在训练数据中而是在测试集中,我们可以在推理时考虑新数据。

诀窍是将此值转换为“其他”并将其包含在 labelEncoder 对象中。然后我们可以在生产中重用它。

c = 'city'
le = preprocessing.LabelEncoder()
train[c] = le.fit_transform(train[c])
test[c] = test[c].map(lambda s: 'other' if s not in le.classes_ else s)
le_classes = le.classes_.tolist()
bisect.insort_left(le_classes, 'other')
le.classes_ = le_classes
test[c] = le.transform(test[c])
test

  city  letters
0   1   a
1   3   b
2   2   c
3   1   a
4   4   b
5   0   b

要将其应用于新数据,我们只需为每一列保存一个le 对象,这可以使用 Pickle 轻松完成。

此答案基于此question,我觉得我并不完全清楚,因此添加了此示例。

【讨论】:

您的意思是区别在于您的解决方案只需要内存中的一列,而我的解决方案需要内存中的所有列? Sehr 你会建议其他还是空?我认为 null 也很好,因为预处理代码会在标签编码器之前处理它。 如果在le.classes_ 中存在比other 更大的值,bisect.insort_left(le_classes, 'other') 最终会在该元素之前插入other 吗?如果是这种情况,other 之后元素的代码会发生变化,从而损害代码映射的完整性。 在修改 labelEncoder 之前注意不要做le.fit_transform(train[c])。否则 labelEncoder 的映射在训练和测试上是不一样的。而是执行le.fit(train[c]),然后在修改labelEncoder 后执行le.transform(train[c]) 将旧答案中的 le.classes_ = le_classes 更改为 le.classes_ = np.array(le_classes) 以保留 preprocessing.LabelEncoder().inverse_transform() 的有用性

以上是关于处理标签编码的未知值的主要内容,如果未能解决你的问题,请参考以下文章

在 Adob​​e AIR 中读取未知编码的文本文件

标签编码器编码缺失值

按值计数的标签编码

SKLearn:标签编码分类值的虚拟变量

如何在 .Net 中创建和解析标签、长度、值 (TLV) 并在 Base64 中对其进行编码

one-hot code 独热编码