树模型遇上类别型特征(Python)

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

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


对于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”等特征就适合从小到大进行整数编码。



fromsklearn.preprocessingimportLabelEncoder encoder=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() forembed_colintarget_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).values score_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


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


##也可以直接fromcategory_encodersimportCountEncoder bm=[] tmp_df=train_df forkincatefeas: t=pd.DataFrame(tmp_df[k].value_counts(dropna=True,normalize=True))#频率 t.columns=[k+'vcount'] bm.append(t) fork,jinzip(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 fromgensim.modelsimportword2vec #加载数据 raw_sentences=["thequickbrownfoxjumpsoverthelazydogs","yoyoyoyougohomenowtosleep"] #切分词汇 sentences=[s.encode('utf-8').split()forsinsentences] #构建模型 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模型训练即可。 forftincategory_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后(高维稀疏),借助神经网络模型做低维稠密表示。


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

相关文章
|
8天前
|
机器学习/深度学习 算法框架/工具 数据库
使用Python实现深度学习模型:智能城市噪音监测与控制
使用Python实现深度学习模型:智能城市噪音监测与控制
25 1
|
4天前
|
机器学习/深度学习 数据采集 传感器
使用Python实现深度学习模型:智能土壤质量监测与管理
使用Python实现深度学习模型:智能土壤质量监测与管理
112 69
|
1天前
|
机器学习/深度学习 数据采集 算法框架/工具
使用Python实现深度学习模型:智能野生动物保护与监测
使用Python实现深度学习模型:智能野生动物保护与监测
11 5
|
3天前
|
机器学习/深度学习 数据采集 算法框架/工具
使用Python实现智能生态系统监测与保护的深度学习模型
使用Python实现智能生态系统监测与保护的深度学习模型
19 4
|
4天前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
12 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
|
5天前
|
机器学习/深度学习 数据采集 数据可视化
使用Python实现深度学习模型:智能废气排放监测与控制
使用Python实现深度学习模型:智能废气排放监测与控制
20 0
|
6天前
|
机器学习/深度学习 数据采集 API
使用Python实现深度学习模型:智能光污染监测与管理
使用Python实现深度学习模型:智能光污染监测与管理
14 0
|
6天前
|
安全 数据处理 开发者
Python中的多线程编程:从入门到精通
本文将深入探讨Python中的多线程编程,包括其基本原理、应用场景、实现方法以及常见问题和解决方案。通过本文的学习,读者将对Python多线程编程有一个全面的认识,能够在实际项目中灵活运用。
|
1天前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###