阿里云天池大数据竞赛——O2O优惠券使用预测(基于XGBoost)(附python Jupter代码)

赛题链接:天池新人实战赛o2o优惠券使用预测-天池大赛-阿里云天池

赛题提供用户在2016年1月1日至2016年6月30日之间真实线上线下消费行为,预测用户在2016年7月领取优惠券后15天以内的使用情况。

题中所给数据的特征较少,所以特征工程的构建是本题的重中之重,如何构建合适的特征向量?

博主认为:一方面要凭借主观经验,比如说到要预测用户优惠券使用情况,我们凭借经验也能想到其会与"用户的商家偏好","商家受欢迎程度","优惠券优惠力度","用户的优惠券偏好"等相关。举个栗子,某用户是某个商家的忠实用户,那么该用户核销该商家优惠券的可能性会更大。

那么问题来了,我们如何从数据中判断某用户是哪几个商家的忠实用户呢?

这就需要落实到具体的特征,比如用户领取特定商家优惠券总数、用户核销特定商家优惠券总数、用户在特定商家的消费次数、用户对特定商家优惠券的核销率等,至此我们将用户对特定商家的偏好这一较为抽象的特征转化为了多个具体的数据指标,这也是我们构建特征工程通常的思路;

另一方面则需要通过模型实际效果来检验不同特征的组合,既然要检验模型在不同特征组合下的效果,我们自然要划分训练集和测试集来进行检验。

博主基于wepon大神滑动窗口划分特征集和测试集的思想,在所给6个月的训练数据集上滑动一个月的“窗口”,将数据集划分为四个特征集和四个测试集,我们在特征集上提取用户、商家、优惠券、用户与商家互动四大类特征,这里划分的基本思想为:我们认为用户对商家的偏好、用户对优惠券的偏好,商家的受欢迎程度在短期内不会有很大变化,因此我们可以在特征集区间提取偏好信息,并将其用在预测集上进行预测。

weapon大神划分数据集链接:O2O-Coupon-Usage-Forecast/code at master · wepe/O2O-Coupon-Usage-Forecast · GitHub

特征集 测试集
2016年1月1日-2016年3月31日 2016年4月1日-2016年4月30日
2016年2月1日-2016年4月30日 2016年5月1日-2016年5月31日
2016年3月1日-2016年5月31日 2016年6月1日-2016年6月30日
2016年4月1日-2016年6月30日 2016年7月1日-2016年7月31日

用户线下相关特征为:

  • 用户领取优惠券次数
  • 用户获得优惠券但没有消费的次数
  • 用户获得优惠券并核销次数
  • 用户领取优惠券后进行核销率
  • 用户100-500 满减优惠券核销率及其占所有核销优惠券的比重
  • 用户5-50 满减优惠券核销率占所有核销优惠券的比重
  • 用户0.2-0.6直接折扣优惠券核销率及占所有核销优惠券的比重
  • 用户核销0.7-0.95直接折扣优惠券核销率及占所有核销优惠券的比重
  • 用户核销优惠券的平均/最低/最高消费折率
  • 用户核销过优惠券的不同商家数量,及其占所有不同商家的比重
  • 用户核销过的不同优惠券数量,及其占所有不同优惠券的比重
  • 用户平均核销每个商家多少张优惠券
  • 用户核销优惠券中的平均/最大/最小用户-商家距离

用户线上相关特征为:

  • 用户线上操作次数
  • 用户线上点击率
  • 用户线上购买率
  • 用户线上领取率
  • 用户线上不消费次数
  • 用户线上优惠券核销次数
  • 用户线上优惠券核销率

商家相关特征为:

  • 商家优惠券被领取次数
  • 商家优惠券被领取后不核销次数
  • 商家优惠券被领取后核销次数
  • 商家优惠券被领取后核销率
  • 商家优惠券核销的平均/最小/最大消费折率
  • 核销商家优惠券的不同用户数量,及其占领取不同的用户比重
  • 商家优惠券平均每个用户核销多少张
  • 商家被核销过的不同优惠券数量
  • 商家被核销过的不同优惠券数量占所有领取过的不同优惠券数量的比重
  • 商家平均每种优惠券核销多少张
  • 商家被核销优惠券的平均时间率
  • 商家被核销优惠券中的平均/最小/最大用户-商家距离

用户商家互动特征为:

  • 用户领取商家的优惠券次数
  • 用户领取商家的优惠券后不核销次数
  • 用户领取商家的优惠券后核销次数
  • 用户领取商家的优惠券后核销率
  • 用户对每个商家的不核销次数占用户总的不核销次数的比重
  • 用户对每个商家的优惠券核销次数占用户总的核销次数的比重
  • 用户对每个商家的不核销次数占商家总的不核销次数的比重
  • 用户对每个商家的优惠券核销次数占商家总的核销次数的比重

优惠券相关特征:

  • 优惠券类型(0.2-0.6直接折扣为0,0.7-0.95直接折扣为1,5-50满减为2,100-500满减为3)
  • 优惠券折率
  • 满减优惠券的最低消费
  • 历史出现次数
  • 历史核销次数
  • 历史核销率
  • 历史核销时间率
  • 领取优惠券是一周的第几天
  • 领取优惠券是否为周末
  • 领取优惠券是一月的第几天
  • 历史上用户领取该优惠券次数
  • 历史上用户消费该优惠券次数
  • 历史上用户对该优惠券的核销率

既然是数据竞赛,我们不可避免地要观察一下测试数据,看看能不能提取一些lekage特征,嘿嘿,注意lekage特征都是在预测区间提取的:

  • 用户当月领取的所有优惠券数目
  • 用户当月领取的特定优惠券数目
  • 用户此次之后/前领取的所有优惠券数目
  • 用户此次之后/前领取的特定优惠券数目
  • 用户上/下一次领取的时间间隔
  • 用户领取特定商家的优惠券数目
  • 用户领取的不同商家数目
  • 用户当天领取的优惠券数目
  • 用户当天领取的特定优惠券数目
  • 用户领取的所有优惠券种类数目
  • 商家被领取的优惠券数目
  • 商家被领取的特定优惠券数目
  • 商家被多少不同用户领取的数目
  • 商家发行的所有优惠券种类数目

注意:在处理特征数据时要十分注意对NAN值和时间数据的处理,为了方便提取时间特征,我们可以将时间数据转化为时间戳数据,这样可以直接调用datetime包中多种时间处理函数。

下面附上博主在划分数据集和提取特征时的代码:

特别需要注意的点为:博主这里的代码是以4月-6月的特征集与7月的测试集举例,对于4,5,6月的特征集最后的“用户是否15内核销”的特征,大家要记得把最后提取lekage中的#去掉,因为4,5,6月我们可以获取用户是否15天内核销的信息,这也是我们在训练和验证数据时的label,但是7月是赛题需要预测的数据,是真正的预测集,在7月这个区间我们无法获取用户是否核销的信息(如果能获取也就不用预测了,哈哈哈哈)

PS:我们在处理nan值时,尽量不要采用fillna()函数,因为其很容易造成内存溢出,采用replace()函数则可以避免这个问题。

PPS:能用pandas自身函数转化的特征,不要写循环!!!!

import pandas as pd
import numpy as np
#这里先保持Nan,后期可以将其填充为'null'
offline_train = pd.read_csv(r"D:\A天池比赛\天猫消费券预测\ccf_offline_stage1_train\ccf_offline_stage1_train.csv",header=0)
offline_test = pd.read_csv(r"D:\A天池比赛\天猫消费券预测\ccf_offline_stage1_test_revised.csv",header=0)
#使数据集3等于test集
dataset3 = offline_test
#数据集3的特征为 取 线上数据中领券和用券日期大于4月1日和小于6月30日的
feature3 = offline_train[((offline_train.Date >= 20160401)&(offline_train.Date <= 20160630))|((offline_train.Date_received>=20160315)&(offline_train.Date_received<=20160630))]


feature0 = feature3#因为要对四个数据集进行同样的特征提取步骤,本来可以写一个函数进行处理,但是博主懒得写就复制了四个文件然后修改了其中的变量。

# 从线下数据中提取用户相关特征
#对用户是否核销标记,用户是否在15内核销标记
from datetime import datetime
df = feature0.copy()
df = df.reset_index(drop=True)
df['Date_received'] = pd.to_datetime(df['Date_received'],format='%Y%m%d')#将时间格式转化为时间戳,后期便于计算时间间隔
df['Date'] = pd.to_datetime(df['Date'],format='%Y%m%d')
df['用户核销间隔'] = np.nan
for i in range(df.shape[0]):
    df['用户核销间隔'][i] = (df['Date'][i]- df['Date_received'][i]).days#时间戳格式可以直接计算两个时间戳之间的天数间隔
    if i % 50000 == 0:#数据很大,建议大家写进度条
        print('当前进度为:%.2f' % (i/df.shape[0]))
