数据科学在消费者分析中的应用(星巴克数据)
背景
这是我在优达学城的一个实验项目,使用的是优达学城提供的数据集,主要的目的是两个:1)通过历史数据,建立一个分类模型,用来预测针对特定消费者属性和活动特点,活动推送后,消费者会不会参与。消费者洞察是数据科学的热门领域,随着数字化的深入,数据的可获得性越来越高,将数据工程,数据科学应用到消费者洞察中,是当下企业最重要的行动之一。
数据集
这个实验提供了三个数据文件:
portfolio.json – 包括推送的 id 和每个推送的元数据(持续时间、种类等等)
profile.json – 每个顾客的人口统计数据
transcript.json – 交易、收到的推送、查看的推送和完成的推送的记录
以下是文件中每个变量的类型和解释 :
portfolio.json
id (string) – 推送的id
offer_type (string) – 推送的种类,例如 BOGO、打折(discount)、信息(informational)
difficulty (int) – 满足推送的要求所需的最少花费
reward (int) – 满足推送的要求后给与的优惠
duration (int) – 推送持续的时间,单位是天
channels (字符串列表)
profile.json
age (int) – 顾客的年龄
became_member_on (int) – 该顾客第一次注册app的时间
gender (str) – 顾客的性别(注意除了表示男性的 M 和表示女性的 F 之外,还有表示其他的 O)
id (str) – 顾客id
income (float) – 顾客的收入
transcript.json
event (str) – 记录的描述(比如交易记录、推送已收到、推送已阅)
person (str) – 顾客id
time (int) – 单位是小时,测试开始时计时。该数据从时间点 t=0 开始
value - (dict of strings) – 推送的id 或者交易的数额
基本步骤
我选择切入的一个角度是,建立一个模型,可以用来评估客户是否会对推送做出回应,哪些因子会对成功回应起关键作用。我分了三个大的步骤:
第一步:数据整理,主要是对三个文件的数据做些格式处理,对某些类别字段做独热编码,最后并合并成一个大的文件,用于数据分析和建模
第二步:数据分析,这一步主要是探索数据,做些可视化的展现,得到一些显性的结论,包括什么因素对活动推送的效果起作用
第三步:数据建模和评估,我根据Scikit Learn官方的Machine Learning Map,找出适合我们这个案例的三个分类模型,做了初步比较,然后再用网格搜索对潜力最大的一个模型进行参数遍历,验证准确率和F1分数值,最后展示因子重要程度
经过三步之后,我给出结论。
衡量指标
对于模型的衡量指标,分类模型有准确率,精确率,召回率和F1分数,比较有用的是准确率和F1分数,我会用F1分数来选择最优的模型,并根据优化后的模型给出结论。同时,根据模型,还可以对各个因子的重要性有认识和把握。我是用的数据分析环境是anaconda的Python 3.7版本,用到的建模工具是Scikit Learn库。
数据集
一共有三个数据文件:
portfolio.json – 包括推送的 id 和每个推送的元数据(持续时间、种类等等)
profile.json – 每个顾客的人口统计数据
transcript.json – 交易、收到的推送、查看的推送和完成的推送的记录
以下是文件中每个变量的类型和解释 :
portfolio.json
id (string) – 推送的id
offer_type (string) – 推送的种类,例如 BOGO、打折(discount)、信息(informational)
difficulty (int) – 满足推送的要求所需的最少花费
reward (int) – 满足推送的要求后给与的优惠
duration (int) – 推送持续的时间,单位是天
channels (字符串列表)
profile.json
age (int) – 顾客的年龄
became_member_on (int) – 该顾客第一次注册app的时间
gender (str) – 顾客的性别(注意除了表示男性的 M 和表示女性的 F 之外,还有表示其他的 O)
id (str) – 顾客id
income (float) – 顾客的收入
transcript.json
event (str) – 记录的描述(比如交易记录、推送已收到、推送已阅)
person (str) – 顾客id
time (int) – 单位是小时,测试开始时计时。该数据从时间点 t=0 开始
value - (dict of strings) – 推送的id 或者交易的数额
业务逻辑
一个活动推送给消费者,就会产生一条推送已收到记录。活动持续时间,这个持续时间是有效期,在推送接收后,有效期范围内,系统会记录浏览行为和完成动作(消费满足了活动门槛),所以一个推送的有效指标就是推送后,有效期内有浏览,并且有完成动作。对于每次推送,lookup出相关的活动信息,消费者信息,就可以运用机器学习的方法,找出这些信息,哪些是对活动效果起决定作用。这对后期活动的设置,定位消费者具有重大的指导意义。
具体过程
首先数据需要进行整理,尤其是transcript数据集,里头混杂了推送接收记录,浏览记录和完成记录,需要拆分出来,从而三个子数据集进行数据连接和匹配后,才能得到推送记录是否产生效果的判断。这一步处理,至关重要。数据集加载进来后,就可以查看数据的内容,决定后续的数据整理步骤,比如在portfolio里头,是推送活动的著信息,channels字段其实包含了多中信息,应该做成独立的标识字段(email, mobile, social)。offer_type是一个类别字段,不方便预测模型进行学习,也要做one-ho编码t处理,pandas.get_dummies,是很有用的工具。
profolio数据集,是消费者相关的主数据,数据集里头有许多年龄超过100,性别为空/“O”的,会被删除。age字段用pandas.cut函数做成几个范围(比如没20年一个年龄段)并做成one hot编码处理。gender字段也一样,也可以做one hot编码处理
transcript数据集是处理重点,实际上用event字段的值进行拆分,可以拆成四个数据集,分别代表交易,推送接收,推送浏览,推送完成。不同的数据表,原始的value值,可以提取出amount或者offer id信息。
1.2 数据整理
经过以上的分析,使用python和pandas的相关处理函数,分别将数据集处理成以下的结果:
对于portfolio数据集,留意channels和offer_type字段派生出来的字段
对于profile数据集,会员注册的年份,年龄范围,性别,都用one-hot编码的方式做成了新的字段,方便后续机器学习处理
对于transcript数据集中event为"offer received", "offer viewed", "offer complete"的记录,处理成三个独立数据集,并从value字段提取出offer id。这里time字段是从0开始的时间戳,是从0开始的小时数:
这三个表,以offer_received作为主表,连接另外两个,就可以得到对于每个接收到的推送,知否能在有效期内(有效期在offer主数据里头,单位是天)能从offer_viewed和offer_completed里头找到相应记录,且完成的时间迟于浏览的时间(有时候用户没有浏览也达到一个推送的条件,也被视为完成动作,这个需要考虑)。做法有很多,用python做一个循环,或者借用SQL用一个语句实现都可以,如:
这时候,一次推送,什么时候送达,结束的时间戳,在有效期范围内什么时间浏览,什么时间完成,是否是一次有效的活动推送,就已经有了,用一个标志位字段记住它。
第二步 数据分析
接下来,结合消费者数据集和活动数据集,可以对推送,通过各种分组汇总,进行观察,得到一些显见的结论,比如,可以对活动门槛,活动期限,消费者性别,注册年份,年龄段和收入区间进行分组,发现:1)门槛高的活动,互动成功的效果差些;2)女性比男性更容易被推送影响;3)年轻人不太关注推送的信息等等。这些信息,对未来的offer design和consumer targetting已经有很大的指导意义了。
第三步:数据建模
但有些影响因素,靠观察,容易遗漏,可以用这个数据集做个建模,我最终使用Scikit Learn随机森林模型,进行的模型优化。如何选择一个合适的模型呢?这个和问题的类别,数据集的大小等都有关系,SK-Learn有个很好的machine learning map,可供参考
根据我们手头的数据和问题的类型(60K的记录数,分类问题)从这个官方的指引中,我们可以看到,应该尝试的模型有LinearSVC,KNeighbors分类器以及继承模型里头的分类器(比如随机森林)。我的思路是:选择这三个模型,先默认参数试一下,是不是都可用,对于指标比较好的,进一步进行参数调优:
1. LinearSVC
2. KNeighbors分类器
3. 随机森林分类器
经过初步尝试,随机森林的表现较好,而且是一个比较可用的程度。进一步对参数进行调优,我又参考了官方文档。根据官方文档,这个模型,主要可用调整的参数是两个:n_estimatiors(接近一个阈值之前,越大越好),max_features(基本即使两个选项None或者sqrt),见下面的官方文档截图:
要搜索出比默认参数最优的参数,最好的工具是GridSerchCV,列出两个参数的取值范围,这个搜索机制会遍历所有可能的组合,选取出最合适的参数形成模型。但是选取最佳模型用哪个评判标准呢(scorer参数),我使用的是F1分数。对于分类模型,有几个重要的指标,说明如下:
准确率:这个指标评估一个模型在所有数据上的表现。在及其特殊的情况下,准确率高,不代表模型实用。以信用卡欺诈识别为例,信用卡欺诈本身是一个样本集里头非常少出现的情况,一个模型,只要对所有的样本都预测不是一个欺诈,就可以达到很高的准确率。但是这个模型并没有什么用。我们的数据没有那么特殊,准确率是一个的评估指标
精确率:这个指标主要衡量预测结果为1的样本,有多大的比例真实是1,这个指标对于促销类的推送有意义,因为我们希望模型帮我门找出真正感兴趣的消费者,以免对不感兴趣的消费者产生困扰,或者浪费促销成本(当然现在的成本在降低)
召回率:这个指标主要衡量样本中为1的,有多大比例被模型准确预测。在特定的场合,比如目前的疾病检测,要尽可能多的预测到正样本,哪怕有些负样本被预测为正样本,也不要紧。这个指标对我们的例子也很有用,因为获取消费者数据不容易,要从现有的消费者数据里头尽量找到合适的消费者
F Beta Score:是精确率和召回率的平衡,是综合考虑精确率和召回率的指标,以下从维基百科中下载的图片能解释这个指标的作用。将Beta值设为1(就是所谓的F1 Score),其实就能同时反映精确率和召回率的影响
在我们这个案例中,准确率重要,精确率和召回率也重要,我综合考虑,选定F1分数值来作为模型选择参数,我的代码示例如下:
经过3折交叉验证,对8个参数组合,它运行完就找出最好的参数,这个最好的参数在GridSearchCV返回的模型变量的best_params里头,可供查看。可以看到,最好的n_estimator达到了800。
最后用返回的这个模型,就可以做测试集验证,示例代码如下(模型性能嘛,比调整前稍好点了):
另外训练出来的分类模型,有个重要参数叫best_estimator_.feature_importances_,这个参数返回找到的最好的分类器的因子重要程度属性,揭示了预测因子的重要性,我通过可视化的方式展现了出来,代码示例供参考:
可见,许多我们仅仅通过数据观察可能会未必能发现其中一些重要的影响因素。比如对整个数据集而言,对推送效果影响最大的是收入(income),奖励力度(reward),推送渠道(social),有效时长(duration),活动门槛(difficulty)。我们光从数据观察,可能会被忽略。
结语
数据分析,数据工程和数据科学,在数字化浪潮中,在数据极大丰富的背景下,将在商业世界中扮演更加重要角色,发挥更加重大的指导作用。让我们一起,学好python,学好数据科学,为未来做好准备。
参考
以下是实验进行中的参考文献和链接:
【1】https://retailanalysis.igd.com/ (一个很好的网站,提供很多关于零售业数据洞察的最新进展)
【2】https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html (Scikit-Learn官方一个关于预测模型选择的实用指引)
【3】https://scikit-learn.org/stable/modules/ensemble.html#forests-of-randomized-trees (官方文档有参数调整的建议)
【4】https://www.jianshu.com/p/1afbda3a04ab (关于模型指标的解释,这里有篇很明细的文章)
【5】https://www.w3school.com.cn/sql/index.asp (这里有一个SQL语法的速查链接,我常用)
【6】https://scikit-learn.org/stable/modules/generated/sklearn.svm.LinearSVC.html#sklearn.svm.LinearSVC
【7】https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html#sklearn.neighbors.KNeighborsClassifier