Static Categorical Variables
参考: http://contrib.scikit-learn.org/category_encoders
参考: https://github.com/YC-Coder-Chen/feature-engineering-handbook
真实世界的数据集还往往包含类别特征。但是由于scikit-learn中的模型只能处理数值特征,因此我们需要将类别特征编码为数值特征但是,很多新的模型开始直接提供类别变量支持,例如lightGBM和Catboost。
这里我们使用category_encoders包,因为它涵盖了更多的编码方法。
1. Ordinal Encoding 序列编码
把所有的相同类别的特征编码成同一个值,例如女=0,男=1,狗狗=2,所以最后编码的特征值是在[0, n-1]之间的整数。
缺点:这个编码的缺点在于它随机的给特征排序了,会给这个特征增加不存在的顺序关系,也就是增加了噪声,与编码后特征的顺序不存在相关性。
from category_encoders import OrdinalEncoder
encoder = OrdinalEncoder(cols = ['a', 'b'],
handle_unknown = 'value',
handle_missing = 'value').fit(train_set,train_y) # 在训练集上训练
# 将 handle_unknown设为‘value’,即测试集中的未知特征值将被标记为-1
# 将 handle_missing设为‘value’,即测试集中的缺失值将被标记为-2
# 其他的选择为:‘error’:即报错;‘return_nan’:即未知值/缺失之被标记为nan
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集
2. One-hot Encoding 独热编码
Onehot方法会创建出对应的N列特征,其中每列代表该样本是否为该特征的某一种取值。因为生成的每一列有值的都是1,所以这个方法起名为Onehot特征。Dummy特征也是一样,只是少了一列,因为第N列可以看做是前N-1列的线性组合。
缺点:但是在离散特征的特征值过多的时候不宜使用,因为会导致生成特征的数量太多且过于稀疏。
from category_encoders import OneHotEncoder
encoder = OneHotEncoder(cols=['a', 'b'],
handle_unknown='indicator',
handle_missing='indicator',
use_cat_names=True).fit(train_set,train_y) # 在训练集上训练
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集
# 将 handle_unknown设为‘indicator’,即会新增一列指示未知特征值
# 将 handle_missing设为‘indicator’,即会新增一列指示缺失值
# 其他的handle_unknown/handle_missing 的选择为:
# ‘error’:即报错; ‘return_nan’:即未知值/缺失之被标记为nan; ‘value’:即未知值/缺失之被标记为0
3. Target Encoding 目标编码
由名字目标编码就可以猜到,目标编码是一种不仅基于特征值本身,还基于相应因变量的类别变量编码方法。
对于分类问题:将类别特征替换为给定某一特定类别值的因变量后验概率与所有训练数据上因变量的先验概率的组合。
对于连续目标:将类别特征替换为给定某一特定类别值的因变量目标期望值与所有训练数据上因变量的目标期望值的组合。
该方法严重依赖于因变量(target)的分布,但这大大减少了生成编码后特征的数量。
参考文献: Micci-Barreca, D. (2001). A preprocessing scheme for high-cardinality categorical attributes in classification and prediction problems. ACM SIGKDD Explorations Newsletter, 3(1), 27-32.
from category_encoders import OneHotEncoder
encoder = TargetEncoder(cols=['a','b'],
handle_unknown='value',
handle_missing='value').fit(train_set,train_y) # 在训练集上训练
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集
# handle_unknown 和 handle_missing 被设定为 'value'
# 在目标编码中,handle_unknown 和 handle_missing 仅接受 ‘error’, ‘return_nan’ 及 ‘value’ 设定
# 两者的默认值均为 ‘value’, 即对未知类别或缺失值填充训练集的因变量平均值
4. Hashing Encoding 哈希编码
哈希编码基于特征哈希的方法。它将哈希函数应用于变量,将任意数量的变量以一定的规则映射到给定数量的变量。特征哈希可能会导致要素之间发生冲突。但哈希编码的优点是它不需要制定和维护原变量与新变量之间的映射关系。因此,哈希编码器的大小及复杂程度不随数据类别的增多而增多。
- 通常哈希编码应用于更高和更稀疏的维空间
- 哈希编码结果与训练集/测试集中的内容无关
- 只要列名匹配,我们就可以在任何新数据集上使用哈希编码方法
- 编码结果仅由哈希函数确定
# 将两列的数据集哈希编码为5列
encoder = HashingEncoder(cols=['a', 'b'],
n_components = 5).fit(train_set,train_y)
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集
5. Catboost Encoder Catboost 编码
CatBoost是一个基于树的梯度提升模型。其在包含大量类别特征的数据集问题中具有出色的效果。该模型针对分类特征提出了一种基于“留一法编码器”的新编码系统。在使用Catboost编码器之前,必须先对训练数据随机排列,因为在Catboost中,编码是基于“时间”的概念,即数据集中观测值的顺序。
from category_encoders.cat_boost import CatBoostEncoder
# 事实上,在使用Catboost编码前,我们本应先打乱数据顺序
#dataset= dataset.reindex(np.random.permutation(cities.index))
# 但由于我们的数据本身已经是随机生成的,故无需打乱
encoder = CatBoostEncoder(cols=['a','b'],
handle_unknown='value',
handle_missing='value').fit(train_set,train_y) # 在训练集上训练
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集
# handle_unknown 和 handle_missing 被设定为 'value'
# 在目标编码中,handle_unknown 和 handle_missing 仅接受 ‘error’, ‘return_nan’ 及 ‘value’ 设定
# 两者的默认值均为 ‘value’, 即对未知类别或缺失值填充训练集的因变量平均值