卡方分箱(Chi Merge 算法)

本文介绍了卡方分箱的原理,包括卡方分布的定义和卡方检验的基本思想,以及如何通过卡方值衡量实际值与理论值的偏离程度。此外,文章还提到了卡方分箱算法在数据处理中的应用,并展示了如何使用Chi Merge算法进行分箱操作。

卡方分箱原理及实现(Chi Merge 算法)

一. 卡方分布

卡方分布的定义:

若k个独立的随机变量Z1,Z2,…,Zk满足标准正态分布N(0, 1), 则这k个随机变量的平方和:
X=∑i=1kZi2 X = \sum_{i=1}^{k}Z_{i}^2 X=i=1kZi2
为服从自由度为k的卡方分布, 记做:
X−χ2(k)或者记作X−χk2 X-\chi^{2}(k) 或者记作X-\chi^2_{k} Xχ2(k)Xχk2

二.卡方检验

卡方检验是以卡方分布为基础的一种假设检验方法, 主要用于分类变量之间的独立性检验

基本思想: 根据样本数据推断总体的分布与期望分布是否有显著性差异, 或者推断两个分类变量是否相关或者独立

一般原假设为: 观察频数与期望频数没有差异, 或者两个变量相互独立不相关

卡方:表示为观察值与理论值间的偏离程度

卡方值的计算公式为:
Xk2=∑(A−E)2E X^{2}_{k} = \sum\frac{(A-E)^2}{E} Xk2=E(AE)2
其中A为实际频数, E为期望频数.

卡方值包含以下两个信息:

1.实际值与理论值偏差的绝对大小

2.差异程度与理论值的相对大小

根据卡方分布, 卡方统计量以及自由度, 可以确定在原假设成立的情况下获得当前统计量和更极端情况的概率p.如果p很小, 说明观察值与理论值的偏离程度

卡方分布表

横轴为p值, 纵轴为自由度

自由度k:(行数-1)*(列数-1)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2DmfpQnm-1579400182449)(C:\Users\15743\Pictures\Saved Pictures\卡方分箱算法.jpg)]

卡方分箱算法

算法主要包含两个阶段: 
初始化阶段和自底向上合并的阶段
1.初始化阶段: 首先按照属性值的大小进行排序(对于非连续特征, 需要先做数值转化, 比如坏账率, 然后排序), 然后将每个属性值单独作为一组
2.合并阶段:  
	(1) 对每一对相邻的组, 计算卡方值  
	(2) 根据计算的卡方值, 对其中最小的一对邻组合并为一组  
	(3) 不断重复(1), (2)直到计算出的卡方值都不低于事先设定的阈值, 或者分组数达到一定的数量
import numpy as np
import pandas as pd

from scipy.stats import chi2
# 计算卡方值
def chi_value(data):
    """
    Calculate Chi-square Value
    """
    assert type(data).__name__ == "ndarray" and np.ndim(data) <= 2
    # 计算行, 列之和
    col_sum = data.sum(axis=0)
    row_sum = data.sum(axis=1)
    e_sum = data.sum()
    # 计算期望频数
    # E = np.ones(arr.shape) * C_N / N
    # E = (E.T * R_N).T
    # square = (arr - E) ** 2 / E

    e = np.ones(data.shape) * col_sum / e_sum
    e = (e.T * row_sum).T
    square = (data - e) ** 2 / e
    square[e == 0] = 0

    return square.sum()