df['Date_received'].fillna('null',inplace=True)#将时间空缺值填充为'null'值,之后方便做筛选
df['Date'].fillna('null',inplace=True)
df['用户是否领取优惠券'] = np.nan
df.用户是否领取优惠券[df['Date_received'] == 'null'] = 0#未领取优惠券设为0
df.用户是否领取优惠券.fillna(1,inplace=True)#领取优惠券设为1
##标记其是否在15天核销和是否核销
df['用户是否15天内核销'] = np.nan
df['用户是否核销'] = np.nan
df.用户是否15天内核销[df['用户核销间隔']<=15] = 1
df.用户是否15天内核销.fillna(0,inplace=True)
df.用户是否核销[df['用户核销间隔']!= 'null'] = 1
df.用户是否核销.fillna(0,inplace=True)
df.用户核销间隔[df.用户核销间隔 == 'null'] = np.nan#把用户间隔转化为np.nan格式
temp1 = df.groupby('User_id')['用户是否领取优惠券'].sum().reset_index(name='用户领取优惠券总数')
temp2 = df.groupby('User_id')['用户是否15天内核销'].sum().reset_index(name='用户15天内核销优惠券总数')
temp3 = df.groupby('User_id')['用户是否核销'].sum().reset_index(name='用户核销优惠券总数')
df1 = pd.merge(df,temp1,how='left')
df1 = pd.merge(df1,temp2,how='left')
df1 = pd.merge(df1,temp3,how='left')
df1['用户总核销率'] = np.nan
df1['用户总核销率'] = df1['用户核销优惠券总数']/df1['用户领取优惠券总数']
df1['用户15天内总核销率'] = np.nan
df1['用户15天内总核销率'] = df1['用户15天内核销优惠券总数']/df1['用户领取优惠券总数']
##获取用户核销间隔特征
tempdf = df1[df1.用户是否核销==1]
temp4 = tempdf.groupby('User_id')['用户核销间隔'].sum().reset_index(name='用户核销总间隔')
temp5 = tempdf.groupby('User_id')['用户核销间隔'].min().reset_index(name='用户核销最小总间隔')
temp6 = tempdf.groupby('User_id')['用户核销间隔'].max().reset_index(name='用户核销最大总间隔')
tempdf = pd.merge(tempdf,temp4,how='left')
tempdf = pd.merge(tempdf,temp5,how='left')
tempdf = pd.merge(tempdf,temp6,how='left')
tempdf['用户核销平均间隔'] = tempdf['用户核销总间隔']/tempdf['用户核销优惠券总数']
tempdf2 = tempdf[['User_id',"用户核销总间隔","用户核销最小总间隔","用户核销最大总间隔","用户核销平均间隔"]]
tempdf2 = tempdf2.drop_duplicates(['User_id'])
tempdf2 = tempdf2.reset_index(drop=True)

df2 = pd.merge(df1,tempdf2,how='left')

### 用户核销过优惠券的商家数量及其占所有不同商家的比重,用户平均核销每个商家多少优惠券
tempdf2 = df1[df1.用户是否核销==1]
#用户核销过的商家数量
temp7 =  tempdf2.groupby(['User_id']).agg({'Merchant_id':"nunique"}).reset_index()
temp7 = temp7.rename(columns = {"Merchant_id":'用户核销过的商家总数量'})
#用户在该商家核销过的优惠券数量
Merchant_num = len(df2.Merchant_id.unique().tolist())
tempdf2['商家总数量'] = Merchant_num
tempdf2 = pd.merge(tempdf2,temp7,how='left')
tempdf2['用户核销过的商家占所有商家的比重'] = tempdf2['用户核销过的商家总数量']/tempdf2['商家总数量']
tempdf2['用户平均核销每个商家的优惠券数量'] = tempdf2['用户15天内核销优惠券总数']/tempdf2['商家总数量']
#用户核销过的不同优惠券数量,及其占不同优惠券的比重
temp8 = tempdf2.groupby(['User_id']).agg({'Coupon_id':"nunique"}).reset_index()
temp8 = temp8.rename(columns = {'Coupon_id':'用户核销过的不同优惠券数量'})
Coupon_num = len(df2.Coupon_id.unique().tolist())
tempdf2['优惠券总类数'] = Coupon_num
tempdf2 = pd.merge(tempdf2,temp8,how='left')
tempdf2['用户核销过的优惠券类数占优惠券总类数的比重'] = tempdf2['用户核销过的不同优惠券数量']/tempdf2['优惠券总类数']

tempdf3 = tempdf2[['User_id',"用户核销过的商家总数量","用户核销过的商家占所有商家的比重","用户平均核销每个商家的优惠券数量",'优惠券总类数', '用户核销过的不同优惠券数量', '用户核销过的优惠券类数占优惠券总类数的比重']]
tempdf3 = tempdf3.drop_duplicates(['User_id'])
tempdf3 = tempdf3.reset_index(drop=True)
df3 = pd.merge(df2,tempdf3,how='left')
###用户对不同类型折扣优惠券的核销情况
offline_train["Discount_rate"].fillna(0,inplace=True)#要从原始数据中取出所有的折扣类型
#offline_train.Discount_rate[offline_train.Discount_rate == 'null'] = 0
Discount_rate_class = offline_train.Discount_rate.value_counts().index.tolist()
from sklearn.preprocessing import LabelEncoder #对不同类型的优惠券进行编码
LE = LabelEncoder()
LE1 = LE.fit(Discount_rate_class)
print(LE1.classes_)
df3["Discount_rate"].fillna('0',inplace=True)
Discount_rate = df3.Discount_rate.values
Discount_rate_class_fit = LE1.transform(Discount_rate)
df3['Discount_rate_class'] = Discount_rate_class_fit

#用户对满200及以上消费券的核销总数
a0 = [0]
a200_300 = [23,24,25,26,27,28,32,33,34,35]
a10_150 = [10,11,12,13,14,15,16,17,18,19,20,21,22,29,30,31,36,37,38,39,40,41,42,43,44,45]
a折扣2_6 = [1,2,3]
a折扣7_95 = [4,5,6,7,8,9]
#df3['是否领取消费券'] = np.nan
df3['用户是否领取满减200及以上优惠券'] = np.nan
df3['用户是否领取满减10到150优惠券'] = np.nan
df3['用户是否领取直接折扣0.2到0.6优惠券'] = np.nan
df3['用户是否领取直接折扣0.7到0.95优惠券'] = np.nan
for i in range(df3.shape[0]):
    if  df3["Discount_rate_class"][i] in a200_300 and df3["Date_received"][i] != 'null':
        df3["用户是否领取满减200及以上优惠券"][i] = 1
        df3["用户是否领取满减10到150优惠券"][i] = 0
        df3["用户是否领取直接折扣0.2到0.6优惠券"][i] = 0
        df3["用户是否领取直接折扣0.7到0.95优惠券"][i] = 0
    elif df3["Discount_rate_class"][i] in a10_150 and df3["Date_received"][i] != 'null' :
        df3["用户是否领取满减200及以上优惠券"][i] = 0
        df3["用户是否领取满减10到150优惠券"][i] = 1
        df3["用户是否领取直接折扣0.2到0.6优惠券"][i] = 0
        df3["用户是否领取直接折扣0.7到0.95优惠券"][i] = 0
    elif df3["Discount_rate_class"][i] in a折扣2_6 and df3["Date_received"][i] != 'null':
        df3["用户是否领取满减200及以上优惠券"][i] = 0
        df3["用户是否领取满减10到150优惠券"][i] = 0
        df3["用户是否领取直接折扣0.2到0.6优惠券"][i] = 1
        df3["用户是否领取直接折扣0.7到0.95优惠券"][i] = 0
    elif df3["Discount_rate_class"][i] in a折扣7_95 and df3["Date_received"][i] != 'null':
        df3["用户是否领取满减200及以上优惠券"][i] = 0
        df3["用户是否领取满减10到150优惠券"][i] = 0
        df3["用户是否领取直接折扣0.2到0.6优惠券"][i] = 0
        df3["用户是否领取直接折扣0.7到0.95优惠券"][i] = 1
    if i % 50000==0:
        print('当前进度为 %.2f' % (i/df3.shape[0])) 

