Meta MMM Robyn Walkthrough 07 - 버짓 얼로케이터로 예산 할당 시뮬레이션 해보기

Meta MMM Robyn Walkthrough 07 - 버짓 얼로케이터로 예산 할당 시뮬레이션 해보기

지금 하려는 것이 무엇인지 확실히 하기 위해서, 먼저 우리가 직전에 했던 것을 상기해보고 시작해야 하겠습니다.

  1. MMM을 처음 실행해 보았음 - 링크
  2. 실행의 결과로 원페이저가 만들어졌고, 그것의 전반적인 결론을 해석했음 - 링크
  3. 원페이저의 상세 데이터를 해석했음 - 링크

종합하면, 모델링의 결과가 나왔고 우리는 그 중 성능이 좋은 모델을 선택합니다. 이 선택의 결과로 로빈은 그 모델에 대해서 설명하는 원페이저를 생성합니다. 우리는 이것을 자세하게 해석하는 과정까지 해본 것이죠.

이제 MMM을 왜 하고 있나? 라는 질문을 다시 던져 봅시다. MMM의 엣지는 채널별 예산 최적화에 있습니다. 특히 로빈은 현재 예산 내에서 수익을 최대화 하거나 특정 타겟 ROAS를 달성하는 예산 배분을 버짓 얼로케이터 라는 기능으로 예측해 줍니다. 이번 튜토리얼에서 할 내용이 이것입니다.

모델을 선택하고 저장하기

원페이저 해석의 결과로 이 모델에 대한 신뢰를 가지게 되었다면, 이 모델에게 예산 최적화를 맞겨볼 수 있습니다. 이를 위해선 먼저 이 모델을 로컬 파일로 저장해줘야 합니다. 공식 튜토리얼 파일인 demo.R에서 아래 부분(Step 4)을 이어서 진행합니다.

Meta MMM Robyn Step 4: Select and save the any model

제 경우엔 ID가 3_204_6 인 모델이 성능이나 설명력이 좋다고 판단하여 이 모델을 저장하려고 합니다. 이럴때는 아래와 같은 코드를 실행해서 변수를 선언 해줍니다.

select_model <- "3_204_6"

이 상태에서 아래와 같이 robyn_write() 함수를 실행해서 이 모델을 로컬 파일로 저장합니다.

ExportedModel <- robyn_write(InputCollect, OutputCollect, select_model, export = create_files)

저장이 올바르게 되었다면 아래 코드를 실행해서 모델의 요약 정보를 확인 해봅니다.

print(ExportedModel)

제 경우엔 이렇게 나옵니다.

Meta MMM Robyn ExportedModel

튜토리얼의 다음 부분에 아래 코드가 있는데요, select_model 에 대한 원페이저 데이터 또는 이미지를 만들 수 있는 명령입니다. export = TRUE 로 한다면 원페이저 이미지도 생성되고, export = FALSE 라면 myOnePager 객체가 가진 원페이저 데이터를 R을 이용해서 조회할 수 있는 상태가 됩니다. 필요하신 경우 활용해 보시기 바랍니다.

myOnePager <- robyn_onepagers(InputCollect, OutputCollect, select_model, export = FALSE)

선택한 모델로 예산 할당 해보기

재미있는 부분이죠. 시작하기 전에 몇가지만 짚고 넘어가봅시다.

robyn_allocator() 함수

예산 할당 기능은 로빈의 robyn_allocator() 가 합니다. 아래 코드를 실행하면 이 함수가 무엇이고 어떤 데이터를 가져다가 쓰는지 알아볼 수 있습니다.

?robyn_allocator

R Studio 우측 하단에 도움말이 생기면서 설명을 보실 수 있을 것입니다. 설명을 보다보면 이 함수가 json_file 이라는 인자(argument)를 받는 것을 알 수 있는데, 우리가 앞 단계에서 로컬 파일로 저장했던 모델을 이 인자에 넣어서 사용할 수 있습니다.

다시 말해서 json_file 은 과거에 저장했던 모델을 import 하는데 사용하면 된다는 것을 알 수 있습니다. 로빈의 다른 많은 함수들도 이 인자를 받을 수 있기 때문에, 한번 저장해 놓았던 모델을 계속해서 재활용하고 업데이트 할 수 있습니다.

미디어 변수들의 순서 재확인

매체별로 예산 할당을 정확하게 하려면, 지금 이 모델에 데이터로써 들어가있는 매체들이 무엇이고, 몇개이고 어떤 순서를 가지고 있는지 정확하게 알고 있어야 합니다. 이것을 보려면 튜토리얼에 있듯이 아래 코드를 실행해 봅니다.

InputCollect$paid_media_spends

InputCollect 객체의 paid_media_spends 가 각 매체의 정보를 가지고 있습니다. 튜토리얼대로 잘 따라왔다면 아래와 같은 순서일 것입니다.

[1] "tv_S"       "ooh_S"      "print_S"    "facebook_S" "search_S"  