def chi_merge(df, col, target, max_group, threshold):
    """
    ChiMerge 卡方分箱
    df: dataframe
    col: 需要分箱的变量
    target: 类标签
    max_group: 最大分组
    threshold: 卡方阈值
    returns:
        cutoffs: 变量分箱列表 list

    """
    assert type(df).__name__ == "DataFrame"

    cross_tab = pd.crosstab(df[col], df[target])
    cross_stat = cross_tab.values

    # 分组区间是左闭右开的,如cutoffs = [1,2,3],则表示区间 [1,2) , [2,3) ,[3,3+)。
    cutoffs = cross_tab.index.values
    print("sorted cutoffs list:", cutoffs, "len cutoffs", len(cutoffs))
    if max_group is None:
        if threshold is None:
            cls_num = cross_stat.shape[-1]
            threshold = chi2.isf(0.05, df=cls_num-1)

    while True:
        min_value = None
        minidx = None

        # 对每一对相邻的组, 计算卡方值
        for i in range(len(cross_stat) - 1):
            chi_val = chi_value(cross_stat[i: i+2])
            print(chi_val)
            if min_value is None or (min_value > chi_val):
                min_value = chi_val
                minidx = i

        if (max_group is not None and max_group < len(cross_stat)) or (threshold is not None and min_value < threshold):
            tmp = cross_stat[minidx] + cross_stat[minidx + 1]
            cross_stat[minidx] = tmp
            cross_stat = np.delete(cross_stat, minidx + 1, minidx)
            cutoffs = np.delete(cutoffs, minidx + 1, 0)
            print("---", cutoffs)
        else:
            break
        return cutoffs


if __name__ == "__main__":
    df = pd.read_csv(r"D:\PycharmProjects\test\toadtest\germancredit.csv")
    df.columns = [i.lower() for i in df.columns]
    # target = "creditability" col = "duration of credit (month)"
    print(chi_merge(df, target="creditability", col='duration of credit (month)', max_group=5, threshold=None))

ion of credit (month)"
print(chi_merge(df, target=“creditability”, col=‘duration of credit (month)’, max_group=5, threshold=None))


分箱原理是一种常用的特征离散化法,可以将连续型特征转化为离散型特征,以便于机器学习算法的处理。其基本思想是将连续型特征划分为若干个区间,使得每个区间内的样本数量尽可能相等,同时区间之间的差异尽可能大。 具体实现过程如下: 1. 将连续型特征按照大小排序,然后将其分为k个等频区间,每个区间内的样本数量相等。 2. 对于每个区间,计算其实际值与期望值之间的差异,使用检验来衡量这种差异的显著性。 3. 如果某个区间的值小于预设的阈值,则将其与相邻的区间合并,直到所有区间的值都大于等于阈值为止。 4. 最终得到的k个区间就是特征的离散化结果。 下面是用Python实现分箱的示例代码: ```python import pandas as pd import numpy as np from scipy.stats import chi2_contingency def chi_merge(df, col, target, max_groups, confidence): """ 分箱函数 :param df: 数据集 :param col: 需要分箱的特征列名 :param target: 目标列名 :param max_groups: 最大分组数 :param confidence: 检验的置信度 :return: 分箱结果 """ # 将数据按照特征列排序 df = df.sort_values(col) # 将目标列转化为二元变量 df['target'] = np.where(df[target] == 1, 1, 0) # 计算每个分组的样本数量 total = df['target'].sum() count = df.groupby(col)['target'].agg(['sum', 'count']) count.columns = ['target', 'total'] count['non_target'] = count['total'] - count['target'] # 初始化分组 groups = [[i] for i in count.index] # 合并分组直到达到最大分组数或者所有分组的值都小于阈值 while len(groups) > max_groups: # 计算相邻分组的chi_values = [] for i in range(len(groups) - 1): group1 = groups[i] group2 = groups[i + 1] obs = np.array([[count.loc[group1, 'target'].sum(), count.loc[group1, 'non_target'].sum()], [count.loc[group2, 'target'].sum(), count.loc[group2, 'non_target'].sum()]]) chi2, p, dof, ex = chi2_contingency(obs) chi_values.append(chi2) # 找到值最小的分组 min_chi = np.min(chi_values) min_index = chi_values.index(min_chi) # 合并分组 groups[min_index] = groups[min_index] + groups[min_index + 1] groups.pop(min_index + 1) # 检查合并后的分组的值是否小于阈值 if min_chi < chi2.isf(1 - confidence, 1): break # 将分组转化为分箱结果 result = {} for i, group in enumerate(groups): for val in group: result[val] = i return result ``` 注意:这段代码中的检验使用了scipy库中的chi2_contingency函数,需要先安装该库。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值