df3['用户是否核销满减200及以上优惠券'] = np.nan
df3['用户是否核销满减10到150优惠券'] = np.nan
df3['用户是否核销直接折扣0.2到0.6优惠券'] = np.nan
df3['用户是否核销直接折扣0.7到0.95优惠券'] = np.nan
for i in range(df3.shape[0]):
    if  df3["Discount_rate_class"][i] in a200_300 and df3["Date"][i] != 'null':
        df3['用户是否核销满减200及以上优惠券'][i] = 1
        df3['用户是否核销满减10到150优惠券'][i] = 0
        df3['用户是否核销直接折扣0.2到0.6优惠券'][i] = 0
        df3['用户是否核销直接折扣0.7到0.95优惠券'][i] = 0
    elif df3["Discount_rate_class"][i] in a10_150 and df3["Date"][i] != 'null':
        df3['用户是否核销满减200及以上优惠券'][i] = 0
        df3['用户是否核销满减10到150优惠券'][i] = 1
        df3['用户是否核销直接折扣0.2到0.6优惠券'][i] = 0
        df3['用户是否核销直接折扣0.7到0.95优惠券'][i] = 0
    elif df3["Discount_rate_class"][i] in a折扣2_6 and df3["Date"][i] != 'null':
        df3['用户是否核销满减200及以上优惠券'][i] = 0
        df3['用户是否核销满减10到150优惠券'][i] = 0
        df3['用户是否核销直接折扣0.2到0.6优惠券'][i] = 1
        df3['用户是否核销直接折扣0.7到0.95优惠券'][i] = 0
    elif df3["Discount_rate_class"][i] in a折扣7_95 and df3["Date"][i] != 'null':
        df3['用户是否核销满减200及以上优惠券'][i] = 0
        df3['用户是否核销满减10到150优惠券'][i] = 0
        df3['用户是否核销直接折扣0.2到0.6优惠券'][i] = 0
        df3['用户是否核销直接折扣0.7到0.95优惠券'][i] = 1
    if i % 50000==0:
        print('当前进度为 %.2f' % (i/df3.shape[0]))


###计算用户不同折扣水平优惠券的偏好
temp9  = df3.groupby('User_id')["用户是否领取满减200及以上优惠券"].sum().reset_index(name='用户满减200及以上优惠券领取数')
temp10  = df3.groupby('User_id')["用户是否领取满减10到150优惠券"].sum().reset_index(name='用户满减10到150优惠券领取数')
temp11  = df3.groupby('User_id')["用户是否领取直接折扣0.2到0.6优惠券"].sum().reset_index(name='用户直接折扣0.2到0.6优惠券领取数')
temp12  = df3.groupby('User_id')["用户是否领取直接折扣0.7到0.95优惠券"].sum().reset_index(name='用户直接折扣0.7到0.95优惠券领取数')
temp13  = df3.groupby('User_id')["用户是否核销满减200及以上优惠券"].sum().reset_index(name='用户满减200及以上优惠券核销数')
temp14  = df3.groupby('User_id')["用户是否核销满减10到150优惠券"].sum().reset_index(name='用户满减10到150优惠券核销数')
temp15  = df3.groupby('User_id')["用户是否核销直接折扣0.2到0.6优惠券"].sum().reset_index(name='用户直接折扣0.2到0.6优惠券核销数')
temp16  = df3.groupby('User_id')["用户是否核销直接折扣0.7到0.95优惠券"].sum().reset_index(name='用户直接折扣0.7到0.95优惠券核销数')
df4 = pd.merge(df3,temp9,how='left')
df4 = pd.merge(df4,temp10,how='left')
df4 = pd.merge(df4,temp11,how='left')
df4 = pd.merge(df4,temp12,how='left')
df4 = pd.merge(df4,temp13,how='left')
df4 = pd.merge(df4,temp14,how='left')
df4 = pd.merge(df4,temp15,how='left')
df4 = pd.merge(df4,temp16,how='left')

df4['用户满减200及以上优惠券占其总核销优惠券比重'] = np.nan
df4['用户满减10到150优惠券占其总核销优惠券比重'] = np.nan
df4['用户直接折扣0.2到0.6优惠券占其总核销优惠券比重'] = np.nan
df4['用户直接折扣0.7到0.95优惠券占其总核销优惠券比重'] = np.nan
df4['用户满减200及以上优惠券占其总核销优惠券比重'] = df4['用户满减200及以上优惠券核销数']/df4['用户核销优惠券总数']
df4['用户满减10到150优惠券占其总核销优惠券比重'] = df4['用户满减10到150优惠券核销数']/df4['用户核销优惠券总数']
df4['用户直接折扣0.2到0.6优惠券占其总核销优惠券比重'] = df4['用户直接折扣0.2到0.6优惠券核销数']/df4['用户核销优惠券总数']
df4['用户直接折扣0.7到0.95优惠券占其总核销优惠券比重'] = df4['用户直接折扣0.7到0.95优惠券核销数']/df4['用户核销优惠券总数']
df4['用户满减200及以上优惠券核销率'] = df4['用户满减200及以上优惠券核销数']/df4['用户满减200及以上优惠券领取数']
df4['用户满减10到150优惠券核销率'] = df4['用户满减10到150优惠券核销数']/df4['用户满减10到150优惠券领取数']
df4['用户直接折扣0.2到0.6优惠券核销率'] = df4['用户直接折扣0.2到0.6优惠券核销数']/df4['用户直接折扣0.2到0.6优惠券领取数']
df4['用户直接折扣0.7到0.95优惠券核销率'] = df4['用户直接折扣0.7到0.95优惠券核销数']/df4['用户直接折扣0.7到0.95优惠券领取数']

##计算用户的平均,最小,最大消费折率
umtmp1 = df4[['User_id','Discount_rate',"Discount_rate_class","用户是否核销","用户核销优惠券总数"]]
umtmp1['满减优惠券消费最低金额'] = np.nan
umtmp1['满减优惠券消费减去金额'] = np.nan
for i in range(umtmp1.shape[0]):
    try:
        umtmp1['满减优惠券消费最低金额'][i] = eval(umtmp1['Discount_rate'][i].split(':')[0])
        umtmp1['满减优惠券消费减去金额'][i] = eval(umtmp1['Discount_rate'][i].split(':')[1])
    except:
        umtmp1['满减优惠券消费最低金额'][i] = 1
        umtmp1['满减优惠券消费减去金额'][i] = umtmp1['Discount_rate'][i]
    if i % 50000 == 0:
        print('当前进度为:%.2f' % (i/umtmp1.shape[0]))
umtmp1['优惠券优惠率'] = umtmp1['满减优惠券消费减去金额']/umtmp1['满减优惠券消费最低金额']

umtmp2 = umtmp1[['满减优惠券消费最低金额','满减优惠券消费减去金额',"优惠券优惠率"]]

df4 = pd.concat([df4,umtmp2],axis=1)

umtmp11 = umtmp1.loc[umtmp1['用户是否核销']==1]
umtmp12 = umtmp11.groupby(["User_id","Discount_rate_class"])['用户是否核销'].sum().reset_index(name='用户该种类型优惠券核销数量')
umtmp12 = pd.merge(umtmp11,umtmp12)
umtmp12['该种优惠券在平均优惠率中的占比'] = (umtmp12['用户该种类型优惠券核销数量']/umtmp12['用户核销优惠券总数'])*umtmp12['优惠券优惠率']
umtmp12 = umtmp12.drop_duplicates(['User_id','Discount_rate_class'])
umtmp13 = umtmp12.groupby('User_id')['该种优惠券在平均优惠率中的占比'].sum().reset_index(name='用户核销优惠券平均优惠折率')
umtmp14 = umtmp12.groupby('User_id')['优惠券优惠率'].max().reset_index(name='用户核销优惠券最大优惠折率')
umtmp15 = umtmp12.groupby('User_id')['优惠券优惠率'].min().reset_index(name='用户核销优惠券最小优惠折率')
umtmp16 = pd.merge(umtmp13,umtmp14)
umtmp16 = pd.merge(umtmp16,umtmp15)

df5 = pd.merge(df4,umtmp16,how='left')
##用户核销时的平均距离、最小距离,最大距离
distance = df5[['User_id','用户核销优惠券总数','用户是否核销','用户是否15天内核销','Distance']]
dtmp1 = distance.loc[distance.用户是否核销 == 1]
dtmp1 = dtmp1.reset_index(drop=True)
dtemp2 = dtmp1.groupby('User_id')['Distance'].sum().reset_index(name='用户核销总距离')
dtemp3 = dtmp1.groupby('User_id')['Distance'].max().reset_index(name='用户核销最大距离')
dtemp4 = dtmp1.groupby('User_id')['Distance'].min().reset_index(name='用户核销最小距离')
dtemp5 = pd.merge(dtmp1,dtemp2,how='left')
dtemp5 = pd.merge(dtemp5,dtemp3,how='left')
dtemp5 = pd.merge(dtemp5,dtemp4,how='left')
dtemp5.drop_duplicates(['User_id'],inplace=True)
dtemp5['用户核销平均距离'] =  dtemp5['用户核销总距离']/dtemp5['用户核销优惠券总数']
df6 = pd.merge(df5,dtemp5,how='left')
df6['用户领取但未核销的优惠券总数'] = df6['用户领取优惠券总数'] - df6['用户核销优惠券总数']
df6['用户领取但未核销的优惠券比率'] = df6['用户领取但未核销的优惠券总数']/df6['用户领取优惠券总数']

User_feature = df6
User_feature.shape#这里应该是63列


User_feature.to_csv(r"D:\B8_4_6月用户相关特征.csv")

