机器学习中的特征工程(四)---- 特征离散化处理方法

简介

特征离散化指的是将连续特征划分离散的过程:将原始定量特征的一个区间一一映射到单一的值。离散化过程也被表述成分箱(Binning)的过程。特征离散化常应用于逻辑回归和金融领域的评分卡中,同时在规则提取,特征分类中也有对应的应用价值。本文主要介绍几种常见的分箱方法,包括等宽分箱、等频分箱、信息熵分箱、基于决策树分箱、卡方分箱等。

分箱原理介绍

数据分箱是一种数据预处理技术,用于减少次要观察误差的影响,是一种将多个连续值分为相对较少的若干分组的方法。下面举个例子来具体说明一下,假设我们有下面一组数据,表示花瓣的宽度,分布如下:
花瓣宽度分布

可以看到花瓣宽度范围区间是0.1~2.5,看起来划分的有点细了,有的时候我们不需要那么精细,比如我们希望将花瓣宽度划分到(‘很窄’,‘窄’、‘正常’、‘宽’、‘很宽’)这5个范围里,那么我们可以将花瓣宽度重新划分为5个区间,将落在对应区间的花瓣宽度映射到之前指定的5个范围内,如下如所示。
分箱
可以看到在分箱之后,数据被规约和简化,有利于理解和解释。总来说特征离散化,即 分箱之后会带来如下优势:
  • 有助于模型部署和应用,加快模型迭代
  • 增强模型鲁棒性
  • 增加非线性表达能力:连续特征不同区间对模型贡献或者重要程度不一样时,分箱后不同的权重能直接体现这种差异,离散化后的特征再进行特征 交叉衍生能力会进一步加强。
  • 提升模型的泛化能力
  • 扩展数据在不同各类型算法中的应用范围

当然特征离散化也有其缺点,总结如下:

  • 分箱操作必定会导致一定程度的信息损失
  • 增加流程:建模过程中加入了额外的的离散化步骤
  • 影响模型稳定性: 当一个特征值处于分箱点的边缘时,此时微小的偏差会造成该特征值的归属从一箱跃迁到另外一箱,影响模型的稳定性。

特征离散化(分箱)可以从不同的角度来进行划分。当分箱方法使用了目标y的信息,那么该分箱方法就属于有监督的分箱方法,反之为无监督的分箱方法。
这里选择sklearn中自带的乳腺癌数据集,下文提及的分箱方法大多是基于此数据集,主要是取其中的‘mean radius’字段,如下:

import seaborn as sns
from sklearn.datasets import load_breast_cancer

bc = load_breast_cancer()
df = pd.DataFrame.from_records(data=bc.data, columns=bc.feature_names)
df['target'] = bc.target
sns.distplot(df['mean radius'], kde=False)
原始特征分布

等宽分箱(Equal-Width Binning)

等宽分箱指的是每个分隔点或者划分点的距离一样,即等宽。实践中一般指定分隔的箱数,等分计算后得到每个分隔点。例如将数据序列分为n份,则 分隔点的宽度计算公式为:
w = \frac {max - min} {n}
这样就将原始数据划分成了n个等宽的子区间,一般情况下,分箱后每个箱内的样本数量是不一致的。使用pandas中的cut函数来实现等宽分箱,代码如下:

value, cutoff = pd.cut(df['mean radius'], bins=4, retbins=True, precision=2)
cutoff
分隔点

可以轻易计算得出任意两个相邻分隔点之间的距离为5.30。按照上述分隔点对数据进行划分后,数据的分布如下:

df1 = value.to_frame()
df1.columns = ['bins']
sns.countplot(df1['bins'])
特征分箱后数据分布

等宽分箱计算简单,但是当数值方差较大时,即数据离散程度很大,那么很可能出现没有任何数据的分箱,这个问题可以通过自适应数据分布的分箱方法--等频分箱来避免

等频分箱(Equal-Frequency Binning)

顾名思义,等频分箱理论上分隔后的每个箱内得到数据量大小一致,但是当某个值出现次数较多时,会出现等分边界是同一个值,导致同一数值分到不同的箱内,这是不正确的。具体的实现可以去除分界处的重复值,但这也导致每箱的数量不一致。如下代码:

s1 = pd.Series([1,2,3,4,5,6])
value, cutoff = pd.qcut(s1, 3, retbins=True)
sns.countplot(value)
等频分箱

每个区间分别是2个数,这没有问题,但是如果某个数字出现的次数较多,则可能出现下面的情况:

s1 = pd.Series([1,2,3,4,5,6,6,6,6])
value, cutoff = pd.qcut(s1, 3, duplicates='drop', retbins=True)
sns.countplot(value)
等频分箱合并

