赞
踩
这是关于预测分数的一个比赛,本来也想了解别人的代码来思考别人是如何做的,顺便自己也要学习一下。废话不多说,这里看下如何处理数据的。
数据集下载可以在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 对比起来差别还是挺大的,
可能代码精简了很多,只是一部分代码,但重点是思考问题的方式,根据对比赛、数据集的理解,加上实验,得到的一些结论。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。