#下面提取商家相关特征
Merchant_Feature = User_feature[['Merchant_id', 'Coupon_id','User_id','Discount_rate','Discount_rate_class','优惠券优惠率', 'Distance',
       'Date_received', 'Date', '用户核销间隔', '用户是否15天内核销', '用户是否核销', '用户是否领取优惠券',
       '用户领取优惠券总数', '用户15天内核销优惠券总数', '用户核销优惠券总数']]
#商家优惠券被领取次数
Mtemp1 = Merchant_Feature.groupby('Merchant_id')['用户是否领取优惠券'].sum().reset_index(name = '商家优惠券被领取次数')
Mtemp2 = Merchant_Feature.groupby('Merchant_id')['用户是否核销'].sum().reset_index(name = '商家优惠券被核销次数')
Mtemp3 = pd.merge(Mtemp1,Mtemp2)
Mtemp3['商家优惠券核销比'] = Mtemp3['商家优惠券被核销次数']/Mtemp3['商家优惠券被领取次数']
Mtemp3['商家优惠券被领取后不核销次数'] = Mtemp3['商家优惠券被领取次数']- Mtemp3['商家优惠券被核销次数']
Merchant_Feature = pd.merge(Merchant_Feature,Mtemp3,how='left')
#计算商家优惠券核销的最小、最大、平均消费折率
Mtmp1 = Merchant_Feature[["Merchant_id",'User_id',"Discount_rate_class","优惠券优惠率","用户是否核销","用户核销优惠券总数",'商家优惠券被领取次数','商家优惠券被核销次数']]
Mtmp1 = Mtmp1.loc[Mtmp1['用户是否核销']==1]
Mtmp1 = Mtmp1.reset_index(drop=True)
Mtmp2 = Mtmp1.groupby(["Merchant_id","Discount_rate_class"])['用户是否核销'].sum().reset_index(name='商家该种类型优惠券核销数量')
Mtmp3 = pd.merge(Mtmp1,Mtmp2)
Mtmp3 ['该种优惠券在平均优惠率中的占比'] = (Mtmp3 ['商家该种类型优惠券核销数量']/Mtmp3 ['商家优惠券被核销次数'])*Mtmp3['优惠券优惠率']
Mtmp4 = Mtmp3.drop_duplicates(subset = ["Merchant_id","Discount_rate_class"],keep='first')
Mtmp5 = Mtmp4.groupby(['Merchant_id'])['该种优惠券在平均优惠率中的占比'].sum().reset_index(name='商家核销优惠券平均优惠折率')
Mtmp6 = Mtmp4.groupby('Merchant_id')['优惠券优惠率'].max().reset_index(name='商家核销优惠券最大优惠折率')
Mtmp7 = Mtmp4.groupby('Merchant_id')['优惠券优惠率'].min().reset_index(name='商家核销优惠券最小优惠折率')
Mtmp8 = pd.merge(Mtmp5,Mtmp6)
Mtmp8 = pd.merge(Mtmp8,Mtmp7 )
Mtmp9 = pd.merge(Mtmp3,Mtmp8,how='left')
Mtmp10 = Mtmp9[['Merchant_id','Discount_rate_class', '优惠券优惠率','商家该种类型优惠券核销数量','该种优惠券在平均优惠率中的占比', '商家核销优惠券平均优惠折率', '商家核销优惠券最大优惠折率', '商家核销优惠券最小优惠折率']]
Mtmp10 = Mtmp10.drop_duplicates(['Merchant_id','Discount_rate_class'])
Mtmp11 = pd.merge(Merchant_Feature,Mtmp10,how='left')
Mtmp12 = Mtmp11[['Merchant_id','User_id','Date_received']]
Mtmp12 = Mtmp12[Mtmp12["Date_received"]!='null']
#核销商家优惠券的不同用户数量,及其占领取不同的用户比重
Mtmp13 = Mtmp11.groupby('Merchant_id').agg({'User_id':"nunique"}).reset_index()
Mtmp13 = Mtmp13.rename(columns = {'User_id':'领取过商家消费券的不同用户数量'})
Mtmp14 = Mtmp11[['Merchant_id','User_id','Date']]
Mtmp14 = Mtmp14[Mtmp14["Date"]!='null']
Mtmp15 = Mtmp14.groupby('Merchant_id').agg({'User_id':"nunique"}).reset_index()
Mtmp15 = Mtmp15.rename(columns = {'User_id':'核销过商家消费券的不同用户数量'})
Mtmp16 = pd.merge(Mtmp13,Mtmp15,how='left')
Mtmp16 = pd.merge(Mtmp13,Mtmp15,how='left')
Mtmp16['商家优惠券核销不同人数占领取不同人数的比重'] = Mtmp16['核销过商家消费券的不同用户数量']/Mtmp16['领取过商家消费券的不同用户数量']
Merchant_Feature2 = pd.merge(Mtmp11,Mtmp16,how='left')
#获取不同用户总数
User_num = len(Merchant_Feature2.User_id.unique().tolist())
#获取商家优惠券平均每个用户核销张数
Merchant_Feature2['商家优惠券平均每个用户核销张数'] = Merchant_Feature2['商家优惠券被核销次数']/User_num
#商家被领取、核销过的不同优惠券数量
Mtmp17 = Merchant_Feature2[['Merchant_id','Coupon_id','Date_received']]
Mtmp18 = Merchant_Feature2[['Merchant_id','Coupon_id','Date']]
Mtmp17 = Mtmp17[Mtmp17['Date_received'] != 'null']
Mtmp19 = Mtmp17.groupby('Merchant_id').agg({'Coupon_id':'nunique'}).reset_index()
Mtmp19 = Mtmp19.rename(columns = {'Coupon_id':'商家被领取的不同优惠券数量'})
Mtmp18 = Mtmp18[Mtmp18['Date'] != 'null']
Mtmp20 = Mtmp18.groupby('Merchant_id').agg({'Coupon_id':'nunique'}).reset_index()
Mtmp20 = Mtmp20.rename(columns = {'Coupon_id':'商家被核销的不同优惠券数量'})
Mtmp21 = pd.merge(Mtmp19,Mtmp20,how='left')
Mtmp21['商家被核销过的不同优惠券数量占所有领取过的不同优惠券数量的比重'] = Mtmp21['商家被核销的不同优惠券数量']/Mtmp21['商家被领取的不同优惠券数量']
Merchant_Feature3 = pd.merge(Merchant_Feature2,Mtmp21,how='left')
Merchant_Feature3['商家平均每种优惠券被核销多少张'] = Merchant_Feature3['商家优惠券被核销次数']/Merchant_Feature3['商家被核销的不同优惠券数量']
#商家被核销优惠券的平均时间间隔
Mtmp22 = Merchant_Feature3[['Merchant_id','User_id','Date','用户核销间隔','用户是否核销','用户是否15天内核销','商家优惠券被核销次数']]
Mtmp23 = Mtmp22[Mtmp22['Date']!='null']
Mtmp24 = Mtmp23.groupby('Merchant_id')['用户核销间隔'].sum().reset_index(name='商家被核销总时间间隔')
Mtmp25 = Mtmp22[Mtmp22['用户是否15天内核销']==1]
Mtmp26 = Mtmp25.groupby('Merchant_id')['用户核销间隔'].sum().reset_index(name='商家15天内被核销总时间间隔')
Mtmp27 = pd.merge(Mtmp22,Mtmp24,how='left')
Mtmp27 = pd.merge(Mtmp27,Mtmp26,how='left')
Mtmp27['商家被核销优惠券的平均时间率'] = Mtmp27['商家被核销总时间间隔']/Mtmp27['商家优惠券被核销次数']
Mtmp27['商家15天内被核销优惠券的平均时间率'] = Mtmp27['商家15天内被核销总时间间隔']/Mtmp27['商家优惠券被核销次数']
#去掉商家相关重复数据
Mtmp27 = Mtmp27[['Merchant_id','商家被核销总时间间隔', '商家15天内被核销总时间间隔', '商家被核销优惠券的平均时间率',
       '商家15天内被核销优惠券的平均时间率']]
Mtmp27 = Mtmp27.drop_duplicates(['Merchant_id'])
Merchant_Feature4 = pd.merge(Merchant_Feature3,Mtmp27,how='left')
#商家被核销优惠券中的平均/最小/最大用户-商家距离
Mdistance =  Merchant_Feature4[['Merchant_id','Coupon_id','Discount_rate_class','Distance','Date','用户是否15天内核销']]
Mdistance = Mdistance[Mdistance['Date']!='null']
Mdistance = Mdistance.reset_index(drop=True)
Mtmp28 = Mdistance.groupby('Merchant_id')['Distance'].sum().reset_index(name='商家被核销优惠券的总距离')
Mtmp29 = Mdistance.groupby('Merchant_id')['Distance'].max().reset_index(name='商家被核销优惠券的最大距离')
Mtmp30 = Mdistance.groupby('Merchant_id')['Distance'].min().reset_index(name='商家被核销优惠券的最小距离')
Merchant_Feature5 = pd.merge(Merchant_Feature4,Mtmp28,how='left')
Merchant_Feature5 = pd.merge(Merchant_Feature5,Mtmp29,how='left')
Merchant_Feature5 = pd.merge(Merchant_Feature5,Mtmp30,how='left')
Merchant_Feature5['商家被核销优惠券的平均距离'] = Merchant_Feature5['商家被核销优惠券的总距离']/Merchant_Feature5['商家优惠券被核销次数']
Merchant_Feature5.商家被核销总时间间隔[Merchant_Feature5['商家优惠券被核销次数']== 0] = np.nan

