ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

风控项目04---特征构造

2020-12-17 12:01:21  阅读:322  来源: 互联网

标签:分箱 ft creditability 04 特征 value 风控 --- data


目录

一:数据准备:

1.1: 数据的内在联系:

1: 关系的种类:
一对一:
一对多:
多对多:

2: 梳理关系画出ER图:例如下图:
在这里插入图片描述
3:明确任务是做什么?
例如:分析厚数据*常登陆*首单用户的逾期情况
数据量大,经常登录,第一次下单的逾期情况分析:
在这里插入图片描述
4: 可以将表结构展示到特征文档当中,说明取数逻辑
在这里插入图片描述

1.2: 样本设计和特征框架:

1: 定义观察期样本:
确定观察期(定X时间切面)和表现期(定Y的标签):申请贷款前往前推一年,申请贷款后,往后推迟一年看看是否逾期。
确定样本数目是否合理:少则1500,多不过5万。

2:数据的EDA:
在这里插入图片描述
3:梳理特征框架:RFM思想:

例如:用户账单关键信息:时间,金额,还款,额度
在这里插入图片描述

二:特征构造:

2.1: 静态信息特征和时间截面特征:

  • 1: 用户静态信息特征: 用户信息基本不变的特征:身份证号
  • 2: 用户时间截面特征:
  • 3: 未来信息:当前截面之后的数据。
    在这里插入图片描述
    案例: 假设用户进行三次贷款,前两次都是没有借贷,第三次才进行借贷。
    我的存储是这样的:
    在这里插入图片描述
    在这里插入图片描述
    当这两张表进行连接时,则总表是:
    在这里插入图片描述
    而实际上是这样的:

在这里插入图片描述
解决方案:加入快照存储:

在这里插入图片描述

2.2: 时间序列特征:

解释什么是时间序列特征?
某些特征,随着时间的变化而变化:例如不断购物,订单特征的不断改变。
在这里插入图片描述

2.3: 时间衍生序列案例:

数据的加载和准备:

import pandas as pd 
import numpy as np 
data = pd.read_excel('data/textdata.xlsx') 
data.head()

在这里插入图片描述
1:根据这个时间序列进行基于经验的人工特征衍生
例如计算最近P个月特征大于0的月份数:

#最近p个月,ft>0的月份数 
def Num(ft,p):
    #ft 特征名字 p特征大于0的月份数
    df=data.loc[:,ft+'1':ft+str(p)] 
    auto_value=np.where(df>0,1,0).sum(axis=1) 
    return ft+'_num'+str(p),auto_value

2:计算最近P个月特征ft等于0的月份数:

#最近p个月,ft=0的月份数 
def zero_cnt(ft,p): 
    df=data.loc[:,ft+'1':ft+str(p)]
    auto_value=np.where(df==0,1,0).sum(axis=1) 
    return ft+'_zero_cnt'+str(p),auto_value

3: 计算近p个月特征ft大于0的月份数是否大于等于1:

#最近p个月,ft>0的月份数是否>=1 
def Evr(ft,p): 
    df=data.loc[:,ft+'1':ft+str(p)]
    arr=np.where(df>0,1,0).sum(axis=1) 
    auto_value = np.where(arr,1,0) 
    return ft+'_evr'+str(p),auto_value

4:最近p个月,ft均值

#最近p个月,ft均值
def Avg(ft,p): 
    df=data.loc[:,ft+'1':ft+str(p)]
    auto_value=np.nanmean(df,axis = 1 )
    return ft+'_avg'+str(p),auto_value

5:计算最近p个月特征ft的和,最大值,最小值:

#最近p个月,ft和 
def Tot(ft,p): 
    df=data.loc[:,ft+'1':ft+str(p)] 
    auto_value=np.nansum(df,axis = 1)
    return ft+'_tot'+str(p),auto_value 

#最近(2,p+1)个月,ft和 
def Tot2T(ft,p):
    df=data.loc[:,ft+'2':ft+str(p+1)] 
    auto_value=df.sum(1) 
    return ft+'_tot2t'+str(p),auto_value 

#最近p个月,ft最大值 
def Max(ft,p): 
    df=data.loc[:,ft+'1':ft+str(p)] 
    auto_value=np.nanmax(df,axis = 1) 
    return ft+'_max'+str(p),auto_value 
#最近p个月,ft最小值 

def Min(ft,p): 
    df=data.loc[:,ft+'1':ft+str(p)]
    auto_value=np.nanmin(df,axis = 1) 
    return ft+'_min'+str(p),auto_value

6: 其余的衍生方法:

