2020招商银行Fintech数据竞赛(信用风险评分)赛后总结

写在前面:第一次参加数据类竞赛,从第一次接触pandas到数据预处理,特征工程的构建,再到最终的模型融合,B榜成绩0.767,排名三百左右,做个简单的赛后总结。

赛题介绍
主办方提供了(1)用户的标签数据(2)过去60天的交易行为(3)过去30天的APP行为数据,分成训练集和测试集合,最终需要预测用户违约的概率。评分标准为AUC。
以下分五个方面介绍流程:
比赛流程
一,EDA(探索性数据分析)
1.查看每个特征的取值范围以及不同取值的个数:

Train_data = pd.read_csv(path)
for col in Train_data.columns:
    print(col)
    #查看可能的取值
    print(Train_data[col].unique())
    #查看不同取值的个数
    print(Train_data[col].value_counts)

2.查看拥有交易信息表和APP行为信息表的用户个数:

print(Train_data.groupby('id').count())

3.查看缺失值存在较多的用户情况:

print(Train_data.loc[(Train_data['atdd_type']=='\\N') & (Train_data['tot_ast_lvl_cd'] == '\\N')])

额外补充一点,pandas的.loc[:,:]函数用处很大,能提取行列值表达。

通过以上的分析,大概知道
1)有80%的用户有交易记录,仅有25% 的用户有APP行为数据。
2)有500个用户缺失值很多,可能是主办方刻意挖去数据。
该分析方法的缺点:缺少可视化,以后打比赛要增加可视化方面的直观感觉。

二,数据预处理
1,转化类型:
数据多数为object类型:
1)简单判断哪些可以转化为数字
2)根据类别的特征来转化对应类型
3)将缺失值‘\N’表示为np.nan(缺失值)

def tag_feature_pre(self,df, categorical_features, int_features, yuanben):
	#将‘\\n’用缺失值表示
    for col in yuanben:
        df[col] = df[col].apply(lambda x: np.nan if x == '\\N' else x)
    #对类型进行转码
    for col in categorical_features:
        df[col] = df[col].astype('category').cat.codes
    #转成int类型
    for col in int_features:
        df[col] = df[col].apply(lambda x: int(x) if x != '\\N' else np.nan)
        return df

当然也试过对类型进行onehot编码和labelencoder编码,但是效果都不佳,这里提供代码:
1)labelencoder:

from sklearn import preprocessing
def type_labelencoder(self,df):
    # Trx_Cod1_Cd和Trx_Cod2_Cd保持类别编码
    df = df.sort_values(['id', 'trx_tm']).reset_index(drop=True)
    df['Trx_Cod1_Cd'] = df['Trx_Cod1_Cd'].fillna('-1')
    #先调用函数
    Trx_Cod1_Cd_le = preprocessing.LabelEncoder()
    #这个过程其实是生成字典
    Trx_Cod1_Cd_le = Trx_Cod1_Cd_le.fit(df.Trx_Cod1_Cd.values)
    Trx_Cod2_Cd_le = preprocessing.LabelEncoder()
    Trx_Cod2_Cd_le = Trx_Cod2_Cd_le.fit(df.Trx_Cod2_Cd.values)
    #转化值
    df['Trx_Cod1_Cd'] = Trx_Cod1_Cd_le.transform(df['Trx_Cod1_Cd'].values)
    df['Trx_Cod2_Cd'] = Trx_Cod2_Cd_le.transform(df['Trx_Cod2_Cd'].values)

2)onehotlable编码:

df_pro = pd.get_dummies(df, prefix_sep="_", columns=df.columns[:-1])

也做过通过众数,平均数来填充空值的尝试,但由于xgb和lgb等有些树模型本身可以处理空值,所以就没管。

总结下:对数据类型进行了处理

三,特征工程
分三个部分讲:
一)用户tag标签数据:
将类别做分桶处理:

#对年龄段做分桶
bin = [i * 10 for i in range(1, 10)]
X_data['age_bin'] = pd.cut(X_data['age'], bin, labels=False)

对其他类别做各种交叉组合,然后根据模型的重要度进行排查。
最后发现:tag实在挖不倒什么有用特征,怎么做auc一直保持在0.68到0.70之间

