干扰AB测试
扫描二维码
随时随地手机看文章
A/B测试是大多数公司用来测试其产品特性的在线实验的黄金标准。虽然A/B测试试验在大多数情况下效果良好,但特别容易受到干扰,特别是在在线市场或社交网络中。在本文中,我们旨在研究带有干扰偏差的情况,以及一些减轻其对评价影响的潜在方法。
A/B测试的基本假设及其违反情况
A/B测试的基本假设之一是Sutva--稳定的单位处理值假设。随机化单元治疗的潜在结果只取决于他们所接受的治疗,而不是分配给其他受试者的治疗。
在市场和社会网络上的实验中,这种情况经常遭到侵犯。可能的侵权行为包括:
· a/b在社交网络上测试实验。比如说,我们想了解在"信码"上添加"故事"功能的效果。一个增加治疗部门人员参与度的功能会影响到与他们有联系的控制部门人员。控制部门的人回应他们的故事,这可以增加他们的参与。这是一个实际治疗效果比我们在实验中看到的要小的例子。
· A/B在里兹野兔市场的测试实验:假设一个里兹野兔市场引入了对骑马者的折扣,并希望在无折扣控制下对其进行测试。另外,利息的度量是乘坐的次数。然而,如果治疗者开始要求更多的乘坐,那么控制者可以使用的驾驶就会减少。这种情况下的治疗效果被夸大了。
· 一个类似的例子是一个广告市场,在这个市场中,多个活动都在竞争一个广告。然而,假设有固定的广告商预算。该预算由治疗和控制部门分摊。想象一下,我们提出的功能增加了点击率。在治疗中,如果预算开始花费更多,控制组的可用预算就会减少。在这种情况下,治疗效果再次膨胀。
减缓干扰效应
通过修改实验设置和因果推理技术,我们可以减轻A/B测试中干扰的影响。我探究了技术背后的直觉,而不是技术细节。我将分享推荐信,这样你也可以稍后再做。
预算分割测试
这通常是在处理和控制之间共享广告商预算等公共资源时使用的。在这方面,预算是按实验流量的比例来分配的,这样处理和控制就有了自己的预算,并且没有拆食。这种方法费用高昂,因为可能导致预算利用不足。有关这方面的更多细节,可在民刘等人的论文中找到。,2021年。我给出了一个基本代码来创建一个预算划分实验系统。
import random
class BudgetSplitTest:
def __init__(self, total_budget, control_traffic_ratio):
self.total_budget = total_budget
self.control_traffic_ratio = control_traffic_ratio
self.treatment_traffic_ratio = 1 - control_traffic_ratio
# Split budget based on traffic ratio
self.control_budget = total_budget * control_traffic_ratio
self.treatment_budget = total_budget * self.treatment_traffic_ratio
# Track spent budget and conversions
self.control_spent = 0
self.treatment_spent = 0
self.control_conversions = 0
self.treatment_conversions = 0
def run_experiment(self, total_impressions):
for _ in range(total_impressions):
if random.random() < self.control_traffic_ratio:
self._serve_control_ad()
else:
self._serve_treatment_ad()
def _serve_control_ad(self):
if self.control_spent < self.control_budget:
spend = min(random.uniform(0.1, 1.0), self.control_budget - self.control_spent)
self.control_spent += spend
if random.random() < 0.1: # 10% conversion rate for control
self.control_conversions += 1
def _serve_treatment_ad(self):
if self.treatment_spent < self.treatment_budget:
spend = min(random.uniform(0.1, 1.0), self.treatment_budget - self.treatment_spent)
self.treatment_spent += spend
if random.random() < 0.15: # 15% conversion rate for treatment
self.treatment_conversions += 1
def get_results(self):
return {
"Control": {
"Budget": round(self.control_budget, 2),
"Spent": round(self.control_spent, 2),
"Conversions": self.control_conversions,
"CPA": round(self.control_spent / self.control_conversions, 2) if self.control_conversions else 0
},
"Treatment": {
"Budget": round(self.treatment_budget, 2),
"Spent": round(self.treatment_spent, 2),
"Conversions": self.treatment_conversions,
"CPA": round(self.treatment_spent / self.treatment_conversions, 2) if self.treatment_conversions else 0
}
}
# Run the experiment
total_budget = 10000
control_traffic_ratio = 0.5 # 50% traffic to control, 50% to treatment
total_impressions = 100000
experiment = BudgetSplitTest(total_budget, control_traffic_ratio)
experiment.run_experiment(total_impressions)
results = experiment.get_results()
转换实验
开关回用在两面市场更常见,比如来夫特,Uber,多达什,所有的用户都在处理和控制之间切换。这里的随机化单元不是用户而是时间单位。如果时间间隔短,这种方法可以从处理到控制产生溢出效应,否则会导致实验能力不足。我们可以使用回归分析等方法来增加功率。
import random
from datetime import datetime, timedelta
class SwitchbackExperiment:
def __init__(self, experiment_name, start_time, end_time, interval_hours=1):
self.name = experiment_name
self.start_time = start_time
self.end_time = end_time
self.interval_hours = interval_hours
self.schedule = self._create_schedule()
self.data = []
def _create_schedule(self):
schedule = []
current_time = self.start_time
while current_time < self.end_time:
schedule.append({
'start': current_time,
'end': current_time + timedelta(hours=self.interval_hours),
'variant': random.choice(['control', 'treatment'])
})
current_time += timedelta(hours=self.interval_hours)
return schedule
def get_active_variant(self, timestamp):
for interval in self.schedule:
if interval['start'] <= timestamp < interval['end']:
return interval['variant']
return None # Outside experiment time range
def record_event(self, timestamp, metric_value):
variant = self.get_active_variant(timestamp)
if variant:
self.data.append({
'timestamp': timestamp,
'variant': variant,
'metric_value': metric_value
})
def get_results(self):
control_data = [event['metric_value'] for event in self.data if event['variant'] == 'control']
treatment_data = [event['metric_value'] for event in self.data if event['variant'] == 'treatment']
return {
'control': {
'count': len(control_data),
'total': sum(control_data),
'average': sum(control_data) / len(control_data) if control_data else 0
},
'treatment': {
'count': len(treatment_data),
'total': sum(treatment_data),
'average': sum(treatment_data) / len(treatment_data) if treatment_data else 0
}
}
# Example usage
if __name__ == "__main__":
# Set up the experiment
start = datetime(2023, 5, 1, 0, 0)
end = datetime(2023, 5, 8, 0, 0) # One week experiment
exp = SwitchbackExperiment("New Pricing Algorithm", start, end, interval_hours=4)
# Simulate events (e.g., rides in a rideshare app)
current_time = start
while current_time < end:
# Simulate more rides during peak hours
num_rides = random.randint(5, 20)
if 7 <= current_time.hour <= 9 or 16 <= current_time.hour <= 18:
num_rides *= 2
for _ in range(num_rides):
# Simulate a ride
ride_time = current_time + timedelta(minutes=random.randint(0, 59))
ride_value = random.uniform(10, 50) # Ride value between $10 and $50
exp.record_event(ride_time, ride_value)
current_time += timedelta(hours=1)
# Analyze results
results = exp.get_results()
图组随机化(GCR)
在社会网络实验中,图形集群随机化是一种进一步减少干扰偏差的技术。 . 该方法在形成集群时考虑到网络结构,有助于在网络社区中隔离处理效果。然后将集群随机分配给处理和控制。由于集群的孤立,干扰会自动减小.
资源调整指标
我们可以使用解释资源分配的衡量标准,而不仅仅侧重于绝对结果。例如,在广告活动中,我们可能不仅仅是衡量点击率,而是跟踪每次点击的成本或广告支出的返回,这使不同预算水平的结果正常化。
合成控制
在出现干扰的情况下,可以构建综合控制组,根据其他单位的指标来模拟处理对某一单位的指标的影响。例如,假设我们把这个国家作为一个整体,在一个预先测试的时期,一个国家的度量标准是根据其他国家的度量标准建模的。当我们在一个国家推广这一特征后,我们可以通过比较这一模型所预测的指标来模拟推广干预的效果。结果的差异可能很大,足以衡量小影响。
信息技术服务
中断时间序列模型。定义干预点,如特征推广,然后使用干预前时间序列预测观测结果。将其与实际观察结果进行比较,以确定干预是否对时间序列产生影响。
乱滚
逐步引入对一小部分用户的更改,并在扩展展开之前监控结果。这使您能够及早发现潜在的问题并减轻干扰的影响。
实际上,所有这些方法都应该与AB测试方法结合使用。例如,可以定义一些指标,以查看是否检测到广告市场的干扰。如果没有问题,AB测试结果是可以信任的,否则,我们可以进行预算分割测试。