一种基于群体特征的比例偏差纠正方案

 

前言:

 

2018年10月,TalkingData组织了面向内部员工的第二届黑客松大赛。其中一个赛题是“如何消除数据的各类偏差,从而产生无偏差的洞察?”针对该题目,本文作者所在的参赛小组提出了一个利用群体特征进行预测的方案,并获得了良好的泛化效果。该方案的重点在于将个体特征转化为群体特征,利用群体特征直接对群体属性进行预测,达到简化问题的目的。

 

本文将对这个方案进行分享,同时尽量采用通俗易懂的措辞和举例,来降低理解问题的门槛,所以非数据科学专业的朋友也可以放心大胆地阅读下去。

 

题目描述

 

由于互联网用户行为本身的差异,我们平常收集的移动端数据也会产生各种偏差,比如男性的数量要比女性多得多,青年/中年人的数量要比老人多得多。另一方面,在很多场景下,我们需要对某一个企业提供的人群包的人口属性进行精准的洞察。 那幺,该如何基于自身带有偏差的数据,来提供对于某个人群包的无偏差的描述?

 

题目翻译

 

上面的描述可能过于专业,我们可以这幺理解:我们已经有一个人群的数据,而且知道这个人群的性别分布,这部分数据称为数据集A。某个企业呢,也有一个人群的数据,他们希望了解这个人群的男女比例,于是请我们来进行猜测,这些数据称为数据集B。

 

一个比较常用的做法就是, 求A和B两个数据集的交集,得到一个数据集C。 然后我们认为C就是A和B的一个采样,可以用采样中的男女比例去估计整体的男女比例,也就是说用C的男女比例去当做B的男女比例。

 

但这样的估计结果往往不准。 首先,获得这个采样的方式太风骚,无法判定C是B的一个随机采样,而经过验证C中的男女比例则更接近A中的男女比例。其次A中的男女比例和B中的男女比例往往差异很大,比如A中可能是0.7,但是B中可能是0.2,而在采样C更接近A的情况下,我们得到的结果就与B相去甚远了—— 即有偏差的洞察。

 

题目需求

 

比赛中已经提供3个数据集A、B、C。数据集A里面的设备我们都了解其性别;数据集B里面我们不知道具体设备的性别,但是知道该集合里面的男女比例。我们的任务是推断出数据集C中的男女比例。对于每一个数据集,都会提供数据集里各设备的特征信息,我们可以对这些设备进行建模。

 

最朴素(Naïve)的解决思路:

 

1. 筛选设备信息特征。

 

2. 由于已经知晓A中的性别情况,可以直接建模预测各设备的性别。

 

3. 模型调试(调参、交叉验证、Averaging、Stacking等各种风骚操作)。

 

4. 预测数据集B各设备的性别,求得男女比例,然后与给定值进行比较,不准确的话回到第三步进行调试。

 

5. 预测C中的性别,算出比例,然后去睡觉。

 

评价

 

这个方法的优点很明显,思路清晰,编码方便,但是缺点也是非常显着的。 首先是计算量较大,数据集A中有220,000人和超过400,000设备特征,在经过筛选后往往还有超过1,000+的特征,于是有220,000 × 1000个entry。如果仅仅是做一次训练的话还好,实际情况是我们还要多次训练做交叉验证来避免过拟合等,所以效率是一个大问题。在这里我们仅考虑用Python scikit-learn的实现,不用Spark等炫技。

 

 

其次,个体的泛化能力有限。 像app很难去区别人的性别,也许存在一些app是和性别强相关的,但是覆盖人数也很有限。更可怕的是,数据集A中的性别也不一定是准确的,数据探索表明其中包含500多个相同的TDID有不同的性别(安能辨我是雄雌),说明数据来源中肯定有脏数据和异常值。异常值就是比如用户是男性,但为了玩“绝地求生”有人带,于是将性别改成了女。这种异常值还是没法检测的,训练出来的模型很可能就把玩“绝地求生”的人都当成了小姐姐。

 

于是(重点来了,敲黑板), 我们设想,能不能跳过对个体的性别预测,直接利用群体的男女比例去预测群体的男女比例呢?

 

我们现在只知道两个群体的男女比例,一个是数据集A,还有一个是数据集B,也就是我们只有两条训练数据,这必然是远远不够的。但是,我们知道数据集A中的各设备的性别情况,我们可以利用抽样的方式从A中得到各种各样的群体,从而扩充我们的训练集。 对于每一个群体,我们把设备特征从0或1的编码转变成该设备特征在这个人群中的占比。 比如以前我们的训练集是十个人,十个人中有七个人装了某app,于是这七个人中的特征“某app”为1,其他三个人为0。但是现在我们把这十条训练数据压成一条,特征“某app”变成0.7,即安装该app的人在这十个人中的占比。

 

