high-cardinality categorical attributes,从字面上理解,即对于某个category特征,不同值的数量非常多,这里暂且把它叫做高数量类别属性。反之,即低数量类别属性(low-cardinality)

对于低数量类别属性,通常在data science中采用的方式是将其转化为one-hot编码,即给每一个类别增加一个特征。但是当类别数量增加的时候,ont-hot编码增加的特征也在增加。所以,one-hot编码无法适用于高数量特征属性。

基本方法(clustering)

目前有一个常见的方法处理这个问题叫做clustering。即将原始的1-to-N的mapping问题变成1-to-k的mapping问题。(k<<N)

为了达到这个目标,这个高数量类别属性首先将依据target的值grouping成k个类(clusters),然后再依据这个grouping的结果进行one-hot编码。

不得不说,这个方法最大程度的保留了原始数据的信息。grouping的方法有一些:其中一个就是Hierarchical clustering Algorithm,它使用一个基于target的的统计距离来grouping,grouping的标准也可以度量每合并两个clusters带来的信息增量的影响,如gain ratio。两个距离最短的clusters将会被合并成一个。这个过程一直被迭代,直到迭代过程没有明显的改善。

这个问题更多解释可见《统计学习方法》5.2.2

cate_A target
a/b/c.... 1/0
... ...

对上述数据集, cate_A为高数量特征属性,其处理方法的伪代码如下:

  1. while improvment > epsilon or unique(cate_A) >= k:
  2. compute Conditional Entropy Target|cate_A: THA1
  3. for _ :
  4. Merge two random labels in cate_A into one
  5. compute Conditional Entropy Target|cate_A: THA
  6. Find the two labels that then compute to a minimum THA2
  7. improvement = THA1 - THA2

上述方法其实很常见,且被运用在决策树的C4.5方法中进行特征选择。

这个方法在最后需要ont-hot编码。

另一方法(smoothing)

Smoothing,简单来说,就是将原来独立的高数量类别特征的每个值映射到概率估计上。基本来讲,这个预处理方法将原始的值放置到实际的机器学习模型之前先通过一个简单的特征处理模型(如贝叶斯模型)。

下面以binary target为例进行方法分析:

当target属性 \(Y\in\{0,1\}\)时,假设要处理的特征为X,该特征的每一个不同的值为\(X_{i}\)。我们要做的是, 将高数量类别特征将映射到一个标量\(S_{i}\)中,\(S_{i}\)代表一个条件概率,即

$X_{i} \to S_{i} \cong P(Y|X=X_{i}) ---(1)$

注意到\(S_{i}\)代表的是条件概率,那么他的值被归一到了0和1之间,这对于神经网络模型也是一个好的预处理。

下一步就是概率估计的过程。我们假设数据集被分成了\(n_{TR}\)个训练集和\(n_{TS}\)个测试集。因为这个概率估计成为了模型训练的一部分,所以只有训练集的数据被使用。注意到不是所有的X的可能值都会出现在训练集中,有的值可能只出现在测试集或者新进来的数据中。所以,这个映射过程必须要能够处理这个特征的不可预见性的值。

如果该特征某个值如\(X=X_{i}\)出现的数量足够多,那么这个概率估计可以这样计算:

$S_{i}=\frac{n_{iY}}{n_{i}} ---(2)$

这是一个后验概率的计算过程。然而不幸的是,特征的值的数量分布通常是不均匀的,有很多值的数量非常少。所以这种使用\(P(Y|X=X_{i})\)的直接估计是不太可靠的。

为了减小这种小数量值的影响,\(S_{i}\)的计算可能被分成两个概率的组合。后验概率的计算如公式(2),先验概率的计算如\(P(Y) = \frac{n_{Y}}{n_{TR}}\)。整个组合计算公式为:

$S_{i}=\lambda(n_{i})\frac{n_{iY}}{n_{i}}+(1-\lambda(n_{i}))\frac{n_{Y}}{n_{TR}} ---(3)$

\(n_{Y}\)代表在整个数据集中\(Y=1\)的数量。\(\lambda(n_{i})\)是一个在0-1之间的单调递增函数。

原理:一方面,当特征的某个值的数量很多,即\(\lambda\cong1\)时,公式即为(2),计算后验概率。另一方面,当特征的某个值的数量很少时,即\(\lambda\cong0\)时,公式前项为0,只计算先验概率。

所以,关键我们怎么选取\(\lambda(n_{i})\)这个函数呢?有一个典型函数如下:

$\lambda(n)=\frac{1}{1+\exp^{-\frac{n-k}{f}}} ---(4)$

