在数据挖掘项目的数据中,数据类型可以分为两种:有序的连续数值 和 无序的类别型特征。

对于xgboost、GBDT等boosting树模型,基学习通常是cart回归树,而cart树的输入通常只支持连续型数值类型的,像年龄、收入等连续型变量Cart可以很好地处理,但对于无序的类别型变量(如 职业、地区等),cart树处理就麻烦些了,如果是直接暴力地枚举每种可能的类别型特征的组合,这样找类别特征划分点计算量也很容易就爆了。

在此,本文列举了 树模型对于类别型特征处理的常用方法,并做了深入探讨~

一、one-hot编码处理

我们可以直接对类别型特征做Onehot处理(这也是最常用的做法),每一类别的取值都用单独一位0/1来表示, 也就是一个“性别”类别特征可以转换为是否为“男”、“女” 或者“其他” 来表示,如下:

display(df.loc[:,['Gender_Code']].head())# onehot
pd.get_dummies(df['Gender_Code']).head()

但是onehot的重大缺点在于,对于取值很多的类别型特征,可能导致高维稀疏特征而容易导致树模型的过拟合。如之前谈到面对高维稀疏的onehot特征,一旦有达到划分条件,树模型容易加深,切分次数越多,相应每个切分出的子特征空间的统计信息越来越小,学习到的可能只是噪音(即 过拟合)。

使用建议:Onehot天然适合神经网络模型,神经网络很容易从高维稀疏特征学习到低微稠密的表示。当onehot用于树模型时,类别型特征的取值数量少的时候还是可以学习到比较重要的交互特征,但是当取值很多时候(如 大于100),容易导致过拟合,是不太适合用onehot+树模型的。(注:此外 onehot 还有增加内存开销以及训练时间开销等缺点)

二、  Ordinal Encoder

OrdinalEncoder也称为顺序编码 (与 label encoding,两者功能基本一样),特征/标签被转换为序数整数(0 到 n_categories - 1)

使用建议:适用于ordinal feature ,也就是虽然类别型特征,但它存在内在顺序,比如衣服尺寸“S”,“M”, “L”等特征就适合从小到大进行整数编码。

from sklearn.preprocessing import  LabelEncoderencoder = LabelEncoder()df[col] = encoder.transform(df[col])

三、target encoding

target encoding 目标编码也称为均值编码,是借助各类别特征对应的标签信息做编码(比如二分类 简单以类别特征各取值 的样本对应标签值“0/1”的平均值),是一种常用有监督编码方法(此外还有经典的WoE编码),很适合逻辑回归等弱模型使用。

使用建议 : 当树模型使用目标编码,需加入些正则化技巧,减少Target encoding方法带来的条件偏移的现象(当训练数据集和测试数据集数据结构和分布不一样的时候会出条件偏移问题),主流的方法是使用Catboost编码 或者 使用cross-validation求出target mean或bayesian mean。

# 如下简单的target  mean代码。也可以用:from category_encoders import TargetEncoder target_encode_columns = ['Gender_Code']
target = ['y']target_encode_df = score_df[target_encode_columns + target].reset_index().drop(columns = 'index', axis = 1)
target_name = target[0]
target_df = pd.DataFrame()
for embed_col in target_encode_columns:val_map = target_encode_df.groupby(embed_col)[target].mean().to_dict()[target_name]target_df[embed_col] = target_encode_df[embed_col].map(val_map).valuesscore_target_drop = score_df.drop(target_encode_columns, axis = 1).reset_index().drop(columns = 'index', axis = 1)
score_target = pd.concat([score_target_drop, target_df], axis = 1)

四、CatBoostEncoder

CatBoostEncoder是CatBoost模型处理类别变量的方法(Ordered TS编码),在于目标编码的基础上减少条件偏移。其计算公式为:

  • TargetCount : 对于指定类别特征在target value的总和

  • prior:对于整个数据集而言,target值的总和/所有的观测变量数目

  • FeatureCount:观测的特征列表在整个数据集中的出现次数。

CBE_encoder = CatBoostEncoder()
train_cbe = CBE_encoder.fit_transform(train[feature_list], target)
test_cbe = CBE_encoder.transform(test[feature_list])

五、CountEncoder

也称为频数编码,将类别特征各取值转换为其在训练集出现的频率,这样做直观上就是会以类别取值的频次为依据 划分高频类别和低频类别。至于效果,还是要结合业务和实际场景。

