金融风控-->客户流失预警模型-->特征工程
2017-07-10 15:28
447 查看
上一篇博文中,我们对金融数据(连续性变量,类别性变量)进行了可视化操作,以及单因子分析,多因子分析等初始预处理。得出了变量和目标变量的相关性。
本篇博文中将对金融数据进行全面详细的数据预处理以及特征工程。这里包括以下几点:
极端值的处理
缺失值的处理
特殊变量的处理
构造流失行为的特征
处理离群值或者极端值并不是数据建模的必要流程,然而,了解它们对预测模型的影响也是大有裨益的。
数据分析师们需要自己判断处理离群值的必要性,并结合实际问题选取处理方法。
检测离群值的重要性:由于离群值的存在,模型的估计和预测可能会有很大的偏差或者变化
可以选择对极端值不敏感的模型,例如KNN,决策树
那么如何检测某个特征数据是否存在极端值呢?
1)对样本数据进行可视化
由上图可知,对于“ASSET_CUR_ALL_BAL”这个特征的数据,很明显存在离群点。
经过对数据的统计可知:
①大于10000000的样本只占0.006%
②除去极端值外,其余样本的均值是115443,标准差是179359
③极端值是均值的386倍,偏离247个标准差
2) 3-sigma方法检
一般来说,如果某个特征数据,最大值为maxValue,均值为mean,标准差为std。如果满足maxValue>mean+3*std,那么我们就认为这个特征数据存在离群点。
那么如果某个特征数据存在离群点,应该如何进行处理呢?
人为降低极端值到某个正常的值,例如用95%的分位点代替 例:因为透支的原因,导致信用卡使用额度超过100%,可以用100%来代替
删除极端值(慎重) 例:极个别持卡人的年龄超过85岁
单独建模型 例:信用卡额度特别高
完全随机缺失:缺失值跟其他变量无关,例如婚姻状况的缺失
随机缺失:缺失值依赖于其他变量,例如“配偶姓名”的缺失取决于“婚姻状况”
完全非随机缺失:缺失值依赖于自己,例如高收入人群不愿易提供家庭收入
处理方法
删除有缺失值的属性或者样本(土豪行为)
插补填充(常用于完全随机缺失且缺失度不高的情形中)
将缺失当成一种属性值(常用于完全非随机缺失)
连续变量缺失值的处理
1)对于完全随机缺失,当缺失率不高时,可以:
用常数补缺,例如均值 特别地,如果存在极端值,要考虑是否剔除极端值后再计算均值
从非缺失值中随机抽样赋予缺失样本
2)对于依赖于其他某变量的随机缺失,可以在同一层内,用完全随机缺失的方法进行补缺
例如:变量“收入”取决于“工作状态”。当“工作状态”=“有工作”时,缺失的“收入”可以用所有“有工作”的持卡人的已知收入的均值代替
3)对于完全非随机缺失,可以当成一种属性,将该变量转化成类别变量
直接进行二值化,将该特征数据分为缺失值和非缺失值两类
考虑给定一个step(比如age,我们可以考虑每隔2/3岁为一个步长),然后把它离散化,之后把NaN作为一个type加到属性类目中。
类别变量缺失值的处理
当缺失率很低时
最常出现的类别补缺
可以从其他已知的样本中随机抽样进行补缺
当缺失率很高时
考虑剔除该属性
当缺失率介于“很低”和“很高”时
可以当成一种类别
one-hot编码
浓度编码
WOE编码
对日期/时间型变量
时间是否为一个节日,是否在一个时间段(类别型);或者计算距离某个日子变成间隔型;或者某个时间段内发生了多少次变成组合型等等;这个需要结合具体应用场景。使其变成离散型。
可以基于某个基准日期,转化为天数
以观察点为基准,将所有开户日期转为距离观察点的天数(month-on-book)
丰富的内部交易明细数据,包括本币活期储蓄波动率,本币活期储蓄月日均余额,。。。,电话银行总交易笔数
可以构建的特征:
①不同交易的数额的比例
②单笔交易的平均数额
③某种交易的笔数占全部交易笔数的比例
例如:
最大波动=max{本币一年以下波动,本币一年以上波动率,储蓄类资产波动率,本币储蓄波动率}
若信息存在冗余,需要按情况进行剔除
情况一:
“本币活期月日均余额占比” = 1 – “本币定期月日均余额占比”
变量“本币活期月日均余额占比 ”与“本币定期月日均余额占比”存在冗余性,知道其一必知道其二,需要剔除一个。
情况二
“资产当前总余额 ”= “本币储蓄当前总余额 ”+ “外币储蓄当前总余额”
如果是(广义)线性回归模型,三者不能同时放进模型。对于树模型,可以将其中任意两个放进模型,剩余的做转换,比如做一个离散变换。
外部数据包含了客户在电信运营商的详情
包括:
通话时间与次数
话费详情
特定的呼叫行为
其他信息
可以衍生的特征
月平均通话时间的变化=过去三个月月平均通话时间 − 过去六个月月平均通话时间
月平均通话次数的变化=过去三个月月平均通话次数 − 过去六个月月平均通话次数
月平均缴纳话费的变化=过去三个月月平均缴纳话费 − 过去六个月月平均缴纳话费
本篇博文中将对金融数据进行全面详细的数据预处理以及特征工程。这里包括以下几点:
极端值的处理
缺失值的处理
特殊变量的处理
构造流失行为的特征
极端值的处理
极端值:又称离群值,往往会扭曲预测结果并影响模型精度。回归模型(线性回归,广义线性回归)中离群值的影响尤其大,使用该模型时我们需要对其进行检测和处理。处理离群值或者极端值并不是数据建模的必要流程,然而,了解它们对预测模型的影响也是大有裨益的。
数据分析师们需要自己判断处理离群值的必要性,并结合实际问题选取处理方法。
检测离群值的重要性:由于离群值的存在,模型的估计和预测可能会有很大的偏差或者变化
可以选择对极端值不敏感的模型,例如KNN,决策树
那么如何检测某个特征数据是否存在极端值呢?
1)对样本数据进行可视化
由上图可知,对于“ASSET_CUR_ALL_BAL”这个特征的数据,很明显存在离群点。
经过对数据的统计可知:
①大于10000000的样本只占0.006%
②除去极端值外,其余样本的均值是115443,标准差是179359
③极端值是均值的386倍,偏离247个标准差
2) 3-sigma方法检
一般来说,如果某个特征数据,最大值为maxValue,均值为mean,标准差为std。如果满足maxValue>mean+3*std,那么我们就认为这个特征数据存在离群点。
那么如果某个特征数据存在离群点,应该如何进行处理呢?
人为降低极端值到某个正常的值,例如用95%的分位点代替 例:因为透支的原因,导致信用卡使用额度超过100%,可以用100%来代替
def decrease_extreme_value(validDf,col): descStats = validDf[col].describe() mu = descStats['mean'] std = descStats['std'] maxVal = descStats['max'] # detect the extreme value using 3-sigma method if maxVal > mu + 3 * std: for i in list(validDf.index): if validDf.loc[i][col] > mu + 3 * std: # decrease the extreme value to normal level validDf.loc[i][col] = mu + 3 * std # re-calculate the mean based on cleaned data mu = validDf[col].describe()['mean']
删除极端值(慎重) 例:极个别持卡人的年龄超过85岁
单独建模型 例:信用卡额度特别高
缺失值的处理
缺失类型完全随机缺失:缺失值跟其他变量无关,例如婚姻状况的缺失
随机缺失:缺失值依赖于其他变量,例如“配偶姓名”的缺失取决于“婚姻状况”
完全非随机缺失:缺失值依赖于自己,例如高收入人群不愿易提供家庭收入
处理方法
删除有缺失值的属性或者样本(土豪行为)
插补填充(常用于完全随机缺失且缺失度不高的情形中)
将缺失当成一种属性值(常用于完全非随机缺失)
连续变量缺失值的处理
1)对于完全随机缺失,当缺失率不高时,可以:
用常数补缺,例如均值 特别地,如果存在极端值,要考虑是否剔除极端值后再计算均值
从非缺失值中随机抽样赋予缺失样本
def MakeupMissing(df,col,method): ''' :param df: dataset containing columns with missing value :param col: columns with missing value :param type: the type of the column, should be Continuous or Categorical :return: the made up columns ''' #Take the sample with non-missing value in col validDf = df.loc[df[col] == df[col]][[col]] if validDf.shape[0] == df.shape[0]: return 'There is no missing value in {}'.format(col) #copy the original value from col to protect the original dataframe missingList = [i for i in df[col]] #get the descriptive statistics of col descStats = validDf[col].describe() mu = descStats['mean'] std = descStats['std'] maxVal = descStats['max'] #detect the extreme value using 3-sigma method if maxVal > mu+3*std: for i in list(validDf.index): if validDf.loc[i][col] > mu+3*std: #decrease the extreme value to normal level validDf.loc[i][col] = mu + 3 * std #re-calculate the mean based on cleaned data mu = validDf[col].describe()['mean'] for i in range(df.shape[0]): if df.loc[i][col] != df.loc[i][col]: ##自己不等于自己,表示该数值为NAN缺失值 #use the mean or sampled data to replace the missing value if method == 'Mean': missingList[i] = mu ## mu为剔除极端值以后的均值 elif method == 'Random': missingList[i] = random.sample(validDf[col],1)[0] ##从非缺失值内随机抽一个样本进行填充
2)对于依赖于其他某变量的随机缺失,可以在同一层内,用完全随机缺失的方法进行补缺
例如:变量“收入”取决于“工作状态”。当“工作状态”=“有工作”时,缺失的“收入”可以用所有“有工作”的持卡人的已知收入的均值代替
3)对于完全非随机缺失,可以当成一种属性,将该变量转化成类别变量
直接进行二值化,将该特征数据分为缺失值和非缺失值两类
考虑给定一个step(比如age,我们可以考虑每隔2/3岁为一个步长),然后把它离散化,之后把NaN作为一个type加到属性类目中。
类别变量缺失值的处理
当缺失率很低时
最常出现的类别补缺
可以从其他已知的样本中随机抽样进行补缺
对于类别型变量的随机抽样补缺这里需要详细讲下: 现在我们假设有一个类别型变量X,它有三个类型的取值分别为[x1,x2,x3],我们分布计算出x1,x2,x3在X中出现频率,分别为p1,p2,p3, 并将其频率代替为其概率。很明显p1+p2+p3=1。再计算出其累积概率,以列表形式[0,p1,p1+p2,p1+p2+p3]。每次遇到一个缺失值时, 随机抽取一个值a~unifor(0,1),a是(0,1)之间的数, 如果a<p1:把x1来代替这个缺失值;如果p1<a<=p1+p2:把x2代替这个缺失值; 如果p1+p2<a<=p1+p2+p3:把x3代替这个缺失值。 证明:p(p1<a<p1+p2)=p(a<p1+p2)-p(a<p1) ##因为a是从(0,1)之间均匀抽出来的 =(p1+p2)-p1 =p2,P2正好对应x2类别的概率,故此时我们用x2代替这个缺失值。。
def MakeupMissing(validDf,col){ freqDict = {} recdNum = validDf.shape[0] for v in set(validDf[col]): vDf = validDf.loc[validDf[col] == v] freqDict[v] = vDf.shape[0] * 1.0 / recdNum # find the category with highest probability modeVal = max(freqDict.items(), key=lambda x: x[1])[0] freqTuple = freqDict.items() # cumulative sum of each category freqList = [0] + [i[1] for i in freqTuple] freqCumsum = cumsum(freqList) for i in range(df.shape[0]): if df.loc[i][col] != df.loc[i][col]: if method == 'Mode': missingList[i] = modeVal if method == 'Random': # determine the sampled category using unifor distributed random variable a = random.random(1) position = [k + 1 for k in range(len(freqCumsum) - 1) if freqCumsum[k] < a <= freqCumsum[k + 1]][0] missingList[i] = freqTuple[position - 1][0] }
当缺失率很高时
考虑剔除该属性
当缺失率介于“很低”和“很高”时
可以当成一种类别
特殊变量的处理
对类别型变量编码one-hot编码
浓度编码
这里需要详细讲下浓度编码: 某类别型特征下,每一类数据对应的流失率或者是违约率(也可以是非流失率或者非违约率)作为这类数据的编码。 例如性别这个特征:男性人数为x1,男性中流失人数x11,女性人数x2,女性中流失人数x22。 那么我们以x11/x1作为男性编码;x22/x2作为女性编码。
def Encoder(df, col, target): ''' :param df: the dataset containing categorical variable :param col: the name of categorical variabel :param target: class, with value 1 or 0 :return: the numerical encoding for categorical variable df[target]:非0即1. ''' encoder = {} for v in set(df[col]): if v == v: subDf = df[df[col] == v] else: xList = list(df[col]) nanInd = [i for i in range(len(xList)) if xList[i] != xList[i]] subDf = df.loc[nanInd] encoder[v] = sum(subDf[target])*1.0/subDf.shape[0] newCol = [encoder[i] for i in df[col]] return newCol
WOE编码
对日期/时间型变量
时间是否为一个节日,是否在一个时间段(类别型);或者计算距离某个日子变成间隔型;或者某个时间段内发生了多少次变成组合型等等;这个需要结合具体应用场景。使其变成离散型。
可以基于某个基准日期,转化为天数
以观察点为基准,将所有开户日期转为距离观察点的天数(month-on-book)
def Date2Days(df, dateCol, base): ''' :param df: the dataset containing date variable in the format of 2017/1/1 :param date: the column of date :param base: the base date used in calculating day gap :return: the days gap ''' base2 = time.strptime(base,'%Y/%m/%d') base3 = datetime.datetime(base2[0],base2[1],base2[2]) date1 = [time.strptime(i,'%Y/%m/%d') for i in df[dateCol]] date2 = [datetime.datetime(i[0],i[1],i[2]) for i in date1] daysGap = [(date2[i] - base3).days for i in range(len(date2))] return daysGap
构建流失行为的特征
内部自有数据丰富的内部交易明细数据,包括本币活期储蓄波动率,本币活期储蓄月日均余额,。。。,电话银行总交易笔数
可以构建的特征:
①不同交易的数额的比例
②单笔交易的平均数额
③某种交易的笔数占全部交易笔数的比例
例如:
最大波动=max{本币一年以下波动,本币一年以上波动率,储蓄类资产波动率,本币储蓄波动率}
### Calculate the ratio between two variables def ColumnDivide(df, colNumerator, colDenominator): ''' :param df: the dataframe containing variable x & y :param colNumerator: the numerator variable x :param colDenominator: the denominator variable y :return: x/y ''' N = df.shape[0] rate = [0]*N xNum = list(df[colNumerator]) xDenom = list(df[colDenominator]) for i in range(N): #if the denominator is non-zero, work out the ratio if xDenom[i]>0: rate[i] = xNum[i]*1.0/xDenom[i] # if the denominator is zero, assign 0 to the ratio else: rate[i] = 0 return rate
若信息存在冗余,需要按情况进行剔除
情况一:
“本币活期月日均余额占比” = 1 – “本币定期月日均余额占比”
变量“本币活期月日均余额占比 ”与“本币定期月日均余额占比”存在冗余性,知道其一必知道其二,需要剔除一个。
#本币活期月日均余额占比 = 1 - 本币定期月日均余额占比 del modelData['LOCAL_CUR_MON_AVG_BAL_PROP']
情况二
“资产当前总余额 ”= “本币储蓄当前总余额 ”+ “外币储蓄当前总余额”
如果是(广义)线性回归模型,三者不能同时放进模型。对于树模型,可以将其中任意两个放进模型,剩余的做转换,比如做一个离散变换。
外部数据包含了客户在电信运营商的详情
包括:
通话时间与次数
话费详情
特定的呼叫行为
其他信息
可以衍生的特征
月平均通话时间的变化=过去三个月月平均通话时间 − 过去六个月月平均通话时间
月平均通话次数的变化=过去三个月月平均通话次数 − 过去六个月月平均通话次数
月平均缴纳话费的变化=过去三个月月平均缴纳话费 − 过去六个月月平均缴纳话费
相关文章推荐
- 金融风控-->客户流失预警模型-->GBDT建模
- 金融风控-->客户流失预警模型-->神经网络建模
- 金融风控-->客户流失预警模型-->金融数据分析
- 金融风控-->申请评分卡模型-->特征工程(特征分箱,WOE编码) 标签: 金融特征分箱-WOE编码 2017-07-16 21:26 4086人阅读 评论(2) 收藏 举报 分类: 金融风
- 金融风控-->申请评分卡模型-->特征工程(特征分箱,WOE编码)
- PD逆向工程:SqlServer2005---->物理模型---->概念模型
- <转>特征工程(二)
- 大数据:“人工特征工程+线性模型”的尽头
- 不会做特征工程的 AI 研究员不是好数据科学家!上篇 - 连续数据的处理方法 本文作者:s5248 编辑:杨晓凡 2018-01-19 11:32 导语:即便现代机器学习模型已经很先进了,也别
- 商业银行建立客户流失预测模型的方法研究
- scikit-learn(工程中用的相对较多的模型介绍):2.3. Clustering(可用于特征的无监督降维)
- 流失预警模型--实时查询
- 大数据:“人工特征工程+线性模型”的尽头
- 机器学习处理流程、特征工程,模型设计实例
- kaggle数据挖掘竞赛初步--Titanic<数据变换> 完整代码: https://github.com/cindycindyhi/kaggle-Titanic 特征工程系列: Titanic
- Kaggle泰坦尼克特征工程和模型融合
- 数据挖掘案例:建立客户流失模型
- 大数据:“人工特征工程+线性模型”的尽头
- 金融工程---最大熵模型(MaxEnt)
- 特征工程:数据处理,模型训练集锦(二)