天池O2O新人赛

在实验室大腿的帮助下,成功参加了天池的新人赛

步骤

参考《100行代码入门天池O2O优惠券使用新人赛》,比赛步骤如下:

  • 赛题介绍:本赛题目标是预测投放的优惠券是否核销。
  • 数据分析: 其中包含一些常见的数据处理,比如str to numeric。
  • 特征工程: 主要是简单的提取了折扣相关信息和时间信息。
  • 模型建立: 简单的线性模型。

Step1:赛题介绍

本次赛题为《生活大实惠:O2O优惠券使用预测》,个性化投放是提高优惠券核销率的重要技术,它可以让具有一定偏好的消费者得到真正的实惠,同时赋予商家更强的营销能力。本次大赛为参赛选手提供了O2O场景相关的丰富数据,希望参赛选手通过分析建模,精准预测用户是否会在规定时间内使用相应优惠券。

这个题目告诉我们O2O优惠劵需要准确被投放到具有相应偏好消费者手里。需要做到的是精准预测用户的使用行为。

Step2:数据说明及评价分析

数据

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

评价方式

本赛题目标是预测投放的优惠券是否核销。针对此任务及一些相关背景知识,使用优惠券核销预测的平均AUC(ROC曲线下面积)作为评价标准。 即对每个优惠券coupon_id单独计算核销预测的AUC值,再对所有优惠券的AUC值求平均作为最终的评价标准。

AUC是一个模型评价指标,用于二分类模型的评价。AUC值是一个概率值,随机挑选一个正样本以及一个负样本,当前的分类算法根据计算得到的Score值将这个正样本排在负样本前面的概率就是AUC值。读起来有些绕,其实就是说AUC值越大,正样本排在负样本前面的可能越大,即越有可能预测正确(更好的分类)。

Step3:特征工程

赛题给了4部分数据,分别是线上优惠劵使用预测样本,线下优惠劵使用预测样本,用户线下优惠劵待预测集和提交样例。因为是才开始,所以只选用了线下样本和线下待预测集。

1
2
train = pd.read_csv('ccf_offline_stage1_train.csv')
test = pd.read_csv('ccf_offline_stage1_test_revised.csv')

样本划分和数据清洗

首先分析数据Date项特征,对样本进行打标。根据15内领取优惠券并购买相应商品标记为1,领取未消费标记为0,剩余标记为-1.打标完成后,清洗掉所有-1项。

1
2
3
4
5
6
7
8
9
def get_label(data):
if pd.isnull(data.Date) == True and pd.isnull(data.Coupon_id) !=True:
return 0
elif pd.isnull(data.Date) != True and pd.isnull(data.Coupon_id) !=True:
if (datetime.datetime.strptime(str(int(data.Date)),"%Y%m%d") - datetime.datetime.strptime(str(int(data.Date_received)),"%Y%m%d")).days <= 15:
return 1
else:
return 0
return -1

折扣特征

然后开始对折扣特征Discount_rate进行分析,将折扣分为直接打折和满减两种打标,同时计算折扣率,添加满值和减值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#type 1满减  0打折
def get_discount_type(row):
if pd.isnull(row):
return np.nan
elif ':' in row:
return 1
else:
return 0

def convert_rate(row):
if pd.isnull(row):
return 1.0
elif ':' in row:
rows = row.split(':')
return 1.0 - float(rows[1])/float(rows[0])
else:
return float(row)

def get_discount_man(row):
if ':' in row:
return int(row.split(':')[0])
else:
return 0

def get_discount_jian(row):
if ':' in row:
return int(row.split(':')[1])
else:
return 0

周末日期特征

分析周末特征,即领取优惠券周几,是否为周末做标签。将领取优惠券日期转换为独热码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def get_weekday(row):
if row == 'nan':
return np.nan
else:
return date(int(row[0:4]), int(row[4:6]), int(row[6:8])).weekday() + 1

train_new_process['weekday'] = train_new_process['Date_received'].astype(str).apply(get_weekday)
#weekday_type 周末为1 其他为0
train_new_process['weekday_type'] = train_new_process['weekday'].apply(lambda x: 1 if x in [6,7] else 0)

#领取日期转换 独热码
weekdaycols = ['weekday_' + str(i) for i in range(1,8)]
temp = pd.get_dummies(train_new_process['weekday'].replace('nan',np.nan))
temp.columns = weekdaycols
train_new_process[weekdaycols] = temp

Step4:模型建立

将数据按日期划分,5月16日以前作为训练集,5月16至6月16之间作为验证集。训练特征分别为折扣率,打折类型,满减价格,距离,领取日期,是否周末。模型使用随机梯度下降的线性分类器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#特征
original_feature = ['rate','type','man','jian','distance','weekday','weekday_type'] + weekdaycols
print('----------train-----------')
model = SGDClassifier(
loss='log',
penalty='elasticnet',
fit_intercept=True,
max_iter=100,
shuffle=True,
alpha = 0.01,
l1_ratio = 0.01,
n_jobs=1,
class_weight=None
)
model.fit(train_set[original_feature],train_set['label'])

训练完成之后将模型放入测试集进行分类预测。

1
2
3
4
5
6
7
print('----predict-----')
#TODO 修改训练集格式,输出
test_predict = model.predict_proba(test_new[original_feature])
test_pre_new = test_new[['User_id','Coupon_id','Date_received']].copy()
test_pre_new['label'] = test_predict[:,1]
test_pre_new.to_csv('submit1.csv', index=False, header=False)
test_pre_new.head()

当然,由于特征选取较少,提取比较粗糙。通过AUC评价得分并不会太高。

总结

作为初次踏入数据分析的项目中,参考别人项目完整走完一次数据分析实战流程,让我感受颇多。使用python进行数据处理,还有很长的路等我学习。