## 也可以直接 from category_encoders import  CountEncoderbm = []
tmp_df=train_df
for k in catefeas:t = pd.DataFrame(tmp_df[k].value_counts(dropna=True,normalize=True)) # 频率t.columns=[k+'vcount']bm.append(t)
for k,j in zip(catefeas, range(len(catefeas))):# 联结编码df = df.merge(bm[j], left_on=k, right_index=True,how='left')

六、 神经网络embedding

当类别的取值数量很多时(onehot高维),如果直接onehot,从性能或效果来看都会比较差,这时通过神经网络embedding是不错的方法,将类别变量onehot输入神经网络学习一个低维稠密的向量,如经典的无监督词向量表征学习word2vec 或者 基于有监督神经网络编码。

使用建议:特别适合类别变量取值很多,onehot后高维稀疏,再做NN低维表示转换后应用于树模型。

# word2vec
from gensim.models import word2vec
# 加载数据
raw_sentences = ["the quick brown fox jumps over the lazy dogs","yoyoyo you go home now to sleep"]
# 切分词汇
sentences= [s.encode('utf-8').split() for s in sentences]# 构建模型
model = word2vec.Word2Vec(sentences,size=10)  # 词向量的维数为10#  各单词学习的词向量
model['dogs']
# array([-0.00449447, -0.00310097,  0.02421786, ...], dtype=float32)

七、lgb类别特征处理

为了解决one-hot编码(one vs many )处理类别特征的不足。lgb采用了Many vs many的切分方式,简单来说,是通过对每个类别取值进行数值编码(类似于目标编码),根据编码的数值寻找较优切分点,实现了类别特征集合的较优切分。

  • 具体算法原理:

1 、特征取值数目小于等于4(参数max_cat_to_onehot):直接onehot 编码,逐个扫描每一个bin容器,找出最佳分裂点;

2、 特征取值数目大于4:max bin的默认值是256 取值的个数大于max bin数时,会筛掉出现频次少的取值。再统计各个特征值对应的样本的一阶梯度之和,二阶梯度之和,以一阶梯度之和 / (二阶梯度之和 + 正则化系数)作为该特征取值的编码。将类别转化为数值编码后,从大到小排序,遍历直方图寻找最优的切分点

简单来说,Lightgbm利用梯度统计信息对类别特征编码。我个人的理解是这样可以按照学习的难易程度为依据划分类别特征组,比如某特征一共有【狼、狗、猫、猪、兔】五种类别取值,而【狼、狗】类型下的样本分类难度相当高(该特征取值下的梯度大),在梯度编码后的类别特征上,寻找较优划分点可能就是【狼、狗】|vs|【猫、猪、兔】

使用建议:  通常使用lgb类别特征处理,效果是优于one-hot encoding,而且用起来也方便。

# lgb类别处理:简单转化为类别型特征直接输入Lgb模型训练即可。for ft in category_list:train_x[ft] = train_x[ft].astype('category')
clf = LGBMClassifier(**best_params)
clf.fit(train_x, train_y)

经验小结

  • 对于取值数量很少(<10)的类别型特征,相应的各取值下的样本数量也比较多,可以直接Onehot编码。

  • 对于取值数量比较多(10到几百),这时onehot从效率或者效果,都不及lightgbm梯度编码或catboost目标编码,而且直接使用也很方便。(需要注意的是,个人实践中这两种方法在很多取值的类别特征,还是比较容易过拟合。这时,类别值先做下经验的合并或者尝试剔除某些类别特征后,模型效果反而会更好)

  • 当几百上千的类别取值,可以先onehot后(高维稀疏),借助神经网络模型做低维稠密表示。

以上就是主要的树模型对类别特征编码方法。实际工程上面的效果,还需具体验证。计算资源丰富的情况下,可以多试几种编码方法,再做特征选择,选取比较有效的特征,效果杠杠的!!

- END -

- 推荐阅读-

深度学习系列

  • 1、一文概览神经网络模型

  • 2、一文搞定深度学习建模预测全流程(Python)

  • 3、一文浅谈深度学习泛化能力

  • 4、一文弄懂CNN及图像识别(Python)

机器学习系列

  • 1、一文全览机器学习建模流程(Python代码)

  • 2、一文解决样本不均衡(全)

  • 3、一文速览机器学习的类别(Python代码)

  • 4、Python特征选择(全)

文末,粉丝福利来了!!关注【算法进阶】

