中国移动“梧桐杯”金融赛道TOP1开源

容器GPUClickHouse

梧桐杯的比赛复赛已经结束,已经得奖的肯定满心欢舞,没有得奖的选手也不需要灰心,下次再来过。为了给大家提升竞赛能力,我们ChallengeHub在梧桐杯的每个赛道都给大家准备了初赛的Top方案(金融赛道B榜Top1,城市赛道B榜Top2,生活赛道A榜Top4,B榜由于队伍原因未提交B榜),内容丰富,诚意满满,希望大家多多支持,你们的支持是我们最大的动力。

金融赛道的代码贡献者是小泽,竞赛届的新秀(dalao),首先恭喜他在初赛获得了第一,复赛获得了第二的好成绩了,废话不多说,来看他的分享吧(下文中代码以及都是作者所述,无一修改)。

比赛链接https://js.dclab.run/v2/cmptDetail.html?id=463

初赛要求选手依照主办方已给数据找出“羊毛党”,具体包含:利用用户通信、流量、app使用等行为数据。picture.image

由于之前主要是在生活赛道,来金融的时候大家已经发现数据中奇数月和偶数月分布差异很大,并且采用1、3月份建模效果最好。所以我这一块主要还是怼的业务特征。

数据处理

首先是对数据做了一些转型以及填充编码处理


          
            
data.replace('\\N', np.NaN, inplace=True)  
#所有从网络侧到用户侧的数据流,都属于下行流量;从用户侧到网络侧是数据流,则属于上行流量,一般用户来说下行流量远大于上行流量  
f_features = ['gprs\_fee', 'overrun\_flux\_fee', 'out\_actvcall\_dur', 'actvcall\_fee',  
       'out\_activcall\_fee', 'monfix\_fee', 'gift\_acct\_amt', 'call\_cnt',  
       'up\_flux', 'down\_flux', 'p2psms\_up\_cnt',  
       'p2psms\_cmnct\_fee', 'p2psms\_pkg\_fee']  
data[f_features] = data[f_features].astype('float')  
  
cat_cols = ['if\_group','if\_family','sms\_inpkg\_ind']  
def encode\_df(data):  
    for col in cat_cols:     
        print(col)  
        encode = LabelEncoder()  
        data[col] = data[col].fillna('unkown')          
        encode.fit(data[col])          
        data[col] = encode.transform(data[col])  
    return data  
  
data=encode_df(data)  

        

特征工程

然后是一些根据业务背景做的一些简单的业务特征


          
            
data['total\_flow']=data['up\_flux']+data['down\_flux']  
data['average\_flow']=data['total\_flow']/data['call\_cnt']  
data['aver\_up\_fee'] = data['up\_flux']/data['call\_cnt']  
data['aver\_down\_fee'] = data['down\_flux']/data['call\_cnt']  
data['total\_liuliang\_fee']=data['gprs\_fee']+data['overrun\_flux\_fee']  
data['total\_yu\_e'] = data['chrg\_amt'] + data['gift\_acct\_amt']  
data['p2p\_feeall'] = data['p2psms\_cmnct\_fee'] + data['p2psms\_pkg\_fee']  
  
data['use\_money'] = data['total\_yu\_e'] - data['monfix\_fee']  
data['aver\_chrg'] = data['chrg\_amt'] / data['chrg\_cnt']  
  
data['total\_cnt'] = data['call\_cnt'] + data['chrg\_cnt'] + data['p2psms\_up\_cnt']  
data.drop(['actvcall\_fee','out\_activcall\_fee','overrun\_flux\_fee','gprs\_fee'],axis=1,inplace=True)  

        

接下来是分组特征,分组特征往往表现出比较极端的效果,对模型的影响还是较大,后面需要细致的调试。


          
            
data_usr=data.sort_values(by=['phone','month']).reset_index()  
data_usr.fillna(data_usr.median(),inplace=True)  
  
def get\_features1(data):  
    data_count=pd.DataFrame()  
    data_count['phone']=data['phone'].unique()  
    for f in tqdm(['chrg\_amt','total\_liuliang\_fee','total\_yu\_e','p2p\_feeall','total\_flow',  
                  'p2psms\_up\_cnt']):  
        df_temp = data.groupby('phone')[f].agg(**{  
            'df\_{}\_mean'.format(f): 'mean',  
            'df\_{}\_std'.format(f): 'std',  
            'df\_{}\_max'.format(f): 'max',  
            'df\_{}\_min'.format(f): 'min',  
            'df\_{}\_sum'.format(f): 'sum',  
        }).reset_index()  
        data_count=pd.merge(data_count,df_temp,on='phone',how='left')   
          
    for f in tqdm(['monfix\_fee']):  
        df_temp = data.groupby('phone')[f].agg(**{  
            'df\_{}\_sum'.format(f): 'sum',  
        }).reset_index()  
        data_count=pd.merge(data_count,df_temp,on='phone',how='left')     
          
    return data_count  
  
data_usr=get_features1(data_usr)  

        

对数据做EDA分析可以发现部分行为特征做01分箱往往可以表现出比较好的效果


          
            
def f(x):  
    if x>0:  
        return 1  
    else:  
        return 0     
data['if\_flux\_na']=0  
data.loc[(data['up\_flux'].isnull())&(data['down\_flux'].isnull()),['if\_flux\_na']] = 1  
data.loc[data['down\_flux']!=np.nan,['if\_flux\_na']] = 0  
data.loc[data['up\_flux']!=np.nan,['if\_flux\_na']] = 0  
  