#最近p个月,最近一次ft>0到现在的月份数
def Msg(ft,p):
    df=data.loc[:,ft+'1':ft+str(p)] 
    df_value=np.where(df>0,1,0) 
    auto_value=[]
    for i in range(len(df_value)):
        row_value=df_value[i,:] 
        if row_value.max()<=0: 
            indexs='0' 
            auto_value.append(indexs)
        else:
            indexs=1 
            for j in row_value: 
                if j>0:
                    break 
                    indexs+=1
            auto_value.append(indexs) 
    return ft+'_msg'+str(p),auto_value
...

7: 最终我们能够衍生出很多列:
但是:上面这种无差别聚合方法进行聚合得到的结果,通常具有较高的共线性,但信息量并无明显增加,影响模型的鲁棒性和稳定性。

2.4:特征交叉(特征组合):

1:指不同特征之间基于常识、经验、数据挖掘技术进行分段组合实现特征构造,产生包
含更多信息的新特征。

2: 了解辛普森悖论:
辛普森悖论(Simpson’s Paradox)亦有人译为辛普森诡论,为英国统计学家EH!辛普森(EH.Simpson)于1951年提出的悖论,即在某个条件下的两组数据,分别讨论时都会满足某种性质,可是一旦合并考虑,却可能导致相反的结论

案例:例一:一所美国高校的两个学院,分别是法学院和商学院,新学期招生。人们怀疑这两个学院有性别歧视。现作如下统计:
在这里插入图片描述
为什么导致这个问题呢?
在这里插入图片描述
3:所以我们有些时候需要将特征交叉在一起使用。

2.5:特征变换:

  • 1:什么是分箱? : 分箱就是将连续变量离散化,合并成较少的状态。
  • 2:特征构造的过程中,对特征做分箱处理时必不可少的过程。
    例如: 年收入和年龄的关系:
    一个人的年收入可能在20到30谁的时候涨幅比较大,30到40岁涨幅比较小,40到50岁基本不变,50以后可能收入下降。这样的一个关系,如果我们用线性去拟合,则肯定不符合整体的规律,因此我们考虑将线性转换成一段一段的。(分箱操作)
  • 3:分箱有什么作用?
    在这里插入图片描述
  • 4:常见的分箱方法?
    等频分箱:
    在这里插入图片描述
    等距分箱:
    在这里插入图片描述
    卡方分箱:使用卡方检验确定最优分箱阈值
    将数据按等频或等距分箱后,计算卡方值,将卡方值较小的两个相邻箱体合并使得不同箱体的好坏样本比例区别放大,容易获得高IV。
    卡方分箱是利用独立性检验来挑选箱划分节点的阈值。卡方分箱的过程可以拆分为初始化和合并两步
    初始化:根据连续变量值大小进行排序,构建最初的离散化
    合并:遍历相邻两项合并的卡方值,将卡方值最小的两组合并,不断重复直到满足分箱数目要求

什么是卡方检验?
在这里插入图片描述

在这里插入图片描述

2.6:卡方分箱案例:

  • Toad 是专为工业界模型开发设计的Python工具包,特别针对评分卡的开发。
  • 安装toad工具:
    在这里插入图片描述

1: 加载数据:
data.replace({})是将原有的good和bad类型转换成01。

import pandas as pd 
import numpy as np 
import toad 
data = pd.read_csv('data/germancredit.csv')
data.replace({'good':0,'bad':1},inplace=True) 
print(data.shape) # 1000 data and 20 features 
data.head()

2:进行分箱操作:

# 1:初始化一个combiner类 
combiner = toad.transform.Combiner()

# 2: 训练数据并指定分箱方法,其它参数可选 
# min_samples: 每箱至少包含样本量,可以是数字或者占比 
# method='chi'指定分箱的方式:卡方分箱
# y='creditability' 是指定我们的标签列
combiner.fit(data,y='creditability',method='chi',min_samples = 0.05)

# 3:以字典形式保存分箱结果 
bins = combiner.export() 

# 4: 查看按照duration.in.month这一列分箱的结果: 
print('duration.in.month:', bins['duration.in.month'])

注意:分箱是根据每个特征列都会分成不同的分箱结果,而不是按照所有特征列分箱成一种分箱结果。
在这里插入图片描述
3:进行分箱处理:

import matplotlib.pyplot as plt
%matplotlib inline
from toad.plot import bin_plot 

# 1:初始化一个Combiner类
c2 = toad.transform.Combiner() 

# 2:这个时候我们传递进来的只是duration.in.month这一列,和y的便签 方法是卡方分箱,n_bins=7,指定分箱结果是7个
c2.fit(data[['duration.in.month','creditability']], y='creditability', method='chi',n_bins=7) 
# 3: 学习规律,数据已经是分箱之后的数据了。
transformed = c2.transform(data[['duration.in.month','creditability']],labels=True)

