什么是数据分箱
一般在建立分类模型时,需要对连续变量离散化,特征离散化后,模型会更稳定,降低了模型过拟合的风险。比如在建立申请评分卡模型时用logsitic作为基模型就需要对连续变量进行离散化,离散化通常采用分箱法。
分箱的重要性及其优势
- 离散特征的增加和减少都很容易,易于模型的快速迭代;
- 稀疏向量内积乘法运算速度快,计算结果方便存储,容易扩展;
- 离散化后的特征对异常数据有很强的鲁棒性:比如一个特征是年龄>30是1,否则0。如果特征没有离散化,一个异常数据“年龄300岁”会给模型造成很大的干扰;
- 逻辑回归属于广义线性模型,表达能力受限;单变量离散化为N个后,每个变量有单独的权重,相当于为模型引入了非线性,能够提升模型表达能力,加大拟合;
- 离散化后可以进行特征交叉,由M+N个变量变为M*N个变量,进一步引入非线性,提升表达能力;
- 特征离散化后,模型会更稳定,比如如果对用户年龄离散化,20-30作为一个区间,不会因为一个用户年龄长了一岁就变成一个完全不同的人。当然处于区间相邻处的样本会刚好相反,所以怎么划分区间是门学问;
- 特征离散化以后,起到了简化了逻辑回归模型的作用,降低了模型过拟合的风险。
- 可以将缺失作为独立的一类带入模型。
- 将所有变量变换到相似的尺度上
分箱方法
数据分箱是下列情形下常用的方法:
-
某些数值自变量在测量时存在随机误差,需要对数值进行平滑以消除噪音。
-
有些数值自变量有大量不重复的取值,对于使用<、>、=等基本操作符的算法(如决策树)而言,如果能减少这些不重复取值的个数,就能提高算法的速度。
-
有些算法只能使用分类自变量,需要把数值变量离散化。
分箱例子
数据被归入几个分箱之后,可以用每个分箱内数值的均值、中位数或边界值来替代该分箱内各观测的数值,也可以把每个分箱作为离散化后的一个类别。例如,某个自变量的观测值为1,2.1,2.5,3.4,4,5.6,7,7.4,8.2.假设将它们分为三个分箱,(1,2.1,2.5),(3.4,4,5.6),(7,7.4,8.2),那么使用分箱均值替代后所得值为(1.87,1.87,1.87),(4.33,4.33,4.33),(7.53,7.53,7.53),使用分箱中位数替代后所得值为(2.1,2.1,2.1),(4,4,4),(7.4,7.4,7.4),使用边界值替代后所得值为(1,2.5,2.5),(3.4,3.4,5.6),(7,7,8.2)(每个观测值由其所属分箱的两个边界值中较近的值替代)。 数据分箱的常用方法假设要将某个自变量的观测值分为k个分箱,一些常用的分箱方法有:1.无监督分箱
(1)等宽分箱:将变量的取值范围分为k个等宽的区间,每个区间当作一个分箱。
(2)等频分箱:把观测值按照从小到大的顺序排列,根据观测的个数等分为k部分,每部分当作一个分箱,例如,数值最小的1/k比例的观测形成第一个分箱,等等。
(3)基于k均值聚类的分箱:使用第五章将介绍的k均值聚类法将观测值聚为k类,但在聚类过程中需要保证分箱的有序性:第一个分箱中所有观测值都要小于第二个分箱中的观测值,第二个分箱中所有观测值都要小于第三个分箱中的观测值,等等。
有监督分箱
在分箱时考虑因变量的取值,使得分箱后达到最小熵(minimumentropy)或最小描述长度(minimumdescriptionlength)。这里仅介绍最小熵。
-
假设因变量为分类变量,可取值1,…,J。令pl(j)表示第l个分箱内因变量取值为j的观测的比例,l=1,…,k,j=1,…,J;那么第l个分箱的熵值为=Jj=1[-pl(j)×log(pl(j))]。如果第l个分箱内因变量各类别的比例相等,即pl(1)=…=pl(J)=1/J,那么第l个分箱的熵值达到最大值;如果第l个分箱内因变量只有一种取值,即某个pl(j)等于1而其他类别的比例等于0,那么第l个分箱的熵值达到最小值。
-
令rl表示第l个分箱的观测数占所有观测数的比例;那么总熵值为=kl= 1rl×=Jj=1[-pl(j)×log(pl(j ))]。需要使总熵值达到最小,也就是使分箱能够最大限度地区分因变量的各类别。
分箱例子
下面是没有分箱之前的例子
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
import numpy as np
import matplotlib.pyplot as plt
import mglearn
X,y = mglearn.datasets.make_wave(n_samples=100)
line = np.linspace(-3,3,1000,endpoint=False).reshape(-1,1)
reg = DecisionTreeRegressor(min_samples_split=3).fit(X,y)
plt.plot(line,reg.predict(line),label='decsion tree')
reg = LinearRegression().fit(X,y)
plt.plot(line,reg.predict(line),label='linear regression')
plt.plot(X[:,0],y,'o',c='k')
plt.ylabel("Regression output")
plt.xlabel("Input feature")
得到下面的输出
我们假设将特征的输入范围(在这个例子中是从 -3 到 3)划分成固定个数的箱子(bin),比如 10 个,那么数据点就可以用它所在的箱子来表示。为了确定这一点,我们首先需要定义箱子。在这个例子中,我们在 -3 和 3 之间定义 10 个均匀分布的箱子。我们用np.linspace函数创建 11 个元素,从而创建 10 个箱子,即两个连续边界之间的空间
bins = np.linspace(-3,3,11)
print("bins: {}".format(bins))
输出分箱为
bins: [-3. -2.4 -1.8 -1.2 -0.6 0. 0.6 1.2 1.8 2.4 3. ]
这里第一个箱子包含特征取值在 -3 到 -2.4 之间的所有数据点,第二个箱子包含特征取值在 -2.4 到 -1.8 之间的所有数据点,以此类推
接下来,我们记录每个数据点所属的箱子。这可以用np.digitize函数轻松计算出来:
which_bin = np.digitize(X, bins=bins)
print("\nData points:\n", X[:5])
print("\nBin membership for data points:\n", which_bin[:5])
输出对应为
bins: [-3. -2.4 -1.8 -1.2 -0.6 0. 0.6 1.2 1.8 2.4 3. ]
Data points:
[[-0.75275929][ 2.70428584]
[ 1.39196365][ 0.59195091]
[-2.06388816]]
Bin membership for data points:
[[ 4]
[10]
[ 8]
[ 6]
[ 2]]
这样沃恩就把数据集中单个连续输入特征变为了一个分类特征,用于表示数据点所在的bin,如要在这个数据上应用机器学习算法,我们可以使用OneHotEncoder将这个离散的特征变为one-hot编码
from sklearn.preprocessing import OneHotEncoder
# 使用OneHotEncoder进行变换
encoder = OneHotEncoder(sparse=False)
# encoder.fit找到which_bin中的唯一值
encoder.fit(which_bin)
# transform创建one-hot编码
X_binned = encoder.transform(which_bin)
那么接下来我们对原有数据进行变换,构建新的线性模型和决策树模型,输出如下
我们可以看出两条线应该是重合在了一起,对于每个箱子,二者都预测一个常数值。因为每个箱子内的特征是不变的,所以对于一个箱子内的所有点,任何模型都会预测相同的值
网友评论