乐趣区

关于深度学习:使用手工特征提升模型性能

本文将应用信用守约数据集介绍手工特色的概念和创立过程。

通过对原始数据进行手工的特色工程,咱们能够将模型的准确性和性能晋升到新的程度,为更准确的预测和更理智的业务决策铺平道路,能够以前所未有的形式优化模型并晋升业务能力。

原始数据就像一个没有图片的拼图游戏——但通过特色工程,咱们能够将这些碎片拼在一起,尽管领有大量数据的确是寻求建设机器学习模型的金融机构的宝库,但同样重要的是要抵赖并非所有数据都提供信息。并且手工特色是人工设计进去,每一步操作可能说出理由,也带来了可解释性。

特色工程不仅仅是抉择最好的特色。它还波及缩小数据中的乐音和冗余,以进步模型的泛化能力。这是至关重要的,因为模型须要在看不见的数据上体现良好能力真正有用。

数据集形容

本文中形容的数据集通过匿名解决和屏蔽,以保护客户数据的机密性。特色可分类如下:

  D_* = 拖欠变量
  S_* = 收入变量
  P_* = 领取变量
  B_* = 均衡变量
  R_* = 危险变量 

总共有 100 个整数特色和 100 个浮点特色代表过来 12 个月客户的状态。该数据集蕴含无关客户报表的信息,从 1 到 13 不等。客户的每张信用卡报表之间可能有 30 到 180 天的距离(即客户的信用卡报表可能缺失)。每个客户都由一个客户 ID 示意。customer_ID= 0 的客户前 5 条的样本数据如下所示:

在 700 万个 customer_ID 中,98% 的标签为“0”(好客户,无默认),2% 的标签为“1”(坏客户,默认)。

数据集很大,所以咱们应用 cudf 来减速解决,如果你没有装置 cudf,那么应用 pandas 也是一样的

 # LOAD LIBRARIES
 import pandas as pd, numpy as np # CPU libraries
 import cudf # GPU libraries
 import matplotlib.pyplot as plt, gc, os
 
 df = cudf.read_parquet('./data.parquet')

特色生成办法

有数百种想法可用于生成特色;然而咱们还确保这些特色有助于进步模型的性能,下图显示了特色工程中应用的一些根本办法:

聚合特色

聚合是了解简单数据的秘诀。通过计算分类分组变量(如 customer_ID (C_ID) 或产品类别)的汇总统计数据或数值变量的聚合,咱们能够发现一些不可见的模式和趋势。借助均值、最大值、最小值、标准差和中值等汇总统计数据,咱们能够构建更精确的预测模型,并从客户数据、交易数据或任何其余数值数据中提取有意义的见解。

能够计算每个客户的这些统计属性

 cat_features = ["B_1","B_2","D_1","D_2","D_10","P_21","D_126","D_3","D_42","R_66","R_68"]
 num_features = [col for col in all_cols if col not in cat_features] #all features accept cateforical features.
 test_num_agg = df.groupby("customer_ID")[num_features].agg(['mean', 'std', 'min', 'max', 'last','median']) #grouping by customerID
 test_num_agg.columns = ['_'.join(x) for x in test_num_agg.columns]

均值:一个数值变量的平均值,能够给出数据集中趋势的个别意义。平均值能够捕捉:

客户领有的均匀银行余额。

  • 均匀客户收入。
  • 两个信用报表之间的均匀工夫(信用付款之间的工夫)。
  • 借钱的均匀危险。

标准偏差 (Std):掂量数据围绕均值的散布状况,能够深刻理解数据的变异水平。余额的高度可变性表明客户有生产。

最小值和最大值能够捕捉客户的财产,也能够捕捉无关客户收入和危险的信息。

