卡方分箱、KS分箱、最优IV分箱、树结构分箱、自定义分箱

简介: 卡方分箱、KS分箱、最优IV分箱、树结构分箱、自定义分箱

分箱

分箱的概念

什么是分箱?如果你初入机器学习的道路,你可能比较的懵逼,为什么要分箱?


数据分箱指的是将连续数据离散化;离散化对异常值具有鲁棒性,运算更快方便存储,而且特征可变性更强方便迭代,特征离散后的模型更加稳定。

那是因为分箱对有些模型带来的好处比起调参优化都要来的直接

举个例子

决策树可以构建更为复杂的数据模型,但这强烈依赖于数据表示。有一种方法可以让线性模型在连续数据上变得更加强大,就是使用特征分箱(binning,也叫离散化,即 discretization)将其划分为多个特征,如下所述。


image.png


比如数据集很大、维度很高,但有些特征与输出的关系是非线性的——那么分箱是提高建模能力的好方法。

 

卡方分箱及代码实现


1.先确定最终分几个箱,也就是最后分几个离散值。

2.如果变量样本大于100,那么先等距的划分为100箱。

3.计算每一对相邻箱间的卡方值

4.将卡方值最小的两个区间合并,一直重复3-4直到满足最终分箱个数。


def tagcount(series,tags):
    """
    统计该series中不同标签的数量,可以针对多分类
    series:只含有标签的series
    tags:为标签的列表,以实际为准,比如[0,1],[1,2,3]
    """
    result = []
    countseries = series.value_counts()
    for tag in tags:
        try:
            result.append(countseries[tag])
        except:
            result.append(0)
    return result
def ChiMerge3(df, num_split,tags=[1,2,3],pvalue_edge=0.1,biggest=10,smallest=3,sample=None):  
    """
    df:只包含要分箱的参数列和标签两列
    num_split:初始化时划分的区间个数,适合数据量特别大的时候。
    tags:标签列表,二分类一般为[0,1]。以实际为准。
    pvalue_edge:pvalue的置信度值
    bin:最多箱的数目
    smallest:最少箱的数目
    sample:抽样的数目,适合数据量超级大的情况。可以使用抽样的数据进行分箱。百万以下不需要
    """
    import pandas as pd
    import numpy as np
    import scipy
    variable = df.columns[0]
    flag = df.columns[1]
#进行是否抽样操作
    if sample != None:
        df = df.sample(n=sample)
    else:
        df   
#将原始序列初始化为num_split个区间,计算每个区间中每类别的数量,放置在一个矩阵中。方便后面计算pvalue值。    
    percent = df[variable].quantile([1.0*i/num_split for i in range(num_split+1)],interpolation= "lower").drop_duplicates(keep="last").tolist()
    percent = percent[1:]
    np_regroup = []
    for i in range(len(percent)):
        if i == 0:
            tempdata = tagcount(df[df[variable]<=percent[i]][flag],tags)
            tempdata.insert(0,percent[i])
        elif i == len(percent)-1:
            tempdata = tagcount(df[df[variable]>percent[i-1]][flag],tags)
            tempdata.insert(0,percent[i])
        else:
            tempdata = tagcount(df[(df[variable]>percent[i-1])&(df[variable]<=percent[i])][flag],tags)
            tempdata.insert(0,percent[i])
        np_regroup.append(tempdata)
    np_regroup = pd.DataFrame(np_regroup)
    np_regroup = np.array(np_regroup)
#如果两个区间某一类的值都为0,就会报错。先将这类的区间合并,当做预处理吧
    i = 0
    while (i <= np_regroup.shape[0] - 2):
        check = 0
        for j in range(len(tags)):
            if np_regroup[i,j+1] ==0 and np_regroup[i+1,j+1]==0:
                check += 1
        """
        这个for循环是为了检查是否有某一个或多个标签在两个区间内都是0,如果是的话,就进行下面的合并。
        """
        if check>0:
            np_regroup[i,1:] = np_regroup[i,1:] + np_regroup[i+1,1:]
            np_regroup[i, 0] = np_regroup[i + 1, 0]
            np_regroup = np.delete(np_regroup, i + 1, 0)
            i = i - 1
        i = i + 1
#对相邻两个区间进行置信度计算
    chi_table = np.array([])
    for i in np.arange(np_regroup.shape[0] - 1):
        temparray = np_regroup[i:i+2,1:]
        pvalue = scipy.stats.chi2_contingency(temparray,correction=False)[1]
        chi_table = np.append(chi_table, pvalue)
    temp = max(chi_table)
