본문 바로가기

계량경제학/인과추론의 데이터과학

[논문 + 코드구현] Experimentation and startup performance: Evidence from A/B testing

A/B 테스팅 툴의 도입이 스타트업 성과에 미치는 요인 #DID #2WFE

논문 주소: 

https://www.hbs.edu/ris/Publication%20Files/AB_Testing_R_R_08b97538-ed3f-413e-bc38-c239b175d868.pdf

데이터: https://drive.google.com/drive/folders/1NDOJ11OsoNKg_qU_xDx_to8kf2ksJpeq or Management Science 저널 

참고: https://playinpap.github.io/two-way-fixed-effects/

참고한 코드: https://drive.google.com/drive/folders/1NDOJ11OsoNKg_qU_xDx_to8kf2ksJpeq

 

정책의 점진적인 도입 효과를 추론하고 싶다면? (two-way fixed effects model)

이번 포스팅에서는 데이터가 존재하는 논문을 바탕으로 2요인 고정효과 모형을 추정하는 구체적인 방법을 다룹니…

playinpap.github.io

 

Summary 

AB test가 스타트업의 퍼포먼스에 미치는 영향을 two-way fixed effect으로 분석함 

AB test 채택한 기업이 AB test 툴 1년 사용 후 성과가 30% ~ 100% 향상됨을 확인함 

 

Variable Construction

AB test tool 사용 여부 [ABTesting]

기업이 AB test 툴 (AB Tasty, Adobe Target Standard, Experimentl.ly, Google Optimize, Google Website Optimizer, Omniture Adobe Test and Target, Optimizely, Optimost, Split Optimizer, Visual Website Optimizer)을 사용했는지 여부

 

기술 스택 [Technology Stack]

AB test tool 이외의 기술 툴, 데이터가 skew 되어 있어서 로그 변환하여 사용함 

 

Log(Visits + 1) [Y]

1주일동안 페이지 방문 횟수에 로그 취한 값 

 

Two-way Fixed Effects

모델 설명

  • Yit: 1주일동안 방문 횟수에 log를 취한 값 
  • β: 기업의 A/B Test tool 도입이 퍼포먼스에 미친 영향 (ABTesting_it의 효과)
  • ABTesting_it: i 기업이 t 시점에 AB Test 도입 여부 
  • θ: TechnologyStack_it의 효과
  • Technology_Stack_it: i 기업이 t 시점에 보유한 AB test 이외의 기술 스택의 수 (performance의 차이가 AB test에 의한 효과임을 control 하기 위함) 
  • γt: 시점에 대한 fixed effect (time variant trend를 control 하기 위함: 인터넷 사용률의 증가, 경제 상황의 변화 등) 
  • αi: 기업에 대한 fixed effect (기업 간 time invariant 효과를 제거하기 위함: 초기 스타트업 퍼포먼스 차이, 특정 전략의 존재, 위치 이점, 창업자의 교육 배경, 기업의 자원 등)

참고 사항 

  • Canonical DID with 2WFE에서 아래와 같은 수식을 사용했음. 
  • 아래 식에서 β = treatment group과 counter factual의 treatment effect 차이라고 정의했음. 
  • Treat_i * Post_t로 정의한 것이 위의 모델에서 A/B Testing_it와 같다! (수식 형태가 다르다고 다른 모형이 아님)

모델 결과 해석

위의 모델 식에서 time fixed effect, individual fixed effect, technology stack control을 조합하여 서로 다른 모델을 만들었을 때의 효과를 분석함 

 

(모델 1) [Week FE]

^β = 2.957*** -> AB Test를 사용하는 기업이 그렇지 않은 기업에 비해 방문 횟수가 약 296% 많다 (종속변수에 log 변환 했으므로 % 단위로 해석)

 

(모델 2) [Week FE + Technology Stack Control]

Yit = β (A/B Testing it) + θ (Technology Stackit) + γt +εit

^β = 0.190∗∗∗ -> AB Test를 사용하는 기업이 그렇지 않은 기업에 비해 방문 횟수가 약 19% 많다 

 

(모델 3) [Week FE + Firm FE]

 

Yit = β (A/B Testing it) + αi +γt + εit

^β = 0.553∗∗∗ -> AB Test를 사용하는 기업이 그렇지 않은 기업에 비해 방문 횟수가 약 55.3% 많다

 

(모델 4) [Week FE + Firm FE + Technology Stack Control]

Yit = β (A/B Testing it) + θ (Technology Stackit) + αi + γt + εit

^β = 0.131∗∗∗ -> AB Test를 사용하는 기업이 그렇지 않은 기업에 비해 방문 횟수가 약 13.1% 많다 

코드 구현 

(1) load data

from google.colab import drive
drive.mount('/content/gdrive', force_remount=True)
data = pd.read_csv("/content/gdrive/MyDrive/DIDSampleData/ab_dataDeMean.csv", 
                   sep='delemeter', header=None)

 

(2) firm, time에 대한 고정 효과를 고려하기 위한 변수 생성 

-1) week_id를 고정한 채로 pageview, ABTest, Stack 변수를 집계한 변수 생성 

# compute the mean of log1p_pageviews by week_id
avgW_log1p_pageviews = data.groupby('week_id')['log1p_pageviews'].transform('mean')
# demean log1p_pageviews by subtracting the mean
data['demW_log1p_pageviews'] = data['log1p_pageviews'] - avgW_log1p_pageviews

