4 特征构造
学习目标
- 知道未来信息的概念,及处理未来信息的方法
- 掌握从原始数据构造出新特征的方法
- 掌握特征变换的方法
- 掌握缺失值处理的方法
1 数据准备
1.1 梳理数据的内在逻辑
关系种类
一对一:一个用户有一个注册手机号
一对多:一个用户多笔借款
多对多:一个用户可以登录多个设备,一个设备可以有多个用户登录
- 举例
下图中,蓝色框为二月当期账单,红色框为订单
梳理类ER图
-
任务:分析厚数据常登陆首单用户的逾期情况
-
可以将表结构展示到特征文档当中,说明取数逻辑
1.2 样本设计和特征框架
- 定义观察期样本
- 确定观察期(定X时间切面)和表现期(定Y的标签)
- 确认样本数目是否合理
- 数据EDA
- 看数据总体分布
- data.shape
- data.isnull()
- data.info()
- data.describe()
- 看好坏样本分布差异
- data[data[label]==0].describe() 好用户
- data[data[label]==1].describe() 坏用户
- 看单个数据
- data.sample(n=10,random_state=1)
- 梳理特征框架
- RFM生成新特征
举例 行为评分卡中的用户账单还款特征
-
用户账单关键信息:时间,金额,还款,额度
-
小结:在构建特征前,要完成
-
类ER图
-
样本设计表
-
特征框架表
2 特征构造
2.1 静态信息特征和时间截面特征
用户静态信息特征
- 用户的基本信息(半年内不会变化)
用户时间截面特征
- 未来信息当前时间截面之后的数据
- 时间截面数据在取数的时候要小心,**避免使用未来信息 **
- 产生未来信息最直接的原因:缺少快照表
- 金融相关数据原则上都需要快照表记录所有痕迹(额度变化情况,多次申请的通过和拒绝情况…)
缺少快照表的可能原因
- 快照表消耗资源比较大,为了性能不做
- 原有数据表设计人员疏忽,没做
- 借用其他业务数据(如电商)做信贷
举例
首次借贷 二次借贷 爬虫授权 三次借贷
——————————————————————→
用户 | 借款 | 授权爬虫 | 逾期 |
---|---|---|---|
u1 | l11 | N | 0 |
u1 | l12 | N | 0 |
u1 | l13 | Y | 0 |
u2 | l21 | N | 0 |
u2 | l22 | N | 0 |
u2 | l23 | Y | 1 |
u3 | l11 | N | 0 |
u3 | l12 | N | 0 |
u3 | l13 | Y | 0 |
实际存储
用户 | 授权 |
---|---|
u1 | Y |
u2 | Y |
u3 | Y |
用户 | 借款 | 逾期 |
---|---|---|
u1 | l11 | 0 |
u1 | l12 | 0 |
u1 | l13 | 0 |
u2 | l21 | 0 |
u2 | l22 | 0 |
u2 | l23 | 1 |
u3 | l11 | 0 |
u3 | l12 | 0 |
u3 | l13 | 0 |
join 结果
用户 | 借款 | 授权爬虫 | 逾期 |
---|---|---|---|
u1 | l11 | Y | 0 |
u1 | l12 | Y | 0 |
u1 | l13 | Y | 0 |
u2 | l21 | Y | 0 |
u2 | l22 | Y | 0 |
u2 | l23 | Y | 1 |
u3 | l11 | Y | 0 |
u3 | l12 | Y | 0 |
u3 | l13 | Y | 0 |
解决方案: 加入快照表
用户 | 授权 | 时间 |
---|---|---|
u1 | Y | t3 |
u2 | Y | t3 |
u3 | Y | t3 |
2.2 时间序列特征
用户时间序列特征
- 从观察点往前回溯一段时间的数据
时间序列特征衍生
特征聚合:将单个特征的多个时间节点取值进行聚合。特征聚合是传统评分卡建模的主要特征构造方法。
- 举例,计算每个用户的额度使用率,记为特征ft,按照时间轴以月份为切片展开
- 申请前30天内的额度使用率ft1
- 申请前30天至60天内的额度使用率ft2
- 申请前60天至90天内的额度使用率ft3
- 申请前330天至360天内的额度使用率ft12
- 得到一个用户的12个特征
import pandas as pd
import numpy as np
data = pd.read_excel('data/textdata.xlsx')
data.head()
显示结果
customer_id ft1 ft2 ft3 ft4 ft5 ft6 ft7 ft8 ft9 … gt3 gt4 gt5 gt6 gt7 gt8 gt9 gt10 gt11 gt12 0 111 9 11.0 12 13 18 10 12 NaN NaN … 10 0 18 10 12 NaN NaN NaN NaN NaN 1 112 11 -11.0 10 10 13 13 10 NaN NaN … 10 10 13 13 10 NaN NaN NaN NaN NaN 2 113 0 11.0 10 12 6 10 0 25.0 10.0 … 10 12 6 10 0 25.0 10.0 NaN NaN NaN 3 114 -7 -1.0 9 8 7 0 -19 10.0 11.0 … 10 10 12 0 -19 10.0 11.0 NaN NaN NaN 4 115 11 NaN 6 10 0 17 19 10.0 30.0 … 6 10 0 17 19 10.0 30.0 15.0 NaN NaN 5 rows × 26 columns
- 可以根据这个时间序列进行基于经验的人工特征衍生,例如计算最近P个月特征大于0的月份数
#最近p个月,ft>0的月份数
def Num(ft,p): #ft 特征名字 p特征大于0的月份数df=data.loc[:,ft+'1':ft+str(p)]# np.where df>0 向量计算 会拿着每一个数跟0做比较, 返回的也是一个数组# 条件为true 返回1 条件为False 返回0auto_value=np.where(df>0,1,0).sum(axis=1)return ft+'_num'+str(p),auto_value
- 计算最近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
- 计算近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
- 计算最近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
- 计算最近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
- 其余衍生方法
#最近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=1for j in row_value:if j>0:breakindexs+=1auto_value.append(indexs)return ft+'_msg'+str(p),auto_value#最近p个月,最近一次ft=0到现在的月份数
def Msz(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=1for j in row_value:if j>0:breakindexs+=1auto_value.append(indexs)return ft+'_msz'+str(p),auto_value #当月ft/(最近p个月ft的均值)
def Cav(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value = df[ft+'1']/np.nanmean(df,axis = 1 ) return ft+'_cav'+str(p),auto_value #当月ft/(最近p个月ft的最小值)
def Cmn(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value = df[ft+'1']/np.nanmin(df,axis = 1 ) return ft+'_cmn'+str(p),auto_value #最近p个月,每两个月间的ft的增长量的最大值
def Mai(ft,p):arr=np.array(data.loc[:,ft+'1':ft+str(p)]) auto_value = []for i in range(len(arr)):df_value = arr[i,:]value_lst = []for k in range(len(df_value)-1):minus = df_value[k] - df_value[k+1]value_lst.append(minus)auto_value.append(np.nanmax(value_lst)) return ft+'_mai'+str(p),auto_value #最近p个月,每两个月间的ft的减少量的最大值
def Mad(ft,p):arr=np.array(data.loc[:,ft+'1':ft+str(p)]) auto_value = []for i in range(len(arr)):df_value = arr[i,:]value_lst = []for k in range(len(df_value)-1):minus = df_value[k+1] - df_value[k]value_lst.append(minus)auto_value.append(np.nanmax(value_lst)) return ft+'_mad'+str(p),auto_value #最近p个月,ft的标准差
def Std(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value=np.nanvar(df,axis = 1)return ft+'_std'+str(p),auto_value #最近p个月,ft的变异系数
def Cva(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value=np.nanvar(df,axis = 1)/(np.nanmean(df,axis = 1 )+1e-10)return ft+'_cva'+str(p),auto_value #(当月ft) - (最近p个月ft的均值)
def Cmm(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value = df[ft+'1'] - np.nanmean(df,axis = 1 ) return ft+'_cmm'+str(p),auto_value #(当月ft) - (最近p个月ft的最小值)
def Cnm(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value = df[ft+'1'] - np.nanmin(df,axis = 1 ) return ft+'_cnm'+str(p),auto_value #(当月ft) - (最近p个月ft的最大值)
def Cxm(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value = df[ft+'1'] - np.nanmax(df,axis = 1 ) return ft+'_cxm'+str(p),auto_value #( (当月ft) - (最近p个月ft的最大值) ) / (最近p个月ft的最大值) )
def Cxp(ft,p):df=data.loc[:,ft+'1':ft+str(p)]temp = np.nanmax(df,axis = 1 )auto_value = (df[ft+'1'] - temp )/ tempreturn ft+'_cxp'+str(p),auto_value #最近p个月,ft的极差
def Ran(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value = np.nanmax(df,axis = 1 ) - np.nanmin(df,axis = 1 ) return ft+'_ran'+str(p),auto_value #最近p个月中,特征ft的值,后一个月相比于前一个月增长了的月份数
def Nci(ft,p):arr=np.array(data.loc[:,ft+'1':ft+str(p)]) auto_value = []for i in range(len(arr)):df_value = arr[i,:]value_lst = []for k in range(len(df_value)-1):minus = df_value[k] - df_value[k+1]value_lst.append(minus) value_ng = np.where(np.array(value_lst)>0,1,0).sum()auto_value.append(np.nanmax(value_ng)) return ft+'_nci'+str(p),auto_value #最近p个月中,特征ft的值,后一个月相比于前一个月减少了的月份数
def Ncd(ft,p):arr=np.array(data.loc[:,ft+'1':ft+str(p)]) auto_value = []for i in range(len(arr)):df_value = arr[i,:]value_lst = []for k in range(len(df_value)-1):minus = df_value[k] - df_value[k+1]value_lst.append(minus) value_ng = np.where(np.array(value_lst)<0,1,0).sum()auto_value.append(np.nanmax(value_ng)) return ft+'_ncd'+str(p),auto_value #最近p个月中,相邻月份ft 相等的月份数
def Ncn(ft,p):arr=np.array(data.loc[:,ft+'1':ft+str(p)]) auto_value = []for i in range(len(arr)):df_value = arr[i,:]value_lst = []for k in range(len(df_value)-1):minus = df_value[k] - df_value[k+1]value_lst.append(minus) value_ng = np.where(np.array(value_lst)==0,1,0).sum()auto_value.append(np.nanmax(value_ng)) return ft+'_ncn'+str(p),auto_value #最近P个月中,特征ft的值是否按月份严格递增,是返回1,否返回0
def Bup(ft,p):arr=np.array(data.loc[:,ft+'1':ft+str(p)]) auto_value = []for i in range(len(arr)):df_value = arr[i,:]value_lst = []index = 0for k in range(len(df_value)-1):if df_value[k] > df_value[k+1]:breakindex =+ 1if index == p: value= 1 else:value = 0auto_value.append(value) return ft+'_bup'+str(p),auto_value #最近P个月中,特征ft的值是否按月份严格递减,是返回1,否返回0
def Pdn(ft,p):arr=np.array(data.loc[:,ft+'1':ft+str(p)]) auto_value = []for i in range(len(arr)):df_value = arr[i,:]value_lst = []index = 0for k in range(len(df_value)-1):if df_value[k+1] > df_value[k]:breakindex =+ 1if index == p: value= 1 else:value = 0auto_value.append(value) return ft+'_pdn'+str(p),auto_value #最近P个月中,ft的切尾均值,这里去掉了数据中的最大值和最小值
def Trm(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value = []for i in range(len(df)):trm_mean = list(df.loc[i,:])trm_mean.remove(np.nanmax(trm_mean))trm_mean.remove(np.nanmin(trm_mean))temp=np.nanmean(trm_mean) auto_value.append(temp)return ft+'_trm'+str(p),auto_value #当月ft / 最近p个月的ft中的最大值
def Cmx(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value = (df[ft+'1'] - np.nanmax(df,axis = 1 )) /np.nanmax(df,axis = 1 ) return ft+'_cmx'+str(p),auto_value #( 当月ft - 最近p个月的ft均值 ) / ft均值
def Cmp(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value = (df[ft+'1'] - np.nanmean(df,axis = 1 )) /np.nanmean(df,axis = 1 ) return ft+'_cmp'+str(p),auto_value #( 当月ft - 最近p个月的ft最小值 ) /ft最小值
def Cnp(ft,p):df=data.loc[:,ft+'1':ft+str(p)]auto_value = (df[ft+'1'] - np.nanmin(df,axis = 1 )) /np.nanmin(df,axis = 1 ) return ft+'_cnp'+str(p),auto_value #最近p个月取最大值的月份距现在的月份数
def Msx(ft,p):df=data.loc[:,ft+'1':ft+str(p)]df['_max'] = np.nanmax(df,axis = 1)for i in range(1,p+1):df[ft+str(i)] = list(df[ft+str(i)] == df['_max'])del df['_max']df_value = np.where(df==True,1,0)auto_value=[]for i in range(len(df_value)):row_value=df_value[i,:]indexs=1for j in row_value:if j == 1:breakindexs+=1auto_value.append(indexs)return ft+'_msx'+str(p),auto_value#最近p个月的均值/((p,2p)个月的ft均值)
def Rpp(ft,p):df1=data.loc[:,ft+'1':ft+str(p)]value1=np.nanmean(df1,axis = 1 )df2=data.loc[:,ft+str(p):ft+str(2*p)]value2=np.nanmean(df2,axis = 1 ) auto_value = value1/value2return ft+'_rpp'+str(p),auto_value #最近p个月的均值 - ((p,2p)个月的ft均值)
def Dpp(ft,p):df1=data.loc[:,ft+'1':ft+str(p)]value1=np.nanmean(df1,axis = 1 )df2=data.loc[:,ft+str(p):ft+str(2*p)]value2=np.nanmean(df2,axis = 1 ) auto_value = value1 - value2return ft+'_dpp'+str(p),auto_value #(最近p个月的ft最大值)/ (最近(p,2p)个月的ft最大值)
def Mpp(ft,p):df1=data.loc[:,ft+'1':ft+str(p)]value1=np.nanmax(df1,axis = 1 )df2=data.loc[:,ft+str(p):ft+str(2*p)]value2=np.nanmax(df2,axis = 1 ) auto_value = value1/value2return ft+'_mpp'+str(p),auto_value #(最近p个月的ft最小值)/ (最近(p,2p)个月的ft最小值)
def Npp(ft,p):df1=data.loc[:,ft+'1':ft+str(p)]value1=np.nanmin(df1,axis = 1 )df2=data.loc[:,ft+str(p):ft+str(2*p)]value2=np.nanmin(df2,axis = 1 ) auto_value = value1/value2return ft+'_npp'+str(p),auto_value
- 将上面衍生的方法封装成函数
#定义批量调用双参数的函数
def auto_var2(feature,p):#global data_newtry:columns_name,values=Num(feature,p)data_new[columns_name]=valuesexcept:print("Num PARSE ERROR",feature,p)try:columns_name,values=Nmz(feature,p)data_new[columns_name]=valuesexcept:print("Nmz PARSE ERROR",feature,p)try:columns_name,values=Evr(feature,p)data_new[columns_name]=valuesexcept:print("Evr PARSE ERROR",feature,p)try:columns_name,values=Avg(feature,p)data_new[columns_name]=valuesexcept:print("Avg PARSE ERROR",feature,p)try:columns_name,values=Tot(feature,p)data_new[columns_name]=valuesexcept:print("Tot PARSE ERROR",feature,p) try:columns_name,values=Tot2T(feature,p)data_new[columns_name]=valuesexcept:print("Tot2T PARSE ERROR",feature,p) try:columns_name,values=Max(feature,p)data_new[columns_name]=valuesexcept:print("Tot PARSE ERROR",feature,p)try:columns_name,values=Max(feature,p)data_new[columns_name]=valuesexcept:print("Max PARSE ERROR",feature,p)try:columns_name,values=Min(feature,p)data_new[columns_name]=valuesexcept:print("Min PARSE ERROR",feature,p)try:columns_name,values=Msg(feature,p)data_new[columns_name]=valuesexcept:print("Msg PARSE ERROR",feature,p)try:columns_name,values=Msz(feature,p)data_new[columns_name]=valuesexcept:print("Msz PARSE ERROR",feature,p)try:columns_name,values=Cav(feature,p)data_new[columns_name]=valuesexcept:print("Cav PARSE ERROR",feature,p)try:columns_name,values=Cmn(feature,p)data_new[columns_name]=valuesexcept:print("Cmn PARSE ERROR",feature,p) try:columns_name,values=Std(feature,p)data_new[columns_name]=valuesexcept:print("Std PARSE ERROR",feature,p) try:columns_name,values=Cva(feature,p)data_new[columns_name]=valuesexcept:print("Cva PARSE ERROR",feature,p) try:columns_name,values=Cmm(feature,p)data_new[columns_name]=valuesexcept:print("Cmm PARSE ERROR",feature,p) try:columns_name,values=Cnm(feature,p)data_new[columns_name]=valuesexcept:print("Cnm PARSE ERROR",feature,p) try:columns_name,values=Cxm(feature,p)data_new[columns_name]=valuesexcept:print("Cxm PARSE ERROR",feature,p) try:columns_name,values=Cxp(feature,p)data_new[columns_name]=valuesexcept:print("Cxp PARSE ERROR",feature,p)try:columns_name,values=Ran(feature,p)data_new[columns_name]=valuesexcept:print("Ran PARSE ERROR",feature,p)try:columns_name,values=Nci(feature,p)data_new[columns_name]=valuesexcept:print("Nci PARSE ERROR",feature,p)try:columns_name,values=Ncd(feature,p)data_new[columns_name]=valuesexcept:print("Ncd PARSE ERROR",feature,p)try:columns_name,values=Ncn(feature,p)data_new[columns_name]=valuesexcept:print("Ncn PARSE ERROR",feature,p)try:columns_name,values=Pdn(feature,p)data_new[columns_name]=valuesexcept:print("Pdn PARSE ERROR",feature,p) try:columns_name,values=Cmx(feature,p)data_new[columns_name]=valuesexcept:print("Cmx PARSE ERROR",feature,p) try:columns_name,values=Cmp(feature,p)data_new[columns_name]=valuesexcept:print("Cmp PARSE ERROR",feature,p) try:columns_name,values=Cnp(feature,p)data_new[columns_name]=valuesexcept:print("Cnp PARSE ERROR",feature,p) try:columns_name,values=Msx(feature,p)data_new[columns_name]=valuesexcept:print("Msx PARSE ERROR",feature,p)try:columns_name,values=Nci(feature,p)data_new[columns_name]=valuesexcept:print("Nci PARSE ERROR",feature,p)try:columns_name,values=Trm(feature,p)data_new[columns_name]=valuesexcept:print("Trm PARSE ERROR",feature,p)try:columns_name,values=Bup(feature,p)data_new[columns_name]=valuesexcept:print("Bup PARSE ERROR",feature,p)try:columns_name,values=Mai(feature,p)data_new[columns_name]=valuesexcept:print("Mai PARSE ERROR",feature,p)try:columns_name,values=Mad(feature,p)data_new[columns_name]=valuesexcept:print("Mad PARSE ERROR",feature,p)try:columns_name,values=Rpp(feature,p)data_new[columns_name]=valuesexcept:print("Rpp PARSE ERROR",feature,p)try:columns_name,values=Dpp(feature,p)data_new[columns_name]=valuesexcept:print("Dpp PARSE ERROR",feature,p)try:columns_name,values=Mpp(feature,p)data_new[columns_name]=valuesexcept:print("Mpp PARSE ERROR",feature,p)try:columns_name,values=Npp(feature,p)data_new[columns_name]=valuesexcept:print("Npp PARSE ERROR",feature,p)return data_new.columns.size
- 对之前数据应用封装的函数
data_new = pd.DataFrame()
for p in range(1, 12): for inv in ['ft', 'gt']: auto_var2(inv, p)
data_new.columns.tolist()
显示结果
array(['ft_num1', 'ft_evr1', 'ft_avg1', 'ft_tot1', 'ft_tot2t1', 'ft_max1','ft_min1', 'ft_msg1', 'ft_msz1', 'ft_cav1', 'ft_cmn1', 'ft_std1','ft_cva1', 'ft_cmm1', 'ft_cnm1', 'ft_cxm1', 'ft_cxp1', 'ft_ran1','ft_nci1', 'ft_ncd1', 'ft_ncn1', 'ft_pdn1', 'ft_cmx1', 'ft_cmp1','ft_cnp1', 'ft_msx1', 'ft_bup1', 'ft_rpp1', 'ft_dpp1', 'ft_mpp1','ft_npp1', 'gt_num1', 'gt_evr1', 'gt_avg1', 'gt_tot1', 'gt_tot2t1','gt_max1', 'gt_min1', 'gt_msg1', 'gt_msz1', 'gt_cav1', 'gt_cmn1','gt_std1', 'gt_cva1', 'gt_cmm1', 'gt_cnm1', 'gt_cxm1', 'gt_cxp1',........])
- 上面这种无差别聚合方法进行聚合得到的结果,通常具有较高的共线性,但信息量并无明显增加,影响模型的鲁棒性和稳定性。
- 评分卡模型对模型的稳定性要求远高于其性能
- 在时间窗口为1年的场景下,p值会通过先验知识,人为选择3、6、12等,而不是遍历全部取值1~12
- 在后续特征筛选时,会根据变量的显著性、共线性等指标进行进一步筛选
- 特征组合:又叫特征交叉(Feature crossing),指不同特征之间基于常识、经验、数据挖掘技术进行分段组合实现特征构造,产生包含更多信息的新特征。
特征维度 | 男程序猿 | 女程序媛 |
---|---|---|
青年 | 青年男程序猿 | 青年女程序媛 |
中年 | 中年男程序猿 | 中年女程序媛 |
-
可以通过决策树模型,基于特定指标,贪心地搜索最优的特征组合形式。上一小结最后的案例为例
-
基于上述规则可以得出以下特征
x['n1'] = x.apply(lambda x:1 if x.amount_tot>48077.5 \ and sale_amount_cnt<=3.5 else 0)
x['n2'] = x.apply(lambda x:1 if x.amount_tot>48077.5 \ and sale_amount_cnt>3.5 else 0)
- 利用决策树实现特征的自动组合,可以有效降低建模人员的工作难度
- 最近一次(cur