#把pvalue最大的两个区间进行合并。注意的是,这里并没有合并一次就重新循环计算相邻区间的pvalue,而是只更新影响到的区间。
    while (1):
        #终止条件,可以根据自己的期望定制化
        if (len(chi_table) <= (biggest - 1) and temp <= pvalue_edge):
            break
        if len(chi_table)<smallest:
            break
        num = np.argwhere(chi_table==temp)
        for i in range(num.shape[0]-1,-1,-1):
            chi_min_index = num[i][0]
            np_regroup[chi_min_index, 1:] = np_regroup[chi_min_index, 1:] + np_regroup[chi_min_index + 1, 1:]
            np_regroup[chi_min_index, 0] = np_regroup[chi_min_index + 1, 0]
            np_regroup = np.delete(np_regroup, chi_min_index + 1, 0)
            #最大pvalue在最后两个区间的时候,只需要更新一个,删除最后一个。大家可以画图,很容易明白
            if (chi_min_index == np_regroup.shape[0] - 1):
                temparray = np_regroup[chi_min_index-1:chi_min_index+1,1:]
                chi_table[chi_min_index - 1] = scipy.stats.chi2_contingency(temparray,correction=False)[1]
                chi_table = np.delete(chi_table, chi_min_index, axis=0)
            #最大pvalue是最先两个区间的时候,只需要更新一个,删除第一个。
            elif (chi_min_index == 0):
                temparray = np_regroup[chi_min_index:chi_min_index+2,1:]
                chi_table[chi_min_index] = scipy.stats.chi2_contingency(temparray,correction=False)[1]
                chi_table = np.delete(chi_table, chi_min_index+1, axis=0)
            #最大pvalue在中间的时候,影响和前后区间的pvalue,需要更新两个值。
            else:
                # 计算合并后当前区间与前一个区间的pvalue替换
                temparray = np_regroup[chi_min_index-1:chi_min_index+1,1:]
                chi_table[chi_min_index - 1] = scipy.stats.chi2_contingency(temparray,correction=False)[1]
                # 计算合并后当前与后一个区间的pvalue替换
                temparray = np_regroup[chi_min_index:chi_min_index+2,1:]
                chi_table[chi_min_index] = scipy.stats.chi2_contingency(temparray,correction=False)[1]
                # 删除替换前的pvalue
                chi_table = np.delete(chi_table, chi_min_index + 1, axis=0)
        #更新当前最大的相邻区间的pvalue
        temp = max(chi_table)
    print("*"*40)
    print("最终相邻区间的pvalue值为:")
    print(chi_table)
    print("*"*40)
    #把结果保存成一个数据框。
    """
    可以根据自己的需求定制化。我保留两个结果。
    1. 显示分割区间,和该区间内不同标签的数量的表
    2. 为了方便pandas对该参数处理,把apply的具体命令打印出来。方便直接对数据集处理。
        serise.apply(lambda x:XXX)中XXX的位置
    """
    #将结果整合到一个表中,即上述中的第一个
    interval = []
    interval_num = np_regroup.shape[0]
    for i in range(interval_num):
        if i == 0:
            interval.append('x<=%f'%(np_regroup[i,0]))
        elif i == interval_num-1:
            interval.append('x>%f'%(np_regroup[i-1,0]))
        else:
            interval.append('x>%f and x<=%f'%(np_regroup[i-1,0],np_regroup[i,0]))
    result = pd.DataFrame(np_regroup)
    result[0] = interval
    result.columns = ['interval']+tags
    #整理series的命令,即上述中的第二个
    premise = "str(0) if "
    length_interval = len(interval)
    for i in range(length_interval):
        if i == length_interval-1:
            premise = premise[:-4]
            break
        premise = premise + interval[i] + " else " + 'str(%d+1)'%i + " if "
    return result,premise
pandas.cut:
pandas.cut(x, bins, right=True, labels=None, retbins=False, precision=3, include_lowest=False)
参数:
x,类array对象,且必须为一维,待切割的原形式
bins, 整数、序列尺度、或间隔索引。如果bins是一个整数,它定义了x宽度范围内的等宽面元数量,但是在这种情况下,x的范围在每个边上被延长1%,以保证包括x的最小值或最大值。如果bin是序列,它定义了允许非均匀in宽度的bin边缘。在这种情况下没有x的范围的扩展。
right,布尔值。是否是左开右闭区间
labels,用作结果箱的标签。必须与结果箱相同长度。如果FALSE,只返回整数指标面元。
retbins,布尔值。是否返回面元
precision,整数。返回面元的小数点几位
include_lowest,布尔值。第一个区间的左端点是否包含
t/cc_jjj/article/details/78878878

自定义分箱代码实现

import pandas as pd
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]
# 有一组人员年龄数据,希望将这些数据划分为“18到25”,“26到35”,“36到60”,“60以上”几个面元
bins = [18, 25, 35, 60, 100]
# 返回的是一个特殊的Categorical对象 → 一组表示面元名称的字符串
cats = pd.cut(ages, bins)
print(cats)
group_names = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior']###打上标签
cats1 = pd.cut(ages, bins, labels=group_names)
print(cats1)
aa = pd.value_counts(cats)  # 按照区间计数
print(aa)

变量分箱对模型的好处

1、降低异常值的影响,增加模型的稳定性


通过分箱来降低噪声,使模型鲁棒性更好


2、缺失值作为特殊变量参与分箱,减少缺失值填补的不确定性(分箱还可以解决缺失值 )


分箱的方法往往要配合变量编码使用,这就大大提高了变量的可解释性


3、增加变量的非线性