Merchant_Feature5.shape#这里应该有41列
Merchant_Feature5.to_csv(r"D:\B8_4_6月商家相关特征.csv")

#下面提取用户商家交互特征
Utemp1 = User_feature[['User_id', 'Merchant_id','用户是否领取优惠券','用户是否15天内核销','用户领取优惠券总数', '用户15天内核销优惠券总数','用户领取但未核销的优惠券总数']]
Utemp2 = Merchant_Feature5[['商家优惠券被领取次数','商家优惠券被核销次数','商家优惠券被领取后不核销次数']]
Utemp3 = pd.concat([Utemp1,Utemp2],axis=1)
Utemp4 = Utemp3.groupby(['User_id','Merchant_id'])["用户是否领取优惠券"].sum().reset_index(name='用户领取商家的优惠券次数')
Utemp5 = Utemp3.groupby(['User_id','Merchant_id'])["用户是否15天内核销"].sum().reset_index(name='用户核销商家的优惠券次数')
Utemp6 = pd.merge(Utemp4,Utemp5)
Utemp6['用户领取商家优惠券未核销的次数'] = Utemp6['用户领取商家的优惠券次数']- Utemp6['用户核销商家的优惠券次数']
Utemp6['用户领取商家优惠券后核销率'] = Utemp6['用户核销商家的优惠券次数']/Utemp6['用户领取商家的优惠券次数']
Utemp7 = pd.merge(Utemp3,Utemp6,how='left')
Utemp7['用户对每个商家的不核销次数占用户总的不核销次数的比重'] = Utemp7['用户领取商家优惠券未核销的次数']/Utemp7['用户领取但未核销的优惠券总数']
Utemp7['用户对每个商家的优惠券核销次数占用户总的核销次数的比重'] = Utemp7['用户核销商家的优惠券次数']/Utemp7['用户15天内核销优惠券总数']
Utemp7['用户对每个商家的不核销次数占商家总的不核销次数的比重'] = Utemp7['用户领取商家优惠券未核销的次数']/Utemp7['商家优惠券被领取后不核销次数']
Utemp7['用户对每个商家的优惠券核销次数占商家总的核销次数的比重'] = Utemp7['用户核销商家的优惠券次数']/Utemp7['商家优惠券被核销次数']
User_Merchant_feature = Utemp7
User_Merchant_feature.shape#应该是18列
User_Merchant_feature.to_csv(r"D:\B8_4_6月用户商家互动特征.csv")

#下面提取优惠券相关特征
Coupon_feature = User_feature[['User_id', 'Merchant_id', 'Coupon_id','Discount_rate', 'Discount_rate_class','Date_received', 'Date', '用户是否领取优惠券','用户是否15天内核销', '用户是否核销','用户核销间隔']]
import numpy as np
#优惠券类型,将优惠券折扣类型分为4类
Coupon_feature['优惠券类型'] = np.nan
a0 = [0]
a200_300 = [23,24,25,26,27,28,32,33,34,35]
a10_150 = [10,11,12,13,14,15,16,17,18,19,20,21,22,29,30,31,36,37,38,39,40,41,42,43,44,45]
a折扣2_6 = [1,2,3]
a折扣7_95 = [4,5,6,7,8,9]
for i in range(Coupon_feature.shape[0]):
    if Coupon_feature['Discount_rate_class'][i] in a200_300:
        Coupon_feature['优惠券类型'][i]  =  1
    elif Coupon_feature['Discount_rate_class'][i] in a10_150:
        Coupon_feature['优惠券类型'][i]  =  2
    elif Coupon_feature['Discount_rate_class'][i] in a折扣2_6:
        Coupon_feature['优惠券类型'][i]  =  3
    elif Coupon_feature['Discount_rate_class'][i] in a折扣7_95:
        Coupon_feature['优惠券类型'][i]  =  4 
    if i % 50000 == 0:
        print('当前进度为:%.2f' % (i/Coupon_feature.shape[0]))
#该优惠券历史出现次数,历史核销次数,历史核销率,历史核销时间率
Ctemp1 = Coupon_feature[['Coupon_id','User_id']]
Ctemp1 = Ctemp1.groupby('Coupon_id').count().reset_index()
Ctemp1 = Ctemp1.rename(columns={'User_id':'该优惠券历史出现次数'})
Ctemp2 = Coupon_feature.groupby('Coupon_id')['用户是否15天内核销'].sum().reset_index(name='该优惠券历史核销次数')
Ctemp3 = pd.merge(Ctemp1,Ctemp2)
Ctemp3['该优惠券历史核销率'] = Ctemp3['该优惠券历史核销次数']/Ctemp3['该优惠券历史出现次数']
Coupon_feature2 = pd.merge(Coupon_feature,Ctemp3,how='left')
Coupon_feature2['Date'].fillna('null',inplace=True)
Coupon_feature2['Date_received'].fillna('null',inplace=True)
Ctemp4 = Coupon_feature2[['Coupon_id','Date',"用户核销间隔"]]
Ctemp5 = Ctemp4[Ctemp4['Date']!='null']
Ctemp6 = Ctemp5.groupby('Coupon_id')['用户核销间隔'].sum().reset_index(name='优惠券核销总时长')
Coupon_feature2 = pd.merge(Coupon_feature2,Ctemp6,how='left')
Coupon_feature2['该优惠券历史核销时间率'] = Coupon_feature2['优惠券核销总时长']/Coupon_feature2['该优惠券历史核销次数']
Ctemp7 = Coupon_feature2.groupby(['Coupon_id'])['用户是否领取优惠券'].sum().reset_index(name='历史上用户领取该优惠券次数')
Coupon_feature2 = pd.merge(Coupon_feature2,Ctemp7,how='left')
Coupon_feature2['历史上用户对该消费券的核销率'] = Coupon_feature2['该优惠券历史核销次数']/Coupon_feature2['历史上用户领取该优惠券次数']
Coupon_feature2.Date_received[Coupon_feature2.Date_received=='null'] = np.nan
Coupon_feature2['Date_received'] = pd.to_datetime(Coupon_feature2['Date_received'],format='%Y-%m-%d')
Coupon_feature2['Date_received'].fillna('null',inplace=True)
#获取优惠券领取时间为一周第几天和一个月的第几天
Coupon_feature2['优惠券领取时间为一周第几天'] = np.nan
Coupon_feature2['优惠券领取时间为一月第几天'] = np.nan
for i in range(Coupon_feature2.shape[0]):
    if Coupon_feature2['Date_received'][i] != 'null':
        Coupon_feature2['优惠券领取时间为一周第几天'][i] = Coupon_feature2['Date_received'][i].weekday()
        Coupon_feature2['优惠券领取时间为一月第几天'][i] = Coupon_feature2['Date_received'][i].day
    if i % 50000 == 0:
        print('当前进度为:%.2f' % (i/Coupon_feature2.shape[0]))
Coupon_feature2.shape#这里应该有21列
Coupon_feature2.to_csv(r"D:\A天池比赛\天猫消费券预测\B8_4_6月消费券相关特征.csv")

#下面提取用户线上特征
import pandas as pd
import numpy as np
online_train = pd.read_csv(r"D:\天猫消费券预测\ccf_online_stage1_train\ccf_online_stage1_train.csv",header=0)
online_feature2 = online_train[(online_train.Date>=20160401)&(online_train.Date<=20160631)|((online_train.Date_received>=20160401)&(online_train.Date_received<=20160631))]
online_feature0 = online_feature2

