厉害啦,猎聘大数据研究院搞事情啦

前言

基于上次对ABtest的概述,下面我们将介绍一款强大而实用的A/B实验分流的工具包,重点是开源的喔~

Macaw 简介

Macaw是由猎聘网大数据研究院开源的一个用于AB实验分流的工具包。 它可以支持复杂的AB实验分流场景。

例如: 多层分域正交实验,按照用户特征取部分流量进行实验,使用bandit算法自动优化流量分配等。

目前支持的分流方法有如下几种:

实现按照key哈希的实验选择方法, 能够保证不同层的实验策略正交组合。

按照用户属性的基于规则表达式的分流算法。例如: area = 北京

基于Thompson Sampling 算法的实验策略选择方法:大部分流量会分配到目前为止表现最好的策略,少部分流量会分配到其它策略进行实验。

基于UCB算法的实验策略选择方法:如果有新策略则选择新策略,否则选择置信区间上界最大的那个策略。

基于Epsilon Greedy算法的策略选择方法:在大部分情况下,选择目前最优的策略;在其他情况下,随机选择。

Macaw的开源代码库的地址是https://github.com/lpdig/macaw 。欢迎使用并和我们一起不断改进它!

应用场景

场景一

一个页面有多个功能点想要修改,希望对每个功能点的多个方案做对比试验,如下图:

组合起来有 3 * 2 * 3 = 18套方案。 在此场景下,如果手动去调整每种组合的流量是一个非常繁琐的过程,而且不容易保证对一个功能的不同策略之间的对比不受其它功能的影响。

使用多层正交实验能很好的应对这种场景:

1.将一个功能点的不同实验策略划分为一层

2.每一层都独享全部的流量

3.通过算法保证不同层之间的策略正交组合

那么最终的流量划分将如下图所示:

场景二

在实验初期的时候,如果一开始就拿出全部流量去做大规模的实验可能风险会比较高。 一般情况我们会先按照某种规则,选择一部分用户做试点实验, 如果效果能达到预期再开始大规模的实验。

比如:只拿出北京和上海地区的用户做实验,其它使用已有的策略。 流量划分规则如下:

在macaw中引入了域的概念来实现在一个实验中使用多个流量划分的规则。在选择策略的时候,macaw会先通过哈希或者规则表达式的方式(由配置决定)将流量导入到某个域,再在域中选择具体的策略。

场景三

通过[实验--> 分析 --> 调整流量]的方式做决策,反映周期都会比较长。

macaw中也实现了几种常用bandit算法,来支持通过收集到的每个策略的历史表现实时调整流量的场景。

关于bandit,后面会做进一步说明。

基本概念

实验策略(policy):由一个策略的名称和一组参数构成。策略在此包中是个抽象的概念,它实际对应的是业务系统的某种实验策略,可以是某种实体,也可以是一组实验参数(比如推荐算法的某种策略,或者页面上按钮的某个配色方案等)。

层(layer):一个应用中,业务方可能会同时进行几组不同的AB对照实验,其中每一组AB对照实验即为一层。其中每一层都会使用到全部的流量。

域(domain):在AB实验过程中,实验者可以配置多个域。在选择实验策略时,会先将流量分配到某个域,再在此域内选择每一层的实验策略。使用域的目的是为了支持在同一个实验中,支持多种多层实验策略的组合方式。

策略、层、域的关系,可以参考下图:

其中,每一个橙色框代表一个域, 蓝色的框代表一个层,处于域、层相交的地方的就是各个策略。

目前支持的域的种类有:

1.固定组合域(FixedGroup):此域中的每一层只有一个固定的实验策略。

2.多层正交域(MultiLayerHash): 使用哈希算法,将流量按照配置的比例划分到每一层的各个实验策略。并且保证不同层的实验策略是正交组合。

3.Thompson Sampling域(MultiLayerThompson): Thompson Sampling算法实现的策略选择域。

此域的大部分流量会分配到目前为止表现最好的策略,少部分流量会分配到其它策略进行实验。