#4:传给bin_plot的数据必须是分箱转化之后的 
bin_plot(transformed,x='duration.in.month',target='creditability')

在这里插入图片描述
上图中柱形图表示每一箱的占比,折线图表示每一箱的坏样本率。一般折线图要呈现出单调的趋势。

4: 在风控中,我们希望得到的是坏样本率是个单调的,因此需要修改箱体的个数:
改成分5个箱体:

c2 = toad.transform.Combiner() 
c2.fit(data[['duration.in.month','creditability']], y='creditability', method='chi',n_bins=5) 
# 改成5箱 
transformed = c2.transform(data[['duration.in.month','creditability']],labels=True) 
#传给bin_plot的数据必须是分箱转化之后的
bin_plot(transformed,x='duration.in.month',target='creditability')

在这里插入图片描述

5: 测试其他分箱方法:
chi: 卡方分箱
kmeans: 聚类分箱

for method in ['chi', 'dt', 'quantile', 'step', 'kmeans']:
    c2 = toad.transform.Combiner() 
    c2.fit(data[['duration.in.month','creditability']], y='creditability', method=method, n_bins=5) 
    bin_plot(c2.transform(data[['duration.in.month','creditability']],labels=True), x='duration.in.month',target='creditability')

2.7:编码方案:

  • 1:多值无序类别特征需要做encoding处理,常见encoding方法:Onehot Encoding、Label Encoding、WOE Encoding

1: Onehot Encoding:
在这里插入图片描述
2:Label Encoding:
假设未婚的占比为20% 已婚的占比 40% 离异的占比为 10% 丧偶的占比为 30% 则我们用哪个0.2,0.4,0.1,0.3分别代表这个三列。

3:WOE Encoding:

在这里插入图片描述

2.8:使用toad计算woe:

1: 进行分箱操作:

# 导入划分测试集和训练集的包
from sklearn.model_selection import train_test_split 

# 1: 按照测试集为25%划分测试集和训练集
X_train,X_test,Y_train,Y_test = train_test_split(data.drop('creditability',axis=1),data['creditability'],test_size=0.25,random_state=450)

# 2:将训练集和测试集的标签列和特征列进行合并
data_train = pd.concat([X_train,Y_train],axis=1) 
data_test = pd.concat([X_test,Y_test],axis=1) 

#3:增加一列区分训练/测试的特征 
data_train['type'] = 'train' 
data_test['type'] = 'test' 



# 4:设置分箱边界
adj_bin = {'duration.in.month': [9, 12, 18, 33]} 

# 5: 创建一个Combiner对象
c2 = toad.transform.Combiner() 
# 设置分箱边界
c2.set_rules(adj_bin)
# 将训练集和测试集进行合并
data_ = pd.concat([data_train,data_test],axis = 0) 
# 
temp_data = c2.transform(data_[['duration.in.month','creditability','type']]) 


#绘制badrate_plot图 
from toad.plot import badrate_plot, proportion_plot 
# x = 指定X轴,x有两种值一个test/train
badrate_plot(temp_data, target = 'creditability', x = 'type', by = 'duration.in.month')

#绘制每一箱占比情况图 
proportion_plot(temp_data['duration.in.month'])

在这里插入图片描述
在这里插入图片描述
根据图我们发现:上面第一张图中的第一箱和第二箱的bad_rate存在倒挂,说明bad_rate不单调,需要调整。可以将第一箱和第二箱进行合并。

# 假定将第一箱、第二箱合并 
adj_bin = {'duration.in.month': [9,18,33]} 

c2.set_rules(adj_bin)
temp_data = c2.transform(data_[['duration.in.month','creditability','type']]) 
badrate_plot(temp_data, target = 'creditability', x = 'type', by = 'duration.in.month')

在这里插入图片描述
2:计算WOE的值:

#将特征的值转化为分箱的箱号。 
binned_data = c2.transform(data_train)
#计算WOE
transer = toad.transform.WOETransformer() 
#对WOE的值进行转化,映射到原数据集上。对训练集用fit_transform,测试集用transform. 
data_tr_woe = transer.fit_transform(binned_data, binned_data['creditability'], exclude= ['creditability','type']) 
data_tr_woe.head()

在这里插入图片描述

2.9: 时间序列缺失值处理:

白户:用户最后一次逾期距今的天数,如果填0,表示用户不会逾期?我们可以找最大的逾期天数,用这个最大的值填充。因为白户我们认为风险很大,不可能填充0。

在这里插入图片描述

2.10: 时间序列处理未来信息:

在这里插入图片描述
在这里插入图片描述

2.11:用户关联特征:

在这里插入图片描述

在这里插入图片描述

标签:分箱,ft,creditability,04,特征,value,风控,---,data
来源: https://blog.csdn.net/qq_41341757/article/details/111300982

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有