企业级机器学习 Pipline - 特征feature处理 - part 1
企业级机器学习 Pipline - 特征feature处理 - part 1
part 0, 往期回顾
log数据处理 : 处理原始hive表或hdfs上log日志数据
sample特征处理 :样本打标签、样本清洗、采样以及CXR校准。
在上文 样本sample特征 处理的逻辑中,我们选取了能唯一标识一次流量的若干字段,例如:用户硬件唯一性id是 imei 、当前用户行为触发id是 triggerId 、当前广告位置标记 posid 、当前用户作用的对象id是 adid 、是否有点击标志的 label 字段以及Log行为发生的时间戳字段 timestamp 。上面这些字段在下游处理特征时都非常重要。
以上字段大概就是记录一个用户(imei)在某个时刻(timestamp)在某个广告位置(posid)上触发(triggerid)的某条广告(adid)的某次行为知否发生转化(label)。
part 1, 本期正文
书接上文,我们分别介绍了企业级机器学习 Pipline之 log 数据处理 、 样本sample 处理,按照这里文章组织的结构,下面我们开始介绍 特征feature处理 。
特征feature处理 相比于 样本sample处理 的区别在于: 样本唯一性的标识一次行为状态,为特征feature处理准备了必要的字段,在样本阶段决定了模型训练所使用的 sample条数 , 正负样本比例 以及 用户分布 ,下游流程均不会改变这些。
所谓 特征feature处理 就是拿到更多的广告侧(ad)、用户侧(user)、流量以及上下文侧(context)数据,简称为(AUC)三方数据,丰富模型能够使用到的各个方面的特征数据以及组织形式。
一般拿到一份数据,我们都会会去 观察这份数据 各个字段的 取值形式 、统计以下各个字段的 覆盖率 ,对数据做一些 宏观 上的 统计与处理 在进行使用。
如果是 id类 特征,可以把当作 sparse 类型进行处理,甚至 文字型、类别型 特征 都把作为离散特征处理。
如果是 连续特征 ,一般把进行分桶离散化之后加入到模型取得embeding等。也有类似于 gbdt+lr 这种方式,把连续特征用树模型进行离散化后和别的模型联合使用,在工业界也取得了很好的线上效果。当然也有把连续特征直接丢到 dense 模型里作为一个维度的,但是我做的一些实验效果都一般,进行了一波负优化。
字段的覆盖率对特征影响是至关重要的,一般在70%以上才会有较多的正向效果。当然也有另类,像是实时特征,短期内有行为的用户量特别少,但是效果仍然特别明显。
下面贴一段使用spark-shell
来统计数据字段覆盖率的代码:
@欢迎关注作者公众号 算法全栈之路
val df=spark.read.textFile("/hdfs/user/app/data.20210701/*")
.map(
e=>(
e.split("\t")(4),
e.split("\t")(5)
)).toDF("appname","flag").cache();
val re=df.agg(
(sum(when($"appname"===("-"),0).otherwise(1))/count("*")).as("appnamec"),
(sum(when($"flag"===("-"),0).otherwise(1))/count("*")).as("flagC")
).show()
特征数据 按照 取数时间 可分为 聚合历史多天特征、天级别特征、实时特征,其中 实时特征 可以看作 天级别 特征的补充。
也可分为 单列特征 、交叉特征 、序列特征, 其中序列特征又可以分为 聚合历史序列特征 和 实时序列 特征。
( 这里的实时特征均是指 近实时 )
对于一个机器学习系统的 特征features处理 环节,我们主要从以下4个方面来进行介绍:
(1) 上下文侧特征
(2) 广告侧特征
(3) 用户侧特征
(4) 特征组织形式
1.1, 上下文侧特征(Context)
所谓上下文侧特征,携带着当前请求的环境上下文相关的信息。环境 包括 设备上下文 与 请求上下文。
设备上下文 包括类似于用户请求时用的设备的操作系统os、软件的版本version、设备的语言language、当前请求的设备硬件id、设备的宽和高(屏幕大小) 等。
请求上下文 包括类似于用户请求的时间戳、请求渠道、sessionid、请求ip、手机网络类型net 、广告位posid、请求广告条数 等。有做的更深入的,会考虑当前广告在广告位展示中上文的广告的情况来作为当前广告的特征,就像百度的ubmq。
对这些特征,我们一般会进行一定的处理。例如:
(1) 对于 ip字段,我们会截取ip的前一段、2段,3段前缀。毕竟前缀相似的ip,在网络空间中有一定程度的相似性。
(2) 对于时间戳timestamp字段,我们可以把时间戳转化为年月日时分秒,得到该请求是周末/工作日,一天的各个阶段也可以进行分桶bucket.
以上这些特征,我们可以存储为 triggerId 作为key, 对应的各个字段作为value 的形式。使用 样本sample 中的 triggerId字段 来 leftjoin 上下文数据, jon不上的部分,赋予默认值。(保证样本条数不改变)。
这也是 sample 里保留 triggerid字段 的原因,下文相同。
1.2,广告侧特征 (Ad)
所谓广告侧特征,一般是指我们广告的 item 相关 的特征。
广告相对于推荐系统的自然量来说,广告的数量要小的多。 一般app下载类广告来说,可能app的包数量也就5k左右,广告数量也不是很多。所以 广告的各种id 本身就是一个很强的特征。
广告侧特征,一般包括:
(1) 广告id类特征 。广告id,广告计划id(planid),idealid,以及对应的广告的 一级类别id,二级类别id (就像抖音,一级列别可以把划分为娱乐类,二级类别可以把划分为短视频类)。
(2) 泛化性特征 。广告名称、广告主公司名称、广告主公司类别、广告主为当前广告设置的关键字、一句话介绍、广告的竞价类型、 模板id、历史x天平均出价bid、广告标签、广告的定向时间段、广告的人群定向、是否是新物料广告。
(3) 个性化特征 。如果是 应用App 类广告的话,还有包名称,包大小、下载次数、应用榜单的排名、评论数、好评数等。
(4) 统计性特征。我们可以基于 广告的各个维度 进行统计,好比广告粒度的历史7天平均点击率,平均下载率,转化率,点击次数,下载次数,转化次数等。一般工程师们统计号平均点击率等数据之后也会采取一些分桶操作,例如:(点击率*1000)/5。类似于这样的方法。
广告 的 item相关 特征,一般对于一个广告系统来说是描绘物料本身概念的特征,都是非常重要的特征。对于这些特征我们一般也会进行id直接使用,数值型特征进行分桶,以及和别的特征进行叉乘等。下文特征的组织形式在进行介绍。
以上这些特征,我们可以存储为 adid 作为key, 对应的各个字段作为value 的形式。使用 样本sample 中的 adid 来 leftjoin 广告数据, jon不上的部分,赋予默认值。
1.3,用户侧特征 (User)
一般我们可以取到的 上下文侧 和 广告侧 特征都是相对容易的,在特征优化的最初阶段都会把尝试个遍 。 而 用户侧特征,可以基于我们 不断丰富与完善 的用户行为日志不断扩充,工程师们可以做的事情非常多。下文我们使用 App下载广告 的 广告系统 作为demo 来进行介绍。
用户侧特征一般包括:
(1)用户的基础属性。包括用户的年龄、性别、学历、省份、市区等。
(2) 用户的历史聚合行为特征。例如用户过去7/14/30天看过哪些广告/自然量(view)、点过哪些广告、 下载过哪些App、安装过哪些App 、使用过哪些App、以及使用各个App的 时长、用户历史搜索过哪些词等。考虑到线上对 实时性 predict 的要求,这些用户行为list可以按照时间倒序排列,截取最近 5/10 个行为参与模型训练。
(3)统计特征。例如:某个用户过去7/14/30天的广告的平均点击率、下载率、转化率等。同时拿到用户行为的 item 之后,我们也可以得到这些 item 对应的各个粒度的类别特征,好比用户特别喜欢体育、游戏、美女娱乐等,在这些类别上的点击率非常高。
(4) 实时特征。在这里我们把实时特征看作天级别特征的补充。用户最在最近的一天以内,看了哪些,点了哪些,下载了哪些,搜索了哪些等。得到用户在一天内聚合数据的序列。对于这个list,工程师们可以拿到当前请求的时间戳和list里各个行为的时间戳做减法,并根据间隔时间大小划分成段做离散化。在这里要注意离线模块不要引起特征数据穿越。
特征穿越可能回导致离线模型的 auc奇高,甚至达到 0.999* ,在离线部分观察指标是可以看出来的。
用户侧特征,随着用户行为数据的不断丰富,工程师们可以做的事情非常多,这里就不再深入介绍了。
以上这些特征,我们可以存储为 imei 作为key, 对应的各个字段作为value 的形式。使用 样本sample 中的 imei 来 leftjoin 用户数据, jon不上的部分,赋予默认值。
用户的行为数据非常丰富,我们可能会存储非常多的用户数据,均已imei为key 即可。join数据的时候挨个left join就好。
注意使用用户历史数据的时候,样本的时间要早于用户行为时间,可以有效避免数据穿越。
1.4,特征组织形式
书接上文,我们已经 分别介绍了 上下文侧、用户侧、广告侧 的特征的各种形式。但是在实际使用的时候,我们不单单会使用单列特征,也会进行一定的叉乘。
一般来说,工程师们会把 广告侧和上下文侧进行交叉 ,得到得是 当前上下文 对 当前广告 点击率的倾向性。
更多的,工程师们也会把 广告侧 和 用户侧进行交叉,得到的是 当前 用户以及当前用户的某些历史行为 对 当前广告 点击率的倾向性。如果是用户行为序列,我们就把广告测和用户序列挨个进行交叉即可。
不光有二阶叉乘,也有更高更多阶级的叉乘。不光可以手动进行特征处理,也可以使用模型进行特征的处理。虽然dnn 可以进行高阶叉乘,但是手工的特征选择也是必不可少的。
序列特征工程师们一般在 dnn 模型会进行pooling 操作。常规选择是 sum pooling
或则 average pooling
。也会引入attention 操作进行 加权sum pooling 的操作,其中attention 又有self attention
和din attention
之分。也有做法会考虑序列特征里的时间因素,像是阿里巴巴的 dien 网络等。
这里已经牵扯到 dnn 网络结构 的变动了,后面的文章中会逐渐介绍,如果有感兴趣的可以私下交流下~
到这里,企业级机器学习 Pipline 特征feature处理 的理论部分就已经介绍完成啦,本期内容太长没有讲代码,只能在下期再介绍工业实践的实际操作了。
码字不易,觉得有收获就点赞、分享、再看三连吧~
欢迎扫码关注作者的公众号: 算法全栈之路