data['if\_czcs']=data['chrg\_cnt'].apply(f)  
data['if\_call']=data['call\_cnt'].apply(f)  
data['if\_p2psms']=data['p2psms\_up\_cnt'].apply(f)  
data['if\_czje']=data['chrg\_amt'].apply(f)  

        

接下来的特征主要是考虑两个特征之间的相关性,比如上、下行流量的一些衍生关系。B榜还是挺有用的,A榜的上下行流量数据特征基本没啥用,所以这里只是提一下这方面的思路,具体还是要看大家自己线下对比效果。


          
            
def get\_features2(df):  
    features = [['gift\_acct\_amt','monfix\_fee'],['up\_flux','down\_flux']]  
    for fea in features:  
        df[f'{fea[0]}\_{fea[1]}\_std'] = df[fea].std(1)  
        df[f'{fea[0]}\_{fea[1]}\_max'] = df[fea].max(1)  
        df[f'{fea[0]}\_{fea[1]}\_min'] = df[fea].min(1)  
  
        df[f'{fea[0]}\_{fea[1]}\_sub'] = df[fea[0]] - df[fea[1]]  
    return df  
  
X_train = get_features2(X_train)  
X_test = get_features2(X_test)  

        

模型训练

模型依旧采用的是五折的lgb,由于时间问题并没有尝试五折的catboost,这题的类别特征不是很多,具体的效果没有进行对比


          
            
KF = StratifiedKFold(n_splits=5, random_state=2021, shuffle=True)  
params = {  
          'objective':'binary',  
          'metric':'binary\_error',   
          'learning\_rate':0.04,   
          'num\_iterations': 10000,   
          'silent':True  
}  
  
oof_lgb = np.zeros(len(X_train))  
predictions_lgb = np.zeros((len(X_test)))  
  
# 五折交叉验证  
for fold_, (trn_idx, val_idx) in enumerate(KF.split(X_train.values, y.values)):  
    print("fold n°{}".format(fold_))  
    print('trn\_idx:',trn_idx)  
    print('val\_idx:',val_idx)  
    trn_data = lgb.Dataset(X_train.iloc[trn_idx][features],label=y.iloc[trn_idx])      
    val_data = lgb.Dataset(X_train.iloc[val_idx][features],label=y.iloc[val_idx])  
    num_round = 10000  
    clf = lgb.train(  
        params,  
        trn_data,  
        num_round,  
        valid_sets = [trn_data, val_data],  
        verbose_eval=500,  
        early_stopping_rounds=200,    
        categorical_feature=cat_cols,      
    )         
    oof_lgb[val_idx] = clf.predict(X_train.iloc[val_idx][features], num_iteration=clf.best_iteration)  
    predictions_lgb[:] += (clf.predict(X_test[features], num_iteration=clf.best_iteration))/5   
print("AUC score: {}".format(roc_auc_score(y, oof_lgb)))  
print("F1 score: {}".format(f1_score(y, [1 if i >= 0.5 else 0 for i in oof_lgb])))  
print("Precision score: {}".format(precision_score(y, [1 if i >= 0.5 else 0 for i in oof_lgb])))  
print("Recall score: {}".format(recall_score(y, [1 if i >= 0.5 else 0 for i in oof_lgb])))  

        

写在最后

到这里基本就结束了,是不是觉得很不可思议?百余行代码就可以获得较好的成绩,也没有用比较花里胡哨的模型,所以根据数据去实现好的业务特征往往就是会带来意想不到的效果,由于做金融赛道的时候只剩下一周时间还有部分想法没有实现,这里也一并分享给大家(仅供参考):1.对类别特征做交叉 2.对数值特征(比如余额)做更为细致的分箱 3.研究业务背景,根据已有的特征去实现更强的业务特征 4.尝试更换其他模型,比如catboost

再次感谢小泽的分享,最后贴上小泽的CSDN链接:https://blog.csdn.net/qq\_43240913/article/details/116329467

小泽是一个大三的学生,热爱技术,喜欢数据挖掘,大家喜欢的话可以关注他一下,多多交流(有问题就找他)。

picture.image 期待你的关注

关于梧桐杯金融赛道Top1的分享到此就结束了,当然城市生活赛道的分享也会尽快带给大家的。

另外,想了解更多算法,数据分析,数据挖掘等方面的知识,欢迎关注ChallengeHub公众号,添加微信进入微信交流群,或者进入QQ交流群。关注公众号或者进群可以直接获得上面的代码,而且也有很多机器学习的资料可以获取。

picture.image picture.image

长按二维码关注ChallengeHub

ChallengeHub出品

写在最后,最近梧桐杯有一个复活赛,希望大家可以投票支持下我们复活,下面是投票二维码(直接扫码进入投票页面,直接投票,无需注册,每个人可以投三票,可以投给同一个人),大家投票给8号队伍,希望大家可以稍微支持一下。

picture.image

推荐阅读:

竞赛姿势必会:特征工程中的奇淫技巧

冲击冠军24W,独家开源方案,马栏山防盗链赛道

0
0
0
0
关于作者
关于作者

文章

0

获赞

0

收藏

0

相关资源
如何利用云原生构建 AIGC 业务基石
AIGC即AI Generated Content,是指利用人工智能技术来生成内容,AIGC也被认为是继UGC、PGC之后的新型内容生产方式,AI绘画、AI写作等都属于AIGC的分支。而 AIGC 业务的部署也面临着异构资源管理、机器学习流程管理等问题,本次分享将和大家分享如何使用云原生技术构建 AIGC 业务。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论