ROAS 계산CPA 계산파이썬
0으로 나눌 수 없는 광고 지표는 어떻게 계산할까
그로스앤디 · 2026-08-26 발행· 9분 읽기
목차
코드 해부 1편에서는 JSON 파일이 Python으로 들어와 결과 파일로 나가는 흐름을 살펴봤습니다. 2편에서는 목표와 캠페인을 딕셔너리·리스트·집합에 담았고, 3편에서는 잘못된 값이 계산 단계로 넘어오지 않도록 검증과 예외 처리를 적용했어요.
이제 신뢰할 수 있는 광고 데이터를 마케터가 판단에 사용할 수 있는 성과 지표로 바꿀 차례입니다.
광고비·노출·클릭·전환·매출
→ CTR·CVR·CPC·CPA·ROAS
CTR·CPA·ROAS는 캠페인을 비교하고, 예산을 조정하고, 목표 달성 여부를 판단하는 (마케터에게 익숙한) 기준이죠.
하지만 엑셀 셀마다 수식을 다시 쓰거나 매체별 리포트에서 서로 다른 계산 규칙을 사용하면 같은 데이터도 다른 결과로 보일 수 있어요.
계산식을 함수규칙으로 만들면 모든 캠페인에서 같은 기준을 반복하며 적용할 수 있습니다. 이후 광고 리포트나 대시보드를 자동화할 때도 이 함수를 그대로 재사용할 수 있고, 전환이나 노출이 0인 상황을 억지로 숫자 0으로 표시하는 오류도 막을 수 있죠.
이번 글에서는 익숙한 마케팅 수식을 안전하고 재사용 가능한 Python 함수로 바꾸는 과정을 살펴봅니다.
마케팅 수식 자체는 익숙할 수 있어요. 하지만 수식을 코드로 옮길 때, 새로운 질문이 생길 수 있어요.
- 노출이 0이면 CTR은 어떻게 표시할까?
- 전환이 0이면 CPA를 0이라고 해도 될까?
- 같은 계산을 캠페인별 성과와 전체 성과에 어떻게 재사용할까?
- 계산값은 언제 반올림해야 할까?
캠페인 지표의 다섯 가지 계산식
이 프로그램이 계산하는 지표는 다음과 같습니다.
| 지표 | 계산식 | 의미 |
|---|---|---|
| CTR | 클릭 ÷ 노출 × 100 | 노출 중 클릭 비율 |
| CVR | 전환 ÷ 클릭 × 100 | 클릭 중 전환 비율 |
| CPC | 광고비 ÷ 클릭 | 클릭 한 번당 비용 |
| CPA | 광고비 ÷ 전환 | 전환 한 건당 비용 |
| ROAS | 매출 ÷ 광고비 × 100 | 광고비 대비 매출 비율 |
예제 캠페인의 값은 다음과 같아요.
campaign = {
"spend": 300000,
"impressions": 50000,
"clicks": 1200,
"conversions": 34,
"revenue": 1050000,
}
직접 계산하면 다음 결과가 나옵니다.
CTR = 1,200 ÷ 50,000 × 100 = 2.40%
CVR = 34 ÷ 1,200 × 100 ≈ 2.83%
CPC = 300,000 ÷ 1,200 = 250원
CPA = 300,000 ÷ 34 ≈ 8,823.53원
ROAS = 1,050,000 ÷ 300,000 × 100 = 350%
0으로 나누면 멈춰버리는 계산식
(미집행 캠페인을 포함하여) 광고 노출이 0이거나 전환이 한 건도 없는 캠페인이 생기는건 실무 마케팅에서 흔하게 일어날 수 있는 일이죠 .
campaign = {
"spend": 100000,
"impressions": 0,
"clicks": 0,
"conversions": 0,
"revenue": 0,
}
이때 clicks / impressions를 그대로 실행하면 ZeroDivisionError가 발생합니다.
분모가 0인 지표는 0이라고 단정할 수도 없습니다.
전환이 0일 때 CPA 0원이라고 표시하면 비용 없이 전환을 만든 것처럼 오해할 수 있어요. 하지만 실제 의미는 “계산할 수 없음”에 가깝습니다.
계산할 수 없는 항목 분리하기
프로그램은 모든 지표에서 반복되는 나눗셈 규칙을 divide_or_none()으로 분리합니다.
def divide_or_none(numerator, denominator, multiplier=1):
if denominator == 0:
return None
return numerator / denominator * multiplier
이 함수의 입력은 세 가지입니다.
numerator: 분자denominator: 분모multiplier: 계산 뒤 곱할 값, 기본값은 1
이때 함수는 분모가 0이면 나누지 않고 None을 반환합니다.
None은 계산 결과 0이 아니라 “현재 값으로는 계산할 수 없음”이라는 상태를 전달합니다.
divide_or_none(34, 1200, 100) # 2.8333...
divide_or_none(300000, 34) # 8823.529...
divide_or_none(300000, 0) # None
None을 반환하면 오류로 프로그램 전체를 멈추지 않고, 계산 불가 상태를 다음 함수까지 데이터로 전달할 수 있습니다.
기본 매개변수를 계산식에 넣기
CTR·CVR·ROAS는 백분율이므로 마지막에 100을 곱합니다. CPC·CPA는 금액이므로 그대로 사용하고요.
multiplier=1이라는 기본 매개변수 덕분에 하나의 함수를 두 방식으로 사용할 수 있습니다.
# 비율 지표
divide_or_none(clicks, impressions, 100)
# 금액 지표
divide_or_none(spend, clicks)
별도의 calculate_percent()와 calculate_currency()를 만들지 않아도 공통 규칙을 재사용할 수 있습니다.
다섯 지표를 하나의 함수로 묶기
calculate_metrics()는 캠페인 딕셔너리를 받고 다섯 지표가 담긴 새 딕셔너리를 반환합니다.
def calculate_metrics(campaign):
return {
"ctr": divide_or_none(
campaign["clicks"], campaign["impressions"], 100
),
"cvr": divide_or_none(
campaign["conversions"], campaign["clicks"], 100
),
"cpc": divide_or_none(campaign["spend"], campaign["clicks"]),
"cpa": divide_or_none(campaign["spend"], campaign["conversions"]),
"roas": divide_or_none(campaign["revenue"], campaign["spend"], 100),
}
이때 입력 데이터는 수정하지 않습니다. 같은 캠페인을 넣으면 같은 지표 딕셔너리가 나오기 때문에 함수만 떼어 확인하기도 쉬워요.
캠페인 dict
→ calculate_metrics()
→ 지표 dict
함수는 입력과 출력 사이의 한 가지 규칙을 만드는 단위죠.
같은 계산 함수 재활용하기
전체 캠페인 성과를 계산할 때도 새로운 수식을 만들 필요는 없어요.
totals = {
"spend": sum(campaign["spend"] for campaign in campaigns),
"impressions": sum(campaign["impressions"] for campaign in campaigns),
"clicks": sum(campaign["clicks"] for campaign in campaigns),
"conversions": sum(campaign["conversions"] for campaign in campaigns),
"revenue": sum(campaign["revenue"] for campaign in campaigns),
}
totals도 calculate_metrics()가 요구하는 키를 가지고 있으므로 같은 함수에 넣을 수 있습니다.
metrics = calculate_metrics(totals)
캠페인 한 건과 전체 합계가 같은 데이터 모양을 사용하기 때문에 계산 함수를 재사용할 수 있습니다.
계산값과 표시값 분리하기
때론, 계산 결과가 딱 떨어지지 않을 때도 있죠.
8823.529411764706
round_metrics()는 결과를 화면과 JSON에서 읽기 쉬운 소수 둘째 자리로 정리합니다.
def round_metrics(metrics):
rounded = {}
for name, value in metrics.items():
rounded[name] = None if value is None else round(value, 2)
return rounded
여기서도 None은 그대로 유지합니다.
계산 불가 상태를 숫자 0으로 바꾸지 않기 위해서예요.
화면에 출력할 때는 단위까지 붙입니다.
def format_percent(value):
return "계산 불가" if value is None else f"{value:,.2f}%"
def format_currency(value):
return "계산 불가" if value is None else f"{value:,.0f}원"
원자료
→ 계산값
→ 반올림값
→ 사람이 읽는 표시값
이 경계를 나누면 계산 규칙과 화면 표현을 서로 독립적으로 바꿀 수 있습니다.
지표 하나를 직접 다시 만들어보세요
다음 순서로 CPA 계산을 자료 없이 다시 작성해보세요.
- 광고비와 전환 수를 받는 함수를 만든다.
- 전환 수가 0이면
None을 반환한다. - 그렇지 않으면 광고비를 전환 수로 나눈다.
- 결과가 숫자면 원화 문자열로 표시한다.
- 전환 수 34와 0을 각각 넣어 확인한다.
안전한 계산은 정상 값에서만 정답을 내는걸 넘어, 계산할 수 없는 값을 정직하게 표시하는 것까지 포함합니다.
다음 글인 전체 성과를 하나로 합치는 조건문·반복문·집계에서는 계산된 지표를 목표 ROAS·CPA와 비교합니다. 조건문과 반복문이 개별 캠페인의 상태를 판정하고,
정상 캠페인만 모아 전체 성과를 만드는 과정을 살펴볼게요.
관련 키워드
ROAS 계산CPA 계산CTR 계산파이썬 함수ZeroDivisionError