本来是要分成3个箱子的,但是由于出现同一个数值被分到了不同的箱子里,因此被合并了,所以最后只有2个箱子。
同样,我们对乳腺癌数据进行等频分箱,该数据分布正常,等频分箱后每箱数量基本一致。

value, cutoff = pd.qcut(df['mean radius'], 4, duplicates='drop', retbins=True)
sns.countplot(value)
等频分箱

上述的等宽和等频分箱容易出现的问题是每箱中信息量变化不大。例如,等宽分箱不太适合分布不均匀的数据集、离群值;等频方法不太适合特定的值占比过多的数据集,如长尾分布。

信息熵分箱

上面介绍的分箱方法对建模的优化有限。如果分箱后箱内样本对y的区分度好,那么这是一个好的分箱。通过信息论理论,我们可知信息熵衡量了这种区分能力。当特征按照某个分隔点划分为上下两部分后能达到最大的信息增益,那么这就是一个好的分隔点。由上可知,信息熵分箱是有监督的分箱方法。其实决策树的节点分裂原理也是基于信息熵。
首先我们需要明确信息熵和信息增益的计算方式,分别如下:
Entropy(y) = - \sum_{i=1}^m p_i log_2{p_i} \\ Gain(x) = Entropy(y) - Info_{split}(x)
在二分类问题中,m=2
信息增益的物理含义表达为:x的分隔带来的信息对y的不确定性带来的增益。
对于二值化的单点分隔,如果我们找到一个分隔点将数据一分为二,分成P_1P_2两部分,那么划分后的信息熵的计算方式为:
Info_{split}(x) = P1_{ratio}Entropy(x_{p1}) + P2_{ratio}Entropy(x_{p2})
下面以一个实例来介绍一下信息熵分箱的计算过程,假如我们有以下数据,我们以特征'x=3'来作为特征x的分隔点,则其带来的信息增益为0.420,如下:

data = [[1,0],[2,1],[3,0],[4,1],[5,1]]
df = pd.DataFrame(data, columns=['x','y'])
df

原始数据
接下来我们来计算信息增益,先计算分隔前的信息熵,如下:
Entroy(y) = -\lbrace \frac {2}{5} * log_2 \frac {2}{5} + \frac {3}{5} * log_2 \frac {3}{5} \rbrace = 0.971
接下来计算划分后的信息熵:
Info_{split}(x) = P_1Entropy(x < 3) + P_2Entropy(x \ge 3) \\ P_1Entropy(x < 3) = \frac {3}{5} * -\lbrace \frac {2}{3} * log_2 \frac {2}{3} + \frac {1}{3} * log_2 \frac {1}{3} \rbrace = 0.551\\ P_2Entropy(x \ge 3) = \frac {2}{5} * -\lbrace \frac {2}{2} * log_2 \frac {2}{2} + \frac {0}{2} * log_2 \frac {0}{2} \rbrace = 0
故信息增益为:
Gain(x) = 0.971 - 0.551 = 0.420
类似的可以计算其他分隔点的信息增益,最终选取信息增益最大时对应的分隔点。同时也可以看出,当分箱后,某个箱中的标签y的类别(0或者1)的比例相等时,其熵值最大,表明此特征划分几乎没有区分度。而当某个箱中的数据的标签y为单个类别时,那么该箱的熵值达到最小的0,即纯度最纯,最具区分度。从结果上来看,最大信息增益对应分箱后的总熵值最小。

决策树分箱

其实上一节中已经说到,由于决策树的结点选择和划分也是根据信息熵来计算的,因此我们其实可以利用决策树算法来进行特征选择,具体做法如下:
还是以乳腺癌数据为例,首先取其中‘mean radius’字段,和标签字段‘target’来拟合一棵决策树,代码如下:

from sklearn.tree import DecisionTreeClassifier

dt = DecisionTreeClassifier(criterion='entropy', max_depth=3) # 树最大深度为3
dt.fit(df['mean radius'].values.reshape(-1, 1), df['target'])

接着我们取出这课决策树的所有叶节点的分割点的阈值,如下:

qts = dt.tree_.threshold[np.where(dt.tree_.children_left > -1)]
qts = np.sort(qts)
res = [np.round(x, 3) for x in qts.tolist()]
res
决策树分割点阈值

注意这里只给出了6个点,但是相当于分了7个箱子,分别设为a-g,我们可以将划分后的效果绘制出来:

l = df['mean radius'].values.tolist()

r = []
for i in l:
    if i < res[0]:
        r.append('a')
    elif i >= res[-1]:
        r.append('g')
    else:
        for j in range(0, 5):
            if i > res[j] and i <= res[j+1]:
                r.append(chr(98+j))
                break
ax = sns.countplot(r)
ax
划分后的数据分布

卡方分箱

