特征工程-类别特征处理

在表格型数据建模上,核心就是特征工程,而特征工程的核心在于类别特征处理,作者最近在做讯飞酒店价格预测比赛以及时间序列建模相关模型,现在将类别特征处理总结如下。

先解释一下什么是类别特征,如数据集合中出现的枚举类别特征:性别: “男”, “女”; 颜色: “红色”,“白色”,“蓝色”....

类别特征处理的核心就是对类别特征进行编码,首先思考为什么需要对类别特征进行编码?这里要从数据集合在数据集上建模的算法回答:1.首先一方面实际数据集中,充斥着大量的类别特征,如性别,颜色,省市等行政划分,这些都是以字符的形式存在数据集合中,截止到目前为止,只有较少的建模算法能直接处理这样的数据特征(朴素贝叶斯、lightGBM、CatBoost) 等树基于熵减类模型,绝大多数建模算法需要对这类特征进行转化为数值特征,输入模型进行运算才能使用;2.另一方面直接使用离散特征,在模型效果上较差,这时候需要人为的添加先验信息,对离散特征进行一定程度的编码之后输入到模型。这是需要将离散特征进行编码的根本原因。接下来介绍具体编码方法One-Hot Encoder、Label Encoder、O、Target Encoder、CatBoost Encoder、Embedding 5种大类编码方法。

  1. One-Hot Encoder
from sklearn.preprocessing import OneHotEncoder
data = [["本科", "男"],["硕士", "女"], ["博士", "女"], ["大专", "人妖"]]
encoder = OneHotEncoder().fit(data)
test_data1 = [["博士","男"]]
encoder_data1 = encoder.transform(test_data1)
print("output", encoder_data1.toarray())
test_data2 =  [["大专","人妖"]]
encoder_data2 = encoder.transform(test_data2)
print("output", encoder_data2.toarray())

output [[1. 0. 0. 0. 0. 0. 1.]]
output [[0. 1. 0. 0. 1. 0. 0.]]

这里请出神器 sklearn 给出了One-Hot 编码的处理案例,其核心思想是通过0,1 扩展维度来对枚举值进行编码,在学位这个维度,本科、硕士、博士、大专 需要四个0,1 位对其进行表示,如 博士可以编码为 [1,0,0,0] , 大专:[0, 1, 0, 0]性别这里有三个取值 男,女,人妖 ; 男的编码[0,0,1], 女:[0,1,0], 人妖:[1,0,0];

适用情形:对数值大小敏感的模型必须使用one-hot encoding。典型的例子就是LR和SVM。二者的损失函数对数值大小是敏感的,并且变量间的数值大小是有比较意义的。可以看出One-Hot 编码通过扩展维度个数,消除了枚举值之间的大小差异,具体什么意思呢,如果我们认为性别上,男、女、人妖 这三种性别平等,那么这种one-hot 编码是恰到好处的,从编码上看不出这些特征的相对大小。这样的编码特性,适合对特征大小敏感的模型,如LR,SVM 等模型;

当One-Hot 用于树模型时,类别型特征的取值数量少的时候还是可以学习到比较重要的交互特征,但是当取值很多时候(如大于100), 维度剧增,容易导致过拟合,此时 One-Hot是不太适合用于在树模型中的,但是对于lightGBM、CatBoost 直接说明是类别型特征,就会自动进行特征处理。对xgboost 需要对类别型特征进行处理。对于lightGBM 则不需要进行类别特征处理,因为lightgbm在做树的节点分裂的时候,对于category特征的候选分裂点计算过程不涉及排序。类别特征大小对算法不care。

One-Hot 缺点:枚举值取值较多,导致维度激增,引入高维稀疏的问题,模型参数需要对应激增,但是因为高维稀疏问题,模型参数得不到学习优化,一般某个离散特征基数在10~100 的时候,可以使用One-Hot 特征编码;

One-Hot 的另一个缺点是如果对多列进行One-Hot 编码,在LR模型中,因为逻辑回归要求变量特征相互独立,如果你只有一个属性需要做one-hot编码还好,如果你有多个属性需要做one-ont编码,那么当某个样本的多个one-hot属性同时为1时,这两个属性就完全相关了,会导致矩阵变为一个奇异矩阵(非满秩),也就是奇异矩阵不能求解唯一解,经过训练得不出唯一的模型解,但是你又不可能把同一个属性的某一个one-hot延伸变量删除,改善这一问题的办法是WOE 编码。

  1. Label Encoder、Ordinal Encoder

Label Encoder ,Ordinal Encoder 这两种编码思路类似,就是把枚举值映射为数字的过程,Label Encoder 将离散特征映射到 整数(0, n_categories - 1) 之间的编码;Label Encoder 只对一列数据进行编码,而 Ordinary Encoder 是对Label Encoder 的扩展,对多列进行Label Encoder; 下面还是请出sklearn 给出案例:

from sklearn.preprocessing import LabelEncoder
data = ["0大专", "1本科", "2硕士", "3博士"]
encoder = LabelEncoder().fit(data)
test_data = ["3博士", "0大专", "1本科"]
print(encoder.transform(test_data))

输出 [3 0 1]