4.UCB域(MultiLayerUCB): UCB算法实现的策略选择域。此域选择实验策略的规则是,如果有新策略则选择新策略,否则选择置信区间上界最大的那个策略。

5.EpsilonGreedy域(多层EpsilonGreedy域): 可以指定一定比例的流量做实验(平均分配到各个策略),其它流量全部分配到当前表现最好的策略。

使用方式

引入Jar包

配置、初始化实验

实验实体的创建主要通过ExperimentApp.Builder对象来生成。

Builder对象可以通过代码逐步配置,也可以由一个json的配置直接转换而成。例如:

通过Json配置初始化ExperimentApp

关于配置的说明请参考下面的几个章节。

获取实验策略

实验初始化完成后,可以直接使用生成的ExperimentApp对象的getPolicy方法获取实验策略。

传入的参数是用来分流的对象,可以是一个包含各种属性的user对象,也可以直接使用userId之类的字符串。

具体使用什么需要根据实验使用的分流算法以及相关的配置来决定

配置说明

applicationId: 此实验的ID/名称

totalSize: 总的桶数。流量哈希到域的基数。 如果没有使用Hash策略的域,则可以不设置此参数。

audienceDefinition: 对实验受众的描述,由一组受众特征组成

features: 受众的特征

property: 特征的字段名

description:描述

keyProperty:boolean类型,是否是key。如果是,则会分配流量的时候用来做hash计算。

domain: 域的配置

domainId: domain的唯一标识

ruleStrategy: 流量划分到当前域的策略,取值为[Hash/ExpressionBase]. 可多选。

Hash: 会根据当前domain的size和application的totalSize比例,把一定比例的流量分配到当前域

ExpressionBase: 会根据ruleExpression把符合规则的受众流量分配到当前域。

在一个实验中,支持两重类型的域同时存在。 流量分配的时候ExpressionBase类型的域会有限匹配,匹配不到的流量才会分配到Hash域。

如果多个ExpressionBase域的规则有重叠的部分(比如 domain1 的规则是age > 10,domain2的规则是age > 20)流量会分配到第一个匹配到的域。

另外,ExpressionBase域的size只是本域内的base流量,不受application 的totalSize的限制。

ruleExpression: 使用ExpressionBase策略的表达式,例如: (age > 10) and (sex = 男)。 如果有多个限制条件, 每个子条件都需要加小括号。目前支持的表达式有:

domainType: domain的类型,每种类型的domain内部都对应一种分流算法。 取值为:FixedGroup/MultiLayerHash/MultiLayerUCB/MultiLayerThompson

description: domain的描述。

size: 当前domain的桶数

isDefault: 是否是默认域。 在配置实验策略时,没有指定域ID的策略,都会分配到默认域。

默认域只能有一个,而且可以不配置size。totalSize - 非默认域的size和就是默认域的size。

layer:层的配置

layerId: 层的唯一标识

description: 层的说明信息

policies: 本层的所有备选实验策略

name : 策略的名称。也是策略的唯一标识。

size : 策略所占的桶数。只有分配到MultiLayerHash域,此参数才会起作用。如果是UCB或者Thompson的实验策略,则会根据策略的评估参数进行选择,此项配置不会生效。

domainIds : 此策略所属的域。 同一个策略可以指定多个域,也可以不指定域,如果没有指定域,则此策路会分配到默认域。

param : 此策略的参数。业务系统自己定义,没有特别的要求。

isDefault: 是否是默认实验, 每一层的默认实验最多只能有一个。非必填,默认实验的使用规则如下:

默认实验的domainId配置和size配置都不会生效。默认实验策略会在初始化的时候添加到所有域。

FixedGroup域如果配置了实验策略,则使用配置的策略,如果没有,则使用默认策略

MultiLayerHash域的剩余流量(域的总流量 - 所有配置策略的流量)都会分配到默认策略。

MultiLayerUCB/MultiLayerThompson根据各自的评估算法分配流量

estimateParam : 实验策略评估参数。如果使用了bandit域(MultiLayerUCB或者MultiLayerThompson)则需要指定此参数。

每个实验策略对应一个参数。