中位数:当数据高度歪斜时,应用平均值并不是一个更好的主见,因而能够应用中值(能够应用数值的两头值。

最新值可能是最重要的特色,因为它们蕴含无关公布给客户的最新已知信用申明的信息,也就表明目前客户账户的最新状态。

独热编码

对分类变量应用上述统计属性是不明智的,因为计算最小值、最大值或标准偏差并不能给咱们任何有用的信息。那么咱们应该怎么做呢? 能够应用像 count 这样的特色,和惟一的数量来计算特色,最新的值也能够应用

 cat_features = ["B_1","B_2","D_1","D_2","D_10","P_21","D_126","D_3","D_42","R_66","R_68"]
 test_cat_agg = df.groupby("customer_ID")[cat_features].agg(['count', 'last', 'nunique'])
 test_cat_agg.columns = ['_'.join(x) for x in test_cat_agg.columns]

然而这些信息不会捕捉客户是否被归类到特定的类别中。所以咱们通过对变量进行独热编码,而后对变量(例如均值、总和和最初)进行聚合来实现。

平均值将捕捉客户属于该类别的总次数 / 银行对帐单总数的比率。总和将只是客户属于该类别的总次数。

 from cuml.preprocessing import OneHotEncoder
 df_categorical = df_last[cat_features].astype(object)
 ohe = OneHotEncoder(drop='first', sparse=False, dtype=np.float32, handle_unknown='ignore')
 ohe.fit(df_categorical)with open("ohe.pickle", 'wb') as f: 
     pickle.dump(ohe, f) #save the encoder so that it can be used for test data as well df_categorical = pd.DataFrame(ohe.transform(df_categorical).astype(np.float16),index=df_categorical.index).rename(columns=str)
 df_categorical['customer_ID']=df['customer_ID']
 df_categorical.groupby('customer_ID').agg(['mean', 'sum', 'last'])

基于排名的特色

在预测客户行为方面,基于排名的特色是十分重要的。通过依据支出或收入等特定属性对客户进行排名,咱们能够深刻理解他们的财务习惯并更好地治理危险。

应用 cudf 的 rank 函数,咱们能够轻松计算这些特色并应用它们来为预测提供信息。例如,能够依据客户的生产模式、债权支出比或信用评分对客户进行排名。而后这些特色可用于预测守约或辨认有可能拖欠付款的客户。

基于排名的特色还可用于辨认高价值客户、指标营销工作和优化贷款优惠。例如,能够依据客户承受贷款提议的可能性对客户进行排名,而后将排名最高的客户作为指标。

 df[feat+'_rank']=df[feat].rank(pct=True, method='min')

PCT 用于是否做百分位排名。客户的排名也能够基于分类特色来计算。

 df[feat+'_rank']=df.groupby([cat_feat]).rank(pct=True, method='min')

特色组合

特色组合的一种风行办法是线性或非线性组合。这包含采纳两个或多个现有特色,将它们组合在一起创立一个新的复合特色。而后应用这个复合特色来辨认独自查看单个特色时可能不可见的模式、趋势和相关性。

例如,假如咱们正在剖析客户生产习惯的数据集。能够从集体特色开始,比方年龄、支出和地点。然而通过以线性或非线性的形式组合这些个性,能够创立新的复合个性,使咱们可能更多地理解客户。能够联合支出和地位来创立一个复合特色,该特色通知咱们某一地区客户的均匀收入。

然而并不是所有的特色组合都有用。要害是要确定哪些组合与试图解决的问题最相干,这须要对数据和问题畛域有粗浅的了解,并仔细分析创立的复合特色和试图预测的指标变量之间的相关性。

下图展现了一个组合特色并将信息用于模型的过程。作为筛选条件,这里只抉择那些与指标相关性大于最大值 0.9 的特色。

 features=[col for col in train.columns if col not in ['customer_ID',target]+cat_features]
 for feat1 in features:
   for feat2 in features:
     th=max(np.corr(feat1,Y)[0],np.corr(feat1,Y)[0]) #calculate threshold
     feat3=df[feat1]-df[feat2] #difference feature
     corr3=np.corr(feat3,Y)[0]
     if(corr3>max(th,0.9)): #if correlation greater than max(th,0.9) we add it as feature
       df[feat1+'_'+feat2]=feat3

基于工夫 / 日期的特色

在数据分析方面,基于工夫的特色十分重要。通过依据工夫属性(例如月份或星期几)对数据进行分组,能够创立弱小的特色。这些特色的范畴能够从简略的平均值(如支出和收入)到更简单的属性(如信用评分随工夫的变动)。

借助基于工夫的特色,还能够辨认在孤立地查看数据时可能看不到的模式和趋势。下图演示了如何应用基于工夫的特色来创立有用的复合属性。

首先,计算一个月内的值的平均值(能够应用该月的某天或该月的某周等),将取得的 DF 与原始数据合并,并取各个特色之间的差。

 features=[col for col in train.columns if col not in ['customer_ID',target]+cat_features]
 month_Agg=df.groupby([month])[features].agg('mean')#grouping based on month feature
 month_Agg.columns = ['_month_'.join(x) for x in month_Agg.columns]
 month_Agg.reset_index(inplace=True)
 df=df.groupby(month_Agg,on='month')
 for feat in features: #create composite features b taking difference
   df[feat+'_'+feat+'_month_mean']=df[feat]-df[feat+'_month_mean']

还能够通过应用工夫作为分组变量来创立基于排名的特色,如下所示

 features=[col for col in train.columns if col not in ['customer_ID',target]+cat_features]
 month_Agg=df.groupby([month])[features].rank(pct=True) #grouping based on month feature
 month_Agg.columns = ['_month_'.join(x) for x in month_Agg.columns]
 month_Agg.reset_index(inplace=True)
 df=pd.concat([df,month_Agg],axis=1) #concat to original dataframe

滞后特色

滞后特色是无效预测金融数据的重要工具。这些特色包含计算工夫序列中以后值与之前值之间的差值。通过将滞后特色纳入剖析,能够更好地了解数据中的模式和趋势,并做出更精确的预测。

如果滞后特色显示客户间断几个月按时领取信用卡账单,可能会预测他们未来不太可能守约。相同,如果提早特色显示客户始终提早或错过付款,可能会预测他们更有可能守约。

 # difference function calculate the lag difference for numerical features 
 #between last value and shift last value.
 def difference(groups,num_features,shift):
     data=(groups[num_features].nth(-1)-groups[num_features].nth(-1*shift)).rename(columns={f: f"{f}_diff{shift}" for f in num_features})
     return data
 #calculate diff features for last -2nd last, last -3rd last, last- 4th last
 def get_difference(data,num_features):
     print("diff features...")
     groups=data.groupby('customer_ID')
     df1=difference(groups,num_features,2).fillna(0)
     df2=difference(groups,num_features,3).fillna(0)
     df3=difference(groups,num_features,4).fillna(0)
     df1=pd.concat([df1,df2,df3],axis=1)
     df1.reset_index(inplace=True)
     df1.sort_values(by='customer_ID')
     del df2,df3
     gc.collect()
     return df1train_diff = get_difference(df, num_features)

基于滚动窗口的个性

这些特色只是取最初 3(4,5,…x) 值的平均值,这取决于数据,因为基于工夫的最新值携带了对于客户最新状态的信息。

 xth=3 #define the window size
 df["cumulative"]=df.groupby('customer_ID').sort_values(by=['time'],ascending=False).cumcount()
 last_info=df[df["cumulative"]<=xth]
 last_info = last_info.groupby("customer_ID")[num_features].agg(['mean', 'std', 'min', 'max', 'last','median']) #grouping by customerID
 last_info.columns = ['_'.join(x) for x in last_info.columns]

其余的特征提取办法

下面的办法曾经创立了足够多的特色来构建一个很棒的模型。然而依据数据的性质,还能够创立更多的特色。例如:能够创立像 null 计数这样的特色,它能够计算客户以后的总 null 值,从而帮忙捕捉基于树的算法无奈了解的特色散布。

 def calc_nan(df,features):
     print("calculating nan_info...")
     df_nan = (df[features].mul(0) + 1).fillna(0) #marke non_null values as 1 and null as zero
     df_nan['customer_ID'] = df['customer_ID']
     nan_sum = df_nan.groupby("customer_ID").sum().sum(axis=1) #total unknown values for a customer
     nan_last = df_nan.groupby("customer_ID").last().sum(axis=1)#how many last values that are not known
     del df_nan
     gc.collect()
     return nan_sum,nan_last

这里能够不应用平均值,而是应用修改的平均值,如基于工夫的加权平均值或 HMA(hull moving average)。

总结

在本文中介绍了一些在事实世界中用于预测守约危险的最常见的手工个性策略。然而总是有新的和翻新的办法来设计特色,并且手工设置特色的办法是费时费力的,所以咱们将在前面的文章中介绍如何实用工具进行主动的特色生成。

https://avoid.overfit.cn/post/2740ca61afb3438dbb8ab36b2250f37e

作者:Priyanshu Chaudhary

退出移动版