Adstock 심화 — 광고 효과의 잔향을 모델링하는 법
MMM의 절반은 adstock 함수를 잘 잡는 일입니다. Geometric·Delayed·Weibull 세 가지 형태와 채널별 추천 파라미터, 그리고 잘못 잡았을 때 채널 기여도가 휘는 방식을 마케터 시선에서 정리합니다.
들어가며 — 마케터가 이 글을 읽어야 하는 이유
MMM 채널 기여도가 통념과 어긋나게 나왔다면 90%는 adstock 함수를 잘못 잡은 탓입니다. TV 광고가 즉시 반응으로 모델링되거나, 검색 광고에 4주 잔향이 잡히면 채널 계수는 휘어집니다. 그 휘어진 계수가 분기 예산 재배분 슬라이드에 그대로 올라갑니다.
왜 TV 광고 잔향이 검색 광고보다 길어야 할까요? 검색 광고는 구매 의도가 이미 있는 사람에게 닿아 클릭→구매가 당일 일어납니다. TV 브랜드 광고는 아직 구매 의도가 없는 사람에게 닿아 며칠~몇 주 뒤에 검색하고, 그 검색이 또 며칠 뒤 구매로 이어집니다. 두 채널의 causal pathway가 다르기 때문에 adstock 형태도 달라야 합니다. 같은 형태로 잡으면 TV 기여도가 과소평가되거나 검색 기여도가 과대평가됩니다.
이 글은 adstock의 세 가지 표준 형태, PyMC-Marketing으로 fit하는 코드, decay 파라미터별 잔향 시뮬레이션, posterior predictive 잔차 시각화까지 마케터 시선에서 정리합니다. mmm-introduction에서 MMM 큰 그림을 잡았다면 이 글이 adstock 심화 단계입니다.
광고는 본 즉시 사라지지 않습니다. TV 브랜드 광고를 본 사람은 며칠 뒤에 검색하고, 검색 결과를 본 며칠 뒤에 구매할 수 있습니다. 광고비를 그 주 매출과만 매칭하면 진짜 효과의 일부가 누락됩니다. 광고비 시계열 에 adstock 함수를 적용해 변환된 시계열 를 만들면, 회귀 모델은 매출과 의 관계를 학습합니다. adstock이 잔향을 잘 표현했다면 회귀 계수는 안정적이고, 그렇지 않으면 다른 채널·외생 변수로 효과가 새어 나갑니다.
Adstock 형태 — Geometric·Delayed·Weibull
Geometric — 가장 단순하고 가장 흔함
는 잔향 비율(decay rate)입니다. 면 100짜리 광고비를 쓴 다음 주에도 50, 그 다음 주에 25, 12.5… 식으로 감쇠합니다. 이 형태는 즉시 효과가 가장 크고 시간이 지날수록 매끄럽게 줄어듭니다. 검색·디스플레이처럼 즉시 반응이 큰 채널에 잘 맞습니다.
절반 효과 도달 시간 (half-life)
decay rate 를 마케터 단어로 번역하려면 절반 효과 도달 시간(half-life)이 직관적입니다.
| half-life (주) | 직관 | |
|---|---|---|
| 0.2 | 0.4 | 거의 즉시 |
| 0.5 | 1.0 | 1주 후 절반 |
| 0.7 | 1.9 | 약 2주 후 절반 |
| 0.85 | 4.3 | 한 달 후 절반 |
분석 결과를 마케팅팀에 설명할 때 “decay 0.7”보다 “효과의 절반이 약 2주에 사라짐”이 훨씬 잘 전달됩니다.
Delayed Adstock — peak가 즉시가 아닌 채널
브랜드 광고는 즉시 반응이 아닙니다.
TV·OOH·BTL 같은 브랜드 광고는 본 즉시 구매가 일어나지 않습니다. 며칠 ~ 몇 주 뒤에 검색·매장 방문·구매로 이어집니다. geometric으로 모델링하면 첫 주 효과가 가장 크다고 가정하니까 잔차에 패턴이 남습니다.
Weibull adstock는 스케일, 는 모양 파라미터입니다. 일 때 peak가 이 아닌 다른 시점으로 이동합니다.
Hill adstock — Robyn에서 자주 쓰는 형태가 peak 시점, 가 곡선 가파름을 잡습니다. PyMC-Marketing·Robyn 모두 이 패밀리를 지원합니다.
PyMC fit과 잔향 시뮬레이션
GeometricAdstock fit 코드
import pandas as pdimport pymc as pmfrom pymc_marketing.mmm.transformers import GeometricAdstockfrom pymc_marketing.mmm import MMM, GeometricAdstockSaturation
# df: 주 단위 데이터 (date, sales, spend_meta, spend_naver, spend_tv, ...)df = pd.read_csv("weekly_data.csv", parse_dates=["date"])
# 채널별 adstock 형태 지정adstock = GeometricAdstock(l_max=8) # 최대 lag window = 8주
mmm = MMM( date_column="date", channel_columns=["spend_meta", "spend_naver", "spend_tv"], adstock=adstock, # 전 채널 동일 형태 적용 saturation=GeometricAdstockSaturation(), control_columns=["holiday", "promo"], # 외생 변수)
# NUTS 샘플러 (기본값: 2 chains, 1000 draws)with mmm.build_model(df, target_column="sales"): idata = pm.sample( draws=1000, tune=500, target_accept=0.9, random_seed=42, return_inferencedata=True, )
# 수렴 진단import arviz as azprint(az.summary(idata, var_names=["alpha"])[ ["mean", "sd", "r_hat"] ])# r_hat < 1.01 이어야 수렴 OK출력 해석: alpha 파라미터의 posterior mean이 채널별로 다르게 나옵니다. TV가 0.75, Naver 검색이 0.35라면 TV의 잔향이 2.4배 길다는 의미입니다. r_hat이 1.01을 넘으면 chain이 수렴하지 않은 것이고, target_accept=0.95로 높이거나 tune 기간을 늘려야 합니다.
decay 파라미터별 잔향 시뮬레이션
import numpy as npimport matplotlib.pyplot as plt
def geometric_adstock_series(spend_series, alpha, l_max=12): """단일 광고 집행 이후 잔향 시계열 계산""" n = len(spend_series) + l_max A = np.zeros(n) for t, x in enumerate(spend_series): A[t] = x for t in range(1, n): A[t] += alpha * A[t - 1] return A[:len(spend_series) + l_max]
# 1주 집행 후 8주 동안 잔향 비교impulse = np.array([100.0] + [0.0] * 11) # 1주 집행 후 11주 공백weeks = np.arange(12)alphas = [0.2, 0.5, 0.7, 0.85]
plt.figure(figsize=(9, 5))for a in alphas: resp = geometric_adstock_series(impulse, alpha=a)[:12] half_life = -np.log(2) / np.log(a) plt.plot(weeks, resp, marker='o', ms=4, label=f"α={a}, half-life={half_life:.1f}주")
plt.xlabel("집행 후 경과 주"); plt.ylabel("잔향 강도 (원래 집행 = 100)")plt.title("Geometric Adstock — decay 파라미터별 잔향 비교")plt.legend(); plt.tight_layout(); plt.show()# → alpha=0.85 (TV)는 8주 뒤에도 37%, alpha=0.2 (검색)는 1주 만에 거의 소멸이 plot을 마케팅팀 회의에 띄우면 “TV가 즉시 효과 곡선이라면 보고 직관적으로 이상한데”가 바로 나옵니다. prior 설정의 직관 검증으로 가장 효과적인 sanity check입니다.
채널 기여도 영향과 잔차 진단
같은 데이터에 대해 adstock 형태를 바꾸면 채널 기여도가 어떻게 흔들리는지가 가장 중요한 점입니다.
| Adstock | TV 계수 | TV 기여도 비중 | Search 계수 |
|---|---|---|---|
| geometric =0.7 | 0.4 | 12% | 1.2 |
| delayed peak=2주 | 0.65 | 19% | 0.95 |
같은 데이터인데 TV 기여도가 12% → 19%로 바뀌고, search가 그만큼 빠집니다. adstock 형태를 잘못 잡으면 채널 간 기여도 분배가 흔들리고, 이건 분기 예산 재배분 의사결정을 직접 흔듭니다.
posterior predictive 잔차 시각화 — 잔차로 adstock 오설정 잡기
import matplotlib.pyplot as plt
# posterior predictive 체크ppc = mmm.sample_posterior_predictive(idata, df)# ppc["sales"]: shape (chains*draws, n_weeks)
sales_actual = df["sales"].valuessales_pred_mean = ppc["sales"].mean(axis=0)residuals = sales_actual - sales_pred_mean
fig, axes = plt.subplots(2, 1, figsize=(12, 7))
# 상단: 실제 vs 예측axes[0].plot(df["date"], sales_actual, label="실제 매출", lw=1.5)axes[0].plot(df["date"], sales_pred_mean, label="예측 (posterior mean)", ls="--", lw=1.5)axes[0].fill_between( df["date"], ppc["sales"].quantile(0.05, axis=0), ppc["sales"].quantile(0.95, axis=0), alpha=0.2, label="90% PI")axes[0].legend(); axes[0].set_title("Posterior Predictive Check")
# 하단: 잔차axes[1].axhline(0, color="red", ls="--")axes[1].bar(df["date"], residuals, width=5, color="steelblue", alpha=0.6)axes[1].set_title("잔차 — 패턴이 남으면 adstock 오설정 신호")
plt.tight_layout(); plt.show()# → 잔차가 큰 TV 집행 직후 양의 연속 패턴을 보이면 delayed adstock으로 교체잔차가 특정 캠페인 주 이후 며칠간 지속적으로 양수라면, 모델이 그 광고 효과의 후행분을 잡지 못하고 있다는 신호입니다. 이때는 geometric → delayed (Weibull 또는 Hill) adstock으로 바꿔야 합니다. 잔차가 random walk에 가까우면 adstock 형태가 맞는 것입니다. 오설정이 의심될 때는 mmm-validation-holdout의 posterior predictive 검증 절차를 병행하세요.
Adstock 파라미터 학습 vs 고정
데이터에서 학습할까, 고정할까
PyMC-Marketing은 adstock 파라미터를 prior와 함께 학습합니다. 하지만 데이터가 부족하면(주 단위 2년 = 104주) 다중공선성으로 학습이 불안정해집니다. 그럴 땐 두 옵션이 있습니다.
- 학습 — prior로 평균을 잡고 데이터에 맡김. 데이터 충분(2년+), 시장 변동 큼
- 고정 — 분석가가 직접 값을 박아 넣음. 데이터 부족(1년 미만), 통념 강함
분기 단위 adstock 모니터링
학습한 adstock이 분기마다 휙휙 바뀌면 모델이 불안정합니다. 분기 결과로 다음 분기 prior를 업데이트하는 흐름을 둡니다. 사실상 채널 잔향에 대한 베이지안 학습 루프입니다. 이 루프가 1년 이상 쌓이면 시장 평균이 아닌 우리 회사 데이터에 기반한 adstock 룩업 테이블이 만들어집니다.
실무 워크플로 — 분기 1회 adstock 점검
| 단계 | 활동 | 출력 |
|---|---|---|
| 1 | 작년 동분기 adstock 결과 회수 | ·peak 시계열 |
| 2 | 채널 변경 사항 점검(크리에이티브·매체) | 변화 리스트 |
| 3 | prior 평균을 작년 결과로 잡고 stddev 확대 | 새 prior |
| 4 | 모델 fit 후 posterior 검토 및 잔차 점검 | 새 adstock·잔차 plot |
| 5 | 마케팅팀과 직관 검증 | 통념 일치 여부 |
이 다섯 단계면 30분~1시간 회의 한 번으로 끝냅니다. adstock 점검 후 saturation 파라미터로 넘어가는 흐름은 mmm-saturation-curves에서 이어집니다.
함정 모음
- 너무 긴 tail — 가 0.95 근처면 효과가 무한정 누적되어 회귀에서 불안정. 일반적으로 0.85 정도 상한
- 외생 변수와 혼동 — 시즌·할인이 광고비와 같이 움직이면 잔향이 실제보다 길게 추정됨
- 부정확한 lag window — Weibull·Hill 류는 lag window L을 충분히 길게 잡지 않으면 tail이 잘림
- 샘플 누락 — 신규 채널의 첫 8~12주는 cold start. 이 시기 데이터를 그대로 쓰면 adstock이 왜곡
- 리포지셔닝 — 같은 채널이라도 캠페인 톤·크리에이티브가 바뀌면 adstock도 변함. 분기마다 재추정
마치며
adstock은 MMM에서 가장 자주 잘못 잡히는 부분이고, 잘못 잡혔을 때 채널 기여도가 가장 크게 휘는 부분입니다. TV 광고 잔향이 검색보다 길어야 하는 이유를 인과 경로로 이해하고, PyMC-Marketing으로 직접 fit하고, 잔차 plot으로 오설정을 잡는 루프가 분기마다 돌아야 합니다.
adstock을 잘 잡고 나면 saturation 곡선이 의미 있어지고, saturation이 의미 있어야 한계 ROAS 기반 예산 재배분이 신뢰할 수 있습니다. 세 단계가 이어지는 흐름입니다.
다음에 읽을 글- MMM saturation 곡선 — adstock 변환 후 이어지는 단계
- MMM 모델 검증과 holdout — adstock 오설정 시 posterior predictive 잔차 확인
- bayesian-mmm-pymc-marketing — PyMC-Marketing 전체 fit 흐름
참고
- Jin et al., “Bayesian Methods for Media Mix Modeling with Carryover and Shape Effects” (Google): https://research.google/pubs/pub46001/
- Robyn, “Adstock implementation”: https://facebookexperimental.github.io/Robyn/
- PyMC-Marketing, “Adstock transformations”: https://www.pymc-marketing.io/en/stable/notebooks/general/transformations.html
- “Carryover effects in advertising” (Tellis 2009): https://psycnet.apa.org/record/2009-04609-001
- Recast, “Adstock explained”: https://getrecast.com/adstock/
퍼포먼스 마케팅 카테고리의 다른 글
전체 보기 →-
2026·06·05
ROAS 보고서가 늘 거짓말하는 이유 — incrementality 3대장
Meta 대시보드 ROAS 5가 실제로는 1.x인 이유. last-click·view-through·incremental 세 가지 ROAS의 차이와, holdout·geo-lift·ghost ads·conversion lift로 진짜 증분을 측정하는 법을 마케터 시선으로 정리합니다.
-
2026·05·16
DSP·SSP·DMP 인프라 해부 — 매체 영업 미팅에서 듣는 약자들의 정체
매체 영업 미팅에서 DSP, SSP, DMP, CDP, ad exchange, 헤더비딩 같은 약자들이 쏟아집니다. 각각이 어느 회사이고, 광고비가 어디로 흘러가며, 마케터가 의사결정할 때 어떤 의미를 갖는지 한 글에 정리합니다.
-
2026·05·16
Lookback window가 ROAS를 바꾸는 법 — click 7d, view 1d, 28d, 90d의 차이
같은 캠페인이라도 attribution lookback window를 click 7d / view 1d / 28d / 90d 중 어느 걸로 보느냐에 따라 ROAS가 두 배까지 차이납니다. 매체별 default와 그것을 마케터가 어떻게 의사결정에 써야 하는지를 정리합니다.
-
2026·05·09
Brand lift study 설계 — 광고가 인지·호감도를 끌어올렸나
브랜드 광고는 ROAS로 잡히지 않고 인지·호감도·구매의향으로만 측정됩니다. 노출 그룹과 비노출 그룹을 비교하는 brand lift study의 설계, 표본 계산, 실무 함정을 마케터 시선에서 정리.