数据预处理的分箱操作

介绍

我们在建立模型前,一般需要对特征变量进行离散化,特征离散化后,模型会更稳定,降低模型过拟合的风险。尤其是采用 logsitic 建立评分卡模型时,必须对连续变量进行离散化。而特征离散化处理通常采用的就是分箱法,数据分箱(也称为离散分箱或分段)是一种数据预处理技术,用于减少次要观察误差的影响,提高泛化性。

数据分箱又分为有监督分箱和无监督分箱,是否使用标签进行离散化(分箱)决定了有监督还是无监督的离散化方法。

知识点

  • 无监督分箱
  • split 分箱
  • merge 分箱

无监督分箱

这里为了实验,我们就随机生成了一些实验数据,下面先来看下具体详情:

import pandas as pd
import numpy as np

data = pd.read_csv("data.csv")
data.shape
(252939, 88)
data.head()
datetimecategory_1category_14category_77category_21category_13category_62category_68category_42category_28...category_71category_3category_34category_58category_47category_25category_48ycategory_74category_79
02020-06-130.4957201163880090-99910006...01000070.574799310.5607081.00-1.079
12020-10-220.51754973489320038-99920065...11000080.390684510.4956321.00100.0132
22020-09-110.43599286077800021910011229...12000000.4738263720.4623641.01400.020
32020-05-050.504451872010000143-999100433...11000080.4917363420.4407231.01-1.053
42020-05-130.51143584634920056-99920030...11000080.529865010.4746241.01400.083

其中 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()
DataCategories
00.5747991
10.3906842
20.4738260
30.4917360
40.5298650

下面是用聚类方式划分的分布情况

cluster_cut.Categories.hist()

在这里插入图片描述

同时在聚类分析中还有一个对聚类效果的评价,这里简单介绍一下,常用的聚类效果评价标准。

对于每个点 𝑖 为已聚类数据中的样本,𝑏𝑖 为 𝑖 到其它族群的所有样本的平均距离,𝑎𝑖 为 𝑖 到本身簇的距离平均值,最终计算出所有的样本点的轮廓系数平均值。这就是轮廓系数:

s = b − a m a x ( a , b ) s = \frac{b - a}{max(a, b)} s=max(a,b)ba

如果 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 的计算方式,以适应多分类问题。

featurey0y1
x 1 x_1 x1ab
x 2 x_2 x2cd
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)(an(a+b)(a+c))2+n(a+b)(b+d)(bn(a+b)(b+d))2+n(c+d)(a+c)(cn(c+d)(a+c))2+n(c+d)(b+d)(dn(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(adbc)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(YX)=i=1npilogpi

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]]

总结

我们本节主要介绍了分箱的相关知识,总结一下,分箱给模型带来的好处有以下几点:

  • 使得模型的鲁棒性更高,对缺失值和异常值不敏感。
  • 降低模型过拟合的风险。
  • 离散化后,特征的改变,数据分布的小变动不会对模型有较大的影响
  • 将评分映射到不同的分区中使得模型的可解释性更强。
  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盡盡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值