# compute the mean of log1p_pageviews by week_id
avgW_using_ab_only = data.groupby('week_id')['using_ab_only'].transform('mean')
# demean log1p_pageviews by subtracting the mean
data['demW_using_ab_only'] = data['using_ab_only'] - avgW_using_ab_only

# compute the mean of log1p_stack2 by week_id
avgW_log1p_stack2 = data.groupby('week_id')['log1p_stack2'].transform('mean')
# demean log1p_pageviews by subtracting the mean
data['demW_log1p_stack2'] = data['log1p_stack2'] - avgW_log1p_stack2

 

-2) firm_id를 고정한 채로 pageview, ABTest, Stack 변수를 집계한 변수 생성 

# compute the mean of log1p_pageviews by firm_id
avgF_log1p_pageviews = data.groupby('firm_id')['log1p_pageviews'].transform('mean')
# demean log1p_pageviews by subtracting the mean
data['demF_log1p_pageviews'] = data['log1p_pageviews'] - avgF_log1p_pageviews

# compute the mean of log1p_pageviews by firm_id
avgF_using_ab_only = data.groupby('firm_id')['using_ab_only'].transform('mean')
# demean log1p_pageviews by subtracting the mean
data['demF_using_ab_only'] = data['using_ab_only'] - avgF_using_ab_only

# compute the mean of log1p_stack2 by firm_id
avgF_log1p_stack2 = data.groupby('firm_id')['log1p_stack2'].transform('mean')
# demean log1p_pageviews by subtracting the mean
data['demF_log1p_stack2'] = data['log1p_stack2'] - avgF_log1p_stack2

 

-3) week_id, firm_id를 고정한 채로 pageview, ABTest, Stack 변수를 집계한 변수 생성 

import numpy as np
# compute the mean of the log1p_pageviews column
avg_log1p_pageviews = np.mean(data['log1p_pageviews'])
# subtract the mean from each element in the column and create a new column
data['demWF_log1p_pageviews'] = data['log1p_pageviews'] - avgW_log1p_pageviews - avgF_log1p_pageviews + avg_log1p_pageviews

# compute the mean of the log1p_pageviews column
avg_using_ab_only = np.mean(data['using_ab_only'])
# subtract the mean from each element in the column and create a new column
data['demWF_using_ab_only'] = data['using_ab_only'] - avgW_using_ab_only - avgF_using_ab_only + avg_using_ab_only

# compute the mean of the log1p_pageviews column
avg_log1p_stack2 = np.mean(data['log1p_stack2'])
# subtract the mean from each element in the column and create a new column
data['demWF_log1p_stack2'] = data['log1p_stack2'] - avgW_log1p_stack2 - avgF_log1p_stack2 + avg_log1p_stack2

 

 

(3) 모델에 대한 OLS 생성 

(모델 1) [Week FE]

# Table (2) Column (1) [WeekFE]

# Add dummy variables to explanatory variables
X = sm.add_constant(data[['demW_using_ab_only']])
X = pd.concat([X], axis=1)

# Fit a linear model with clustered standard errors
ols_model = sm.OLS(data['demW_log1p_pageviews'], X)
ols_results = ols_model.fit(cov_type='cluster', cov_kwds={'groups': data['firm_id']})

# Print the regression summary
print(ols_results.summary())

 

 

 

(모델 2) [Week FE + Technology Stack Control]

# Table (2) Column (2) [WeekFE] + [Tech Stack Control]

# Add dummy variables to explanatory variables
X = sm.add_constant(data[['demF_using_ab_only','demF_log1p_stack2']])
X = pd.concat([X], axis=1)

# Fit a linear model with clustered standard errors
ols_model = sm.OLS(data['demF_log1p_pageviews'], X)
ols_results = ols_model.fit(cov_type='cluster', cov_kwds={'groups': data['firm_id']})

# Print the regression summary
print(ols_results.summary())

 

 

 

(모델 3) [Week FE + Firm FE]

# Table (2) Column (3) [WeekFE] + [FirmFE]

# Add dummy variables to explanatory variables
X = sm.add_constant(data[['demWF_using_ab_only']])
X = pd.concat([X], axis=1)

# Fit a linear model with clustered standard errors
ols_model = sm.OLS(data['demWF_log1p_pageviews'], X)
ols_results = ols_model.fit(cov_type='cluster', cov_kwds={'groups': data['firm_id']})

# Print the regression summary
print(ols_results.summary())

 

 

(모델 4) [Week FE + Firm FE + Technology Stack Control]

# Table (2) Column (4) [WeekFE] + [FirmFE] + [TechStack Control]

# Add dummy variables to explanatory variables
X = sm.add_constant(data[['demWF_using_ab_only','demWF_log1p_stack2']])
X = pd.concat([X], axis=1)

# Fit a linear model with clustered standard errors
ols_model = sm.OLS(data['demWF_log1p_pageviews'], X)
ols_results = ols_model.fit(cov_type='cluster', cov_kwds={'groups': data['firm_id']})

# Print the regression summary
print(ols_results.summary())

 

 

질문사항! 

time fixed effect를 모델에 넣은 경우 -> cluster standard error의 기준 = firm 

firm fixed effect를 모델에 넣은 경우 -> cluster standard error의 기준 = time 

time fixed effect, firm fixed effect를 모델에 넣은 경우 -> cluster standard error의 기준 = firm + time 아닌가? 

왜 모두 firm만 cluster standard error로 쓰지?