一、前言

近期学习了一下天池中o2o优惠券使用预测的学习赛,主要任务是通过分析建模,精准预测用户是否会在规定时间内使用相应优惠券。这次的参与主要是学习为主,牛刀小试。

二、解决方案

  • 数据分析:对于给定的数据集进行分析处理。
  • 特征工程:挖掘出更具代表性的特征。
  • 模型建立:使用随机梯度下降法进行建模(SGDClassifier)

三、功能实现

1、导入相关的库

#导入常规用的库
import numpy as np
import pandas as pd
from datetime import date  #日期
#数据集划分相关库
from sklearn.model_selection import KFold, train_test_split,StratifiedKFold, cross_val_score,GridSearchCV
#管道输入函数,自定义模型
from sklearn.pipeline import Pipeline
#SGD随机梯度下降分类器以及逻辑回归
from sklearn.linear_model import SGDClassifier, LogisticRegression
#数据预处理库,归一化处理
from sklearn.preprocessing import StandardScaler
#评价指标
from sklearn.metrics import log_loss, roc_auc_score, auc, roc_curve
from sklearn.preprocessing import MinMaxScaler
%matplotlib inline
%config InlineBackend.figure_format = 'retina'  #高清图嵌入

2、导入数据集并观察分析

dfoff = pd.read_csv(r'E:\天池020优惠券使用预测\Code\data\ccf_offline_stage1_train.csv',keep_default_na=False).iloc[:,0:7]
dfon = pd.read_csv(r'E:\天池020优惠券使用预测\Code\data\ccf_online_stage1_train.csv',keep_default_na=False)
dftest = pd.read_csv(r'E:\天池020优惠券使用预测\Code\data\ccf_offline_stage1_test_revised.csv',keep_default_na=False

观察dfoff的前五行,查看数据集情况。

分析结论:

print('有优惠券,购买商品: %d'% dfoff.loc[(dfoff['Date_received']!='null')&(dfoff['Date']!='null')].shape[0])
print('有优惠券,未购买商品: %d'% dfoff.loc[(dfoff['Date_received']!='null')&(dfoff['Date']=='null')].shape[0])
print('无优惠券,购买商品: %d'% dfoff.loc[(dfoff['Date_received']=='null')&(dfoff['Date']!='null')].shape[0])
print('无优惠券,未购买商品: %d'% dfoff.loc[(dfoff['Date_received']=='null')&(dfoff['Date']=='null')].shape[0])


可以看出无优惠券但是也购买的商品的客户还是很多的,为了更加精准的把优惠券发放到会购买商品的客户手里,我们需要建立预测模型进行预测。

3、打折率(Discount_rate)特征处理
从上述显示的数据集来看,除了ID外先看第一个有用的特征,打折率,我们都知道如果商品打折得多购买的欲望就更强,因此我们应该好好分析一下打折率。
首先对打折率这个特征的值进行统计观察:

dfoff['Discount_rate'].unique()


发现打折率的值主要分为以下4中情况:
(1)没有打折,null值
(2)0~1范围,表示直接打折
(3)满多少减多少
(4)干扰值
我们可以先把干扰值所在处的样本去除,干扰值为’2418’和’7751’

#除去干扰值所在样本
dfoff = dfoff[(dfoff['Discount_rate']!='2418') & (dfoff['Discount_rate']!='7751') ]
dfoff['Discount_rate'].value_counts()

数据预处理完都,对打折率特征进行分析处理:

#区分打折函数,没打折返回null,满减返回1,直接打折返回0
def getDiscountType(row):if row == 'null':return 'null'elif ':' in row:return 1else:return 0#折扣率转化,没打折的原价返回1,满减的计算出打折率返回,直接打折的返回原值
def convertRate(row):if row == 'null':return 1.0elif ':' in row:rows = row.split(':')return 1.0 - float(rows[1])/float(rows[0])else:return row#满多少特征提取
def getDiscountMan(row):if ':' in row:rows = row.split(':')return rows[0]else:return 0#减多少特征提取
def getDiscountJian(row):if ':' in row:rows = row.split(':')return rows[1]else:return 0#数据预处理,调用以上函数,进行封装
def processData(df):df['discount_type'] = df['Discount_rate'].apply(getDiscountType)df['discount_rate'] = df['Discount_rate'].apply(convertRate)df['discount_man'] = df['Discount_rate'].apply(getDiscountMan)df['discount_jian'] = df['Discount_rate'].apply(getDiscountJian)return df

以上打折函数编写完毕后,输入要分析处理的数据集进行打折率特征处理:

dfoff = processData(dfoff)
dftest = processData(dftest)
dfoff.head()


4、距离(Distance)特征处理

#观察Distance的类型
dfoff['Distance'].unique()


对空值进行处理,把空值转换为-1

dfoff['Distance'] = dfoff['Distance'].replace('null', -1).astype(int)
dftest['Distance'] = dftest['Distance'].replace('null', -1).astype(int)

5、领券日期(Date_received)

dfoff['Date_received'].unique()


对领券日期进行类型划分以及独热编码处理:

  • weekday : {null, 1, 2, 3, 4, 5, 6, 7}

  • weekday_type : {1, 0}(周六和周日为1,其他为0)

  • Weekday_1 : {1, 0, 0, 0, 0, 0, 0}

  • Weekday_2 : {0, 1, 0, 0, 0, 0, 0}

  • Weekday_3 : {0, 0, 1, 0, 0, 0, 0}

  • Weekday_4 : {0, 0, 0, 1, 0, 0, 0}

  • Weekday_5 : {0, 0, 0, 0, 1, 0, 0}

  • Weekday_6 : {0, 0, 0, 0, 0, 1, 0}

  • Weekday_7 : {0, 0, 0, 0, 0, 0, 1}

(1)提取星期特征

def getWeekday(row):if row == 'null':return rowelse:return date(int(row[0:4]),int(row[4:6]),int(row[6:8])).weekday() + 1dfoff['weekday'] = dfoff['Date_received'].astype(str).apply( getWeekday)
dftest['weekday'] = dftest['Date_received'].astype(str).apply( getWeekday)
dfoff.head()


(2)日期类型特征提取

#日期类型,周末返回1,工作日返回0
dfoff['weekday_type'] = dfoff['weekday'].apply(lambda x: 1 if x in [6,7] else 0)
dftest['weekday_type'] = dftest['weekday'].apply(lambda x: 1 if x in [6,7] else 0)
#回复索引
dfoff.index = range(dfoff.shape[0])
dftest.index = range(dftest.shape[0])

(3)把星期特征进行独热编码

weekdaycols = ['weekday_' + str(i) for i in range(1,8)]
tmpdf = pd.get_dummies(dfoff['weekday'].replace('null', np.nan))
tmpdf.columns = weekdaycols
dfoff[weekdaycols] = tmpdf
tmpdf = pd.get_dummies(dftest['weekday'].replace('null', np.nan))
tmpdf.columns = weekdaycols
dftest[weekdaycols] = tmpdf

6、标签提取

标签主要分为三种情况:

  • Date_received == ‘null’:表示没有领到优惠券,无需考虑,y = -1

  • (Date_received != ‘null’) & (Date != ‘null’) & (Date - Date_received <= 15):表示领取优惠券且在15天内使用,即正样本,y = 1

  • (Date_received != ‘null’) & ((Date == ‘null’) | (Date - Date_received > 15)):表示领取优惠券未在在15天内使用,即负样本,y = 0

pd.options.display.max_columns = None    #解除列限制
#定义标签备注函数
def label(row):if row['Date_received'] == 'null':return -1elif row['Date'] != 'null':td = pd.to_datetime(row['Date'],format='%Y%m%d') - pd.to_datetime(row['Date_received'],format='%Y%m%d')if td <= pd.Timedelta(15,'D'):return 1return 0
dfoff['label'] = dfoff.apply(label, axis=1)

7、建立线性模型 SGDClassifier

使用上面提取的14个特征,进行模型建立。

  • 训练集:20160101-20160515;验证集:20160516-20160615。

  • 用线性模型 SGDClassifier

  • 使用上面提取的14个特征。

  • 训练集:20160101-20160515;验证集:20160516-20160615。

  • 用线性模型 SGDClassifier

(1)数据集划分

df = dfoff[dfoff['label']!=-1].copy()
train = df[df['Date_received'] < '20160516'].copy()
valid = df[df['Date_received'] >= '20160516'].copy()

(2)观察是否具有样本不平衡

#观察是否具有样本不平衡问题
train['label'].value_counts()


(3)选定需要分析的特征

original_feature = ['discount_rate','discount_type','discount_man', 'discount_jian','Distance', 'weekday_type'] + weekdaycols
original_feature


(4)模型建立

def check_model(data,predictors):classifier =lambda: SGDClassifier(loss='log'#逻辑损失,penalty='elasticnet',fit_intercept=True,max_iter=100,shuffle=True,n_jobs=1,class_weight=None)# 管道机制使得参数集在新数据集(比如测试集)上的重复使用,管道机制实现了对全部步骤的流式化封装和管理。model = Pipeline(steps=[('ss', StandardScaler()), # transformer('en', classifier())  # estimator])parameters = {'en__alpha': [ 0.001, 0.01, 0.1],'en__l1_ratio': [ 0.001, 0.01, 0.1]}# StratifiedKFold用法类似Kfold,但是他是分层采样,确保训练集,测试集中各类别样本的比例与原始数据集中相同。folder = StratifiedKFold(n_splits=3, shuffle=True)grid_search = GridSearchCV(model, parameters, cv=folder, n_jobs=-1,  # -1 means using all processorsverbose=1)grid_search = grid_search.fit(data[predictors], data['label'])return grid_search

模型训练:

predictors = original_feature
model = check_model(train, predictors)

8、验证
对验证集中每种优惠券预测的结果计算 AUC,再对所有优惠券的 AUC 求平均。计算 AUC 的时候,如果 label 只有一类,就直接跳过,因为 AUC 无法计算。

#第一列分类为0的概率,第二类分类为1的概率
y_valid_pred = model.predict_proba(valid[predictors])
y_valid_pred
```![在这里插入图片描述](https://img-blog.csdnimg.cn/20200423102953840.png)
提取正类样本
```csharp
valid1 = valid.copy()
valid1['pred_prob'] = y_valid_pred[:,1]
valid1.head()

AUC面积计算

# 以优惠券种类数进行分局,计算出每种优惠券的AUC,并最后计算所有AUC的平均值
vg = valid1.groupby(['Coupon_id'])
aucs = []
for i in vg:tmpdf = i[1] if len(tmpdf['label'].unique()) != 2:continuefpr, tpr, thresholds = roc_curve(tmpdf['label'], tmpdf['pred_prob'], pos_label=1)aucs.append(auc(fpr, tpr))
print(np.average(aucs))

9、测试
使用测试进行测试,并把结果保存为天池比赛中的结果形式

y_test_pred = model.predict_proba(dftest[predictors])
dftest1 = dftest[['User_id','Coupon_id','Date_received']].copy()
dftest1['Probability'] = y_test_pred[:,1]
dftest1.to_csv(r'E:\天池020优惠券使用预测\Code\data\submit1.csv',index=False, header=False)
dftest1.head(5)


10、导入及保存模型

import os
import pickle
if not os.path.isfile('1_model.pkl'):with open(r'E:\天池020优惠券使用预测\Code\1_model.pkl', 'wb') as f:pickle.dump(model, f)
else:with open(r'E:\天池020优惠券使用预测\Code\1_model.pkl', 'rb') as f:model = pickle.load(f)

最后,把结果文档提交到天池中,得到成绩:

四、总结

从成绩来看效果欠佳,但笔者是本着学习的心态进行参与,后续会在这个基础上尝试使用其他一些更加出色的模型比如:XGboost、随机森林等模型进行尝试。

天池o2o优惠券使用预测(入门)相关推荐

  1. 天池 O2O 优惠券使用预测思路解析与代码实战

    个人网站:redstonewill.com 前阵子因为机器学习训练营的任务安排,需要打一场 AI 比赛.然后就了解到最近热度很高且非常适合新人入门的一场比赛:天池新人实战赛o2o优惠券使用预测.今天, ...

  2. 【机器学习】天池O2O优惠券使用预测_系统性总结与心得

    Preface:上半年参加天池的O2O优惠券预测赛排名第二,同时参加了学校数据仓库老师的课程改革建设团队,于是把参赛经验总结成文,准备分享给该课程的学弟学妹.现在我把总结的参赛教程文章也发到CSDN上 ...

  3. 天池O2O优惠券使用预测

    参考文献: 题目简介: https://tianchi.aliyun.com/getStart/information.htm?raceId=231593 https://blog.csdn.net/ ...

  4. 天池比赛:o2o优惠券使用预测

    一.比赛背景 O2O:全称Online To Offline,线上线下电子商务,是把线上的消费者带到现实的商店中去:在线支付线下商品.服务,再到线下去享受服务.通过打折(例如团购).提供信息.服务(例 ...

  5. O2O优惠券使用预测项目总结

    O2O优惠券使用预测笔记 前言 项目介绍 数据 评价方式 赛题分析 基本思路 数据集划分 特征工程 模型选取 过程及代码 导入python库 导入与划分数据集 特征工程 模型训练与调参 预测测试集 总 ...

  6. Sklearn:天池新人实战赛o2o优惠券使用预测 part1

    日萌社 人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新) 阿里云官网:天池新人实战赛o2o优惠券使用预测 数据集下载链接 ...

  7. Sklearn:天池新人实战赛o2o优惠券使用预测 part2

    日萌社 人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新) 阿里云官网:天池新人实战赛o2o优惠券使用预测 数据集下载链接 ...

  8. 【天池】优惠券使用预测

    代码:mirrors / wepe / o2o-coupon-usage-forecast · GitCode blog:生活大实惠:O2O优惠券使用预测_Julyaaaa的博客-CSDN博客 比赛网 ...

  9. W12 - 999、O2O优惠券使用预测

    初学耗时:999h 注:CSDN手机端暂不支持章节内链跳转,但外链可用,更好体验还请上电脑端. 『   因为要去见那个不一般的人,所以我就不能是一般人.』  W99.阿里大学征服路 - W系列总纲   ...

最新文章

  1. docker mysql容器启动不_Mysql容器启动失败-解决方案
  2. Oracle笔记(十三) 视图、同义词、索引
  3. 修改input file默认样式
  4. 路由器上不了网?PPPoE协议了解一下
  5. time库python_Python的time库的一些简单函数以及用法
  6. Drools 7.4.1.Final参考手册(六) 用户手册
  7. Linux最常用的基础命令 下篇
  8. Ubuntu安装摄像头软件GTK_UVC_Viewer
  9. 3h精通OpenCV(二)-基本功能
  10. 为ScrollView增加圆角的三种方式,及自定义属性【在Linearlayout中新增ScrollView支持滚动 后续】...
  11. 面试:Spring Boot的优缺点
  12. 《Redis系列第五篇、hset与hget的使用|CSDN创作打卡》
  13. 个人支付免费开通支付宝付款功能(免费签约)支付宝当面付开通集成到网站教程
  14. sql server 2000 各版本的区别
  15. ns手柄pc驱动_颜值、功能、手感同步在线 北通宙斯机械游戏手柄体验
  16. 【腾讯Bugly干货分享】从0到1打造直播 App
  17. MySQL 序号(排序)函数:row_number() 、rank() 、 dense_rank()、ntile()
  18. 网购使用的计算机网络技术,浅议计算机网络技术的应用与发展
  19. 图解next和hasnext
  20. 计算机没网络本地连接接下来,电脑本地连接没有了网络连接的本地连接不见的解决方法...

热门文章

  1. 02 ABY框架的搭建及踩到的坑
  2. 数字化转型的失败原因及成功之道
  3. 人脸识别技术的简单认识(含原理)
  4. 不同平台下移植x264
  5. 批量压缩多文件-批处理(四)
  6. 最新在线客服系统源码软件代码+自动回复+管理后台
  7. java如何获取Class类对象
  8. Java获取本机ip和服务器ip
  9. 搭建react项目并配置路由
  10. 什么是LSI关键词?