
该开源方案在初赛A榜成绩为0.948,初赛B榜为0.940。仅为大家开阔思路使用,希望对大家有一定的帮助。

防羊毛党评分模型旨在从普通用户中区分出羊毛党用户号码。

这里以初赛A榜的处理为例
第一步是处理一下数据格式问题
1import pandas as pd
2import numpy as np
3
4data = pd.read_csv("data/data_a.csv")
5label = pd.read_csv("data/train_label.csv")
6to_predict_a = pd.read_csv("data/to_pred_a.csv")
7
8# 数据中存在'\N',替换为nan
9data = data.sort_values(by = ["phone","month"]).reset_index(drop = True)
10data = data.replace(r"\N",np.nan)
11# 转化一下数据格式
12data["if_family"] = data["if_family"].astype(float)
13data["if_group"] = data["if_group"].astype(float)
14
15data["gprs_fee"] = data["gprs_fee"].astype(float)
16data["overrun_flux_fee"] = data["overrun_flux_fee"].astype(float)
17data["out_actvcall_dur"] = data["out_actvcall_dur"].astype(float)
18data["actvcall_fee"] = data["actvcall_fee"].astype(float)
19data["out_activcall_fee"] = data["out_activcall_fee"].astype(float)
20data["monfix_fee"] = data["monfix_fee"].astype(float)
21data["gift_acct_amt"] = data["gift_acct_amt"].astype(float)
22data["call_cnt"] = data["call_cnt"].astype(float)
23data["up_flux"] = data["up_flux"].astype(float)
24data["down_flux"] = data["down_flux"].astype(float)
25data["sms_inpkg_ind"] = data["sms_inpkg_ind"].astype(float)
26data["p2psms_up_cnt"] = data["p2psms_up_cnt"].astype(float)
27data["p2psms_cmnct_fee"] = data["p2psms_cmnct_fee"].astype(float)
28data["p2psms_pkg_fee"] = data["p2psms_pkg_fee"].astype(float)
第二步的思想是将训练集1,2月份的数据横向的拼接起来,测试机的3,4月份数据横向的拼接起来,然后列名需要重新命名
1data_1 = data[data["month"].isin([202001])].reset_index(drop=True)
2data_2 = data[data["month"].isin([202002])].reset_index(drop=True)
3data_3 = data[data["month"].isin([202003])].reset_index(drop=True)
4data_4 = data[data["month"].isin([202004])].reset_index(drop=True)
5
6col1 = data_1.columns
7col1 = [col+"_b" for col in col1 if col not in ["phone","month"]]
8data_1.columns = ["phone","month"] + col1
9col2 = data_2.columns
10col2 = [col+"_f" for col in col2 if col not in ["phone","month"]]
11data_2.columns = ["phone","month"] + col2
12data_1_2 = data_1[["phone"]+col1].merge(data_2[["phone"]+col2],on = "phone",how = "left").reset_index(drop=True)
13
14col3 = data_3.columns
15col3 = [col+"_b" for col in col3 if col not in ["phone","month"]]
16data_3.columns = ["phone","month"] + col3
17col4 = data_4.columns
18col4 = [col+"_f" for col in col4 if col not in ["phone","month"]]
19data_4.columns = ["phone","month"] + col4
20data_3_4 = data_3[["phone"]+col3].merge(data_4[["phone"]+col4],on = "phone",how = "left").reset_index(drop=True)
21
22data = pd.concat([data_1_2,data_3_4],axis=0).reset_index(drop=True)
23data = data.merge(label,on="phone",how="left")
24data.to_csv("data/merge_data.csv",index=False)
第三步就是建模过程,主要的特征就是缺失率、目标编码、以及不同月份之间的变化率、离散特征是否变化这些特征
1import pandas as pd
2import numpy as np
3from tqdm.notebook import tqdm
4
5data_1 = pd.read_csv("data/merge_data.csv")
6data_1['missing_rate'] = (data_1.shape[1] - data_1.count(axis = 1)) / data_1.shape[1]
7cate_cols = ['if_group_b','if_family_b','sms_inpkg_ind_b','if_group_f','if_family_f','sms_inpkg_ind_f']
8dense_cols = [col for col in data_1.columns if col not in cate_cols+["phone","label"]]
9dense = ['chrg_cnt','chrg_amt','gprs_fee','overrun_flux_fee','out_actvcall_dur','actvcall_fee',
10 'out_activcall_fee','monfix_fee','gift_acct_amt','call_cnt','up_flux','down_flux',
11 'p2psms_up_cnt','p2psms_cmnct_fee','p2psms_pkg_fee']
12for col in dense:
13 data_1[col+"_diff"] = data_1[col+"_f"] - data_1[col+"_b"]
14 data_1[col+"_ratio"] = (data_1[col+"_f"] - data_1[col+"_b"]) / (data_1[col+"_b"]+1e-7)
15for col in ['if_group','if_family','sms_inpkg_ind'] + dense:
16 data_1[col+"_ifchange"] = (data_1[col+"_b"]==data_1[col+"_f"]).astype(int)
17for col in ['if_group','if_family','sms_inpkg_ind'] + dense:
18 data_1[col+"_ifchange"] = (data_1[col+"_b"]==data_1[col+"_f"]).astype(int)
19test_df = data_1[data_1["label"].isnull() == True].copy().reset_index(drop=True)
20train_df = data_1[~data_1["label"].isnull() == True].copy().reset_index(drop=True)
21from sklearn.model_selection import StratifiedKFold
22skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=2020)
23enc_list = cate_cols+dense_cols
24for f in tqdm(enc_list):
25 train_df[f + '_target_enc'] = 0
26 test_df[f + '_target_enc'] = 0
27 for i, (trn_idx, val_idx) in enumerate(skf.split(train_df, train_df['label'])):
28 trn_x = train_df[[f, 'label']].iloc[trn_idx].reset_index(drop=True)
29 val_x = train_df[[f]].iloc[val_idx].reset_index(drop=True)
30 enc_df = trn_x.groupby(f, as_index=False)['label'].agg({f + '_target_enc': 'mean'})
31 val_x = val_x.merge(enc_df, on=f, how='left')
32 test_x = test_df[[f]].merge(enc_df, on=f, how='left')
33 val_x[f + '_target_enc'] = val_x[f + '_target_enc'].fillna(train_df['label'].mean())
34 test_x[f + '_target_enc'] = test_x[f + '_target_enc'].fillna(train_df['label'].mean())
35 train_df.loc[val_idx, f + '_target_enc'] = val_x[f + '_target_enc'].values
36 test_df[f + '_target_enc'] += test_x[f + '_target_enc'].values / skf.n_splits
37train_df.shape,test_df.shape
38
39import lightgbm as lgb
40from tensorflow import keras
41from catboost import CatBoostClassifier
42from sklearn.model_selection import StratifiedKFold,train_test_split
43from sklearn.metrics import f1_score, precision_score, recall_score, accuracy_score
44from sklearn.preprocessing import LabelEncoder
45import seaborn as sns
46import matplotlib.pyplot as plt
47from scipy.stats import entropy
48import tensorflow as tf
49import gc
50import os
51from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau
52from sklearn.preprocessing import StandardScaler,MinMaxScaler
53from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau,LambdaCallback
54from sklearn.metrics import roc_auc_score
5556remove_col = []
57for col in train_df.columns:
58 if col not in ["phone", "label"]:
59 if train_df[col].nunique() < 2:
60 remove_col.append(col)
61feature_name = [i for i in train_df.columns if i not in ["phone", "label"]+remove_col]
62print(len(feature_name))
63X_train = train_df[feature_name].reset_index(drop=True)
64X_test = test_df[feature_name].reset_index(drop=True)
65y = train_df['label'].reset_index(drop=True).astype(int)
66
67oof = np.zeros(X_train.shape[0])
68prediction = np.zeros(X_test.shape[0])
69seeds = [5, 4, 2, 1015, 2020, 2048, 1024]
70num_model_seed = len(seeds)
71print("Catboost训练")
72for model_seed in range(num_model_seed):
73 print('--'*20+str(seeds[model_seed])+'--'*20)
74 oof_cat = np.zeros(X_train.shape[0])
75 prediction_cat = np.zeros(X_test.shape[0])
76 skf = StratifiedKFold(n_splits=5, random_state=seeds[model_seed], shuffle=True)
77 for index, (train_index, test_index) in enumerate(skf.split(X_train, y)):
78 print(index)
79 train_x, test_x, train_y, test_y = X_train[feature_name].iloc[train_index], X_train[feature_name].iloc[test_index], y.iloc[train_index], y.iloc[test_index]
80 cate_fea=[]
81 clf = CatBoostClassifier(iterations=10000, depth=8,learning_rate=0.1, loss_function='Logloss',cat_features=cate_fea
82 ,verbose=True,eval_metric='AUC',counter_calc_method='Full',task_type='GPU',metric_period=50)
83 clf.fit(
84 train_x, train_y,
85 eval_set=[(test_x,test_y)],
86 early_stopping_rounds=200,
87 verbose=True,
88 use_best_model=True,
89 )
90 oof_cat[test_index] = clf.predict_proba(test_x)[:, 1]
91
92 prediction_cat += clf.predict_proba(X_test)[:, 1] / 5
93 del clf
94 oof += oof_cat / num_model_seed
95 prediction += prediction_cat / num_model_seed

主要的上分点:
特征筛选
CatBoost比LightGBM要好
连续特征的不同月份的变化率特征
关于初赛B榜的处理,我个人的做法是将初赛b榜的数据与初赛a榜的数据合并到一起,然后处理与上述的程序一致,只不过在最后读取预测概率的时候注意是初赛b榜的数据。

欢迎关注公众号ChallengeHub!!!欢迎加入ChallengeHub学习交流群,微信群扫描下方左侧管理员微信进入哦,qq群扫描下方右侧二维码进入!!!


原文作者:ChallengeHub;如有侵权,请联系管理员删除。