提高了模型的拟合能力


4、增加模型的预测效果


通常假设训练集和测试集满足同分布,分箱使连续变量离散化,更容易满足同分布的假设


即减少模型在训练集的表现和测试集的偏差


相关文章
|
SQL 分布式计算 数据挖掘
Hive SQL初级练习(30题)
Hive SQL初级练习(30题)
|
4月前
|
测试技术 数据安全/隐私保护
当我们谈代码的可维护性到底在谈说什么
这是一篇关于代码可维护性的深度实践指南:从“祖传屎山”的痛悟出发,用真实案例诠释命名、模块化、可测试性、一致性和简洁性五大核心;融合静态分析、自动化、Code Review等落地方法,揭示可维护性本质——不是追求完美,而是对时间、同事与未来的温柔负责。(239字)
338 1
|
8月前
|
数据可视化 前端开发 JavaScript
用Pyecharts绘制交互式中国地图:从数据到可视化全流程解析
Pyecharts是基于ECharts的Python地图可视化利器:支持零代码交互(悬停、缩放)、多级行政区划(省/市/县)、高度定制化(20+样式参数)。本文详解安装配置、数据规范、三步绘图、分段配色、悬停高亮及3D扩展,助你快速生成专业级热力地图。(239字)
1266 1
|
10月前
|
传感器 监控 前端开发
【源码开源】基于STM32的应急救援仓系统 | 救援效率和实时监控
基于STM32的应急救援仓系统充分体现了物联网与智能控制技术在公共安全领域的应用价值。通过环境监测、远程控制和报警管理等功能,实现了救援仓的智能化、可视化和高效管理。系统采用模块化设计,硬件稳定可靠,软件易于扩展升级,并通过MQTT协议保证了数据的实时性和准确性。
【源码开源】基于STM32的应急救援仓系统 | 救援效率和实时监控
|
10月前
|
SQL 自然语言处理 数据可视化
构建AI智能体:四十三、智能数据分析机器人:基于Qwen-Agent与Text2SQL的门票分析方案
摘要:本文介绍了一个基于Qwen-Agent和Text2SQL技术的智能门票数据分析系统。该系统通过自然语言交互降低技术门槛,使业务人员可直接查询和分析数据。系统采用分层架构设计,包含用户交互层、智能代理层、工具执行层和数据服务层,核心功能包括自然语言理解、SQL生成、数据查询和可视化展示。文章详细阐述了系统流程、核心代码实现及优化策略,展示了如何通过大语言模型实现企业级数据分析应用的智能化转型,有效解决了传统数据分析流程中响应慢、沟通成本高等痛点。
790 7
|
人工智能 算法 PyTorch
MindIE-LLM ATB模型推理全流程解析
最近,有很多小伙伴问我,如果他们想自己基于MindIE镜像中的文件适配新模型,可以怎么做? 为了实现这个目标,首先需要了解MindIE-LLM模型在推理过程中的代码调用流程,然后根据新模型的算法进行适配。
658 1
|
人工智能 开发框架 算法
Qwen-Agent:阿里通义开源 AI Agent 应用开发框架,支持构建多智能体,具备自动记忆上下文等能力
Qwen-Agent 是阿里通义开源的一个基于 Qwen 模型的 Agent 应用开发框架,支持指令遵循、工具使用、规划和记忆能力,适用于构建复杂的智能代理应用。
13754 13
Qwen-Agent:阿里通义开源 AI Agent 应用开发框架,支持构建多智能体,具备自动记忆上下文等能力
|
存储 算法 数据处理
Pandas高级数据处理:数据压缩与解压
本文介绍 Pandas 中的数据压缩与解压技术,探讨其在大数据集存储、远程传输和备份归档中的应用场景。Pandas 支持多种压缩格式(如 `.gzip`、`.bz2`、`.zip`),通过 `compression` 参数轻松实现数据的压缩与解压。文中还提供了常见问题的解决方案,如文件扩展名不匹配、内存不足和性能优化,并介绍了自动检测压缩格式和组合压缩加密的高级技巧。掌握这些功能可显著提升数据处理效率。
558 20
|
监控 Ubuntu Linux
使用VSCode通过SSH远程登录阿里云Linux服务器异常崩溃
通过 VSCode 的 Remote - SSH 插件远程连接阿里云 Ubuntu 22 服务器时,会因高 CPU 使用率导致连接断开。经排查发现,VSCode 连接根目录 ".." 时会频繁调用"rg"(ripgrep)进行文件搜索,导致 CPU 负载过高。解决方法是将连接目录改为"root"(或其他具体的路径),避免不必要的文件检索,从而恢复正常连接。
|
机器学习/深度学习 存储 缓存
【机器学习】随机森林、AdaBoost、GBDT、XGBoost从零开始理解
介绍了机器学习中的几种集成学习算法,包括随机森林、AdaBoost、梯度提升决策树(GBDT)和XGBoost,解释了它们的概念、优缺点、算法过程以及系统设计。
2984 5
【机器学习】随机森林、AdaBoost、GBDT、XGBoost从零开始理解

热门文章

最新文章