##探索用户线上点击、购买、领取操作次数
Otemp1 = online_feature0[online_feature0.Action==0]
Otemp2 = Otemp1.groupby('User_id')["Action"].count().reset_index(name = '用户点击总数')
Otemp3 = online_feature0[online_feature0.Action==1]
Otemp4 = Otemp3.groupby('User_id')["Action"].count().reset_index(name = '用户购买总数')
Otemp5 = online_feature0[online_feature0.Action==2]
Otemp6 = Otemp5.groupby('User_id')["Action"].count().reset_index(name = '用户领取总数')
online_feature0_1 = pd.merge(online_feature0,Otemp2,how='left')
online_feature0_1 = pd.merge(online_feature0_1,Otemp4,how='left')
online_feature0_1 = pd.merge(online_feature0_1,Otemp6,how='left')
Otemp7 = online_feature0_1.groupby('User_id')['Action'].count().reset_index(name='用户操作次数')
online_feature0_1 = pd.merge(online_feature0_1,Otemp7,how='left')
online_feature0_1['用户点击率'] = online_feature0_1['用户点击总数']/online_feature0_1['用户操作次数']
online_feature0_1['用户购买率'] = online_feature0_1['用户购买总数']/online_feature0_1['用户操作次数']
online_feature0_1['用户领取率'] = online_feature0_1['用户领取总数']/online_feature0_1['用户操作次数']
online_feature0_1['Date'].fillna('null',inplace=True)
online_feature0_1['Date_received'].fillna('null',inplace=True)
##用户线上领取优惠券情况
Otemp5['用户是否领取优惠券'] = Otemp5['Action']/2
Otemp8 =  Otemp5[['User_id','Merchant_id','Coupon_id','用户是否领取优惠券']]
online_feature0_1 = pd.merge(online_feature0_1,Otemp8,how='left')
online_feature0_1['用户是否领取优惠券'].fillna(0,inplace=True)
online_feature0_1['用户是否消费'] = np.nan
online_feature0_1.用户是否消费[online_feature0_1['Date']!='null'] = 1
online_feature0_1['用户是否消费'].fillna(0,inplace=True)
online_feature0_1['用户是否核销'] = np.nan
online_feature0_1.用户是否核销[online_feature0_1['Date']!='null'] = 1
online_feature0_1.用户是否核销[online_feature0_1['Action']==0] = 0
online_feature0_1.用户是否核销[online_feature0_1['Action']==1] = 0
#用户线上核销次数
Otemp9 = online_feature0_1.groupby('User_id')['用户是否核销'].sum().reset_index(name='用户核销线上优惠券次数')
#用户线上领取优惠券次数
Otemp10 = online_feature0_1.groupby('User_id')['用户是否领取优惠券'].sum().reset_index(name='用户领取线上优惠券次数')
online_feature0_1 = pd.merge(online_feature0_1,Otemp9,how='left')
online_feature0_1 = pd.merge(online_feature0_1,Otemp10,how='left')
#用户线上消费次数
Otemp11 = online_feature0_1.groupby('User_id')['用户是否消费'].sum().reset_index(name='用户线上消费次数')
online_feature0_1 = pd.merge(online_feature0_1,Otemp11,how='left')
online_feature0_1['用户线上不消费次数'] = online_feature0_1['用户操作次数']-online_feature0_1['用户线上消费次数']
online_feature0_1['用户线上优惠券核销率'] = online_feature0_1['用户核销线上优惠券次数']/online_feature0_1['用户领取线上优惠券次数']

online_feature0_1.shape#这里应该是22列
online_feature0_1.to_csv(r"D:\A天池比赛\天猫消费券预测\B8_4_6月online_ueserfeature.csv")

#下面提取测试集的lekage特征
dataset0  = offline_test
dataset0['Date_received'] = pd.to_datetime(dataset0['Date_received'],format='%Y%m%d')
#dataset0['Date'] = pd.to_datetime(dataset0['Date'],format='%Y%m%d')
dataset0['Date_received'].fillna('null',inplace=True)
#dataset0['Date'].fillna('null',inplace=True)
dataset0 = dataset0.reset_index(drop=True)
dataset0['用户是否领取优惠券'] = np.nan
dataset0.用户是否领取优惠券[dataset0['Date_received'] == 'null'] = 0
dataset0.用户是否领取优惠券.fillna(1,inplace=True)
#用户领取的所有优惠券数目
Ttemp1 = dataset0.groupby("User_id")['用户是否领取优惠券'].sum().reset_index(name='用户领取的所有优惠券总数')
#用户领取的特定优惠券数目
Ttemp2 = dataset0.groupby(["User_id",'Coupon_id'])['用户是否领取优惠券'].sum().reset_index(name='用户领取的特定优惠券总数')
Ttemp3 = pd.merge(Ttemp2,Ttemp1,how='left')
Test_feature1 = pd.merge(dataset0,Ttemp3,how='left')
Test_feature1 = Test_feature1.sort_values(by=['User_id','Coupon_id','Date_received'])#按照用户id,Coupon_id,用户领取日期进行排序
Test_feature1 = Test_feature1.reset_index(drop=True)
Ttemp6 = Test_feature1.groupby(['User_id','Coupon_id'])['用户是否领取优惠券'].cumsum().reset_index(name='用户在此之前领取特定优惠券数')
Ttemp6 = pd.DataFrame(Ttemp6.iloc[:,1])
Test_feature1 = pd.concat([Test_feature1,Ttemp6],axis=1)
Test_feature1['用户在此之前领取特定优惠券数'] = Test_feature1['用户在此之前领取特定优惠券数']-1
Test_feature1['用户在此之后领取的特定优惠券总数'] = Test_feature1['用户领取的特定优惠券总数'] - Test_feature1['用户在此之前领取特定优惠券数']
Test_feature1['用户在此之后领取的特定优惠券总数'] = Test_feature1['用户在此之后领取的特定优惠券总数']-1
Test_feature1['优惠券领取时间为一月第几天'] = np.nan
for i in range(Test_feature1.shape[0]):
    if Test_feature1["Date_received"][i] != 'null':
        Test_feature1['优惠券领取时间为一月第几天'][i] = Test_feature1["Date_received"][i].day
    if i % 50000 == 0:
        print('当前进度为:%.2f' % (i/Test_feature1.shape[0]))
Test_feature1['用户上一次领取特定优惠券时间间隔'] = np.nan
Test_feature1['用户下一次领取特定优惠券时间间隔'] = np.nan
i = 0
while i < Test_feature1.shape[0]:
    #print("i:",i)
    j = Test_feature1["用户领取的特定优惠券总数"][i]
    if j > 1:
        #print("j:",j)
        for k in range(1,int(j)):
            #print('k:',k)
            #print('i+k:',i+k)
            m = int(i+k)
            #print('m:',m)
            Test_feature1["用户上一次领取特定优惠券时间间隔"][m] = Test_feature1["优惠券领取时间为一月第几天"][m]-Test_feature1["优惠券领取时间为一月第几天"][m-1]
            Test_feature1["用户下一次领取特定优惠券时间间隔"][m-1] = Test_feature1["优惠券领取时间为一月第几天"][m]-Test_feature1["优惠券领取时间为一月第几天"][m-1]
    i += j
    if i % 50000 == 0:
        print('当前进度为:%.2f' % (i/(Test_feature1.shape[0])))
Test_feature1['优惠券领取时间为一周第几天'] = np.nan
for i in range(Test_feature1.shape[0]):
    if Test_feature1["Date_received"][i] != 'null':
        Test_feature1['优惠券领取时间为一周第几天'][i] = Test_feature1["Date_received"][i].weekday()
    if i % 50000 == 0:
        print('当前进度为:%.2f' % (i/(Test_feature1.shape[0])))
Ttemp7 = Test_feature1.groupby(['User_id','Merchant_id'])['用户是否领取优惠券'].sum().reset_index(name='用户领取特定商家的优惠券数目')
Ttemp8 = Test_feature1[Test_feature1['Date_received']!='null']
Ttemp9 = Ttemp8.groupby(['User_id']).agg({'Merchant_id':'nunique'}).reset_index()
Ttemp9 = Ttemp9.rename(columns={'Merchant_id':'用户领取的不同商家数目'})
Ttemp10 = pd.merge(Ttemp7,Ttemp9,how = 'left')
Test_feature2 = pd.merge(Test_feature1,Ttemp10,how='left')
##用户当天领取的优惠券总数、用户当天领取的特定优惠券数目、用户领取的所有优惠券种类数目
Ttemp10 = Test_feature2.groupby(['User_id',"优惠券领取时间为一月第几天"])["用户是否领取优惠券"].sum().reset_index(name='用户当天领取的优惠券总数')
Ttemp11 = Test_feature2.groupby(['User_id','Coupon_id',"优惠券领取时间为一月第几天"])["用户是否领取优惠券"].sum().reset_index(name='用户当天领取的特定优惠券数目')
Ttemp13 = pd.merge(Ttemp11,Ttemp10,how='left')
Ttemp12 = Test_feature2.groupby(['User_id']).agg({"Coupon_id":"nunique"}).reset_index()
Ttemp12 = Ttemp12.rename(columns={"Coupon_id":'用户领取的所有优惠券种类数目'})
Ttemp14 = pd.merge(Ttemp13,Ttemp12,how='left')
Test_feature3 = pd.merge(Test_feature2,Ttemp14,how='left')