这个公式是一个s形状的函数,当 n=k 时值为 0.5 。

  • 参数 f 控制函数在转折处的斜率,决定了先验概率和后验概率之间的平衡。如果\(f\to\infty\),那么公式(3)变为一个硬间隔,即先验概率和后验概率各占0.5。

  • 参数 k 决定于我们允许的特征值数量的最小值的一半。so important!

我们在来看看经验贝叶斯估计(Empirical Bayes estimation) 的一般公式:

$P=B_{i}y_{i}+(1-B_{i})\overline{y}---(5)$

\(\overline{y}\)是先验概率,\(y_{i}\)是经验后验概率。收缩系数\(B_{i}\)根据不同的估计方法有不同的形式。当所有概率分布服从高斯分布的时候:

$B_{i}=\frac{n_{i}\tau^{2}}{\sigma^{2}+n_{i}\tau^{2}}---(6)$

\(\sigma^{2}\)是值的方差,\(\tau^{2}\)是样本方差。事实上,公式(6)是公式(4)的一般形式。

以下是我在kaggle中看到大佬对该方法的coding实现,借以参考,帮助理解:

  1. def add_noise(series, noise_level):
  2. return series * (1 + noise_level * np.random.randn(len(series)))
  3. def target_encode(trn_series=None,
  4. tst_series=None,
  5. target=None,
  6. min_samples_leaf=1,
  7. smoothing=1,
  8. noise_level=0):
  9. """
  10. trn_series : training categorical feature as a pd.Series
  11. tst_series : test categorical feature as a pd.Series
  12. target : target data as a pd.Series
  13. min_samples_leaf (int) : minimum samples to take category average into account
  14. smoothing (int) : smoothing effect to balance categorical average vs prior
  15. """
  16. assert len(trn_series) == len(target)
  17. assert trn_series.name == tst_series.name
  18. temp = pd.concat([trn_series, target], axis=1)
  19. # Compute target mean
  20. averages = temp.groupby(by=trn_series.name)[target.name].agg(["mean", "count"])
  21. # Compute smoothing
  22. smoothing = 1 / (1 + np.exp(-(averages["count"] - min_samples_leaf) / smoothing))
  23. # Apply average function to all target data
  24. prior = target.mean()
  25. # The bigger the count the less full_avg is taken into account
  26. averages[target.name] = prior * (1 - smoothing) + averages["mean"] * smoothing
  27. averages.drop(["mean", "count"], axis=1, inplace=True)
  28. # Apply averages to trn and tst series
  29. ft_trn_series = pd.merge(
  30. trn_series.to_frame(trn_series.name),
  31. averages.reset_index().rename(columns={'index': target.name, target.name: 'average'}),
  32. on=trn_series.name,
  33. how='left')['average'].rename(trn_series.name + '_mean').fillna(prior)
  34. # pd.merge does not keep the index so restore it
  35. ft_trn_series.index = trn_series.index
  36. ft_tst_series = pd.merge(
  37. tst_series.to_frame(tst_series.name),
  38. averages.reset_index().rename(columns={'index': target.name, target.name: 'average'}),
  39. on=tst_series.name,
  40. how='left')['average'].rename(trn_series.name + '_mean').fillna(prior)
  41. # pd.merge does not keep the index so restore it
  42. ft_tst_series.index = tst_series.index
  43. return add_noise(ft_trn_series, noise_level), add_noise(ft_tst_series, noise_level)

两个方法比较

smoothing方法可以只要通过对本地数据集的操作就可完成预处理,而clustering方法需要更复杂的算法而且可能导致信息量的减少(因为最后仍然需要进行one-hot编码)。

当然,对于smoothing方法来说, \(\lambda\)函数的选择直接影响到了结果,可能不同的\(\lambda\)函数可以适用于不同的分支领域,这都需要实验的考证。


PS:该篇文章主要基于对文献的翻译,这个翻译过程终于让我体会到翻译的不易了,以后我再也不会抱怨专业书翻译者的不专业了。

Reference:

  1. A Preprocessing Scheme for High-Cardinality Categorical Attributes in Classification and Prediction Problems
  2. 《统计学习方法》.李航
  3. Python target encoding for categorical features