二)trade用户交易表
后来看到高分的方案,才知道这是决定比赛上限的数据。
在这里插入图片描述
以下是自己做的特征工程,其实具体也是参考去年第一的方案来的:
2019招商银行FintechTop1方案
分别对Trx_Cod1_Cd和Trx_Cod2_cd交易类别来做的特征分析:
1.包括用户对这些类别:
1)交易最多的种类
2)对这些种类交易次数占据的比例,
3)对这些种类交易金额占据的比例
4)对这些种类不同的金额求和

2.对于时间trx_tm和金额cny_trx_amt所做的:
1)用户总交易额的均值、方差、最大最小值等数字统计
2)用户交易的第一天和最后一天
做到这里几乎都是照搬去年的方案:
我以为这里已经不能再继续深挖了,(但其实这就是为啥最终无法继续往前的原因)

赛后请教了高分的同学:(充分利用了时间金额的统计特性
1)分了每周的统计金额,金额之和,金额平均
2)分了月份之间的差异,收支是否平衡,有比值有差值

还有同学:
1)粗粒度刻画:最后一次交易的时间是否晚于平均值,交易总次数,多少天有交易行为,多少天有交易行为,平均每天的交易金额,平均每次的交易金额等。
等等,该同学借鉴了RFM模型的思想。

三)用户APP上行为
由于此项数据仅有25%的用户拥有,加不加这里的特征对我最终结果无太大影响,所以没有加。

四)特征选择
特征选择用了两种方法:
1.xgboost模型自带输出特征的重要度,剔除重要度为1的特征

from lightgbm import LGBMRegressor,plot_importance
import matplotlib.pylab as plt

x_train,x_val,y_train,y_val = train_test_split(X_data,Y_data,test_size=0.3)

model = LGBMRegressor(num_leaves=127,n_estimators=150,learning_rate=0.01)
model = model.fit(x_train,y_train)
predict = model.predict(x_val)
roc = roc_auc_score(y_val,predict)
print('roc:',roc)

#画出模型前25重要的特征
plt.figure(figsize=(18,40))
plot_importance(model, max_num_features=25)
plt.title("Featurertances")
plt.show()

#输出每个特征的重要度
print(model.feature_importances_)

2.利用mlxtend模块种的SFS和SBS进行特征选择
mlxtend官方文档

from mlxtend.feature_selection import SequentialFeatureSelector as SFS

sfs1 = SFS(knn, 
           k_features=3, 
           forward=True, 
           floating=False, 
           verbose=2,
           scoring='accuracy',
           cv=0)

sfs1 = sfs1.fit(X, y)

利用贪心算法来跑,缺点就是速度非常慢,用实验室电脑跑的,最终效果还行。不建议用在更大型的数据处理中。

五)模型的选择和融合
模型采用xgb和lgb模型,用stacking做了模型融合:
heamy的官方文档
stacking对模型还是有微小的提升,虽然只有一点点,但是打比赛目的就是为了提分。
放个stacking的简单使用说明

# load boston dataset from sklearn
from sklearn.datasets import load_boston
data = load_boston()
X, y = data['data'], data['target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=111)

# create dataset
dataset = Dataset(X_train,y_train,X_test)

# initialize RandomForest & LinearRegression
model_rf = Regressor(dataset=dataset, estimator=RandomForestRegressor, parameters={'n_estimators': 50},name='rf')
model_lr = Regressor(dataset=dataset, estimator=LinearRegression, parameters={'normalize': True},name='lr')

# Stack two models
# Returns new dataset with out-of-fold predictions
pipeline = ModelsPipeline(model_rf,model_lr)
stack_ds = pipeline.stack(k=10,seed=111)

# Train LinearRegression on stacked data (second stage)
stacker = Regressor(dataset=stack_ds, estimator=LinearRegression)
results = stacker.predict()
# Validate results using 10 fold cross-validation
results = stacker.validate(k=10,scorer=mean_absolute_error)

总结:
第一次参加数据挖掘的竞赛,觉得最重要的还是特征工程,能挖到更好的特征就意味着训练出更好的结果。本人在trade类别特征上并未有很多思考,一直在思考和实验tag型特征,也算是一次教训,不能投机蹊跷和思想上投篮,也希望下个比赛自己能做的更好。

  • 8
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值