##商家被领取的优惠券数目、商家被领取的特定优惠券数目、商家被多少不同用户领取的数目、商家发行的所有优惠券种类数目
Temp15 = Test_feature3.groupby('Merchant_id')["用户是否领取优惠券"].sum().reset_index(name='商家被领取优惠券总数')
Temp16 = Test_feature3.groupby(['Merchant_id','Coupon_id'])["用户是否领取优惠券"].sum().reset_index(name='商家被领取特定优惠券总数')
Temp17 = Test_feature3.groupby(['Merchant_id']).agg({"User_id":"nunique"}).reset_index()
Temp17 = Temp17.rename(columns = {"User_id":"商家被多少不同用户领取的数目"})
Temp18 = Test_feature3.groupby(['Merchant_id']).agg({"Coupon_id":lambda x:x.nunique()}).reset_index()
Temp18 = Temp18.rename(columns ={"Coupon_id":'商家发行的所有优惠券种类数目'})
Temp19 = pd.merge(Temp16,Temp15,how='left')
Temp19 = pd.merge(Temp19,Temp17,how='left')
Temp19 = pd.merge(Temp19,Temp18,how='left')
Test_feature4 = pd.merge(Test_feature3,Temp19,how='left')
Temp20 = Test_feature4[['Coupon_id','Discount_rate']]
Temp20['满减优惠券消费最低金额']  = np.nan
Temp20['满减优惠券消费减去金额'] = np.nan
for i in range(Temp20.shape[0]):
    try:
        Temp20['满减优惠券消费最低金额'][i] = eval(Temp20['Discount_rate'][i].split(':')[0])
        Temp20['满减优惠券消费减去金额'][i] = eval(Temp20['Discount_rate'][i].split(':')[1])
    except:
        Temp20['满减优惠券消费最低金额'][i] = 1
        Temp20['满减优惠券消费减去金额'][i] = Temp20['Discount_rate'][i]
    if i % 50000 == 0:
        print('当前进度为:%.2f' % (i/Temp20.shape[0]))
Temp20['优惠券优惠率'] = Temp20['满减优惠券消费减去金额']/Temp20['满减优惠券消费最低金额']
Temp20 = Temp20[['满减优惠券消费最低金额','满减优惠券消费减去金额','优惠券优惠率']]
Test_feature5 = pd.concat([Test_feature4,Temp20],axis=1)
Test_feature5.shape #这里应该是28列,去掉Date列为27列

Discount_rate_class = offline_train.Discount_rate.value_counts().index.tolist()

Test_feature5.Date_received[Test_feature5['Date_received'] == 'null'] = np.nan
#Test_feature5.Date[Test_feature5['Date'] == 'null'] = np.nan
Test_feature5['Date_received'] = pd.to_datetime(Test_feature5['Date_received'],format='%Y-%m-%d')#将时间格式转化为时间戳,后期便于计算时间间隔
#Test_feature5['Date'] = pd.to_datetime(Test_feature5['Date'],format='%Y-%m-%d')
#Test_feature5 ['用户核销间隔'] = np.nan
#for i in range(Test_feature5.shape[0]):
#    Test_feature5['用户核销间隔'][i] = (Test_feature5['Date'][i]- Test_feature5['Date_received'][i]).days#时间戳格式可以直接计算两个时间戳之间的天数间隔
#    if i % 50000 == 0:#数据很大,建议大家写进度条
#        print('当前进度为:%.2f' % (i/Test_feature5.shape[0]))
##标记其是否在15天内核销
#Test_feature5['用户是否15天内核销'] = np.nan
#Test_feature5.用户是否15天内核销[Test_feature5['用户核销间隔']<=15] = 1
#Test_feature5['用户是否15天内核销'].fillna(0,inplace=True)
#Test_feature5['Discount_rate_class'] = np.nan
###用户对不同类型折扣优惠券的核销情况
#offline_train = pd.read_csv(r"D:\A天池比赛\天猫消费券预测\ccf_offline_stage1_train\ccf_offline_stage1_train.csv",header=0)
#offline_train["Discount_rate"].fillna(0,inplace=True)#要从原始数据中取出所有的折扣类型
#offline_train.Discount_rate[offline_train.Discount_rate == 'null'] = 0

Discount_rate_class = [0,'30:5','100:10','200:20','20:5','20:1','50:5','100:30','200:30',
 '300:30','50:10','10:5','0.95','10:1','30:1','150:20','100:20','30:10','50:20','0.9','200:50',
 '150:10','100:5','0.8','50:1','5:1','100:50','150:30','0.85','200:10','100:1','20:10','150:50',
 '300:50','0.5','0.75','0.2','0.6','200:5','300:20','0.7','30:20','300:10','200:100','50:30',
 '150:5','500:30']
from sklearn.preprocessing import LabelEncoder #对不同类型的优惠券进行编码
LE = LabelEncoder()
LE1 = LE.fit(Discount_rate_class)
print(LE1.classes_)
Test_feature5["Discount_rate"].fillna('0',inplace=True)
Discount_rate = Test_feature5.Discount_rate.values
Discount_rate_class_fit = LE1.transform(Discount_rate)
Test_feature5['Discount_rate_class'] = Discount_rate_class_fit
Test_feature5['优惠券类型'] = np.nan
a0 = [0]
a200_300 = [23,24,25,26,27,28,32,33,34,35,46]
a10_150 = [10,11,12,13,14,15,16,17,18,19,20,21,22,29,30,31,36,37,38,39,40,41,42,43,44,45]
a折扣2_6 = [1,2,3]
a折扣7_95 = [4,5,6,7,8,9]
for i in range(Test_feature5.shape[0]):
    if Test_feature5['Discount_rate_class'][i] in a200_300:
        Test_feature5['优惠券类型'][i]  =  1
    elif Test_feature5['Discount_rate_class'][i] in a10_150:
        Test_feature5['优惠券类型'][i]  =  2
    elif Test_feature5['Discount_rate_class'][i] in a折扣2_6:
        Test_feature5['优惠券类型'][i]  =  3
    elif Test_feature5['Discount_rate_class'][i] in a折扣7_95:
        Test_feature5['优惠券类型'][i]  =  4 
    if i % 50000 == 0:
        print('当前进度为:%.2f' % (i/Test_feature5.shape[0]))

Test_feature5.to_csv(r"D:\B8_7月leakage特征.csv")


对四个特征集和测试集分别提取完特征之后,我们就要开始做预测了,模型自然就是著名的XGBoost了。

首先我们需要把从特征集提取到的用户、商家、优惠券、用户商家互动特征顺延到预测集上,接下来就需要利用预测集去训练XGBoost模型,并寻找最优参数,此时我们滑动窗口划分出来的特征集和预测集的特征就可以发挥作用去筛选特征组合和调整模型参数了。

XGBoost调参可以参考这篇帖子偶:机器学习系列(12)_XGBoost参数调优完全指南(附Python代码)_寒小阳的博客-CSDN博客_xgboost参数

#用户线下相关特征
user_faeture35 = pd.read_csv(r"D:\B7_3_5月用户相关特征.csv")
user_faeture35 = pd.DataFrame(user_faeture35.iloc[:,1:])
user_faeture35_choose = user_faeture35[['User_id', '用户领取优惠券总数', '用户15天内核销优惠券总数', '用户核销优惠券总数', '用户总核销率', '用户15天内总核销率',
       '用户核销总间隔', '用户核销最小总间隔', '用户核销最大总间隔', '用户核销平均间隔', '用户核销过的商家总数量',
       '用户核销过的商家占所有商家的比重', '用户平均核销每个商家的优惠券数量','用户核销过的不同优惠券数量',
       '用户核销过的优惠券类数占优惠券总类数的比重', '用户满减200及以上优惠券领取数', '用户满减10到150优惠券领取数',
       '用户直接折扣0.2到0.6优惠券领取数', '用户直接折扣0.7到0.95优惠券领取数', '用户满减200及以上优惠券核销数',
       '用户满减10到150优惠券核销数', '用户直接折扣0.2到0.6优惠券核销数', '用户直接折扣0.7到0.95优惠券核销数',
       '用户满减200及以上优惠券占其总核销优惠券比重', '用户满减10到150优惠券占其总核销优惠券比重',
       '用户直接折扣0.2到0.6优惠券占其总核销优惠券比重', '用户直接折扣0.7到0.95优惠券占其总核销优惠券比重',
       '用户满减200及以上优惠券核销率', '用户满减10到150优惠券核销率', '用户直接折扣0.2到0.6优惠券核销率',
       '用户直接折扣0.7到0.95优惠券核销率','用户核销优惠券平均优惠折率', '用户核销优惠券最大优惠折率', '用户核销优惠券最小优惠折率', '用户核销总距离',
       '用户核销最大距离', '用户核销最小距离', '用户核销平均距离', '用户领取但未核销的优惠券总数', '用户领取但未核销的优惠券比率']]
user_faeture35_choose = user_faeture35_choose.drop_duplicates(['User_id'])