본격적으로 매체별로 예산을 할당할때도 위 순서를 기억하고 있다가 하이퍼 파라미터를 넣어줘야 합니다.

시나리오 1: 주어진 예산 안에서 최종 수익을 최대화 하는 예산 배분 찾기

제목 그대로입니다. 튜토리얼 상에서 'Example 1: max_response default setting: maximize response for latest month' 예제를 수행할 것입니다. 코드는 아래와 같은데요, 몇 가지 중요한 옵션들을 함께 설명합니다.

AllocatorCollect1 <- robyn_allocator(
  InputCollect = InputCollect,
  OutputCollect = OutputCollect,
  select_model = select_model,
  # date_range = "all", # Default to "all"
  # total_budget = NULL, # When NULL, default is total spend in date_range
  channel_constr_low = 0.7,
  channel_constr_up = c(1.2, 1.5, 1.5, 1.5, 1.5),
  # channel_constr_multiplier = 3,
  scenario = "max_response",
  export = create_files
)

아래 5개 옵션을 보죠.

Argument Description
date_range 여기에서 지정한 기간 내의 데이터를 예산 배분 시뮬레이션에 활용합니다. 기본값이 all 로 되어있기에 전체 기간을 지정하려면 이 옵션 없이 함수를 호출해도 됩니다. 하지만 현실적으로 최근 기간을 기준으로 예산 분배를 조정하는 것이 적절할 수 있으므로, 이런 경우는 이 옵션에서 특정 구간을 지정해줘야 할 것입니다.
total_budget 위에서 지정한 기간동안 지출한 총 예산을 말합니다. 기본값이 NULL 로 되어있고, 이 의미는 위 기간동안 발생한 모든 지출을 총 예산으로 보겠다는 의미가 됩니다. number type의 값을 입력해서 구체적인 예산을 지정해 줄 수도 있습니다.
channel_constr_low 각 매체에 예산을 재배분 하다보면 특정 매체에 대해서는 예산이 줄어들 수 있겠죠. 이 줄어드는 정도의 하한선을 정하는 옵션이 이것입니다. 위 예시 코드에선 0.7 이 입력되었는데요, 모든 매채에 대해서 기존에 지출했던 예산에서 최소 70% 는 유지를 해달라는 의미가 됩니다.
channel_constr_up 위 옵션의 카운터 파트로, 재분배 시 각 매체에 지출할 예산의 상한선을 정하는 옵션입니다. 위 옵션과는 다르게 총 5개 값을 주었죠. 우리가 앞서 InputCollect$paid_media_spends 객체에서 조회한 매체의 순서와 매핑되어 있습니다. 그래서 일전에 순서가 중요하다고 이야기 했던 것입니다.
channel_constr_multiplier 위 두 옵션으로 각 매체별 하한과 상한이 정해지긴 하지만, 그것이 optimal이 아닐 가능성도 큽니다. 그래서 존재하는 이 옵션은, 위에서 정한 하한과 상한의 갭에 특정한 배율을 곱합니다. 기본은 3, 즉 3배를 곱하게 되어있고 최대 5까지 늘릴 수 있습니다. 예를 들어 하한이 0.7이고 상한이 1.2라면 둘의 갭은 0.5 입니다. 0.5 * 3 = 1.5죠. 이것의 결과로 모델이 상한과 하한의 갭을 최대 1.5까지 늘릴 수 있는 상태에서 최적의 예산 배분을 찾아 주게됩니다.모델러는 직접 정한 상하한 내에서의 결과와, 로빈이 3배로 늘렸을때의 결과 두가지를 모두 받아볼 수 있습니다.
scenario 두 시나리오 중 하나를 선택할 수 있습니다. "max_response" 는 정해진 예산 안에서 최대의 수익을 만드는 모델링 시나리오 이며, "target_efficiency" 는 특정 ROAS나 CPA를 달성하는 예산을 찾는 시나리오 입니다.

이 옵션들을 유념한 상태에서 예제 코드를 실행하면 결과를 보여주는 원페이저가 파일로 생성됩니다. 생성된 디렉토리로 가서 파일을 열어보세요. 총 3가지 유형으로 데이터를 제시 하는데요, 하나씩 해석해 봅시다.

Total Budget Optimization Result (scaled up to 157 weeks)

Meta MMM Robyn budget allocator onepager Total Budget Optimization Result
  • Initial은 원본 데이터에서 뽑은 수치입니다. ROAS는 1.67, 총 예산은 12.6M, 총 수익은 21.1M 입니다.
  • Bounded는 우리가 직접 channel_constr_lowchannel_constr_up 에 입력한 옵션을 기준으로 모델이 예산 배분을 최적화 했을 때의 결과입니다. 12.6M 만큼의 동일한 예산으로 수익을 24.7M로 ROAS를 1.96으로 끌어올 릴 수 있다고 예상하네요.
  • Bounded x3는 channel_constr_multiplier 에서 지정된 3배수만큼 모델이 더 넓은 범위를 쓰면서 예산 배분을 최적화 했을 때의 결과입니다. 역시 같은 예산으로 수익을 35M, ROAS를 2.79로 66.3% 끌어올릴 수 있다고 예상합니다.

