介绍
我们在建立模型前,一般需要对特征变量进行离散化,特征离散化后,模型会更稳定,降低模型过拟合的风险。尤其是采用 logsitic 建立评分卡模型时,必须对连续变量进行离散化。而特征离散化处理通常采用的就是分箱法,数据分箱(也称为离散分箱或分段)是一种数据预处理技术,用于减少次要观察误差的影响,提高泛化性。
数据分箱又分为有监督分箱和无监督分箱,是否使用标签进行离散化(分箱)决定了有监督还是无监督的离散化方法。
知识点
- 无监督分箱
- split 分箱
- merge 分箱
无监督分箱
这里为了实验,我们就随机生成了一些实验数据,下面先来看下具体详情:
import pandas as pd
import numpy as np
data = pd.read_csv("data.csv")
data.shape
(252939, 88)
data.head()
datetime | category_1 | category_14 | category_77 | category_21 | category_13 | category_62 | category_68 | category_42 | category_28 | ... | category_71 | category_3 | category_34 | category_58 | category_47 | category_25 | category_48 | y | category_74 | category_79 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2020-06-13 | 0.495720 | 11638800 | 90 | -999 | 1 | 0 | 0 | 0 | 6 | ... | 0 | 100007 | 0.574799 | 3 | 1 | 0.560708 | 1.0 | 0 | -1.0 | 79 |
1 | 2020-10-22 | 0.517549 | 734893200 | 38 | -999 | 2 | 0 | 0 | 6 | 5 | ... | 1 | 100008 | 0.390684 | 5 | 1 | 0.495632 | 1.0 | 0 | 100.0 | 132 |
2 | 2020-09-11 | 0.435992 | 860778000 | 21 | 9 | 1 | 0 | 0 | 11 | 229 | ... | 1 | 200000 | 0.473826 | 37 | 2 | 0.462364 | 1.0 | 1 | 400.0 | 20 |
3 | 2020-05-05 | 0.504451 | 872010000 | 143 | -999 | 1 | 0 | 0 | 4 | 33 | ... | 1 | 100008 | 0.491736 | 34 | 2 | 0.440723 | 1.0 | 1 | -1.0 | 53 |
4 | 2020-05-13 | 0.511435 | 846349200 | 56 | -999 | 2 | 0 | 0 | 3 | 0 | ... | 1 | 100008 | 0.529865 | 0 | 1 | 0.474624 | 1.0 | 1 | 400.0 | 83 |
其中 datetime 表示数据日期;y 表示标签值,取值1、0;category_1 ~ category_86 表示用户的特征数据。
等频法:
等频法属于自动分箱,每个箱内的样本数量是相同的,假设有 10000 个样本,设置频数为 100,则按照数值排序后,就会分成 100 个箱子。等频法在 python 中的实现如下所示。
"""
qcut函数是根据数据本身的数量来对数据进行分割
:param X: 原始数据,只接收1维矩阵或Series
:param q: 整数,当q为整数时,代表分箱数
:param duplicates: 默认值为raise,如果X中有重复值时会报错。当duplicates='drop'时,X中有重复值时会对分箱合并
:param labels: 接收array型或False型数据,当labels=False时,只返回分箱的索引。当labels为array时,其长度要和q相等
"""
equal_frequency_cut = pd.qcut(data.category_34, q=5, duplicates="drop", labels = range(0, 5))
下面是分箱后的结果,我们可以看到分箱后的数据基本是均匀分布的(最后两个柱子不均匀是因为有重复数据,在分箱时进行了数据合并)。
import pandas as pd
from sklearn import datasets
equal_frequency_cut.hist()
等距法:
等距法同样属于自动分箱,可以理解为每个箱子中的数据极差是相同的,也就是区间的距离是一致的。等距法在 python 中的实现如下所示。
"""
cut函数是根据数据的值来对数据进行分割
:param X: 原始数据,只接收1维矩阵或Series
:param bins: 为整数时,代表分箱数,和qcut的q参数一样
:param labels: 接收array型或False型数据,当labels=False时,只返回分箱的索引。当labels为array时,其长度要和bins相等
"""
equal_distance_cut = pd.cut(data.category_34, 5, labels = range(0, 5))
同样的我们再来看下分箱完的结果,此时分箱后的数据就不再均匀分布。
equal_distance_cut.hist()
自定义法:
通常在业务中,会根据经验,对分箱规则做出定义。这里的经验既可以是专业人员的之前经验,也可以是数据探索性分析中得出的结论。自定义法在 python 中的实现如下所示。
"""
cut函数是根据数据的值来对数据进行分割
:param X: 原始数据,只接收1维矩阵或Series
:param bins: 为array时,代表自定义分箱区间,默认左开右闭
:param labels: 接收array型或False型数据,当labels=False时,只返回分箱的索引。当labels为array时,其长度要和bins相等
"""
user_defined_cut = pd.cut(data.category_34, [0, 0.5, 0.6, 1], labels = ['(0, 0.5]', '(0.5, 0.6]', '(0.6, 1]'])
下面是划分结果
user_defined_cut.hist()
<matplotlib.axes._subplots.AxesSubplot at 0x27b1500ea88>
聚类法:
分箱其实就是一个聚类的应用,我们希望具有相同特征的数据点能够被放置在同一个箱子中,因此可以通过聚类的方式找到具有相同属性的类别。聚类分箱就是用 python 中的 k-means 函数进行划分。
from sklearn.cluster import KMeans
num_clusters = 3
km_cluster = KMeans(n_clusters=num_clusters, max_iter=300, n_init=40,init='k-means++',n_jobs=-1)
result = km_cluster.fit_predict(np.array(data.category_34).reshape(-1,1))
cluster_cut = pd.DataFrame({'Data':np.array(data.category_34),"Categories":result})
cluster_cut.head()
Data | Categories | |
---|---|---|
0 | 0.574799 | 1 |
1 | 0.390684 | 2 |
2 | 0.473826 | 0 |
3 | 0.491736 | 0 |
4 | 0.529865 | 0 |
下面是用聚类方式划分的分布情况
cluster_cut.Categories.hist()
同时在聚类分析中还有一个对聚类效果的评价,这里简单介绍一下,常用的聚类效果评价标准。
对于每个点 𝑖 为已聚类数据中的样本,𝑏𝑖 为 𝑖 到其它族群的所有样本的平均距离,𝑎𝑖 为 𝑖 到本身簇的距离平均值,最终计算出所有的样本点的轮廓系数平均值。这就是轮廓系数:
s = b − a m a x ( a , b ) s = \frac{b - a}{max(a, b)} s=max(a,b)b−a
如果 sc𝑖 小于 0,说明 𝑎𝑖 的平均距离大于最近的其他簇,聚类效果不好;如果 sc𝑖 越大,说明 𝑎𝑖 的平均距离小于最近的其他簇,聚类效果好。轮廓系数的值是介于 [-1,1],越趋近于 1 代表内聚度和分离度都相对较优,当然一般不会这么高,一般能达到 0.1 就不错了。
一般来讲,无监督分箱对于分布不均匀的数据并不适用。等频和等宽都不能很好的反应“尖头”的数据,除非人工手动干涉,聚类本身对于这类问题的表现也并不稳定,经常可能出现的情况就是“尖头”数据有一部分分到平缓分布的数据里去,导致最终的分箱结果没有代表性。
有监督分箱
上述是无监督的分箱,不需要用到 label 信息。从理论上来说,有监督的分箱会比无监督的分箱更合理。
merge 分箱:
merge 分箱为自底向上的基于合并(merge)机制的分箱方式,如卡方分箱。下面我们就以卡方分箱为例讲讲该分箱方式。
卡方分箱是典型的基于合并机制的自底向上离散化方法。其基于如下假设:如果两个相邻的区间具有非常类似的类分布,则这两个区间可以合并;否则,它们应当保持分开。此处衡量分布相似性的指标就是卡方值。卡方值越低,类分布的相似度越高。一般流程如下:
排序
卡方分箱的第一步即对数据排序,对于连续变量,直接根据变量数值大小排序即可。对于离散变量,由于取值不存在大小关系,无法直接排序。这里一般采用的排序依据是:正例样本的比例,即待分箱变量每个取值中正例样本的比重,对应代码中的 pos_ratio 属性。
那么具体如何排序呢?我们前面提到过,卡方分箱是基于合并机制的离散化方法。因此,初始的分箱状态为:将待分箱变量的每个取值视为一个单独的箱体,后续分箱的目的就是将这些箱体合并为若干个箱体。首先,我们统计待分箱变量的可选取值,以及各个取值的正负样本数量(count),然后判断变量类型确定排序依据。代码如下:
def data_describe(data, var_name_bf, var_name_target, feature_type):
"""
统计各取值的正负样本分布 [累计样本个数,正例样本个数,负例样本个数] 并排序
:param data: DataFrame 输入数据
:param var_name_bf: str 待分箱变量
:param var_name_target: str 标签变量(y)
:param feature_type: 特征的类型:0(连续) 1(离散)
:return: DataFrame 排好序的各组中正负样本分布 count
"""
# 统计待离散化变量的取值类型(string or digits)
data_type = data[var_name_bf].apply(lambda x: type(x)).unique()
var_type = True if str in data_type else False # 实际取值的类型:false(数字) true(字符)
if feature_type == var_type:
ratio_indicator = var_type
elif feature_type == 1:
ratio_indicator = 0
print("特征%s为离散有序数据,按照取值大小排序!" % (var_name_bf))
elif feature_type == 0:
exit(code="特征%s的类型为连续型,与其实际取值(%s)型不一致,请重新定义特征类型!!!" % (var_name_bf, data_type))
# 统计各分箱(group)内正负样本分布[累计样本个数,正例样本个数,负例样本个数]
count = pd.crosstab(data[var_name_bf], data[var_name_target])
total = count.sum(axis=1)
# 排序:离散变量按照pos_ratio排序,连续变量按照index排序
if ratio_indicator:
count['pos_ratio'] = count[count.columns[count.columns.values>0]].sum(axis=1) * 1.0 / total
count = count.sort_values('pos_ratio') #离散变量按照pos_ratio排序
count = count.drop(columns = ['pos_ratio'])
else:
count = count.sort_index() # 连续变量按照index排序
return count, ratio_indicator
其中,var_name_bf 表示需要分箱的变量,函数返回排序后的待分箱变量的统计分布,包括样本取值,正例样本,负例样本。
需要注意的是,如果待分箱变量为离散变量,该方法只能使用于二分类模型。因为计算 pos_ratio 时,要求y ∈ [ 0 , 1 ]。当然,这里可以根据个人需要调整 pos_ratio 的计算方式,以适应多分类问题。
feature | y0 | y1 |
---|---|---|
x 1 x_1 x1 | a | b |
x 2 x_2 x2 | c | d |
… | … | … |
x n x_n xn | … | … |
x1 和 x2 的卡方值计算公式为:
x 2 = ( a − ( a + b ) ( a + c ) n ) 2 ( a + b ) ( a + c ) n + ( b − ( a + b ) ( b + d ) n ) 2 ( a + b ) ( b + d ) n + ( c − ( c + d ) ( a + c ) n ) 2 ( c + d ) ( a + c ) n + ( d − ( c + d ) ( b + d ) n ) 2 ( c + d ) ( b + d ) n x^2 = \frac{(a - \frac{(a+b)(a+c)}{n})^2}{\frac{(a+b)(a+c)}{n}} + \frac{(b - \frac{(a+b)(b+d)}{n})^2}{\frac{(a+b)(b+d)}{n}} + \frac{(c - \frac{(c+d)(a+c)}{n})^2}{\frac{(c+d)(a+c)}{n}} + \frac{(d - \frac{(c+d)(b+d)}{n})^2}{\frac{(c+d)(b+d)}{n}} x2=n(a+b)(a+c)(a−n(a+b)(a+c))2+n(a+b)(b+d)(b−n(a+b)(b+d))2+n(c+d)(a+c)(c−n(c+d)(a+c))2+n(c+d)(b+d)(d−n(c+d)(b+d))2
= n ( a d − b c ) 2 ( a + b ) ( c + d ) ( a + c ) ( b + d ) ( 其 中 n = a + b + c + d ) =\frac{n(ad - bc)^2}{(a + b)(c + d)(a + c)(b + d)}(其中 n = a + b + c + d) =(a+b)(c+d)(a+c)(b+d)n(ad−bc)2(其中n=a+b+c+d)
下面给出计算代码:
def calc_chi2(count, group1, group2):
"""
根据分组信息(group)计算各分组的卡方值
:param count: DataFrame 待分箱变量各取值的正负样本数
:param group1: list 单个分组信息
:param group2: list 单个分组信息
:return: 该分组的卡方值
"""
count_intv1 = count.loc[count.index.isin(group1)].sum(axis=0).values
count_intv2 = count.loc[count.index.isin(group2)].sum(axis=0).values
count_intv = np.vstack((count_intv1, count_intv2))
# 计算四联表
row_sum = count_intv.sum(axis=1)
col_sum = count_intv.sum(axis=0)
total_sum = count_intv.sum()
# 计算期望样本数
count_exp = np.ones(count_intv.shape) * col_sum / total_sum
count_exp = (count_exp.T * row_sum).T
# 计算卡方值
chi2 = (count_intv - count_exp) ** 2 / count_exp
chi2[count_exp == 0] = 0
return chi2.sum()
区间合并
这一部分比较简单,计算得到相邻分组的卡方值后,找到卡方值最小的分组并合。直接给出代码:
def merge_adjacent_intervals(count, chi2_list, group):
"""
根据卡方值合并卡方值最小的相邻分组并更新卡方值
:param count: DataFrame 待分箱变量的
:param chi2_list: list 每个分组的卡方值
:param group: list 分组信息
:return: 合并后的分组信息及卡方值
"""
min_idx = chi2_list.index(min(chi2_list))
# 根据卡方值合并卡方值最小的相邻分组
group[min_idx] = group[min_idx] + group[min_idx+1]
group.remove(group[min_idx+1])
# 更新卡方值
if min_idx == 0:
chi2_list.pop(min_idx)
chi2_list[min_idx] = calc_chi2(count, group[min_idx], group[min_idx+1])
elif min_idx == len(group)-1:
chi2_list[min_idx-1] = calc_chi2(count, group[min_idx-1], group[min_idx])
chi2_list.pop(min_idx)
else:
chi2_list[min_idx-1] = calc_chi2(count, group[min_idx-1], group[min_idx])
chi2_list.pop(min_idx)
chi2_list[min_idx] = calc_chi2(count, group[min_idx], group[min_idx+1])
return chi2_list, group
对应的卡方分箱代码如下:
def Chi_Merge(count, max_interval=6, sig_level=0.05):
"""
基于ChiMerge的卡方离散化方法
:param count: DataFrame 待分箱变量各取值的正负样本数
:param max_interval: int 最大分箱数量
:param sig_level: 显著性水平(significance level) = 1 - 置信度
:return: 分组信息(group)
"""
print("ChiMerge分箱开始:")
# 自由度(degree of freedom)= y类别数-1
deg_freedom = len(count.columns) - 1
# 卡方阈值
chi2_threshold = chi2.ppf(1 - sig_level, deg_freedom)
# 分组信息
group = np.array(count.index).reshape(-1, 1).tolist()
# 计算相邻分组的卡方值
chi2_list = [calc_chi2(count, group[idx], group[idx + 1]) for idx in range(len(group) - 1)]
# 合并相似分组并更新卡方值
while 1:
if min(chi2_list) >= chi2_threshold:
print("最小卡方值%.3f大于卡方阈值%.3f,分箱合并结束!" % (min(chi2_list), chi2_threshold))
break
if len(group) <= max_interval:
print("分组长度%s等于指定分组数%s" % (len(group), max_interval))
break
chi2_list, group = merge_adjacent_intervals(count, chi2_list, group)
print("ChiMerge分箱完成!!!")
return group
停止条件
卡方分箱的停止条件有如下两种选择:
- 分箱个数等于指定的分箱数目(max_interval):限制最终的分箱个数结果,每次将样本中具有最小卡方值的 区间与相邻的最小卡方区间进行合并,直到分箱个数达到限制条件为止。
- 最小卡方值大于卡方阈值(chi2_threshold):根据自由度和显著性水平得到对应的卡方阈值,如果分箱的各区间最小卡方值小于卡方阈值,则继续合并,直到最小卡方值超过设定阈值为止。
可以两个同时用,也可以只用一个,看实际需求调整即可。类别和属性独立时,有 90% 的可能性,计算得到的卡方值会小于 4.6。大于阈值 4.6 的卡方值就说明属性和类不是相互独立的,不能合并。如果阈值选的大,区间合并就会进行很多次,离散后的区间数量少、区间大。
下面我们就来实际操作一下:
from scipy.stats import chi2
# 待分箱变量的类型(0: 连续型变量 1:离散型变量)
feature_type = 1
# 最大分箱数量
max_interval = 5
# 初始化:将每个值视为一个箱体 & 统计各取值的正负样本分布并排序
print("分箱初始化开始:")
count, var_type = data_describe(data, 'category_10', 'y', feature_type)
print("分箱初始化完成!!!")
# 卡方分箱
group = Chi_Merge(count, max_interval)
# 后处理
if not feature_type:
group = [sorted(ele) for ele in group]
group.sort()
# 根据var_type修改返回的group样式(var_type=0: 返回分割点列表;var_typ=1:返回分箱成员列表)
if not feature_type:
group = [ele[-1] for ele in group] if len(group[0])==1 else [group[0][0]] + [ele[-1] for ele in group]
# 包含最小值
group[0] = group[0]-0.001 if group[0]==0 else group[0] * (1-0.001)
# 包含最大值
group[-1] = group[-1]+0.001 if group[-1]==0 else group[-1] * (1+0.001)
group
分箱初始化开始:
特征category_10为离散有序数据,按照取值大小排序!
分箱初始化完成!!!
ChiMerge分箱开始:
最小卡方值4.000大于卡方阈值3.841,分箱合并结束!!!
ChiMerge分箱完成!!!
[[1, 3, 4, 5],
[7, 8, 9, 10],
[11, 12, 13, 14, 15],
[17, 18, 19, 20],
[21, 22, 23],
[24, 25, 26],
[27],
[28, 29],
[30],
[31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42],
[43, 44],
[45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65],
[67, 68, 70],
[71, 72, 73, 74, 76, 78, 79, 80, 81, 82, 83, 84],
[85, 88],
[89, 90, 91, 93, 95, 98],
[99],
[100]]
我们发现分箱后,最终箱体个数与输入的分箱数量不符,这是由分组间的相似性太低导致的,以最终结果为准或者更改分箱方法。
split 分箱:
split 分箱和 merge 分箱原理不同,是自顶向下分箱方法。其中最典型的就是最小熵分箱,其原理是将待分箱特征的所有取值都放到一个箱体里,然后依据最小熵原则进行箱体分裂。这个过程其实很类似决策树的生成过程,只不过决策树首先会涉及到特征的选择,然后才是对选中的特征进行分裂点的选择。而最小熵分箱分箱处理的特征是由用户指定的,下面同样给出计算过程。
条件熵计算
条件熵 H(Y|X),表示在已知随机变量 X 的条件下随机变量 Y 的不确定性。
H ( Y ∣ X ) = ∑ i = 1 n p i ∗ l o g p i H(Y|X) = \sum_{i=1}^{n} p_i*logp_i H(Y∣X)=i=1∑npi∗logpi
def calc_entropy2(count):
"""
计算分组的熵值
:param count: DataFrame 分组的分布统计
:return: float 该分组的熵值
"""
p_clockwise = count.cumsum(axis=0).div(count.sum(axis=1).cumsum(axis=0), axis=0)
entropy_clockwise = -p_clockwise * np.log2(p_clockwise)
entropy_clockwise = entropy_clockwise.fillna(0)
entropy_clockwise = entropy_clockwise.sum(axis=1)
count = count.sort_index(ascending=False)
p_anticlockwise = count.cumsum(axis=0).div(count.sum(axis=1).cumsum(axis=0), axis=0)
entropy_anticlockwise = -p_anticlockwise * np.log2(p_anticlockwise)
entropy_anticlockwise = entropy_anticlockwise.fillna(0)
entropy_anticlockwise = entropy_anticlockwise.sum(axis=1)
entropy = [entropy_clockwise.values[idx] + entropy_anticlockwise.values[len(entropy_clockwise.index) - 2 - idx] for idx in range(len(entropy_clockwise.index) - 1)]
return entropy
划分点确定
给定样本集 D 和连续属性 a a a,假定 a a a 在 D 上出现了 n 个不同的取值,将这些值从小到大进行排序,记为 a 1 , a 2 , . . . , a n {a^1, a^2, ..., a^n} a1,a2,...,an。基于划分点 t 可将 D 分为子集 D t − D_t^- Dt− 和 D t + D_t^+ Dt+,其中 D t − D_t^- Dt− 包含那些在属性 a a a 上取值不大于 t 的样本,而 D 则包含那些在属性 a a a 上取值大于 t 的样本。显然,对相邻的属性取值 a i a^i ai 与 a i + 1 a^{i+1} ai+1 来说,t 在区间 [ a i , a i + 1 ) [a^i, a^{i+1}) [ai,ai+1) 中取任意值所产生的划分结果相同。因此,对连续属性 a a a,我们可考察包含 n-1 个元素的候选划分点集合。
def get_best_cutpoint(count, group, binning_method):
"""
根据指标计算最佳分割点
:param count: 待分箱区间
:param group: # 待分箱区间内值的数值分布统计
:return: 分割点的下标
"""
# 以每个点作为分箱点(左开右闭区间),以此计算分箱后的指标(熵,信息增益,KS)值=左区间+右区间
if binning_method == 'entropy':
entropy_list = calc_entropy2(count)
else:
exit(code='无法识别分箱方法')
# 最大指标值对应的分割点即为最佳分割点
intv = entropy_list.index(min(entropy_list))
return intv
迭代停止条件
得到第一个分裂点后,数据会被划分成两部分。然后分别对左右两部分数据重复划分操作,直到箱体数目达到预定值。
def BestKS_dsct(count, max_interval, binning_method):
"""
基于BestKS的特征离散化方法
:param count: DataFrame 待分箱变量的分布统计
:param max_interval: int 最大分箱数量
:return: 分组信息(group)
"""
# 初始分箱:所有取值视为一个分箱
group = count.index.values.reshape(1,-1).tolist()
# 重复划分,直到KS的箱体数达到预设阈值。
while len(group) < max_interval:
group_intv = group[0] # 待分箱区间
if len(group_intv) == 1:
group.append(group[0])
group.pop(0)
continue
# 选择最佳分箱点。
# 待分箱区间内值的数值分布统计
count_intv = count[count.index.isin(group_intv)]
# 分箱点的下标
intv = get_best_cutpoint(count_intv, group_intv, binning_method)
cut_point = group_intv[intv]
print("cut_point:%s" % (cut_point))
# 状态更新
group.append(group_intv[0:intv+1])
group.append(group_intv[intv+1:])
group.pop(0)
return group
下面我们就来实际操作一下:
from sklearn.tree import DecisionTreeClassifier
# 待分箱变量的类型(0: 连续型变量 1:离散型变量)
feature_type = 1
# 最大分箱数量
max_interval = 5
# 初始化:将每个值视为一个箱体 & 统计各取值的正负样本分布并排序
print("分箱初始化开始:")
count, var_type = data_describe(data, 'category_10', 'y', feature_type)
print("分箱初始化完成!!!")
# entropy 分箱方法
group = BestKS_dsct(count, max_interval, 'entropy')
group.sort()
# 根据var_type修改返回的group样式(var_type=0: 返回分割点列表;var_typ=1:返回分箱成员列表)
if not feature_type:
group = [ele[-1] for ele in group] if len(group[0]) == 1 else [group[0][0]] + [ele[-1] for ele in group]
# 包含最小值
group[0] = group[0] - 0.001 if group[0] == 0 else group[0] * (1 - 0.001)
# 包含最大值
group[-1] = group[-1] + 0.001 if group[-1] == 0 else group[-1] * (1 + 0.001)
group
分箱初始化开始:
特征category_10为离散有序数据,按照取值大小排序!
分箱初始化完成!!!
cut_point:99
cut_point:98
cut_point:95
cut_point:93
[[1,
3,
4,
5,
7,
8,
9,
10,
11,
12,
13,
14,
15,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
62,
63,
64,
65,
67,
68,
70,
71,
72,
73,
74,
76,
78,
79,
80,
81,
82,
83,
84,
85,
88,
89,
90,
91,
93],
[95],
[98],
[99],
[100]]
总结
我们本节主要介绍了分箱的相关知识,总结一下,分箱给模型带来的好处有以下几点:
- 使得模型的鲁棒性更高,对缺失值和异常值不敏感。
- 降低模型过拟合的风险。
- 离散化后,特征的改变,数据分布的小变动不会对模型有较大的影响
- 将评分映射到不同的分区中使得模型的可解释性更强。