#用户线上特征
ONline_User_faeture35 = pd.read_csv(r"D:\B7_3_5月online_ueserfeature.csv")
ONline_User_faeture35 = pd.DataFrame(ONline_User_faeture35.iloc[:,1:])
ONline_User_faeture35_choose = ONline_User_faeture35[['User_id','用户点击总数', '用户购买总数', '用户领取总数', '用户操作次数',
       '用户点击率', '用户购买率', '用户领取率', '用户核销线上优惠券次数', '用户领取线上优惠券次数', '用户线上消费次数', '用户线上不消费次数', '用户线上优惠券核销率']]
ONline_User_faeture35_choose = ONline_User_faeture35_choose.drop_duplicates(['User_id'])

#商家线下特征
merchant_faeture35 = pd.read_csv(r"D:\B7_3_5月商家相关特征.csv")
merchant_faeture35 = pd.DataFrame(merchant_faeture35.iloc[:,1:])
merchant_faeture35_choose = merchant_faeture35[['Merchant_id','商家优惠券被领取次数', '商家优惠券被核销次数', '商家优惠券核销比',
       '商家优惠券被领取后不核销次数','商家核销优惠券平均优惠折率',
       '商家核销优惠券最大优惠折率', '商家核销优惠券最小优惠折率', '领取过商家消费券的不同用户数量', '核销过商家消费券的不同用户数量',
       '商家优惠券核销不同人数占领取不同人数的比重', '商家优惠券平均每个用户核销张数', '商家被领取的不同优惠券数量',
       '商家被核销的不同优惠券数量', '商家被核销过的不同优惠券数量占所有领取过的不同优惠券数量的比重', '商家平均每种优惠券被核销多少张',
       '商家被核销总时间间隔', '商家15天内被核销总时间间隔', '商家被核销优惠券的平均时间率', '商家15天内被核销优惠券的平均时间率',
       '商家被核销优惠券的总距离', '商家被核销优惠券的最大距离', '商家被核销优惠券的最小距离', '商家被核销优惠券的平均距离' ]]
merchant_faeture35_choose = merchant_faeture35_choose.drop_duplicates(['Merchant_id'])

#商家优惠券特征
merchantCoupon_faeture35_choose = merchant_faeture35[['Merchant_id', 'Coupon_id', '商家该种类型优惠券核销数量']]
merchantCoupon_faeture35_choose = merchantCoupon_faeture35_choose.drop_duplicates(['Merchant_id', 'Coupon_id'])

#用户商家线下互动特征
userMerchant_faeture35 = pd.read_csv(r"D:\B7_3_5月用户商家互动特征.csv")
userMerchant_faeture35 = pd.DataFrame(userMerchant_faeture35.iloc[:,1:])
userMerchant_faeture35_choose = userMerchant_faeture35[['User_id', 'Merchant_id','用户领取商家的优惠券次数', '用户核销商家的优惠券次数', '用户领取商家优惠券未核销的次数',
       '用户领取商家优惠券后核销率', '用户对每个商家的不核销次数占用户总的不核销次数的比重',
       '用户对每个商家的优惠券核销次数占用户总的核销次数的比重', '用户对每个商家的不核销次数占商家总的不核销次数的比重',
       '用户对每个商家的优惠券核销次数占商家总的核销次数的比重']]
userMerchant_faeture35_choose = userMerchant_faeture35_choose.drop_duplicates(['User_id', 'Merchant_id'])

#优惠券线下特征
Coupon_faeture35 = pd.read_csv(r"D:\B7_3_5月消费券相关特征.csv")
Coupon_faeture35 = pd.DataFrame(Coupon_faeture35.iloc[:,1:])
Coupon_faeture35_choose = Coupon_faeture35[['Coupon_id','该优惠券历史出现次数', '该优惠券历史核销次数',
       '该优惠券历史核销率', '优惠券核销总时长', '该优惠券历史核销时间率', '历史上用户领取该优惠券次数',
       '历史上用户对该消费券的核销率']]
Coupon_faeture35_choose = Coupon_faeture35_choose.drop_duplicates(['Coupon_id'])

#leakage特征
test6 = pd.read_csv(r"D:\B7_6月leakage特征.csv")
test6 = pd.DataFrame(test6.iloc[:,1:])
test6.rename(columns={'用户是否15天内核销':'label'},inplace=True)

#X6代表为预测6月提取的3-5月特征
X6 = test6.drop(["Discount_rate","Date_received","Date","用户核销间隔",'用户是否领取优惠券'],axis=1)
X61 = pd.merge(X6,user_faeture35_choose,how='left')
X62 = pd.merge(X61,ONline_User_faeture35_choose,how='left')
X62 = pd.merge(X62,merchant_faeture35_choose,how='left')
X62 = pd.merge(X62,merchantCoupon_faeture35_choose,how='left')
X62 = pd.merge(X62,userMerchant_faeture35_choose,how='left')
X62 = pd.merge(X62,Coupon_faeture35_choose,how='left')
X62.to_csv(r"D:\B9_6月训练数据(含label).csv")
dataset1 = X4
dataset2 = X5
dataset3 = X6
dataset4 = X7
dataset12 = pd.concat([X4,X5],axis=0)
dataset23 = pd.concat([X5,X6],axis=0)
dataset123 = pd.concat([X4,X5,X6],axis=0)
dataset1_y = X42.label
dataset1_x = X42.drop(['label'],axis = 1)
dataset2_y = X52.label
dataset2_x = X52.drop(['label'],axis = 1)
dataset3_y = X62.label
dataset3_x = X62.drop(['label'],axis = 1)
dataset12_y = dataset12.label
dataset12_x = dataset12.drop(['label'],axis = 1)
dataset23_y = dataset23.label
dataset23_x = dataset23.drop(['label'],axis = 1)
dataset123_y = dataset123.label
dataset123_x = dataset123.drop(['label'],axis = 1)

import xgboost as xgb
from sklearn.preprocessing import MinMaxScaler


dataset1 = xgb.DMatrix(dataset1_x,label=dataset1_y)
dataset2 = xgb.DMatrix(dataset2_x,label=dataset2_y)
dataset3 = xgb.DMatrix(dataset3_x,label=dataset3_y)
dataset12 = xgb.DMatrix(dataset12_x,label=dataset12_y)
dataset23 = xgb.DMatrix(dataset23_x,label=dataset23_y)
dataset123 = xgb.DMatrix(dataset123_x,label=dataset123_y)
dataset4 = xgb.DMatrix(dataset4)

params={'booster':'gbtree',
	    'objective': 'rank:pairwise',
	    'eval_metric':'auc',
	    'gamma':0.1,
	    'min_child_weight':1.1,
	    'max_depth':5,
	    'lambda':10,
	    'subsample':0.7,
	    'colsample_bytree':0.7,
	    'colsample_bylevel':0.7,
	    'eta': 0.01,
	    'tree_method':'exact',
	    'seed':0,
	    'nthread':12
	    }
cvresult = xgb.cv(params, dataset123, num_boost_round=20000, nfold=5, metrics='auc', seed=0, callbacks=[
            xgb.callback.print_evaluation(show_stdv=False),
            xgb.callback.early_stop(50)
        ])
num_round_best = cvresult.shape[0] - 1
print('Best round num: ', num_round_best)


watchlist = [(dataset123,'train')]
model_final = xgb.train(params,dataset123,num_boost_round=5000,evals=watchlist)

#性能评价函数
from sklearn.metrics import roc_curve
from sklearn.metrics import auc
def myauc(test):
    testgroup = test.groupby(['Coupon_id'])
    aucs = []
    for i in testgroup:
        tmpdf = i[1] 
        if len(tmpdf['label'].unique()) != 2:
            continue
        fpr, tpr, thresholds = roc_curve(tmpdf['label'], tmpdf['pred'], pos_label=1)
        aucs.append(auc(fpr,tpr))
    return np.average(aucs)
temp = X62_example[['Coupon_id','label']].copy()
X62_example_x = X62_example.drop(['label','Coupon_id'],axis = 1)
temp['pred'] = model.predict(xgb.DMatrix(X62_example_x))
temp.pred = MinMaxScaler(copy=True,feature_range=(0,1)).fit_transform(temp['pred'].values.reshape(-1,1))
print(myauc(temp))


offline_test = pd.read_csv(r"D:\ccf_offline_stage1_test_revised.csv",header=0)
dataset4_pred = offline_test[['User_id','Merchant_id','Coupon_id','Date_received']]
dataset4_pred.sort_values(by=['User_id','Merchant_id','Coupon_id'],inplace=True)
dataset4_pred = dataset4_pred[['User_id','Coupon_id','Date_received']]
dataset4_pred['label'] = model_final.predict(dataset4)
dataset4_pred.label = MinMaxScaler(copy=True,feature_range=(0,1)).fit_transform(dataset4_pred.label.values.reshape(-1,1))
dataset4_pred.sort_values(by=['Coupon_id','label'],inplace=True)
dataset4_pred.to_csv(r"D:\xgb_pred2.csv",index=None,header=None)


 

你可能感兴趣的:(python,阿里云,大数据)