Budget Allocation per Paid Media Variable per Week

Meta MMM Robyn budget allocator onepager Budget Allocation per Paid Media Variable per Week

이 차트는 수치를 한 주 단위로 좁혀서 비교할 수 있도록 제시하고 있습니다. Initial에 비해 Bounded와 Bounded x3의 예산 배분 구성과 수익이 어떻게 달라져 있는지 살펴보는 것에 의미가 있습니다. Bounded x3를 보면 더 확실한데요, ooh_S 지출을 줄이면서 그 예산으로 facebook_S 에 대한 투자를 늘리는 것을 권장하고 있네요.

Simulated Response Curve per Week

Meta MMM Robyn budget allocator onepager Simulated Response Curve per Week

각 매체별로 예산을 재배분 하는 것이 수익 곡선 상에서는 어떤 모습으로 표현되는지를 확인할 수 있습니다. Bounded 와 Bounded x3이 색으로 구분되어 곡선 위에 찍혀있죠. 각각 Initial 대비 어떤 방향으로 얼마나 움직였는지를 쉽게 볼 수 있습니다. 각 점에서부터 점선으로 뻗어나가는 데이터는 Bounded 구간의 상한과 하한을 적용했을 때 점이 위치할 좌표를 의미합니다. 참고 삼아서 보기만 해도 됩니다.

종합해보면 모델이 더 많은 자유도를 가지고 모델링한 Bounded x3 설정으로 더 큰 수익을 기대할 수 있을 것 같죠. 현재의 12.6M 예산으로 최대 수익을 낼 수 있는 예산 배분을 이런 식으로 추천 해줍니다.

시나리오 2: 특정 ROAS를 달성하는 예산 찾기

두번째 시나리오는 예산 자체를 바꿔서라도 특정 ROAS를 맞출 수 있도록 하는 지점을 찾는 것을 목표로 합니다. 튜토리얼 상에서 'Example 3: Use default ROAS target for revenue or CPA target for conversion' 부분을 해볼 것입니다.

예제 코드는 다음과 같습니다. 참고로 아래 코드에는 target_value 가 주석처리 되어 있는데요, 이런 경우 기본값인 ROAS 80%가 적용됩니다. 즉 Initial ROAS에서 20가 감소하는 예산을 찾게 된다는 것이죠. 일단 그대로 복사해서 실행해 보겠습니다.

AllocatorCollect3 <- robyn_allocator(
  InputCollect = InputCollect,
  OutputCollect = OutputCollect,
  select_model = select_model,
  # date_range = NULL, # Default: "all" available dates
  scenario = "target_efficiency",
  # target_value = 2, # Customize target ROAS or CPA value
  export = create_files
)

그런데 제 경우엔 잘 되지 않았습니다. 그림에 표시해 놓았지만 두번째 차트엔 ROAS 1.34를 만족하도록, 세번째 차트엔 ROAS 1을 만족하도록 계산이 되어야 하지만 전혀 이루어지지 않았네요.

Meta MMM Robyn budget allocator onepager target_efficiency

그래서 설정을 조금 바꿔서 진행했습니다. 이렇게 하면 최근 56주 데이터만을 대상으로 하고 ROAS 3을 만족하는 예산 배분을 계산하게 될 것입니다.

  • date_range = "last_56"
  • target_value = 3

결과의 일부는 이렇습니다. 두번째 차트가 ROAS 3을 잘 타겟해서 예산을 조정했네요. 예산을 늘려서 달성한 것은 아니고 45.2%를 줄여서 ROAS를 맞췄습니다. 기본적으로 예산 규모가 작을 때 ROAS가 높아지는 경향이 있는 점, 그리고 각 매체의 saturation 지점에 가까워 질수록 ROAS가 낮아지는 점 등을 반영하다보면 예산을 줄여서 ROAS를 맞추는 쪽으로 모델링이 될 수 있을 것입니다.

Meta MMM Robyn budget allocator onepager target_efficiency

마치며 - 총평과 다음 단계

로빈의 버짓 얼로케이터를 시뮬레이션 해보았습니다. 최대 수익을 올릴 수 있도록 예산을 배분해주는 max_response 옵션과, 특정 타겟 ROAS를 달성하도록 예산을 조정해주는 target_efficiency 모두를 테스트 했습니다.

대부분의 광고주는 max_response 옵션에 더 관심이 많을 것이고, 캠페인 초기에 예산을 늘려가는 과정에서는 target_efficiency 옵션이 도움이 될 것 같네요. 비록 테스트 데이터셋에서target_efficiency 가 제대로 동작하지 않았지만, 이 모드가 로빈 3.10 버전에서 새로 생긴 기능이라서 개선의 여지가 있을 것으로 생각합니다.

다음에는 선택한 모델에 최근 데이터를 더해서 모델을 리프레시하는 과정을 진행해 보겠습니다.