高数量类别特征(high-cardinality categorical attributes)的预处理方法的更多相关文章

  1. 对于高并发短连接造成Cannot assign requested address解决方法

    https://www.cnblogs.com/dadonggg/p/8778318.html 感谢这篇文章给予的启发 在tcp四次挥手断开连接时,主动释放连接的一方最后会进入TIME_WAIT状态, ...

  2. 机器学习实战基础(十一):sklearn中的数据预处理和特征工程(四) 数据预处理 Preprocessing & Impute 之 处理分类特征:编码与哑变量

    处理分类特征:编码与哑变量 在机器学习中,大多数算法,譬如逻辑回归,支持向量机SVM,k近邻算法等都只能够处理数值型数据,不能处理文字,在sklearn当中,除了专用来处理文字的算法,其他算法在fit的 ...

  3. 机器学习实战基础(九):sklearn中的数据预处理和特征工程(二) 数据预处理 Preprocessing & Impute 之 数据无量纲化

    1 数据无量纲化 在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布的需求,这种需求统称为将数据“无量纲化”.譬如梯度和矩阵为核心的算法中,譬如逻辑回 ...

  4. Sql Server本地高版本备份数据备份至远程低版本数据库方法

    想要将Sqlserver高版本备份的数据还原到低版本SqlServer2008R2上去,但是这在SqlServer中是没法直接还原数据库的,通过以下方法可以顺利还原. 通过高版本生成sql脚本在低版本 ...

  5. 无法debug断点跟踪JDK源代码——missing line number attributes的解决方法

    在项目工程->Properties->Java Build Path->Libraries中导入的JRE System Library库里,给jar包添加JDK源代码包后,能够直接打 ...

  6. VC6的工程转到VC2010或更高版本出现fatal error C1189编译错误的解决方法

    以前也遇到过,当时解决了没写下来,这次正好又遇到了,就顺手写一下吧,别下次又忘记了. 当VC6的工程转到VC2010或更高版本时编译出现如下错误: c:\program files\microsoft ...

  7. 高并发下用pdo,文件排它锁,redis三种方法对比

    <?php header('content-type:text/html;charset=utf-8');                 // //无控制     // $DB_DSN = ' ...

  8. ArcGis基础——把类别代码替换成对应中文名称的方法

    挂接! 上面是答案,展开一下就是做一个Excel对照表,就两列,代码与中文名称.然后用类别代码字段匹配挂接. 别傻傻找vbs/py代码,不知道拐个弯.

  9. 机器学习实战基础(十二):sklearn中的数据预处理和特征工程(五) 数据预处理 Preprocessing & Impute 之 处理分类特征:处理连续性特征 二值化与分段

    处理连续性特征 二值化与分段 sklearn.preprocessing.Binarizer根据阈值将数据二值化(将特征值设置为0或1),用于处理连续型变量.大于阈值的值映射为1,而小于或等于阈值的值 ...

随机推荐

  1. oracle 11g杀掉锁的sql

    oracle 11g杀掉锁的sql [引用 2013-3-6 17:19:12]     字号:大 中 小 --查询出出现锁的session_idselect session_id from v$lo ...

  2. 完整的treeview菜单实例

    以下是我用treeview控件按部门和员工显示设备领用情况代码. Option Compare Database    Dim rec As New ADODB.Recordset    Dim re ...

  3. Cesium 云服务

    前言 所有行业内都知道云是未来或者现在的趋势,但是真正的完完全全提供地理信息云服务的恐怕只有 Google 一家,然而今天我居然发现 Cesium 提供了云服务,你没有看错,就是曾经的开源 3D 渲染 ...

  4. Google揭开Mesa的神秘面纱——一个具备跨地域复制和近实时特性的可伸缩数据仓库

    http://www.infoq.com/cn/news/2014/08/google-data-warehouse-mesa Google发表了一篇新的论文,该论文描述了他们内部所使用的一个被称为M ...

  5. I want to try to improve myself from today

    I involved in the Internet of Things project team in my university in 2015 and now I have completed ...

  6. Java main方法全解

    1.main方法的重载 package cn.nxl2018; public class Main_test { public static void main(String args[]) { Sy ...

  7. python的统一编码规范

    请注意这一点:没有编码规范的代码没有阅读价值,也更谈不上复用. 目前业界比较流行的Python的编码规范目前主要有PEP8的编程.Google的编码风格.Python Guide和Pocoo Styl ...

  8. 微信小程序之获取用户位置权限(拒绝后提醒)

    微信小程序获取用户当前位置有三个方式: 1. wx.getLocation(多与wx.openLocation一起用) 获取当前的精度.纬度.速度.不需要授权.当type设置为gcj02 返回可用于w ...

  9. 小白突破百度翻译反爬机制,33行Python代码实现汉译英小工具!

    表弟17岁就没读书了,在我家呆了差不多一年吧. 呆的前几个月,每天上网打游戏,我又不好怎么在言语上管教他,就琢磨着看他要不要跟我学习Python编程.他开始问我Python编程什么?我打开了我给学生上 ...

  10. Python入门、练手、视频资源汇总,拿走别客气!

    摘要:为方便朋友,重新整理汇总,内容包括长期必备.入门教程.练手项目.学习视频. 一.长期必备. 1. StackOverflow,是疑难解答.bug排除必备网站,任何编程问题请第一时间到此网站查找. ...