这类特征编码并没有带来维度的增加,只是将枚举取值简单的映射成了整数0,1,2....n-1 的形式,这么以来,也赋予了枚举值大小的含义;这种适合枚举值天然具有大小业务特性,例子中的学历枚举值,可以人为 博士就是最大的,编码为3,专科就是最小的所以编码为0,类似的情形还有年龄的划分编码;衣服尺寸枚举值XL、L,M,S等。

适用情形:离散特征本身就具备大小关系,适合LabelEncoder ,且使用的模型对特征大小敏感;那么这里作者抛出一个问题,就是xgboost 这类树模型,对离散特征应该采取怎样的编码策略: 对于取值基数小于100,且无顺序的特征如城市id,颜色取值 可以使用 One-Hot 编码,但是如果像学历,年龄划分 这类天然具有大小的枚举特征,则建议使用Label Encoder,对于LR,SVM 这类建模特征工程类似。如果特征基数很大, 这时候如果仍然要使用xgboost 可以考虑对特征进行targe encoder;其他树模型如lightGBM、CatBoost 是区分离散特征和连续特征的,对离散特征可以不做处理。

  1. Target Encoder

Target Encoder 适用于把category特征转换为连续特征。它是一种有监督特征编码方法,它用统计方法把每个category特征的枚举值根据目标变量来编码(严格意义上看的话,这种方法有信息泄露的), 而且这种特征处理办法,训练集合和测试集合分布,不要差别太大;在划分训练集合和测试集合的时候,最好先shuffle,或者使用K 折交叉验证。Target Encoder 对分类和回归问题具有不同的表现形式。

回归问题,其实也叫均值编码;

# target_encoding
def target_encoding(
        dataframe: DataFrame,
        target_encoding_columns: List[str],
        serialize_file: str, is_train: bool = True) -> DataFrame:
    mean_dicts = {}
    if is_train:
        for c in target_encoding_columns:
            c_mean = dataframe.groupby([c])["target"].mean()
            mean_dicts[c] = c_mean.to_dict()
        serialization(mean_dicts, serialize_file)
    # 对数据进行变换
    for c in target_encoding_columns:
        if not is_train:
            mean_dicts = deserialization(serialize_file)
        dataframe[c + "_target_mean"] = dataframe[c].map(mean_dicts[c])
    return dataframe

解释说明:这里对离散特征取值 group by 求均值,然后序列化保存,可以用于测试集合.

对于C分类问题,单个category特征会编码为C−1个连续特征。其出发点是用C-1个条件概率P(Y=yi|X=xi)来代替category特征X取值为xi 的特征;

分类问题的TargeEncoding

因为存在过拟合的问题,这里有部分改进,引入了regularlize 技巧等,在此不做过多详述

  1. CatBoost-Encoder

CatBoost-Encoder 出自论文 CatBoost算法这篇论文,主要是为了改进 TargetEncoder 容易出现 当训练数据集和测试数据集数据结构和分布不一样的时候会出条件偏移问题


CatBoost Encoder 算法

这里Dk 的构建,论文中有几种选择,如通过排列,选取前P 个数据的集合,也可以将某条数据排除在外等。

  1. Embedding

Embedding 思想的产生源自Google 2013 年word2vec 这篇轮,改进了单词One-Hot 编码过程中高维稀疏问题,并且能学习到词与词之间的内在联系;后来发展到万物皆可embedding,在离散特征领域,特征基数较高,使用One-Hot 编码时候,会产生高维稀疏问题,使用Target-Encoder 类型编码时候,由于长尾特征较多,容易造成偏移,这时候Embedding 表示就登场,一般在网格数据使用深度学习算法进行建模时候,Embedding 是这类离散特征的必选项。

像CTR 预估中wide&deep ,表格数据建模中的TabNet、TabTransformer 、TabMlp算法等都是对离散特征进行Embedding 处理。

离散特征Embedding 是深度学习在离散特征建模的标配;

TabTransformer

除了深度学习TabTransformer 等算法之外,传统机器学习算法FM 算法也是这个原理。

Embedding 具体表现为静态embedding 和动态embedding,如输入id 的映射,以及 深度学习中,transforner 输出token 的embedding 映射;或者bert 模型中中间几层输出值的聚合(mean、max 操作等)。

Embedding 适用范围:一般是针对纯id类的category特征并且是有内涵的实体(比如usrid,itemid,channelid等等)做embedding(当然这个也和模型有关),有些性别或者职位等级,可能做embedding 意义不大;

缺点:Embedding 向量需要学习,额外带来较多模型参数,在训练数据量较小的情形下,不容易获得较好的结果;与树模型比较,依据从业经验当离散特征对分类或者回归每个特征贡献较为平均(贡献不集中),深度学习模型可以获得较好的结果;然后就是需要较大的数据集一般才能学习到好的结果。

这里思考一个问题, 如果是离散特征不做embedding,是否能用深度学习建模?这里答案是One-Hot(对于技术小于10 的模型),或者前面targe-encoding 技术转换为连续特征。

展开阅读全文

页面更新:2024-03-13

标签:特征   类别   维度   人妖   建模   算法   模型   大小   博士   数据   工程

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top