这是关于预测分数的一个比赛,本来也想了解别人的代码来思考别人是如何做的,顺便自己也要学习一下。废话不多说,这里看下如何处理数据的。
数据集下载可以在kaggle 里找得到,kaggle 国内可以访问,并且也可以用他的平台来跑代码,很方便的做一些事情,先来看下数据探索这一块。这里把测试集和训练集都融合在一起做特征分析,其实是因为有可能出现在测试集而不存再训练集中的特征值,这里一同处理了,
import pandas as pd
import numpy as np
import lightgbm as lgb
from sklearn.kernel_ridge import KernelRidge
from sklearn.linear_model import ElasticNet, BayesianRidge
from sklearn.model_selection import KFold, StratifiedKFold, RepeatedKFold
from sklearn.metrics import mean_squared_error as mse, mean_absolute_error as mae, mean_absolute_error
import xgboost as xgb
import matplotlib.pyplot as plt
import catboost as ctb
## 读取 数据集
path = "../input/mobile-credit/"
train = pd.read_csv(path + '/train_dataset.csv')
print(train.shape)
train['type'] = 1
test = pd.read_csv(path + '/test_dataset.csv')
test['type'] = 0
data = pd.concat([train, test], ignore_index=True)
print(data.shape)
## 来看下数据大概情况
data.info()
print('-'*80)
print(data.dtypes.value_counts())
columnsList = list(data)
print(columnsList)
for col in columnsList:
print('-'*20+' {} '.format(col)+'-'*20)
print(' 不同值个数 = {} 最大值 = {} , 最小值 = {}'.format(len(data[col].value_counts()),data[col].max(),data[col].min()))
print(data[col].value_counts())
代码运行结果:
['type', '信用分', '当月旅游资讯类应用使用次数', '当月是否体育场馆消费', '当月是否到过福州山姆会员店', '当月是否景点游览', '当月是否看电影', '当月是否逛过福州仓山万达', '当月火车类应用使用次数', '当月物流快递类应用使用次数', '当月网购类应用使用次数', '当月视频播放类应用使用次数', '当月通话交往圈人数', '当月金融理财类应用使用总次数', '当月飞机类应用使用次数', '是否4G不健康客户', '是否大学生客户', '是否经常逛商场的人', '是否黑名单客户', '用户实名制是否通过核实', '用户年龄', '用户当月账户余额(元)', '用户最近一次缴费距今时长(月)', '用户编码', '用户网龄(月)', '用户话费敏感度', '用户账单当月总费用(元)', '用户近6个月平均消费值(元)', '缴费用户当前是否欠费缴费', '缴费用户最近一次缴费金额(元)', '近三个月月均商场出现次数']
-------------------- type --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
1 50000
0 50000
Name: type, dtype: int64
-------------------- 信用分 --------------------
不同值个数 = 278 最大值 = 719.0 , 最小值 = 422.0
640.0 605
635.0 597
644.0 595
634.0 594
629.0 592
...
441.0 1
455.0 1
713.0 1
436.0 1
453.0 1
Name: 信用分, Length: 278, dtype: int64
-------------------- 当月旅游资讯类应用使用次数 --------------------
不同值个数 = 934 最大值 = 87681 , 最小值 = 0
0 61206
1 5340
2 4485
3 2504
4 2317
...
674 1
546 1
1569 1
1313 1
735 1
Name: 当月旅游资讯类应用使用次数, Length: 934, dtype: int64
-------------------- 当月是否体育场馆消费 --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
0 62527
1 37473
Name: 当月是否体育场馆消费, dtype: int64
-------------------- 当月是否到过福州山姆会员店 --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
0 97295
1 2705
Name: 当月是否到过福州山姆会员店, dtype: int64
-------------------- 当月是否景点游览 --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
0 52454
1 47546
Name: 当月是否景点游览, dtype: int64
-------------------- 当月是否看电影 --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
0 75620
1 24380
Name: 当月是否看电影, dtype: int64
-------------------- 当月是否逛过福州仓山万达 --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
0 96077
1 3923
Name: 当月是否逛过福州仓山万达, dtype: int64
-------------------- 当月火车类应用使用次数 --------------------
不同值个数 = 180 最大值 = 775 , 最小值 = 0
0 95007
1 1542
2 1228
3 464
4 330
...
147 1
234 1
212 1
170 1
92 1
Name: 当月火车类应用使用次数, Length: 180, dtype: int64
-------------------- 当月物流快递类应用使用次数 --------------------
不同值个数 = 239 最大值 = 8235 , 最小值 = 0
0 98534
1 146
2 127
3 77
4 72
...
477 1
114 1
286 1
625 1
191 1
Name: 当月物流快递类应用使用次数, Length: 239, dtype: int64
-------------------- 当月网购类应用使用次数 --------------------
不同值个数 = 8382 最大值 = 417536 , 最小值 = 0
0 15937
1 1284
2 961
4 837
3 688
...
10844 1
6746 1
6385 1
2940 1
8785 1
Name: 当月网购类应用使用次数, Length: 8382, dtype: int64
-------------------- 当月视频播放类应用使用次数 --------------------
不同值个数 = 16067 最大值 = 1382227 , 最小值 = 0
0 17355
1 1511
2 1418
3 843
4 828
...
11365 1
60477 1
42036 1
19497 1
49528 1
Name: 当月视频播放类应用使用次数, Length: 16067, dtype: int64
-------------------- 当月通话交往圈人数 --------------------
不同值个数 = 554 最大值 = 1906 , 最小值 = 1
16 1762
14 1747
13 1737
15 1718
11 1711
...
652 1
486 1
550 1
1318 1
1151 1
Name: 当月通话交往圈人数, Length: 554, dtype: int64
-------------------- 当月金融理财类应用使用总次数 --------------------
不同值个数 = 7232 最大值 = 496238 , 最小值 = 0
0 18363
1 2158
2 1620
3 1080
4 957
...
9180 1
5082 1
6902 1
21394 1
20714 1
Name: 当月金融理财类应用使用总次数, Length: 7232, dtype: int64
-------------------- 当月飞机类应用使用次数 --------------------
不同值个数 = 209 最大值 = 5856 , 最小值 = 0
0 98632
1 122
7 96
2 90
8 89
...
298 1
150 1
1174 1
233 1
63 1
Name: 当月飞机类应用使用次数, Length: 209, dtype: int64
-------------------- 是否4G不健康客户 --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
0 91131
1 8869
Name: 是否4G不健康客户, dtype: int64
-------------------- 是否大学生客户 --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
0 99638
1 362
Name: 是否大学生客户, dtype: int64
-------------------- 是否经常逛商场的人 --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
0 66928
1 33072
Name: 是否经常逛商场的人, dtype: int64
-------------------- 是否黑名单客户 --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
0 95150
1 4850
Name: 是否黑名单客户, dtype: int64
-------------------- 用户实名制是否通过核实 --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
1 99124
0 876
Name: 用户实名制是否通过核实, dtype: int64
-------------------- 用户年龄 --------------------
不同值个数 = 88 最大值 = 111 , 最小值 = 0
29 4255
36 4227
31 4168
28 4062
30 4021
...
13 1
111 1
105 1
100 1
91 1
Name: 用户年龄, Length: 88, dtype: int64
-------------------- 用户当月账户余额(元) --------------------
不同值个数 = 316 最大值 = 109090 , 最小值 = 10
50 8009
30 7847
40 7777
20 7480
60 6662
...
5280 1
15270 1
3100 1
2140 1
4290 1
Name: 用户当月账户余额(元), Length: 316, dtype: int64
-------------------- 用户最近一次缴费距今时长(月) --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
1 70142
0 29858
Name: 用户最近一次缴费距今时长(月), dtype: int64
-------------------- 用户编码 --------------------
不同值个数 = 100000 最大值 = ffffebe8f3a74834b51e122d76a9d41a , 最小值 = 00011b2d787242499b8683f0e72ec5a2
cb1833d8de1641feb17c5d90cf6c83fb 1
138dab4ccd2f48f9b1aae72b0c14d101 1
ebc74c5d15b748f394dba5eca80e9ffb 1
704d0c39c9ee48f88299f9c269b432a1 1
c84346fc602a4913846d9ce29689be18 1
..
5a39734f0a61416b9661fa19123606ad 1
33e02edbfe2e49a79f7f00c0df69bf1a 1
eab1e711168746e183f3870611cd66aa 1
c54fb03a8dad497a884764a109164ba1 1
4cf641c938bd442994f554e9eb047ad4 1
Name: 用户编码, Length: 100000, dtype: int64
-------------------- 用户网龄(月) --------------------
不同值个数 = 283 最大值 = 288 , 最小值 = 1
5 1280
7 1141
6 1120
8 1031
10 927
...
3 3
287 2
284 2
281 1
280 1
Name: 用户网龄(月), Length: 283, dtype: int64
-------------------- 用户话费敏感度 --------------------
不同值个数 = 6 最大值 = 5 , 最小值 = 0
4 29838
5 21011
2 20622
3 20578
1 7913
0 38
Name: 用户话费敏感度, dtype: int64
-------------------- 用户账单当月总费用(元) --------------------
不同值个数 = 16597 最大值 = 2117.01 , 最小值 = 0.0
18.00 2274
38.00 1816
78.00 1418
58.00 1342
98.00 1250
...
96.35 1
198.21 1
166.79 1
247.56 1
43.44 1
Name: 用户账单当月总费用(元), Length: 16597, dtype: int64
-------------------- 用户近6个月平均消费值(元) --------------------
不同值个数 = 22520 最大值 = 1792.74 , 最小值 = 0.0
18.00 410
38.00 191
18.01 154
40.00 143
88.00 120
...
12.86 1
251.78 1
229.92 1
211.33 1
290.20 1
Name: 用户近6个月平均消费值(元), Length: 22520, dtype: int64
-------------------- 缴费用户当前是否欠费缴费 --------------------
不同值个数 = 2 最大值 = 1 , 最小值 = 0
0 94817
1 5183
Name: 缴费用户当前是否欠费缴费, dtype: int64
-------------------- 缴费用户最近一次缴费金额(元) --------------------
不同值个数 = 532 最大值 = 1000.0 , 最小值 = 0.0
0.00 29357
99.80 22284
49.90 21066
29.94 11740
199.60 5189
...
60.14 1
33.49 1
28.17 1
100.99 1
5.60 1
Name: 缴费用户最近一次缴费金额(元), Length: 532, dtype: int64
-------------------- 近三个月月均商场出现次数 --------------------
不同值个数 = 93 最大值 = 92 , 最小值 = 0
0 20755
1 7607
2 5735
92 4791
3 4190
...
57 296
58 290
56 288
65 285
53 285
Name: 近三个月月均商场出现次数, Length: 93, dtype: int64
还好特征不多,不然这个就得慢慢看了,通过数据情况我们可以得到这些结论:
上述是代码探索方面的内容,我们依旧先参考别人的代码来看下他们是如何思考的,然后我们再提出一些问题和我们的看法。
# 关键特征被fillna 0 了 这里还原回来
data.loc[data['用户年龄'] == 0, '用户年龄'] = None
data.loc[data['用户年龄'] > 100, '用户年龄'] = None
data.loc[data['用户话费敏感度'] == 0, '用户话费敏感度'] = None
data.loc[data['用户近6个月平均消费值(元)'] == 0, '用户近6个月平均消费值(元)'] = None
# 特征 名称 转换一下
data.rename(columns={'用户编码': 'id', '信用分': 'score'}, inplace=True)
origin_bool_feature = ['当月是否体育场馆消费', '当月是否景点游览', '当月是否看电影', '当月是否到过福州山姆会员店', '当月是否逛过福州仓山万达',
'缴费用户当前是否欠费缴费', '是否经常逛商场的人', '是否大学生客户', '是否4G不健康客户', '是否黑名单客户',
'用户最近一次缴费距今时长(月)', '用户实名制是否通过核实']
origin_num_feature = ['用户话费敏感度', '用户年龄', '近三个月月均商场出现次数', '当月火车类应用使用次数', '当月飞机类应用使用次数',
'当月物流快递类应用使用次数', '用户当月账户余额(元)', '用户网龄(月)', '缴费用户最近一次缴费金额(元)',
'当月通话交往圈人数', '当月旅游资讯类应用使用次数', '当月金融理财类应用使用总次数', '当月网购类应用使用次数',
'当月视频播放类应用使用次数', '用户账单当月总费用(元)', '用户近6个月平均消费值(元)']
count_feature_list = []
## 重点看下这些特征,把特征值的count 新增为一列,简单的一个代码就搞定了,map作用还挺大的
for i in ['用户近6个月平均消费值(元)', '用户账单当月总费用(元)', '缴费用户最近一次缴费金额(元)']:
count_feature_list.append('count_' + i)
data['count_' + i] = data[i].map(data[i].value_counts())
# 业务特征 - 话费特征:
# 1、5个月的话费
# 2、当月账单 - 平均账单
# 3、用户最近一次缴费/ 当月账单金额
data['five_all'] = data['用户近6个月平均消费值(元)'] * data['用户网龄(月)'].apply(lambda x: min(x, 6)) - data['用户账单当月总费用(元)']
data['fee_del_mean'] = data['用户账单当月总费用(元)'] - data['用户近6个月平均消费值(元)']
data['fee_remain_now'] = data['缴费用户最近一次缴费金额(元)'] / data['用户账单当月总费用(元)']
# 把一些统计次数的特征 收纳为一个特征,但是这里没有 '近三个月月均商场出现次数' 这个特征,可能是时间维度的问题
data['次数'] = data[['当月网购类应用使用次数', '当月物流快递类应用使用次数', '当月金融理财类应用使用总次数',
'当月视频播放类应用使用次数', '当月飞机类应用使用次数', '当月火车类应用使用次数', '当月旅游资讯类应用使用次数']].sum(axis=1)
## 算次数占比,有一些的特征的占比情况,
for col in ['当月金融理财类应用使用总次数', '当月旅游资讯类应用使用次数']: # 这两个比较积极向上一点
data[col + '_百分比'] = data[col] / data['次数']
## 除以12 得到年限
data['regist_month'] = data['用户网龄(月)'] % 12
# 不知道这个是干嘛的 ,感觉好像是算出 一些 loss比较大的id
lgb_model = lgb.LGBMRegressor(
num_leaves=32, reg_alpha=0., reg_lambda=0.01, objective='mse', metric='mae',
max_depth=-1, learning_rate=0.01, min_child_samples=50,
n_estimators=15000, subsample=0.7, colsample_bytree=0.45, subsample_freq=5,
)
# ab_id 是去除的200个样本的id。是由5折预测出来的结果的loss最大的200个构成。也可以将这200个数据权重设置0.01(线下好像更好了。没机会试了)
ab_id = []
# 设置样本权重
data['temp_label'] = data['score']
# 这里设置为None 而不是删除该数据,因为删除的话,线下一定是提升的,对于线上而言,异常数据依旧存在,所以应该关注在训练集无异常,而测试集有异常下的处理效果
data['sample_weight'] = data['temp_label'] + 200
data['sample_weight'] = data['sample_weight'] / data['sample_weight'].mean()
# 方案1 ,不训练
data.loc[data.id.isin(ab_id), 'temp_label'] = None
# 方案2,样本权重设置低一点
data.loc[data.id.isin(ab_id), 'sample_weight'] = 0.01
# 感谢大佬分享的参数
ctb_params = {
'n_estimators': 10000,
'learning_rate': 0.02,
'random_seed': 4590,
'reg_lambda': 0.08,
'subsample': 0.7,
'bootstrap_type': 'Bernoulli',
'boosting_type': 'Plain',
'one_hot_max_size': 10,
'rsm': 0.5,
'leaf_estimation_iterations': 5,
'use_best_model': True,
'max_depth': 6,
'verbose': -1,
'thread_count': 4
}
ctb_model = ctb.CatBoostRegressor(**ctb_params)
上述代码有点多,帮大家总结一下:
这里我要改一下,使用lightgbm 来训练模型,评价指标值metrics=‘rmse’ ,代码如下:
# 把 测试数据集拿出来训练
data_train = data.drop('id', 1)
df_train = data_train.loc[data['type'] == 1]
y_train = data.loc[data['type'] == 1]['score']
print(df_train.shape)
print(y_train.shape)
params = {
'boosting_type': 'gbdt',
'objective': 'regression',
'learning_rate': 0.005,
'num_leaves': 80,
'max_depth': 7,
'min_data_in_leaf': 20,
'subsample': 1,
'colsample_bytree': 0.7,
}
data_train = lgb.Dataset(df_train, y_train, silent=True)
cv_results = lgb.cv(
params, data_train, num_boost_round=10000, nfold=5, stratified=False, shuffle=True, metrics='rmse',
early_stopping_rounds=50, verbose_eval=100, show_stdv=True)
print('best n_estimators:', len(cv_results['rmse-mean']))
print('best cv score:', cv_results['rmse-mean'][-1])
看下部分实验结果吧:
[100] cv_agg's rmse: 26.6712 + 0.10326
[200] cv_agg's rmse: 17.0392 + 0.0632588
[300] cv_agg's rmse: 11.1587 + 0.0420691
[400] cv_agg's rmse: 7.5608 + 0.0307922
[500] cv_agg's rmse: 5.26283 + 0.0275422
[600] cv_agg's rmse: 3.84734 + 0.0265683
[9000] cv_agg's rmse: 0.669732 + 0.0136983
[9100] cv_agg's rmse: 0.669402 + 0.0136558
[9200] cv_agg's rmse: 0.669015 + 0.0135673
[9300] cv_agg's rmse: 0.668788 + 0.0136241
[9400] cv_agg's rmse: 0.668525 + 0.0136477
[9500] cv_agg's rmse: 0.668247 + 0.0136263
[9600] cv_agg's rmse: 0.667934 + 0.0136192
[9700] cv_agg's rmse: 0.667742 + 0.0135973
[9800] cv_agg's rmse: 0.667451 + 0.0135567
[9900] cv_agg's rmse: 0.667144 + 0.0135732
[10000] cv_agg's rmse: 0.666852 + 0.0135611
best n_estimators: 10000
best cv score: 0.6668517639542803
1、为什么要把脏数据、离散样本特征值置位None?
比如用户年龄,完全可以拆分 年龄段来做一个新特征。
2、置位None的特征是否合适?
意思就是换个模型,这样的值能不能被训练,估计不行吧,我个人认为还是都是数值化比较好,这样换模型比较好,
3、代码跟 参考博客里的PPT 对比起来差别还是挺大的,
可能代码精简了很多,只是一部分代码,但重点是思考问题的方式,根据对比赛、数据集的理解,加上实验,得到的一些结论。
消费者人群画像-信用智能评分Top1
消费者人群画像—信用智能评分