于是这个问题就转换成了, 我们采用什幺抽样方式,能够获得一个训练集,使得训练出来的模型能够在数据集B上得到完美验证?

 

一个更好的解决方案

 

随机抽样

 

随机抽样是最不靠谱的。 抽样出来的各个群体的男女比例一定都是相同,且都等于A的男女比例。因为这些群体都来自于A,且独立同分布。所以不管我们抽样多少次,我们都只会有一个y值,这样训练出来的模型效果注定不好(我们猜测的,不信邪的勇士可以尝试一下)。

 

按照比例对男女进行随机抽样

 

既然我们直接随机抽样的男女比例始终是一定的,那我们为什幺不能自己生成1000个不同的男女比例,然后根据这个男女比例去获得对应的男女样本呢?比如我们想形成一个男女比例为0.5的群体,群体大小定为10,000,那幺我们就需要5000个男性和5000个女性,于是我们就从A中的男性中随机抽样5000次,然后从A中的女性中随机抽样5000次,最后组合得到所需的群体,压缩成一条训练集。

 

这个办法基本上可以回避最朴素的办法的缺点,第一,我们只抽取1000-2000个群体,所以我们训练集的大小控制在1000*1000的范围,可以切换着不同的姿势随意调试训练模型。预测的时候也只需要预测一行数据,而不必对个体进行预测,速度嗖嗖的加快。

 

第二,虽然每次抽样出来的群体中可能包含异常值,但是这个过程会稀释掉异常值,异常值的特征在总体中的占比必然是少数,所以对训练模型的影响可以降到最小。当然不排除当时人品不好抽样出了一堆玩“绝地求生”的“小姐姐”,这种情况下只需要在验证集上测试一下效果即可,效果不好的话重新抽样就行了。

 

特征筛选

 

每个TDID都有一个特征列表,分别由其安装的app、手机品牌等移动设备信息组成。如果我们把所有的特征全都平铺开,计算每一个特征在该人群中占据的比例,就像上文所说,那幺我们将得到超过40万列数据。

 

那幺我们首先想到的就是降维。然而无论是线性降维还是非线性降维,本质上都是将数学上的高维空间映射到低维空间,根本不适用于人群的移动设备数据,做出来的预测太美而不敢想象。当然我们也没有这幺去做,因为这幺多的entry根本装不进内存,于是大胆猜想之后就不再去费力求证了。

 

 

不过凭借常识,就能对人们常用的app有一些了解,所以这些特征的频次分布肯定呈现超长尾,有大量的特征占不到人群的0.01%,所以我们只提取那些频次占比超过1%的特征即可。执行结果让我们很愉悦,只有1000来个特征。

 

构建训练集

 

接下来我们要做的就是从原有的训练集中抽取不同的群体。首先想到的肯定是随机抽样,直接执行sample()就搞定了。然而,sample()函数的抽样服从均匀分布,也就是说,如果原有训练集中男女比例是0.6,那幺无论抽样多少个群体,他们的男女比例都会是0.6。

 

那幺我们可以手动改变这个比例,从训练集中刻意抽取男女比例不为0.6的群体。操作方法也很容易,先产生一个0-1的随机数来代表男女比例,然后根据这个男女比例计算出要抽出的群体的男女数量,再从训练集中抽出对应数量的男女,组成新的群体即可,这样一个比例就对应一个群体,就对应了一条训练数据。当然还要根据上面选取的特征来构建新的特征,即该特征在这个群体中所占的比例。

 

深度学习模型的应用

 

随后我们用PyTorch构建了一个包含两层全连接的神经网络来进行模型的训练。为什幺用神经网络呢,因为这样比较有格调。至于为什幺是ANN不是CNN也不是RNN、LSTM等,毕竟格调还是有成本的,我们想尽量减低复杂度。事实上我们用Lightgbm或者XGBoost效果也是杠杠的,结果基本上都差不多,用传统模型还需要去做Stacking的操作,用神经网络堆叠深度就轻松搞定了。

 

后续结果

 

其实在比赛中并没有拿到令人满意的结果,因为中间对接数据的时候出现了问题。后来修复了问题,并与其他数据集进行比较,这个方案实现的预测偏差确确实实是最小的(真实值:0.5,预测0.52,其余方案0.6左右), 说明用群体去预测群体的想法是完全可靠的。 而且这个方法是可以扩展到群体的其他属性标签,比如工作类型占比等,完全不局限于性别。归根结底,对移动数据难以做到个体精准预测,容易发生过拟合,而通过预测个体来估算群体会导致这种误差放大。然而一个群体的设备特征是显着的,通过这个方法可以规避个体差异,减少outlier对预测的影响,从而实现更精准的洞察。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注