【机器学习】树模型遇上类别型特征(Python)相关推荐

  1. CatBoost 是如何自动高级处理类别型特征的?

    我们知道,CatBoost可以很好地处理类别型数据.然而,它还具有大量的训练参数,可以更好地对类别型特征进行预处理.本文中,小猴子将和大家一起学习如何使用这些参数处理类别型特征的. CatBoost是 ...

  2. 一文了解类别型特征的编码方法

    来源:Unsplash,作者:an Rizzari 2019 年第 78 篇文章,总第 102 篇文章 目录: 问题描述 数据准备 标签编码 自定义二分类 one-hot 编码 总结 问题描述 一般特 ...

  3. KDD 2021 | 谷歌DHE:不使用embedding table的类别型特征embedding

    作者 | Chilia 哥伦比亚大学 NLP搜索推荐 整理 | NewBeeNLP 类别型特征(用户ID/物品ID)的embedding在推荐系统中扮演着重要的作用,标准的方式是用一个(巨大的)emb ...

  4. 如何处理类别型特征?

    目录: 问题描述 数据准备 标签编码 自定义二分类 one-hot 编码 问题描述 一般特征可以分为两类特征,连续型和离散型特征,而离散型特征既有是数值型的,也有是类别型特征,也可以说是字符型,比如说 ...

  5. ML之FE:对pandas的dataframe中的类别型字段进行数字编码化(类别型特征数值化)并导出映射表daiding

    ML之FE:对pandas的dataframe中的类别型字段进行数字编码化(类别型特征数值化)并导出映射表daiding 目录 对pandas的dataframe中的类别型字段进行数字编码化(类别型特 ...

  6. [机器学习] 树模型(xgboost,lightgbm)特征重要性原理总结

    在使用GBDT.RF.Xgboost等树类模型建模时,往往可以通过 feature_importance 来返回特征重要性,各模型输出特征重要性的原理与方法 一 计算特征重要性方法 首先,目前计算特征 ...

  7. lightgbm模型处理类别型特征

    类别型特征编码由于是字符串类型,所以一般需要经过编码处理转换成数值型.本文主要想说的是直接将字符串值传到lightgbm中训练.注意:xgboost模型也需要提前one-hot编码转换才能入模. 下面 ...

  8. 为什么树模型不适合高维稀疏特征

    转载自:https://blog.csdn.net/papaaa/article/details/79910449 思考角度比较好,做个记录 这个问题我也是思考了好久,在平时的项目中也遇到了不少 ca ...

  9. 绝对布局优势_遇上狭长型卫生间基本没救?2种布局教会你,什么叫美观实用兼具...

    很多家庭因为户型原因,不得已要接受一个狭长型的卫生间,而这样的卫生间又该怎么布局,才能完美的容下洗漱台.淋浴和马桶呢? 在唠布局之前,我们要先搞清楚,洗漱区需要的宽度是自身宽度,以及一个人身的宽度:淋 ...

最新文章

  1. Python一元二次方程
  2. 使用Maven 实现打包生成一个可执行jar包:附详细配置解释说明
  3. Sagemaker快速学习
  4. JavaScript语法详解(三)
  5. 洛谷P4841 城市规划(多项式求逆)
  6. Webpack搭建React开发环境
  7. zephir 编译php,使用Zephir来快速编写高性能PHP二进制拓展
  8. Python发展的新时代—冯大辉先生谈《Python源码剖析》
  9. java batik 字体文件_用 Apache batik 1.10 把svg代码转成png图片,文字丢失???
  10. android 蓝牙串口指令,蓝牙串口助手
  11. 谷歌浏览器如何下载在线音频视频
  12. 用户和计算机硬盘系统的接口,硬盘接口类型,教您怎么看硬盘接口的类型
  13. XUI框架之FlowTagLayout流标签的使用,实现原生android没有的功能?
  14. HTML 邮件兼容问题与解决方案
  15. 关于 Bandizip 每次解压都催你更新
  16. 嵌入式面试总结(持续更新)
  17. 机器学习——regression
  18. 2021高考数学成绩查询,吐血整理!2020高考数学评分细则参考,2021高考这样准备少丢分!...
  19. Metabo Analyst使用教程-Pathway Analysis模块
  20. 十天 教你从创意到上线APP

热门文章

  1. 在黑暗中哭泣的众筹,黎明的曙光还未到来
  2. 根据二叉树创建字符串
  3. NLTK11《Python自然语言处理》code10 分析语句的含义
  4. 如何将多个文本文档合并到一个文档中?
  5. Air724UG 4G LTE 模块AT指令连接服务器
  6. Java版本JFrame,计算器和单位换算的实现
  7. 做一次完美的数据迁移
  8. Alluxio FUSE 实现原理
  9. 游戏笔记本电脑推荐 多功能游戏本你见过吗?
  10. PDF怎么快速转换成Excel表格文件?两个方法帮你实现