在了解卡方分箱之前,我们需要先了解几个关键概念,比如卡方分布,卡方检验等。
卡方分布是概率统计常见的一种概率分布,是卡方检验的基础。
卡方分布定义为:若n个独立的随机变量Z_1, Z_2, ...,Z_k满足标准正态分布N(0,1),则n个随机变量的平方和X=\sum_{i=0}^k Z_i^2为服从自由度为k的卡方分布,记为X \sim \chi^2。参数n称为自由度(样本中独立或能自由变化的自变量的个数),不同的自由度是不同的分布。例如,一个标准正态分布的平方就是自由度为1的卡方分布。卡方分布的概率密度函数如下:

卡方分布
卡方检验 :卡方检验属于非参数假设检验的一种,其本质都是度量频数之间的差异。其假设为:观察频数与期望频数无差异或者两组变量相互独立不相关。
\chi^2 = \sum \frac {(O-E)^2}{E}

  • 卡方拟合 优度检验:用于检验样本是否来自于某一个分布,比如检验某样本是否为正态分布
  • 独立性卡方检验,查看两组类别变量分布是否有差异或者相关,以列联表的形式比较。以列联表形式的卡方检验中,卡方统计量由上式给出。

其中,O表示观察到的频数(即实际出现的次数),E表示期望的频数。很明显,越小的卡方值,表明两者相差越小,反之,越大的卡方值表明两者差异越大。下面以一个具体的例子来说明卡方值的计算方式。
下面是观察到的两组样本分布:

观察 bad good 合计
组一 25 50 75
组二 30 15 45
合计 55 65 120

接着是期望频数的计算过程:

期望 bad good
组一 55*(75/120)=34.375 65*(75/120)=40.625
组二 55*(45/120)=20.625 65*(45/120)=24.375

最后是卡方值的计算过程:

a = [25, 50, 30, 15]
b = [34.375, 40.625, 20.625, 24.375]
r= []
for i in zip(a,b):
    r.append((i[0]-i[1])**2 / i[1])
np.sum(r)
卡方值

科学计算库SciPy中包含了卡方检验的实现,例子如下:

from scipy.stats import chi2_contingency
obs = np.array([[25,50],[30,15]])
chi2, p, dof, ex = chi2_contingency(obs, correction=False)
chi2
卡方值

其中dof代表自由度,ex代表期望概率。在得到卡方值以后查询卡方分布表并比较p_value值,继而做出接受或者拒绝原假设的判断。下段代码是输出卡方分布表的实现:

from scipy.stats import chi2

def chi2_table(freedom=10, alpha=None):
    if alpha is None:
        alpha = [0.99, 0.95, 0.9, 0.5, 0.1, 0.05, 0.025, 0.01, 0.005]
    df = pd.DataFrame([chi2.isf(alpha, df=i) for i in range(1, freedom)])
    df.columns = alpha
    df.index = df.index + 1
    return df
chi2_table()
卡方分布表

由表可知,当自由度为1、置信水平为0.05时,对应的卡方值为3.84,而上述例子计算出来的卡方值为12.587,大于3.841。说明在0.05的显著性水平是可以拒绝原假设的,即观察频数与期望频数有差异。换个角度描述卡方检验的物理含义:当两个分箱中,好坏(正负)分布是一致时,卡方为0,相似是接近0,对应到卡方分箱算法中,应该合并这两个分箱。

卡方分箱步骤

卡方分箱是自底向上的(即基于合并的)数据离散化方法。它依赖于卡方检验:具有最小卡方值的相邻区间合并在一起,直到满足确定的停止准则。基本思想: 对于精确的离散化,相对类频率在一个区间内应当完全一致。因此,如果两个相邻的区间具有非常类似的类分布,则这两个区间可以合并;否则,它们应当保持分开。而低卡方值表明它们具有相似的类分布。
卡方检验可以用来评估两个分布的相似性,因此可以将这个特性用到数据分箱的过程中。

理想的分箱是在同一个区间内标签的分布是相同的。卡方分箱就是不断的计算相邻区间的卡方值(卡方值越小表示分布越相似),将分布相似的区间(卡方值最小的)进行合并,直到相邻区间的分布不同,达到一个理想的分箱结果。下面用一个例子来解释:
由上图,第一轮中初始化是5个区间,分别计算相邻区间的卡方值。找到1.2是最小的,合并2、3区间,为了方便,将合并后的记为第2区间,因此得到4个区间。第二轮中,由于合并了区间,影响该区间与前面的和后面的区间的卡方值,因此重新计算1和2,2和4的卡方值,由于4和5区间没有影响,因此不需要重新计算,这样就得到了新的卡方值列表,找到最小的取值2.5,因此该轮会合并2、4区间,并重复这样的步骤,一直到满足终止条件。

参考

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容