干货 | 携程酒店浏览客户流失概率预测
陈无忌,就读于中国科学技术大学计算机学院,15 级硕士研究生。研究方向机器学习、大数据、智能交通等。在校期间多次参加大数据竞赛,在携程云海平台比赛中,两次和队伍一起获得第一名。本文来自陈无忌在“携程技术沙龙——云海机器学习Meetup”上的分享。
*视频由“IT大咖说”提供,时长约34分钟,请在WiFi环境下观看。更多视频可在大咖说平台观看*
https://v.qq.com/txp/iframe/player.html?vid=v0500kpd68w&width=500&height=375&auto=0
客户流失率是考量是业务成绩的一个非常关键的指标。根据历史数据建立模型,使用机器学习的方法预测客户流失概率,可以找出用户流失的因素,从而完善产品,减少客户流失概率。
那么,对于这样的一个问题,我们需要做哪些数据分析?特征又是如何提取?如何选择合适的机器学习模型?如何调整模型的参数?同时对于类似的这些问题,又有什么常见的套路呢?本文将基于客户流失率预测的赛题,以及个人的实战经验,对上述的问题一一做出解答。
接下来,将从以下几个方面对客户流失率预测这个问题进行阐述:首先,对现有的赛题和数据进行了一个简要的分析;然后是特征工程的介绍,着重介绍了针对现有的数据如何有效地提取特征;第三部分是模型及其原理的介绍,介绍了GBDT的原理,以及XGBoost的使用以及调参方法;第四部分介绍了常见的模型融合的方法,包括Bagging和Stacking,以及在本赛题中融合的架构;最后一部分是经验的总结,结合个人多次的参加大数据竞赛的实战经验,分享了相关经验。
问题分析
拿到一个机器学习问题,我们首先需要明白我们要解决一个什么问题。在云海竞赛平台的官方网站上给的赛题描述是非常模糊的一段话(深入了解...找到...),看完这个可能还是不明白需要干什么。没关系,继续看数据,数据如下图所示。数据上面有个label,是1表示客户最后流失了,是0的话表示最后客户没有流失。看到这里,于是明白了,这是一个分类的预测问题。
接着需要关注赛题的评价标准,对于任何比赛,评价标准一直是一个很重要的东西。评价标准即损失函数,直接决定了我们后边分类器的学习目标。对于一个分类的问题而言,最终的评价标准是准确率和召回率的一个组合,常见的就是F1值或者加权的F1值。对于这个比赛,评价标准是要求在达到97%的准确率的情况下,可以使得最后的召回率尽可能的高。这个也很好理解,和携程的业务关系密不可分。
对于客户流失概率而言,我“宁可错杀三千,也不可放过一个”。就是说,我是要尽可能地采取相关的措施,一定不能允许有客户流失的情况发生。同时,因为挽救可能流失的客户需要成本,所以我也要求尽可能高的召回率。
接下来关注的是数据的具体情况。数据的特征除了id和label以外大致可以分为三类,一种是订单本身的特征,比如订单的预定日期以及订单的入住日期等;另外一种是和用户相关的特征;还有一类特征是和酒店相关的特征,比如酒店的点评人数、酒店的星级偏好等。
同时,我们会注意到官方对于赛题数据,曾经做过这样一个解答:如果一个用户浏览了A、B、C、D四个酒店,最后选择了第四个酒店的话,那么会产生四条记录,并且这四条记录的label都会被标记为1。
从这一点我们可以看出,我们在做本地测试集划分的时候需要基于用户进行划分,也就是要保证划分前后的数据是满足独立同分布的。但是很遗憾,为了保护用户的隐私,并没有提供User ID的数据。因此,我们采取了一种近似的方法,就是看所有和用户相关的属性,如果这些属性都是相同的,那么我们就认为这是一个用户的行为。
我们基于上述原则,将原始训练数据集的三分之二划分为训练数据集,三分之一划分为本地测试集。因为这个场景下的时间序列特性不是很明显,所以没有按时间线对数据进行划分。在特征选择和调参的过程中我们主要使用线下的数据集进行的。
我们整个的工作流程如下图所示。线上的测评每天只有一次机会,我们在线下每天进行多次的特征选择和参数调整。整个的流程包括特征的抽取、数据集重采样、特征选择和模型的融合。
特征工程
整个特征工程的总体流程如下所示,相关的数据已经由比赛的主办方提取完成。我们在本次比赛中主要进行了数据采样一直到模型评估中间的工作。在生成了所有特征之后,我们会进行特征选择,我们通过本地的测试集对特征进行评估,保留有效的特征,去除无用的特征。
首先要进行缺失值的填充工作,从下图的数据中我们看到,有大量的缺失值分布在各个特征中。一般情况下填充缺失值的方法是使用均值或者0进行填充。我们在这里用0填充。但是有些属性,比如用户年订单量这样的特征,用0填充的话会产生混淆,填充之后无法判断是本身是0还是后来填充的0。所以我们对于这类特征,在填充0的基础上,构造一列新的特征,标记原始的数据中的0是否是我们填充得到的。
然后是特征的二值化以及特征的多项式变换,二值化主要使用了one-hot。前者将一些用数字枚举的特征变换成多维的0-1编码,后者根据现有特征演化出相关的特征。这一类的特征可以直接通过调用Sklearn的相关函数实现。
在第一部分的数据分析中,提到了这个数据跟用户是息息相关的。所以在这里在对数据进行用户分组之后,需要提出每组的最大值和最小值作为特征,如下图例子所示。
另外还有聚类特征,整个数据集中重要的两个部分,一个是用户相关的数据,一个是酒店相关的数据。因此,我们把这两类主体进行一个聚类,把类的标签号作为一个新的特征。对用户和酒店我们分别使用以下的特征进行聚类。
最后还有一类特征是根据现有特征衍生出来的一些特征,比如访问日期和实际入住日期之间的差值,还有访问日期和入住日期是不是周末等特征。在机器学习中,是否为周末这个特征往往是非常重要的。
模型原理及调参
对于一个分类问题,一般经常使用如下的一些模型。在正常的情况下,GBDT会较Random Forest有更好的效果,但是如果数据的噪声比较大的话,也会出现Random Forest的效果更好的情况。XGBoost是一个机器学习的框架,主要集成了GBDT算法。在本次比赛中,我们主要使用XGBoost作为我们的分类器。
首先先简单介绍一下GBDT分类器的原理,GBDT的核心就在于,每一棵树学的是之前所有树结论和的残差,这个残差就是一个加预测值后能得真实值的累加量。对于残差,一般的计算公式为。但是为了使得这个残差更具有普遍性,所以实际中往往是基于loss Function 在函数空间的的负梯度学习。所以严格说,GredientBoosting算法是基于伪残差的学习。实际上GBDT算法是GB算法的一个特例,只是说它的弱分类器是决策树分类器而已。具体Gredient Boosting的算法如下图所示:
具体的GBDT算法描述如下:首先给所有的样本一个初始值,0或者任意。然后使用一阶导的负梯度的函数计算伪残差。接着使用一个弱分类器(决策树)来对上面的残差训练,得到一个弱分类器能够最好地对残差进行拟合,就是上面的h(x)函数。
相比较GBDT做了很多的改进。虽然说基分类器还是GBDT,但是XGBoost有几个优化,一个是在目标函数中加入了正则项,防止过拟合。通过泰勒展开,最后目标函数变成一个跟一阶导和二阶导相关的式子。关于正则项的部分主要是叶子节点的数量以及叶子节点的loss。除此之外还有其他的一些优化,包括对列进行了抽样,使用了随机森林的思想。然后在对叶子节点进行分裂之前提前进行了排序,很大程度地提高了效率。
下图中红色箭头指向的l即为损失函数;红色方框为正则项,包括L1、L2;红色圆圈为常数项。XGBoost利用泰勒展开三项,做一个近似,我们可以很清晰地看到,最终的目标函数只依赖于每个数据点的在误差函数上的一阶导数和二阶导数。
对于一个XGBoost模型而言,我们有这么多的参数,那么怎么来调整模型的参数,使得单个的模型表现更好呢。根据以往比赛的一些经验,主要调整了树的最大深度,学习的速率,还有树的个数这三个参数来进行调整,调整的方法主要是用GridSearch,通俗的说就是有点像是穷举的意思,遍历尝试找出最优的一些参数的组合。
对于调参而言,不用过于重视在验证集上面的表现,因为毕竟验证集的分布和测试集的分布还是有一定的差别的,为了保证模型的泛化能力,所以我们在调参的时候调到差不多就行。另外一个方面,在选取最优参数的组合做ensemble learning的时候,尽量选择参数差别较大的一类组合做ensemble,因为差别较大的一组做集成学习的话效果会比较好。
模型融合
接下来介绍的模型融合方法。下面的流程图展示了如何进行模型融合。
首先,通过有放回的随机抽样的方法,按照原来数据集正负样本的比例进行随机抽样,从原始数据集中进行抽样,获得了五个训练集。然后对这五个训练数据集分别使用XGBoost分类器进行训练。XGBoost的参数为在前面本地验证集上面采用GridSearch得到的最优的参数。最后使用训练出来的五个模型分别对线上的测试集进行预测,最后将预测得到的结果直接取平均,从而得到最终的结果。
当时,就这个最后的融合而言,有的是直接取平均,有的会按照一定的比例融合。具体的比例依据,有时候是通过尝试不同的比例看线上的结果,同时也要基于模型的原理。对于模型的融合方法的话,我们在这里一般考虑Stacking或者是Bagging。我们在本次比赛中采用了Bagging的方法。所谓的Stacking就是把各个模型的预测结果,再做一个逻辑回归的模型,而不是简单的平均。
现在来讨论为什么说模型融合在这里能够提升模型的效果呢。对于模型的误差来说,一般是两部分的误差,一种是偏差,一种是方差。只有两者都小了才能保证模型拥有最小的整体误差。所谓的偏差是由于模型对于数据集的学习还不到位导致的欠拟合,所谓的方差指的是由于模型对于训练数据集的学习太好了,所以这就导致了在训练数据集上面表现很好,但是到了实际的测试数据集上面表现欠佳,就是传说中的过拟合。
那么这个跟我们的模型提升又有什么关系呢。因为在前面提到了,采用的GBDT算法是对残差进行的拟合,所以说XGBoost的模型是拥有比较小的偏差,但是方差可能就会相对高一点,就是我们感觉会有一些过拟合在里面。所以采取再进行一次Bagging的原因。其实从上图的原理可以看出,前面一幅图的原理是很像随机森林的原理的,只是前面的单分类器用的是XGBoost。
总结
在前文中,从特征选择,模型原理,模型融合等方面进行了一个简单的概括。那么,对于一个机器学习的问题,或者说对于一个大数据竞赛,我们有什么样的相关经验可以总结呢。
首先一点就是要注意数据分析,数据分析是很重要的。数据分析的相关工作包括,我拿到这样一个数据,我需要做一些基本的统计,比如最基本的,在这个问题中,正负样本的比例多少要统计;还有属性的缺失值是不是严重,属性的缺失值的部分占数据总量的比例是多少,以便及时决定是否使用这个属性,或者说采取加特征或者是其他的什么方式。
还比如其他的问题,如果是一个回归的问题,我也需要分析数据,比如我根据歌手的历史被收听的数量来预测这个歌手未来一段时间被收听的数量这样一个问题,我要做好前期的数据分析,包括画出趋势变化图,看看曲线的波动是怎么样的,如果波动大,要看看波动有没有周期性,如果有周期性,要分析是什么样的周期性。
这样直接决定了后面是采用什么样的模型,怎么样提特征,是否加入什么样的规则。还有就是数据的预处理,比如刚才说的缺失值的填充的问题,还有如果正负样本严重不均的话,还要再进行一些重采样。还有一个更好的例子,在讯飞做的道路匹配的项目中,仅仅通过对地图的预处理最后将匹配准确度提高了百分之二十。
然后关于特征,特征决定了模型的上限是多少。在实际的机器学习过程中,模型以及调参最后能够提升的余地十分有限,关键还要选好特征。要想选好一个好的特征,需要对业务相关的问题十分了解,这一点需要和相关的产品以及这个问题的领域专家做好沟通。
关于调参,想要强调的一点是一定要在特征工程做好了之后在进行模型的调参,根据不同的特征模型的最优参数是不一样的。然后在模型调参这里不用花费太多功夫,因为模型调参的提升余地实在是十分有限。
不过在调模型的时候,有一个地方是可以提升的,就是改模型的Loss,将模型的训练目标函数变成最终业务要求的评价函数,能够使得模型在当前评价标准下获得最优的表现。当然,不是每个评价函数都存在一阶导和二阶导,实际处理的过程中可能会推导出一个近似的方法。
最后是关于融合。虽然说模型融合十分有效,但是不建议一开始就进行模型的融合,可以把模型融合作为最后的杀手锏。在前期还是要尽可能的把单模型调好。一般单模型效果好的话,最后融合的结果都还比较理想。
下载PPT请戳文章底部“阅读原文”。
推荐阅读:
*作为上海互联网领军企业,携程致力于营造上海的技术交流氛围,为技术圈小伙伴搭建更好的交流沟通平台,共同成长进步。也欢迎有同样想法的小伙伴,来沟通合作,邮件niuq@ctrip.com*