policyName: 策略名称

total: 当前策略总的实验次数

successes: 当前策略成功转化的次数

参考配置

例1: 普通的两层正交实验, 每一层各有新老两个策略,各占50%流量

{

"applicationId": "test_hash_domain",

"totalSize": 100,

"domains": [ {

"domainId": "multi",

"ruleStrategy": "Hash",

"size":"100",

"domainType": "MultiLayerHash",

"description": "唯一的多层正交域",

"default": true

} ],

"layers": [

{

"layerId": "L1",

"description": "第一层",

"policies": [

{

"domainIds": ["multi"],

"name": "E1",

"size": 50,

"param": {

"url": "url1"

}

}, {

"domainIds":["multi"],

"name": "E2",

"size": 50,

"param": {

"url": "url2"

}

} ]

}, {

"layerId": "L2",

"description": "第二层",

"policies": [

{

"domainIds": ["multi"],

"name": "F1",

"size": 50,

"param": {

"color": "c1"

}

}, {

"domainIds": ["multi"],

"name": "F2",

"size": 50,

"param": {

"color": "c2"

}

}

]

}

]}

例2: 使用北京的用户测试几个新策略,其它的流量使用原来的老策略

{

"applicationId": "test_hash_domain",

"audienceDefinition": {

"features":[{"property":"area", "description":"用户所在地区", "keyProperty":false},{"property":"userId", "description":"用户ID(此处用来做流量划分)", "keyProperty":true}]

},

"domains": [

{

"domainId": "multi",

"domainType": "MultiLayerHash",

"size": 100,

"ruleStrategy": "ExpressionBase",

"description": "新策略的多层正交域",

"ruleExpression": "area = 北京"

},

{

"domainId": "fix",

"domainType": "FixedGroup",

"ruleStrategy": "Hash",

"description": "老策略的固定组合域",

"default": true

}

],

"layers": [

{

"layerId": "L1",

"description": "第一层",

"policies": [

{

"domainIds": ["fix"],

"name": "E1",

"param": {

"url": "old url"

}

},{

"domainIds":["multi"],

"name": "E2",

"size": 30,

"param": {

"url": "u2"

}

},{

"domainIds":["multi"],

"name": "E3",

"default": true,

"param": {

"url": "u3"

}

},{

"domainIds":["multi"],

"name": "E4",

"size": 30,

"param": {

"url": "u4"

}

}

]

},

{

"layerId": "L2",

"description": "第二层",

"policies": [

{

"domainIds": ["fix"],

"name": "F1",

"param": {

"color": "old color"

}

},

{

"domainIds": ["multi"],

"name": "F2",

"size": 50,

"param": {

"color":"color1"

}

},

{

"domainIds": ["multi"],

"name": "F3",

"size": 50,

"param": {

"color":"color2"

}

}

]

}

]}

关于bandit

bandit算法源于强化学习的多臂赌博机的问题(Multi-armed bandit problem),目的是在不知道每个老虎机吐钱的概率分布的情况下,使用某种选择策略使得收益最大化。

这一类的算法也特别适合用来做AB实验。 使用bandit做AB实验,可以安排合理的流量达到实验的目的,又不会冒太大的风险。

目前,macaw实现了如下几种bandit算法:

Thompson Sampling算法: 根据每个实验策略的历史表现(收益数和失败个数)计算beta分布并使用其beta分布产生一个随机数,每次选择生成的随机数最大的那个策略。

UCB算法: 如果有新策略(未被使用过),则选择新策略,否则选择置信区间上界最大的那个。

Epsilon-Greedy算法: 选择一个0~1之间的值epsilon作为阈值。每次选择策略时,先生成一个随机数与epsilon比较,如果小于epsilon,则从所有臂中随机选一个,如果大于epsilon则选择平均收益最大的那个。

由于bandit算法在选择策略的时候,大多会使用某种随机的方法,所以不能保证同一用户每次都分配到相同的策略。如果实验中的不同策略会对造成用户感知上的不适应,则此场景下不适用bandit算法。

DIG

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180712G0F0Q200?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券