‘壹’ 如何在python中实现数据的最优分箱
Monotonic Binning with Python
Monotonic binning is a data preparation technique widely used in scorecard development and is usually implemented with SAS. Below is an attempt to do the monotonic binning with python.
Python Code:
# import packages
import pandas as pd
import numpy as np
import scipy.stats.stats as stats
# import data
data = pd.read_csv("/home/liuwensui/Documents/data/accepts.csv", sep = ","念颤滚, header = 0)
# define a binning function
def mono_bin(Y, X, n = 20):
# fill missings with median
X2 = X.fillna(np.median(X))
r = 0
while np.abs(r) < 1:
d1 = pd.DataFrame({"X": X2, "Y": Y, "Bucket": pd.qcut(X2, n)})
d2 = d1.groupby('Bucket', as_index = True)
r, p = stats.spearmanr(d2.mean().X, d2.mean().Y)
n = n - 1
d3 = pd.DataFrame(d2.min().X, columns = ['min_' + X.name])
d3['max_' + X.name] = d2.max().X
d3[Y.name] = d2.sum().Y
d3['total'] = d2.count().Y
d3[Y.name + '仔余_rate'] = d2.mean().Y
d4 = (d3.sort_index(by = '洞销min_' + X.name)).reset_index(drop = True)
print "=" * 60
print d4
mono_bin(data.bad, data.ltv)
mono_bin(data.bad, data.bureau_score)
mono_bin(data.bad, data.age_oldest_tr)
mono_bin(data.bad, data.tot_tr)
mono_bin(data.bad, data.tot_income)
Output:
============================================================
min_ltv max_ltv bad total bad_rate
0 0 83 88 884 0.099548
1 84 92 137 905 0.151381
2 93 98 175 851 0.205640
3 99 102 173 814 0.212531
4 103 108 194 821 0.236297
5 109 116 194 769 0.252276
6 117 176 235 793 0.296343
============================================================
min_bureau_score max_bureau_score bad total bad_rate
0 443 630 325 747 0.435074
1 631 655 242 721 0.335645
2 656 676 173 721 0.239945
3 677 698 245 1059 0.231350
4 699 709 64 427 0.149883
5 710 732 73 712 0.102528
6 733 763 53 731 0.072503
7 764 848 21 719 0.029207
============================================================
min_age_oldest_tr max_age_oldest_tr bad total bad_rate
0 1 59 319 987 0.323202
1 60 108 235 975 0.26
2 109 142 282 1199 0.235196
3 143 171 142 730 0.194521
4 172 250 125 976 0.128074
5 251 588 93 970 0.095876
============================================================
min_tot_tr max_tot_tr bad total bad_rate
0 0 8 378 1351 0.279793
1 9 13 247 1025 0.240976
2 14 18 240 1185 0.202532
3 19 25 165 1126 0.146536
4 26 77 166 1150 0.144348
============================================================
min_tot_income max_tot_income bad total bad_rate
0 0.00 2000.00 323 1217 0.265407
1 2002.00 2916.67 259 1153 0.224631
2 2919.00 4000.00 226 1150 0.196522
3 4001.00 5833.33 231 1186 0.194772
4 5833.34 8147166.66 157 1131 0.138815
‘贰’ 特征稳定性
part1:特征稳定性
特征稳定性,就磨纳是关注该特征的取值随着瞎运没时间的推移会不会发生大的波动,
对特征稳定性的关注,一定要在建模之前完成,从一开始就避免将那些本身不太稳定的特征选入模型。一旦发现有特征稳定性不满足要求,则需要对其进行剔除后重新建模,避免不必要的重复性劳动。
通常采用PSI(PopulationStability Index,群体稳定性指数)指标评估特征稳定性。
part2:常用方法:
PSI反映了验证样本在各分数段的分布与建模样本分布的稳定性,稳定性是有参照的,因此需要有两个分布—— 实际分布 (actual)和 预期分布 (expected)。其中,在建模时通常以训练样本(In the Sample, INS)作为预期分布,而验证样本通常作为实际分布
<pre>PSI = sum((实际占比-预期占比)* ln(实际占比/预期占比))</pre>
比如训练一个logistic回归模型,预测时候会有个概率输出 p
测试集上的输出设定为p1,将它从小到大排序后10等分,如:
<pre>0.0-0.1
0.1-0.2
0.2-0.3... </pre>
现在用这个模型去对新的样本进行预测,预测结果叫p2,按p1的区间也划分为10等分。
<pre>实际占比 = p2上在各区间的用户占比
预期占比 = p1上各区间的用户占比</pre>
意义就是如果模型更稳定,那么p1和p2上各区间的用户应该是相近的,占比不会变动很大,也就是预测出来的概率不会差距很大。
PS:除了按概率值大小等距十等分外,还可以对概率排序后按数量十等分,两种方法计算得到的psi可能有所区别但数值相差不大
一般认为:
<pre>PSI<0.1 :模型稳定性很高
0.1-0.25:一般,继续监控后续变化
PSI>0.25: 模型稳定性差,建议重做</pre>
step1: 将变量预期分布(excepted)进行分箱(binning)离散化,统计各个分箱里的样本占比 注意: 1. 分箱可以是等频、等距或其他方式,分箱方式不同,将导致计算结果略微有差异; 2. 对于连续型变量(特征变量、模型分数等),分箱数需要设置合理,一般设为10或20;对于离散型变量,如果分箱太多可以提前考虑合并小分箱;分箱数太多,可能会导致每个分箱内的样本量太少而失去统计意义;分箱数太少,又会导致计算结果精度降低
step2: 按相同分箱区间,对实际分布(actual)统计各分箱内的样本占比
step3: 计 算各分箱内的A - E和Ln(A / E),
计算index = (实际占比 - 预期占比)* ln(实际占比 / 预期占比)
step4: 将各分箱的index进行求和,即得到最终的PSI
[图片上传失败...(image-fc79b3-1637314904243)]
相对熵(relative entropy),又被称为Kullback-Leibler散度(Kullback-Leibler divergence)或信息散度(information divergence),是两个概率分布间差异的非对称性度量。
划重点——KL散度不满足对称性。
相对熵可以衡量两个随机分布之间的"距离“。
相对熵和PSI的概念非常相近:当两个随机分布完全一样时,PSI = 0;反之,差异越大,PSI越大。
相对熵的公式:
在信息理论中,相对熵等价于两个概率分布的悄毕信息熵(Shannon entropy)的差值:
[图片上传失败...(image-7a9318-1637314904243)]
其中,P(x)表示数据的真实分布,而Q(x)表示数据的观察分布。上式可以理解为:
[图片上传失败...(image-57d277-1637314904243)]
KL散度具有非对称性
相对熵与PSI之间的关系:
[图片上传失败...(image-76a049-1637314904243)]
将PSI计算公式变形后可以分解为2项:
因此,PSI本质上是实际分布(A)与预期分布(E)的KL散度的一个对称化操作。其双向计算相对熵,并把两部分相对熵相加,从而更为全面地描述两个分布的差异。
在业务上,一般以训练集(INS)的样本分布作为预期分布,进而跨时间窗按月/周来计算PSI,得到Monthly PSI Report,进而剔除不稳定的变量。同理,在模型上线部署后,也将通过PSI曲线报表来观察模型的稳定性。
参考:
(17条消息) PSI群体稳定指数-Python实现_u010654299的博客-CSDN博客_psi python
https://zhuanlan.hu.com/p/79682292
‘叁’ 12个销售价格记录如下怎么写python
1、假设12个销售价格记录组已经排序如下:5, 10, 11, 13, 15, 35, 50, 55, 72, 92, 204, 215 使用如下每种方法将它们划分成四个箱。等频(等深)划分时,15在第几个宴渣箱子内? (2 )
等宽划分晌旁悄:将整个区域启毕划分成N个相同大小的间隔
等频划分:将整个区域划分为N个间隔,各个间隔中包含的样本数目大致相同
举个例子: 假定由年龄组合:{0,4,12,16,18,24,26,28}
按照等宽的话,子区间宽度相同,取宽度为10,则:{0,4},{12,16,16,18},{24,26,28}
等频的话,子集元素个数相同,则 {0,4,12},{16,16,18},{24,26,28} 回归到这个题:分成四个箱子,一个箱子装3个,{5,10,11},{13,15,35}{...}{...}很明显在第二个箱子中
‘肆’ python用卡方检验,自动分箱,结果是否可靠有待验证
def calc_chiSquare(sampleSet, feature, target):
'''
计算某个特征每种属性值的卡方统计量
params:
sampleSet: 样本集
feature: 目标特征
target: 目标Y值 (0或1) Y值为二分类变量
return:
卡方统计量dataframe
feature: 特征名称
act_target_cnt: 实际坏样本数
expected_target_cnt:期望坏样本数
chi_square:卡方统计量
'''
# 计算样本期望频率
target_cnt = sampleSet[target].sum()
sample_cnt = len(sampleSet[target])
expected_ratio = target_cnt * 1.0/sample_cnt
# 对变量按属性值从大到小排序
df = sampleSet[[feature, target]]
col_value = list(set(df[feature]))
# 计算每一个属性值对应的卡方统计量等信息
chi_list = []; target_list = []; expected_target_list = []
for value in col_value:
df_target_cnt = df.loc[df[feature] == value, target].sum()
df_cnt = len(df.loc[df[feature] == value, target])
expected_target_cnt = df_cnt * expected_ratio
chi_square = (df_target_cnt - expected_target_cnt)**2 / expected_target_cnt
chi_list.append(chi_square)
target_list.append(df_target_cnt)
expected_target_list.append(expected_target_cnt)
# 结果输出到dataframe, 对应字段为特征属性值, 卡方统计量, 实际坏样本量塌拆, 期望坏样本量
chi_stats = pd.DataFrame({feature:col_value, 'chi_square':chi_list,
'act_target_cnt':target_list, 'expected_target_cnt':expected_target_list})
return chi_stats[[feature, 'act_target_cnt', 'expected_target_cnt', 'chi_square']]
def chiMerge_maxInterval(chi_stats, feature, maxInterval=5):
'''
卡方分箱合并--最大区间限制法
params:
chi_stats: 卡方统计量dataframe
feature: 目标特征
maxInterval:最大分箱数阈值
return:
卡方合并结果dataframe, 特征分割敏老split_list
'''
桥衫升 group_cnt = len(chi_stats)
split_list = [chi_stats[feature].min()]
# 如果变量区间超过最大分箱限制,则根据合并原则进行合并
while(group_cnt > maxInterval):
min_index = chi_stats[chi_stats['chi_square']==chi_stats['chi_square'].min()].index.tolist()[0]
# 如果分箱区间在最前,则向下合并
if min_index == 0:
chi_stats = merge_chiSquare(chi_stats, min_index+1, min_index)
# 如果分箱区间在最后,则向上合并
elif min_index == group_cnt-1:
chi_stats = merge_chiSquare(chi_stats, min_index-1, min_index)
# 如果分箱区间在中间,则判断与其相邻的最小卡方的区间,然后进行合并
else:
if chi_stats.loc[min_index-1, 'chi_square'] > chi_stats.loc[min_index+1, 'chi_square']:
chi_stats = merge_chiSquare(chi_stats, min_index, min_index+1)
else:
chi_stats = merge_chiSquare(chi_stats, min_index-1, min_index)
group_cnt = len(chi_stats)
chiMerge_result = chi_stats
split_list.extend(chiMerge_result[feature].tolist())
return chiMerge_result, split_list
def chiMerge_minChiSquare(chi_stats, feature, dfree=4, cf=0.1, maxInterval=5):
'''
卡方分箱合并--卡方阈值法
params:
chi_stats: 卡方统计量dataframe
feature: 目标特征
maxInterval: 最大分箱数阈值, default 5
dfree: 自由度, 最大分箱数-1, default 4
cf: 显着性水平, default 10%
return:
卡方合并结果dataframe, 特征分割split_list
'''
threshold = get_chiSquare_distuibution(dfree, cf)
min_chiSquare = chi_stats['chi_square'].min()
group_cnt = len(chi_stats)
split_list = [chi_stats[feature].min()]
# 如果变量区间的最小卡方值小于阈值,则继续合并直到最小值大于等于阈值
while(min_chiSquare < threshold and group_cnt > maxInterval):
min_index = chi_stats[chi_stats['chi_square']==chi_stats['chi_square'].min()].index.tolist()[0]
# 如果分箱区间在最前,则向下合并
if min_index == 0:
chi_stats = merge_chiSquare(chi_stats, min_index+1, min_index)
# 如果分箱区间在最后,则向上合并
elif min_index == group_cnt-1:
chi_stats = merge_chiSquare(chi_stats, min_index-1, min_index)
# 如果分箱区间在中间,则判断与其相邻的最小卡方的区间,然后进行合并
else:
if chi_stats.loc[min_index-1, 'chi_square'] > chi_stats.loc[min_index+1, 'chi_square']:
chi_stats = merge_chiSquare(chi_stats, min_index, min_index+1)
else:
chi_stats = merge_chiSquare(chi_stats, min_index-1, min_index)
min_chiSquare = chi_stats['chi_square'].min()
group_cnt = len(chi_stats)
chiMerge_result = chi_stats
split_list.extend(chiMerge_result[feature].tolist())
return chiMerge_result, split_list
def get_chiSquare_distuibution(dfree=4, cf=0.1):
'''
根据自由度和置信度得到卡方分布和阈值
params:
dfree: 自由度, 最大分箱数-1, default 4
cf: 显着性水平, default 10%
return:
卡方阈值
'''
percents = [0.95, 0.90, 0.5, 0.1, 0.05, 0.025, 0.01, 0.005]
df = pd.DataFrame(np.array([chi2.isf(percents, df=i) for i in range(1, 30)]))
df.columns = percents
df.index = df.index+1
# 显示小数点后面数字
pd.set_option('precision', 3)
return df.loc[dfree, cf]
def merge_chiSquare(chi_result, index, mergeIndex, a = 'expected_target_cnt',
b = 'act_target_cnt', c = 'chi_square'):
'''
params:
chi_result: 待合并卡方数据集
index: 合并后的序列号
mergeIndex: 需合并的区间序号
a, b, c: 指定合并字段
return:
分箱合并后的卡方dataframe
'''
chi_result.loc[mergeIndex, a] = chi_result.loc[mergeIndex, a] + chi_result.loc[index, a]
chi_result.loc[mergeIndex, b] = chi_result.loc[mergeIndex, b] + chi_result.loc[index, b]
chi_result.loc[mergeIndex, c] = (chi_result.loc[mergeIndex, b] - chi_result.loc[mergeIndex, a])**2 /chi_result.loc[mergeIndex, a]
chi_result = chi_result.drop([index])
chi_result = chi_result.reset_index(drop=True)
return chi_result
for col in bin_col:
chi_stats = calc_chiSquare(exp_f_data_label_dr, col, 'label')
chiMerge_result, split_list = chiMerge_maxInterval(chi_stats, col, maxInterval=5)
print(col, 'feature maybe split like this:', split_list)
‘伍’ 如何在python中实现数据的最优分箱
其实任何开发工弊和核具只是把算法变成代码,根本上是你要想清楚如何棚吵分箱。
你所需要的最优分箱应该是从所有分箱的可能中找到具有最小方差的方案,分箱的数量通常按照等频或者等宽划分,还是要预设或者通过最优化计算得到。
然后,对应每种分箱方法计算其方差,你找到找到相应的函数,把这租掘个方差的计算方法实现代码。
对Python完全不熟,帮不了你。你可以搜一些代码,自己调试和验证一下
‘陆’ python 对toad里面的toad.metrics.KS_bucket函数改写成自定义分段
toad函数里面有个 类似于woe 统计各段的好坏,好坏比, 累计好坏比,KS的一个数为
toad.metrics.KS_bucket
此函数中有两个参数,可以 是等频分,也可以 是等距分箱滚雹,但此分箱均是以分数的最大培帆大最小值 为基础划分的。
我想把整成0~1区间的,中槐所以对原函数进行了修改。
‘柒’ python最优分箱中woe计算(求大圣)
>>> list =[None,None,None,None,"a","b","c",None,"d",12,None,2,4,5,4]>>> list = list[4:]>>> len(list)11>>州虚> list['a', 'b', 'c', None, 'd', 12, None, 2, 4, 5, 4]>>>#如果你的册拍燃list 格式是相同的 比如前面4个都是None,这贺扒个格式是固定的,那么切片很容易解决
‘捌’ 利用分箱光滑技术可以进行什么
给定一个数据集waitakere.txt,该数据集中含有大量的噪音数据。具体操作要求:1)该数据集的偶数位均为噪音数据,判断偶数位是否为0,若为0,利用1替换。2)对转换后的数据集进行排序,利用分闭茄箱技术来光滑数据。假设有10个桶,实现“用箱均值光滑”、 “用箱中位数光滑”、“用箱边界光滑”三种技术。
waitakere.txt:
这只是一部分数据,只是为了示例噪音数据
1 0 3 2 0 3
4 0 1 0 0 0
0 0 0 1 0 0
0 0 0 0 7 0
0 8 9 0 9 0
0 6 0 5 0 3
6 0 7 0 1 0
......
登录后侍态局复制
解题思路:首先读入数据到列表里,然后对数据进行排序,将数据划分到10个箱中。对于箱均值光滑,箱中每一个值都被替换为箱中的均值。对于箱中位数光滑,箱中每一个值都被替换为箱中的中位数。对于箱边界光滑,箱中每一个值都被替换为最近的边界值。
以下为python代码实现老让部分:
import numpy as np
def binning(filename,box_num):
my_list=[]
my_list1=[]
noise_data = open(filename)
for line in noise_data.readlines():
dataline=line.strip()
my_list.append(dataline)
for i in range(0,len(my_list)):
my_list[i]=int(my_list[i])
if (i+1) % 2==0 and my_list[i]==0:
my_list[i]=1
my_list1=sorted(my_list)
#print my_list1
box_list=[]
len_box=int(np.ceil(len(my_list1)/float(box_num)))
for i in range(0,10):
each_box=my_list1[i*len_box:(i+1)*len_box]
box_list.append(each_box)
return box_list
def box_mean_smooth(box_list):
for i in range(0,len(box_list)):
box_avg=int(np.average(box_list[i]))
for j in range(0,len(box_list[i])):
box_list[i][j]=box_avg
return box_list
def box_mid_smooth(box_list):
for i in range(0,len(box_list)):
box_mid=int(np.median(box_list[i]))
for j in range(0,len(box_list[i])):
box_list[i][j]=box_mid
return box_list
def box_boundary_smooth(box_list):
for i in range(0,len(box_list)):
left_bdy=box_list[i][0]
right_bdy=box_list[i][-1]
for j in range(0,len(box_list[i])):
if abs(box_list[i][j]-left_bdy)<abs(box_list[i][j]-right_bdy):
box_list[i][j]=left_bdy
else:
box_list[i][j]=right_bdy
return box_list
filename='waitakere.txt'
box_list=binning(filename,10)
print box_list
print box_mean_smooth(box_list)
print box_mid_smooth(box_list)
print box_boundary_smooth(box_list)
登录后复制
下图为实验结果截图:
由于数据较多,截图只是一部分
python
数据
银川旅游景点攻略,这个地方驴友必去之一!良心推荐
精选推荐
广告
python 等深分箱法(均值平滑技术、边界值平滑技术)
1.3W阅读·6评论·24点赞
2020年12月10日
数据挖掘概念与技术(第三版)课后答案——第三章
2.2W阅读·201评论·119点赞
2020年7月3日
python S-G (Savitzky–Golay filter) 平滑滤波和kalman滤波滤掉噪声实现实例,有可视化结果
357阅读·0评论·0点赞
2022年11月10日
R语言数据挖掘(2) 数据预处理
2292阅读·0评论·1点赞
2017年10月10日
数据认知与数据预处理--数据预处理
348阅读·0评论·0点赞
2022年6月23日
数据挖掘复习
815阅读·0评论·0点赞
2021年12月20日
美人鱼公主参加聚会装扮美人鱼游戏
精选推荐
广告
python 数据、曲线平滑处理
9904阅读·0评论·16点赞
2022年4月21日
数据挖掘如何分箱以及如何对每个箱子中的数据进行平滑处理
2.0W阅读·2评论·38点赞
2019年6月24日
数据挖掘概念与技术(原书第三版)范明 孟小峰译-----第三章课后习题答案
2.6W阅读·13评论·21点赞
2017年5月21日
python 数据可视化 -- 真实数据的噪声平滑处理
2779阅读·0评论·2点赞
2019年2月11日
【6】python生成数据曲线平滑处理——(Savitzky-Golay 滤波器、convolve滑动平均滤波)方法介绍,推荐玩强化学习的小伙伴收藏
2612阅读·2评论·3点赞
2021年8月12日
数据挖掘理论与算法笔记
368阅读·0评论·0点赞
2021年6月10日
《数据挖掘概念与技术》学习笔记-第三章
3957阅读·0评论·6点赞
2020年2月14日
这个神奇的库,可以将数据平滑化并找到异常点
135阅读·0评论·0点赞
2022年6月9日
python数据平滑处理,numpy之数据平滑处理
3253阅读·0评论·0点赞
2021年4月27日
python 数据平滑_数据平滑方法的原理和应用
1394阅读·0评论·0点赞
2020年12月9日
python使曲线变得平滑_如何在Python中平滑数据?
3234阅读·0评论·1点赞
2020年12月4日
numpy模块的使用(二)
257阅读·0评论·2点赞
2020年10月3日
去首页
看看更多热门内容
评论1
扣尼奇哇
赞
写得好