2020/5/29
生活大实惠:O2O优惠券使用预测
生活大实惠:O2O优惠券使用预测
Author:陈壮博
数据分析背景
随着移动设备的完善和普及,移动互联网+各行各业进入了高速发展阶段,这其中以O2O(Online to Offline)
消费最为吸引眼球。据不完全统计,O2O行业估值上亿的创业公司至少有10家,也不乏百亿巨头的身影。
O2O行业天然关联数亿消费者,各类APP每天记录了超过百亿条用户行为和位置记录,因而成为大数据科研和
商业化运营的最佳结合点之一。 以优惠券盘活老用户或吸引新客户进店消费是O2O的一种重要营销方式。然
而随机投放的优惠券对多数用户造成无意义的干扰。对商家而言,滥发的优惠券可能降低品牌声誉,同时难以
估算营销成本。 个性化投放是提高优惠券核销率的重要技术,它可以让具有一定偏好的消费者得到真正的实
惠,同时赋予商家更强的营销能力。
数据集及模型评价
数据来源于用户在2016年1月1日至2016年6月30日之间真实线上线下消费行为,目标为预测用户在2016年7月
领取优惠券后15天以内是否核销。评测指标采用AUC,先对每个优惠券单独计算核销预测的AUC值,再对所
有优惠券的AUC值求平均作为最终的评价标准。
字段表
Table 1: 用户线下消费和优惠券领取行为
Field
User_id
Merchant_id
Coupon_id
Discount_rate
Distance
Date_received
Date
Description
用户ID
商户ID
优惠券ID:null表示无优惠券消费,此时Discount_rate和Date_received字段无意义
优惠率:x\in[0,1]代表折扣率;x:y表示满x减y。单位是元
user经常活动的地点离该merchant的最近门店距离是x* 500米(如果是连锁店,则取最近的一家门店),
x\in[0,10]:null表示无此信息,0表示低于500米,10表示大于5公里
领取优惠券日期
消费日期:如果Date=null&Coupon_id != null,该记录表示领取优惠券但没有使用,即负样本;如果
Date!=null&Coupon_id=null,则表示普通消费日期;如果Date!=null&Coupon_id != null,则表示用优惠券消费日
期,即正样本
Table 2: 用户线上点击/消费和优惠券领取行为
file:///C:/Users/1234/Favorites/Desktop/陈壮博:O2O优惠券使用预测 .html
1/72
2020/5/29
生活大实惠:O2O优惠券使用预测
Field
User_id
Merchant_id
Coupon_id
Action
Discount_rate
Date_received
Date
Description
用户ID
商户ID
优惠券ID:null表示无优惠券消费,此时Discount_rate和Date_received字段无意义
0点击,1购买,2领取优惠券
优惠率:x\in[0,1]代表折扣率;x:y表示满x减y。单位是元
领取优惠券日期
消费日期:如果Date=null&Coupon_id != null,该记录表示领取优惠券但没有使用,即负样本;如果
Date!=null&Coupon_id=null,则表示普通消费日期;如果Date!=null&Coupon_id != null,则表示用优惠券消费日
期,即正样本
Table 3:用户O2O线下优惠券使用预测样本
Field
User_id
Merchant_id
Coupon_id
Discount_rate
Distance
Date_received
Description
用户ID
商户ID
优惠券ID:null表示无优惠券消费,此时Discount_rate和Date_received字段无意义
优惠率:x\in[0,1]代表折扣率;x:y表示满x减y。单位是元
user经常活动的地点离该merchant的最近门店距离是x* 500米(如果是连锁店,则取最近的一家门店),
x\in[0,10]:null表示无此信息,0表示低于500米,10表示大于5公里
领取优惠券日期
简单查看数据
In [5]:
In [50]:
table_1_names = ["User_id","Merchant_id","Coupon_id","Discount_rate","Distance","Date_received",
"Date"]
table_2_names = ["User_id","Merchant_id","Action","Coupon_id","Discount_rate","Date_received","D
ate"]
table_3_names = ["User_id","Merchant_id","Coupon_id","Discount_rate","Distance","Date_received"]
In [58]:
data_train_1 = pd.read_csv("O2O_data/offline_train.csv",names=table_1_names)
file:///C:/Users/1234/Favorites/Desktop/陈壮博:O2O优惠券使用预测 .html
2/72
i
m
p
o
r
t
p
a
n
d
a
s
a
s
p
d
2020/5/29
In [59]:
data_train_1.head()
Out[59]:
生活大实惠:O2O优惠券使用预测
User_id Merchant_id Coupon_id Discount_rate Distance Date_received
Date
0 1439408
1 1439408
2 1439408
3 1439408
4 1439408
2632
4663
2632
2632
2632
NaN
11002.0
8591.0
1078.0
8591.0
NaN
150:20
20:1
20:1
20:1
0.0
1.0
0.0
0.0
0.0
NaN 20160217.0
20160528.0
20160217.0
20160319.0
20160613.0
NaN
NaN
NaN
NaN
In [69]:
data_train_1.shape
Out[69]:
(1754884, 7)
In [60]:
data_train_2 = pd.read_csv("O2O_data/online_train.csv",names=table_2_names)
In [61]:
data_train_2.head()
Out[61]:
User_id Merchant_id Action Coupon_id Discount_rate Date_received
Date
NaN
100017492
500:50
20160513.0
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN 20160321.0
NaN 20160618.0
NaN 20160618.0
NaN 20160618.0
0 13740231
1 13740231
2 14336199
3 14336199
4 14336199
18907
34805
18907
18907
18907
2
1
0
0
0
In [33]:
data_train_2.shape
Out[33]:
(11429825, 7)
In [76]:
data_test = pd.read_csv("O2O_data/offline_test_revised.csv",names=table_3_names)
file:///C:/Users/1234/Favorites/Desktop/陈壮博:O2O优惠券使用预测 .html
3/72
2020/5/29
生活大实惠:O2O优惠券使用预测
In [77]:
data_test.head()
Out[77]:
User_id Merchant_id Coupon_id Discount_rate Distance Date_received
0 4129537
1 6949378
2 2166529
3 2166529
4 6172162
450
1300
7113
7113
7605
9983
3429
6928
1808
6500
30:5
30:5
200:20
100:10
30:1
1.0
NaN
5.0
5.0
2.0
20160712
20160706
20160727
20160727
20160708
In [64]:
data_test.shape
Out[64]:
(113640, 6)
解决方案概述
数据集提供了用户线下消费和优惠券领取核销行为的纪录表,用户线上点击/消费和优惠券领取核销行为的纪录
表,记录的时间区间是2016.01.01至2016.06.30,需要预测的是2016年7月份用户领取优惠劵后是否核销。根据
这两份数据表,首先对数据集进行划分,然后提取了用户相关的特征、商家相关的特征,优惠劵相关的特征,
用户与商家之间的交互特征,以及利用预测数据集得到的其它特征(这部分特征在实际业务中是不可能获取到
的)。最后训练了XGBoost,LogisticRegression,RandomForest进行模型融合。
数据集划分
可以采用滑窗的方法得到多份训练数据集,窗口宽度为3.5月,步长为1月,特征区间越小,得到的训练数据集
越多。以下是一种划分方式:20160201-20160615这4.5月当训练集1,20160101-201605014这4.5月当训练
集2,20160315-20160731这4.5月当训练集3,3个训练集中取出后1个月当做验证集,前面3.5月当做真实训练
集。
测试集 20160701-20160731
20160315-20160630
训练集1
20160515-20160615
20160201-20160514
训练集2
20160414-20160514
20160101-20160413
划取多份训练集,一方面可以增加训练样本,另一方面可以做交叉验证实验,方便调参。
file:///C:/Users/1234/Favorites/Desktop/陈壮博:O2O优惠券使用预测 .html
4/72
预
测
区
间
(
提
取
l
a
b
e
l
)
特
征
区
间
(
提
取
f
e
a
t
u
r
e
)
2020/5/29
特征工程
生活大实惠:O2O优惠券使用预测
数据包含online和offline两份数据集,online数据集可以提取到与用户相关的特征,offline数据集可以提取到更
加丰富的特征:用户相关的特征,商家相关的特征,优惠劵相关的特征,用户-商家交互特征。
另外需要指出的是,预测集中,包含了同一个用户在整个7月份里的优惠券领取情况,这实际上是一种
leakage,比如存在这种情况:某一个用户在7月10日领取了某优惠券,然后在7月12日和7月15日又领取了相
同的优惠券,那么7月10日领取的优惠券被核销的可能性就很大了,我在做特征工程时也注意到了这一点,提
取了一些相关的特征。加入这部分特征后,AUC提升了10个百分点,但这些特征在实际业务中是无法获取到
的。
以下简要地说明各部分特征:
用户线下相关的特征
用户领取优惠券次数
用户获得优惠券但没有消费的次数
用户获得优惠券并核销次数
用户领取优惠券后进行核销率
用户各种类满减的优惠券核销率
用户核销各种类满减的优惠券占所有核销优惠券的比重
用户核销优惠券的平均/最低/最高消费折率
用户核销过优惠券的不同商家数量,及其占所有不同商家的比重
用户核销过的不同优惠券数量,及其占所有不同优惠券的比重
用户平均核销每个商家多少张优惠券
用户核销优惠券中的平均/最大/最小用户-商家距离
用户线上相关的特征
用户线上操作次数
用户线上点击率
用户线上购买率
用户线上领取率
用户线上不消费次数
用户线上优惠券核销次数
用户线上优惠券核销率
用户线下不消费次数占线上线下总的不消费次数的比重
用户线下的优惠券核销次数占线上线下总的优惠券核销次数的比重
用户线下领取的记录数量占总的记录数量的比重
file:///C:/Users/1234/Favorites/Desktop/陈壮博:O2O优惠券使用预测 .html
5/72
2020/5/29
生活大实惠:O2O优惠券使用预测
商家相关的特征
商家优惠券被领取次数
商家优惠券被领取后不核销次数
商家优惠券被领取后核销次数
商家优惠券被领取后核销率
商家优惠券核销的平均/最小/最大消费折率
核销商家优惠券的不同用户数量,及其占领取不同的用户比重
商家优惠券平均每个用户核销多少张
商家被核销过的不同优惠券数量
商家被核销过的不同优惠券数量占所有领取过的不同优惠券数量的比重
商家平均每种优惠券核销多少张
商家被核销优惠券的平均时间率
商家被核销优惠券中的平均/最小/最大用户-商家距离
用户-商家交互特征
用户领取商家的优惠券次数
用户领取商家的优惠券后不核销次数
用户领取商家的优惠券后核销次数
用户领取商家的优惠券后核销率
用户对每个商家的不核销次数占用户总的不核销次数的比重
用户对每个商家的优惠券核销次数占用户总的核销次数的比重
用户对每个商家的不核销次数占商家总的不核销次数的比重
用户对每个商家的优惠券核销次数占商家总的核销次数的比重
优惠券相关的特征
优惠券类型(直接优惠为0, 满减为1)
优惠券折率
满减优惠券的最低消费
历史出现次数
历史核销次数
历史核销率
历史核销时间率
领取优惠券是一周的第几天
领取优惠券是一月的第几天
历史上用户领取该优惠券次数
历史上用户消费该优惠券次数
历史上用户对该优惠券的核销率
file:///C:/Users/1234/Favorites/Desktop/陈壮博:O2O优惠券使用预测 .html
6/72
2020/5/29
生活大实惠:O2O优惠券使用预测
其它特征:这部分特征都是在预测区间提取的
用户领取的所有优惠券数目
用户领取的特定优惠券数目
用户此次之后/前领取的所有优惠券数目
用户此次之后/前领取的特定优惠券数目
用户上/下一次领取的时间间隔
用户领取特定商家的优惠券数目
用户领取的不同商家数目
用户当天领取的优惠券数目
用户当天领取的特定优惠券数目
用户领取的所有优惠券种类数目
商家被领取的优惠券数目
商家被领取的特定优惠券数目
商家被多少不同用户领取的数目
商家发行的所有优惠券种类数目
模型设计与模型融合
基于以上提取到的特征,进行模型设计与融合。
单模型
训练了XGBoost,LogisticRegression,RandomForest三种单模型,其中XGBoost表现最好(AUC
值:0.814),RandomForest次之(AUC值:0.789),LogisticRegression相比之下最差(AUC值:0.762)。
加权融合
得到了单模型的预测结果后,直接将概率预测值进行加权融合,使用0.65 XGBoost + 0.35
RandomForest,AUC值为0.816。
Stacking模型
尝试了两层的stacking模型,首先将训练集分为两部分(D1和D2),一部分用于第一层(level 1)的训
练,另一部分用于第二层(level 2)的训练。
level1 在D1上训练了1个XGBoost,1个LogisticRegression,1个RandomForest,将这些模型的预测结果
作为level2的feature,在D2上训练第二层模型。stacking模型的结果相比单模型LogisticRegression有细微
的提升,但这点提升相对于模型复杂度带来的计算代价显得微不足道。
最终模型效果
XGBoost:AUC值0.814
RandomForest:AUC值:0.789
LogisticRegression:AUC值:0.762
加权融合:AUC值为0.816
Stacking模型:AUC值为0.770
file:///C:/Users/1234/Favorites/Desktop/陈壮博:O2O优惠券使用预测 .html
7/72
2020/5/29
生活大实惠:O2O优惠券使用预测
Project CODE
In [134]:
date
In [85]:
off_train = pd.read_csv('O2O_data/offline_train.csv',header=
off_train.columns = ['user_id','merchant_id','coupon_id','discount_rate','distance','date_receiv
ed','date']
off_train.head()
)
Out[85]:
user_id merchant_id coupon_id discount_rate distance date_received
date
0 1439408
1 1439408
2 1439408
3 1439408
4 1439408
2632
4663
2632
2632
2632
NaN
11002.0
8591.0
1078.0
8591.0
NaN
150:20
20:1
20:1
20:1
0.0
1.0
0.0
0.0
0.0
NaN 20160217.0
20160528.0
20160217.0
20160319.0
20160613.0
NaN
NaN
NaN
NaN
In [96]:
len(off_train)
Out[96]:
1754884
In [93]:
off_train.dtypes
Out[93]:
user_id int64
merchant_id int64
coupon_id float64
discount_rate object
distance float64
date_received float64
date float64
dtype: object
In [107]:
off_train.date.max()
Out[107]:
20160630.0
file:///C:/Users/1234/Favorites/Desktop/陈壮博:O2O优惠券使用预测 .html
8/72
i
m
p
o
r
t
p
a
n
d
a
s
a
s
p
d
i
m
p
o
r
t
n
u
m
p
y
a
s
n
p
f
r
o
m
d
a
t
e
t
i
m
e
i
m
p
o
r
t
N
o
n
e