树模型遇上类别型特征(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后(高维稀疏),借助神经网络模型做低维稠密表示。


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

相关文章
|
3天前
|
数据采集 数据可视化 数据挖掘
金融波动率的多模型建模研究:GARCH族与HAR模型的Python实现与对比分析
本文探讨了金融资产波动率建模中的三种主流方法:GARCH、GJR-GARCH和HAR模型,基于SPY的实际交易数据进行实证分析。GARCH模型捕捉波动率聚类特征,GJR-GARCH引入杠杆效应,HAR整合多时间尺度波动率信息。通过Python实现模型估计与性能比较,展示了各模型在风险管理、衍生品定价等领域的应用优势。
96 65
金融波动率的多模型建模研究:GARCH族与HAR模型的Python实现与对比分析
|
1月前
|
机器学习/深度学习 数据可视化 TensorFlow
使用Python实现深度学习模型的分布式训练
使用Python实现深度学习模型的分布式训练
178 73
|
1月前
|
机器学习/深度学习 数据采集 供应链
使用Python实现智能食品消费需求分析的深度学习模型
使用Python实现智能食品消费需求分析的深度学习模型
88 21
|
1月前
|
机器学习/深度学习 数据采集 搜索推荐
使用Python实现智能食品消费偏好预测的深度学习模型
使用Python实现智能食品消费偏好预测的深度学习模型
93 23
|
1月前
|
机器学习/深度学习 数据采集 数据挖掘
使用Python实现智能食品消费习惯预测的深度学习模型
使用Python实现智能食品消费习惯预测的深度学习模型
132 19
|
1月前
|
机器学习/深度学习 数据采集 数据挖掘
使用Python实现智能食品消费趋势分析的深度学习模型
使用Python实现智能食品消费趋势分析的深度学习模型
139 18
|
1月前
|
机器学习/深度学习 数据采集 数据挖掘
使用Python实现智能食品消费模式预测的深度学习模型
使用Python实现智能食品消费模式预测的深度学习模型
63 2
|
机器学习/深度学习 算法 数据挖掘
一文归纳Python特征生成方法(全)
创造新的特征是一件十分困难的事情,需要丰富的专业知识和大量的时间。机器学习应用的本质基本上就是特征工程。 ——Andrew Ng
|
1月前
|
人工智能 数据可视化 数据挖掘
探索Python编程:从基础到高级
在这篇文章中,我们将一起深入探索Python编程的世界。无论你是初学者还是有经验的程序员,都可以从中获得新的知识和技能。我们将从Python的基础语法开始,然后逐步过渡到更复杂的主题,如面向对象编程、异常处理和模块使用。最后,我们将通过一些实际的代码示例,来展示如何应用这些知识解决实际问题。让我们一起开启Python编程的旅程吧!
|
1月前
|
存储 数据采集 人工智能
Python编程入门:从零基础到实战应用
本文是一篇面向初学者的Python编程教程,旨在帮助读者从零开始学习Python编程语言。文章首先介绍了Python的基本概念和特点,然后通过一个简单的例子展示了如何编写Python代码。接下来,文章详细介绍了Python的数据类型、变量、运算符、控制结构、函数等基本语法知识。最后,文章通过一个实战项目——制作一个简单的计算器程序,帮助读者巩固所学知识并提高编程技能。

热门文章

最新文章