通过分析用户线上线下的消费行为,建立模型,预测现阶段用户是否会在规定时间内使用相应优惠券,以便商家个性化投放,提高优惠券核销率。
数据为用户在2016年1月1日至2016年6月30日之间真实线上线下消费行为,预测用户在2016年7月领取优惠券后15天以内的线下使用情况。
我们的目标是要预测用户优惠券的线下使用情况,线上数据我们重点关注与用户相关的特征(是作为线下数据的一个辅助),线下我们关注的特征数据就比较多了:用户特征、商户特征、优惠券特征、用户商户组合特征、用户优惠券组合特征。
数据分析:
1、预测集中的用户,是线下训练数据集里出现过的用户,也就是老用户。
2、根据经验,我们知道活跃用户更可能使用优惠券,活跃商家所发出的优惠券更可能被使用,用户对某个商家的喜爱程度越高越可能使用这个商家发的优惠券
3、用户在周末更有时间更可能使用优惠券
4、预测集中的商家,几乎都是线下训练数据集中出现过的商家。
本题所有数据记录的时间区间是2016.01.01至2016.06.30,需要预测的是线下2016年7月份用户领取优惠劵后15天内是否核销。根据这两份数据表,我们首先需要对数据集进行划分(采用滑窗的方式),特征区间为3.5个月,预测区间为一个月。要保证滑到最后,测试集的预测区间正好是7月。也可以用其他的方式划分,特征区间越小,得到的训练数据集越多。
特征区间(提取feature) | 预测区间(预测label) | |
---|---|---|
训练集 | 20160101~20160413 | 20160414~20160514 |
验证集 | 20160201~20160514 | 20160515~20160615 |
测试集 | 20160315~20160630 | 20160701~20160731 |
为什么要这样划分呢?第一,划分训练集和验证集,方便我们交叉验证;第二,我们的训练和预测是与时间有关系的,如果是用train_test_split随机划分,可能会导致训练数据是6月份,而预测数据却是5月份,这与现实是不符合的,这就是数据泄露:
数据泄露就是说用了不该用的数据,比如
(1)在训练模型时,利用了测试集的数据、信息
(2)在当前使用了未来的数据
(3)在交叉验证进行调参时,使用了验证集的信息参与模型建立
具体说下第三点,比如对特征进行标准化,正确的方法应该是在训练集上标准化,然后应用到验证集上,而非先标准化,再划分验证集。再比如说,要对数据进行pca降维,应该是在训练集上pca,然后作用到验证集上,而非对整个数据集进行pca。通常都忽略了这一点。
如果数据集划分的不好,可能会导致在训练数据上效果很好,线下测试也还不错,但是在线上表现却不好。
注意数据集的划分是不能只根据Date_Received(优惠券领取日期)来划分,否则划分出来的数据都是有优惠券的用户,没有领取优惠券的用户数据都被丢弃了。
因为我们要预测的是用户领取优惠券之后的使用情况,所以,预测区间可以根据用户领取优惠券时间来划分,特征区间麻烦一点,如果消费时间不为空,通过消费时间划分;如果消费时间为空,则根据优惠券领取时间划分。(不能单纯的用领取时间或消费时间划分,因为这两个时间都可能是空)
测试集的预测区间的划分是从ccf_offline_stage1_test_revised.csv中读取的。
#划分特征区间数据集,通过领取时间和消费时间
def filter_feature_data(data,start_time,end_time):
return data[((data['Date'] > start_time) & (data['Date'] < end_time))|((data['Date']=='null')&(data['Date_received'] > start_time) & (data['Date_received'] < end_time))]
#划分预测区间数据集,根据领取时间
def filter_label_data(data,start_time,end_time):
return data[(data['Date_received'] > start_time) & (data['Date_received'] < end_time)]
#划分线下数据集
def offline_data_split(origin,test_data):
#训练集
train_feature_data=filter_feature_data(origin,train_feature_start_time,train_feature_end_time)
train_label_data=filter_label_data(origin,train_label_start_time,train_label_end_time)
#验证集
validate_feature_data = filter_feature_data(origin, validate_feature_start_time, validate_feature_end_time)
validate_label_data = filter_label_data(origin, validate_label_start_time, validate_label_end_time)
#测试集
predict_feature_data = filter_feature_data(origin, predict_feature_start_time, predict_feature_end_time)
predict_label_data = filter_label_data(test_data.astype(str), predict_label_start_time, predict_label_end_time)
return train_feature_data,train_label_data,validate_feature_data,validate_label_data,predict_feature_data,predict_label_data
# 划分线上数据集
def online_data_split(origin):
# 训练集
train_feature_data = filter_feature_data(origin, train_feature_start_time, train_feature_end_time)
# 验证集
validate_feature_data = filter_feature_data(origin, validate_feature_start_time, validate_feature_end_time)
# 测试集
predict_feature_data = filter_feature_data(origin, predict_feature_start_time, predict_feature_end_time)
return train_feature_data, validate_feature_data,predict_feature_data
查看哪些列有空值:
data=pd.read_csv('data/ccf_offline_stage1_train.csv')
print(data.isnull().any())
输出(True为有空值):
User_id False
Merchant_id False
Coupon_id True
Discount_rate True
Distance True
Date_received True
Date True
dtype: bool
我们的预测目标是七月份用户领券使用情况,即用或者不用,转化为二分类问题,然后通过分类算法预测结果。
因此通过Date和Date_received两个列来生成target。
然后是特征提取,包括用户特征、商户特征、优惠券特征、用户商户组合特征、用户优惠券组合特征。
每一条消费记录,除了本条提取出来的组合特征,还有结合训练集数据计算出来的特征(比如用户领取优惠券到消费的等待时间,这是一条的,而用户优惠券的核销率,这是通过整个数据集计算出的)。
注意我们预测七月份用户领取优惠券的使用情况,就要根据用户的历史消费使用优惠券的情况,然后当该用户七月份领取了优惠券之后,来判断用户是否会用掉这张优惠券。
用户相关的特征(以User_id为基准统计)
1、Date和Date_received两列---->用户领取优惠券消费次数、用户无优惠券消费次数、用户领取优惠券但没有消费、用户优惠券的核销率 、优惠券领取到使用的时间等待,以15天为界,小于15天: ( 1 − x − y 15 ) (1-\frac{x-y}{15}) (1−15x−y)。等待时间越短,这个值越大;大于15天:0.
2、Discount_rate分为两种:直接折扣消费和满减----->用户直接折扣消费、用户使用优惠券的满减类别(以1234表示)、折扣率、用户优惠券消费的各个满减档次的次数、用户优惠券消费平均消费折率、限时低价消费次数(线上+线下)
3、Merchant_id、Coupon_id、Date三列:用户优惠券消费过的不同商家数量
4、Coupon_id、Date两列:用户优惠券消费过的不同优惠券数量
5、Action:点击行为分三种,点击、购买、领取优惠券,每个类型的点击率。(线上)
商家相关的特征(以Merchant_id为基准统计)
1、Coupon_id、Date两列:无优惠券消费次数、获得优惠券但没有消费次数、优惠券消费次数、优惠券被领取后的核销率
2、Discount_rate分为两种:直接折扣消费和满减----->用户直接折扣消费、用户使用优惠券的满减类别(以1234表示)、折扣率、商家优惠券消费的各个满减档次的次数、用户优惠券消费平均消费折率、
3、Date和Date_received两列:领取到使用的时间等待
4、User_id、Coupon_id、Date三列:使用本商家优惠券消费过的不同用户数量
5、User_id、Coupon_id、Date三列:用户在本商家消费过的不同优惠券数量
用户-商家相关的特征(以User_id、Merchant_id为基准统计groupby([‘User_id’, ‘Merchant_id’])
Coupon_id、Date两列:用户对商家无优惠券消费次数、用户对商家获得优惠券但没有消费次数、用户对商家优惠券消费次数、用户对商家优惠券被领取后的核销率、用户对每个商家的不消费次数占用户不消费的所有商家的比重、用户对每个商家的优惠券消费次数占用户优惠券消费所有商家的比重、用户对每个商家的普通消费次数占用户普通消费所有商家的比重
这三类特征提取完成之后保存在user_features.csv、merchant_features.csv、user_merchant_features.csv三个文件中,注意,在每个文件中的User_id是唯一的。
这一部分就是结合预测区间的数据(1个月)和前面特征区间提取出来的特征数据(3.5个月)生成训练数据。这个训练数据就是用来训练模型的。
因此这一部分依然需要提取特征数据,除了特征数据外,还要生成每一条记录的target(除了最后的测试集的预测区间,它没有label,是需要我们预测的)。
预测区间的特征抽取:
1、距离。[0,10]范围内的数字,/10,如果是空则设为-1.
2、优惠券类型:折扣0,满减1(满减档次不同,也要考虑),无优惠券-1.
3、优惠券折率(主要是计算满减的折率,折扣的不用计算,可以直接用)
4、用户和优惠券之间的关系汇总:用户领取的优惠券数量、用户领取的每种优惠券的数量、商家被领取的优惠券的数量、商家被领取的每种优惠券的数量、用户领取每个商家的优惠券数量。
5、用户和商家的关系汇总:每个用户相关的商家数量(或领取了优惠券、或购买了东西)、#每个商家相关的用户数量(或领取了本商家的优惠券、或购买了本商家的东西)
预测区间生成target:
Coupon_id、Date两列非空且领取优惠券时间到消费时间<15天,这样的target标为1,其余的为0.
训练数据:train_features.csv、
标签数据:labels.csv
在train、validate、predict下各有一份。predict目录下只有train_features.csv
1、xgboost模型训练。
结果:
model.best_score: 0.868995, model.best_iteration: 91, model.best_ntree_limit: 92
output offline model data
Average auc of train matrix: 0.751128208956236
Average auc of validate matrix 0.6841286615724935
[[113670 5071]
[ 4948 3357]]
文件执行顺序:
1、data_split.py 划分数据集,线上数据集产生六个文件,分别是:offline_train_feature_data.csv、offline_train_label_data.csv、offline_validate_feature_data.csv、offline_validate_label_data.csv、
offline_predict_feature_data.csv、offline_train_label_data.csv
线下数据集产生3个文件:online_train_feature_data.csv、online_validate_feature_data.csv、online_predict_feature_data.csv
2、feature_extract.py 特征提取,针对训练集、验证集、测试集的特征区间进行特征提取,产生各自的特征文件:user_features.csv、merchant_features.csv、user_merchant_features.csv
3、gen_data.py 产生训练模型用的数据,仍然是针对训练集、验证集、测试集,其中训练集和验证集各产生两个文件:train_features.csv(第2步产生的特征.merge(预测区间的特征))、labels.csv(预测区间的标签),测试集只产生一个文件:train_features.csv
4、利用第3步产生的训练数据,进行模型的训练,计算AUC值、best_score、混淆矩阵等,训练好之后,进行test数据集的预测,将结果放在submission.csv中。
随手记:
1、把常量提取出来在config.py中定义。
2、把数据集划分后的结果分别写在csv文件中,把提取出的特征DataFrame也写在csv文件中,这样在调试的时候,后期训练模型就不用重复前面的操作了,直接读取文件就可。
3、pd.read_csv读取文件时,一定要注意keep_default_na=False属性,这会影响后续的一系列数据处理和比较。
参数调优(使用交叉验证):
总结与收获
大数据在实际场景中的应用
特征提取对提高模型效果的重要性(划分训练集、特征组合)
如何运用python进行数据处理,特征提取
学习xgboost的参数设置与调优
后续:加入其它模型,进行模型融合。
参考:
赛题:https://tianchi.aliyun.com/getStart/information.htm?spm=5176.100067.5678.2.594e1db7rxv16q&raceId=231593
https://github.com/InsaneLife/O2O-Predict-Coupon-Usage
冠军代码:https://github.com/wepe/O2O-Coupon-Usage-Forecast
https://blog.csdn.net/iqqiqqiqqiqq/article/details/79888179
https://blog.csdn.net/chris_lee_hehe/article/details/78611911
https://blog.csdn.net/shine19930820/article/details/53995369
https://blog.csdn.net/cjsyr6wt/article/details/78200444?locationNum=11&fps=1
https://blog.csdn.net/weixin_38168620/article/details/80659154