디지털 광고의 입찰 (Bidding in Digital Advertising)
광고주가 사용자에게 광고를 노출하기 위해 지불할 의향이 있는 금전적 가치를 설정하는 과정.
- 입찰 (Bid): 광고주가 원하는 액션(action)에 대해 지불하고자 하는 최대 금액입니다. 주로 세 가지 주요 액션이 있음:
- 클릭 (Click): PPC (Pay-Per-Click). 검색 광고나 소셜 미디어 광고에서 사용됨. 사용자가 광고를 클릭할 때 비용이 부과됨.
- 노출 (Impression): 더 많은 잠재고객에게 도달하기 위해 비용을 지불하며, 주로 브랜드 인지도 캠페인에 사용함.
- 전환 (Conversion): 사용자가 구매나 뉴스레터 구독과 같은 특정 행동을 완료했을 때만 비용을 지불함. 원하는 액션이 완료되었을 때 비용이 부과됨.
- 경매 환경 (Auction Environment): Google, Facebook 등과 같은 플랫폼에서 여러 광고주가 광고 게재 위치를 두고 경쟁하는 환경을 의미함.
입찰 최적화 (Bidding Optimization)
예산 제약 내에서 광고 노출 극대화, 전환 증대, 또는 투자 수익률(ROI) 개선과 같은 특정 목표를 달성하기 위해 디지털 광고 경매에서 전략적으로 입찰가를 설정하는 과정.
검색 광고 경매 (Search Ad Auctions)
광고주는 키워드와 입찰가를 제출함. 광고주의 키워드가 사용자의 검색어와 일치하면 해당 광고주는 경매에 참여하게 됨.
작동 방식:
- 키워드 매칭 (Keyword Matching): 사용자가 “러닝화”를 검색하면, 해당 키워드를 등록한 광고주들이 광고 위치를 두고 입찰함.
- 입찰 및 순위 결정 (Bidding and Ranking): 광고주들은 키워드에 대한 입찰가를 제출함. 광고 플랫폼은 입찰가와 품질 점수(Quality Score) 같은 다른 요소를 기반으로 광고 순위를 매김.
- 품질 점수 조정 (Quality Score Adjustment): 광고, 랜딩 페이지, 그리고 예상 클릭률(CTR)의 관련성과 품질을 측정하는 지표. 품질 점수가 높으면 더 낮은 비용으로 더 좋은 광고 위치를 차지할 수 있음.
- 광고 게재 (Ad placement): 가장 높은 순위의 광고가 검색 결과 페이지의 가용한 광고 슬롯에 노출됨.
경매 유형 (Auction Types)
최고가 경매 (First Price Auction)
최고가 경매에서는 가장 높은 금액을 입찰한 사람이 자신이 입찰한 금액을 그대로 지불함. 이 방식은 입찰자가 자신의 실제 가치대로 입찰하도록 유도함. 왜냐하면 이기면 그 금액을 지불해야 한다는 것을 알기 때문.
- 지불 금액: 자신이 입찰한 금액.
- 입찰 전략: 입찰가 조정 (Bid shading) - 과도한 지불을 피하기 위해 실제 가치보다 낮게 입찰.
차가 경매 (Second Price Auction)
차가 경매에서는 가장 높은 금액을 입찰한 사람이 이기지만, 두 번째로 높은 입찰가에 약간의 추가금(예: $0.01)을 더한 금액을 지불함. 이 방식은 입찰자가 자신의 실제 가치를 입찰하도록 유도함. 이기기 위해 필요한 만큼만 지불하면 되기 때문.
- 지불 금액: 두 번째로 높은 입찰가 + 약간의 추가금
- 입찰 전략: 자신의 실제 가치대로 입찰
일반화된 차가 경매 (Generalized Second Price Auction, GSP)
온라인 광고에서 사용되는 차가 경매의 변형으로, 여러 개의 광고 슬롯이 존재함. 광고주들이 이 슬롯들을 두고 입찰하며, 가장 높은 입찰자가 첫 번째 슬롯을, 두 번째로 높은 입찰자가 두 번째 슬롯을 차지하는 식. 각 광고주는 자신 바로 아래 순위의 광고주가 제시한 입찰가를 지불함.
- 특징: 여러 개의 광고 슬롯.
- 지불 금액: 각 광고주는 자신 바로 아래 순위의 광고주가 제시한 입찰가를 지불함.
플랫폼별 경매 방식
- Google & Microsoft Bing:
- 최고가 경매 (First Price Auction)
- 단순하고 프로그래매틱 광고 환경과 잘 맞기 때문에 선택됨. 또한, 입찰가 조정(bid shading) 가능성을 줄여 더 높은 입찰을 유도함.
- Amazon & Walmart:
- 일반화된 차가 경매 (GSP, Generalized Second Price Auction)
- 여러 광고 슬롯에 적합하고, 광고주들이 자신의 실제 가치를 입찰하도록 유도하기 위해 선택됨. 관련성 높은 광고를 노출하여 사용자 경험을 개선.
실제 가치 추정 (True Value Estimation)
추정은 주로 세 가지 요소에 기반함:
-
클릭률 (Click-Through Rate, CTR): 광고가 노출되었을 때 사용자가 클릭할 예상 확률.
-
전환율 (Conversion Rate, CR): 사용자가 광고를 클릭한 후 원하는 행동(예: 구매, 가입)을 완료할 예상 확률.
-
전환당 수익 (Return per Conversion): 각 전환으로부터 발생할 것으로 예상되는 수익.
실제 가치 (True Value):
조정 계수 (Shading Factor):
최적의 입찰가를 결정하기 위해 실제 가치에 적용하는 승수(multiplier). 이는 경쟁, 예산 제약, 위험 감수 수준과 같은 요소를 고려함.
예를 들어, 조정 계수가 0.8이라는 것은 광고주가 경매에서 이기는 것과 과도한 지불을 피하는 것 사이의 균형을 맞추기 위해 자신의 예상 실제 가치의 80%를 입찰할 의향이 있음을 의미함.
최적 입찰가 탐색 방법
디지털 광고 경매에서 최적의 입찰가를 찾는 세 가지 주요 접근 방식이 있음.
- 게임 이론 (Game Theory): 내쉬 균형(Nash equilibrium)에 도달하기 위해 경쟁 행동을 모델링.
- 운영 연구, 최적화 (Operation Research, Optimization): 제약 조건(예: 예산, 입찰 한도) 하에서 목적 함수(예: 이익, ROI)를 최대화하는 최적화 모델을 구축.
- 강화 학습 (Reinforcement Learning): 시행착오를 통해 최적의 입찰 전략을 학습하는 머신러닝 알고리즘을 사용.
- 에이전트 (Agent): 입찰을 하는 광고주
- 환경 (Environment): 입찰이 이루어지는 경매 플랫폼
Definition (Terms)
- 내쉬 균형 (Nash Equilibrium): 다른 플레이어들이 자신의 전략을 바꾸지 않는 한, 어떤 플레이어도 자신의 전략을 변경하여 이익을 얻을 수 없는 상태를 말함.
- 강화 학습 (Reinforcement Learning): 에이전트가 환경 내에서 행동을 취하고 누적 보상을 최대화함으로써 의사결정을 학습하는 머신러닝의 한 유형.
클릭당 비용 (CPC, Cost Per Click) 입찰
CPC는 품질의 척도. 그러나 대부분의 품질 함수는 플랫폼에 의해 공개되지 않음. 광고주는 입찰가에 수신된 클릭 수를 곱한 금액을 지불함.
예시:
- 슬롯 1: 3.2 * 100 클릭 = $320
- 슬롯 2: 2.5 * 80 클릭 = $200
- 슬롯 3: 1.8 * 50 클릭 = $90
이것이 플랫폼이 광고 순위를 매길 때 품질 점수를 고려하는 이유.
코드 실습
최고가 경매 (First Price Auction)
가정:
- 4명의 광고주.
- 경매 유형: first price auction.
- 클릭률 (CTR): (0.05, 0.15) 사이의 무작위 값
- 전환율 (CR): (0.01, 0.1) 사이의 무작위 값
- 전환당 수익 (Revenue per Conversion): (50, 200) 사이의 무작위 값
목표:
- 위 가정 하에 최고가 경매를 시뮬레이션.
- 입찰가와 함께 승자를 찾음.
import random
# 입찰가 조정 및 추정된 실제 가치를 가진 광고주를 나타내는 클래스 정의class Advertiser: def __init__(self, name, ctr, cr, rpc, shading_factor = 0.9): self.name = name self.ctr = ctr self.cr = cr self.rpc = rpc self.shading_factor = shading_factor self.true_value = self.estimate_true_value() self.shaded_bid = self.apply_bid_shading()
def estimate_true_value(self): return self.ctr * self.cr * self.rpc
def apply_bid_shading(self): return self.shading_factor * self.true_value
# 경매 시뮬레이션advertisers = [ Advertiser("광고주 A", random.uniform(0.05, 0.15), random.uniform(0.01, 0.1), random.uniform(50, 200)), Advertiser("광고주 B", random.uniform(0.05, 0.15), random.uniform(0.01, 0.1), random.uniform(50, 200)), Advertiser("광고주 C", random.uniform(0.05, 0.15), random.uniform(0.01, 0.1), random.uniform(50, 200)), Advertiser("광고주 D", random.uniform(0.05, 0.15), random.uniform(0.01, 0.1), random.uniform(50, 200)),]
# 입찰가 출력for advertiser in advertisers: print(f"{advertiser.name}: CTR={advertiser.ctr:.4f}, CR={advertiser.cr:.4f}, RPC={advertiser.rpc:.2f}, 실제 가치={advertiser.true_value:.2f}, 조정된 입찰가={advertiser.shaded_bid:.2f}")
winner = max(advertisers, key=lambda x: x.shaded_bid)
print(f"\n승자: {winner.name}, 입찰가 ${winner.shaded_bid:.2f}")결과:
광고주 A: CTR=0.0961, CR=0.0668, RPC=144.91, 실제 가치=0.93, 조정된 입찰가=0.84광고주 B: CTR=0.0814, CR=0.0682, RPC=192.09, 실제 가치=1.07, 조정된 입찰가=0.96광고주 C: CTR=0.1183, CR=0.0116, RPC=187.26, 실제 가치=0.26, 조정된 입찰가=0.23광고주 D: CTR=0.0702, CR=0.0813, RPC=174.54, 실제 가치=1.00, 조정된 입찰가=0.90
승자: 광고주 B, 입찰가 $0.96차가 경매 (Second Price Auction)
위와 동일한 가정을 사용하되, 경매 유형은 second price auction.
import random
class Advertiser: def __init__(self, name, ctr, cr, rpc, shading_factor = 0.9): self.name = name self.ctr = ctr self.cr = cr self.rpc = rpc self.shading_factor = shading_factor self.true_value = self.estimate_true_value()
def estimate_true_value(self): return self.ctr * self.cr * self.rpc
# 경매 시뮬레이션advertisers = [ Advertiser("광고주 A", random.uniform(0.05, 0.15), random.uniform(0.01, 0.1), random.uniform(50, 200)), Advertiser("광고주 B", random.uniform(0.05, 0.15), random.uniform(0.01, 0.1), random.uniform(50, 200)), Advertiser("광고주 C", random.uniform(0.05, 0.15), random.uniform(0.01, 0.1), random.uniform(50, 200)), Advertiser("광고주 D", random.uniform(0.05, 0.15), random.uniform(0.01, 0.1), random.uniform(50, 200)),]
bids = sorted(advertisers, key=lambda x: x.true_value, reverse=True)
print("광고주별 추정 실제 가치(입찰가) 및 배정된 슬롯:")for i, advertiser in enumerate(bids): if i < 3: print(f"{advertiser.name} - 실제 가치: {advertiser.true_value:.2f}, 배정 슬롯: {i+1}")
print("\n경매 결과:")for i in range(3): if i < 3: name, bid = bids[i].name, bids[i].true_value price = bids[i+1].true_value if i+1 < len(bids) else 0 # 다음으로 높은 입찰가를 지불 가격으로 책정 print(f"{name}가(이) 슬롯 {i+1}을(를) ${bid:.2f}에 입찰하여 ${price:.2f}에 낙찰받았습니다.")결과:
광고주별 추정 실제 가치(입찰가) 및 배정된 슬롯:광고주 A - 실제 가치: 1.48, 배정 슬롯: 1광고주 B - 실제 가치: 0.82, 배정 슬롯: 2광고주 D - 실제 가치: 0.78, 배정 슬롯: 3
경매 결과:광고주 A가(이) 슬롯 1을(를) $1.48에 입찰하여 $0.82에 낙찰받았습니다.광고주 B가(이) 슬롯 2을(를) $0.82에 입찰하여 $0.78에 낙찰받았습니다.광고주 D가(이) 슬롯 3을(를) $0.78에 입찰하여 $0.16에 낙찰받았습니다.품질 점수가 조정된 차가 검색 광고 경매 (Quality Adjusted Second Price Search Ad Auction)
5명의 광고주가 3개의 슬롯을 두고 경쟁하는, 품질 점수가 조정된 차가 검색 광고 경매를 시뮬레이션하는 프로그램. 각 광고주에 대해 클릭률(CTR)은 0.02에서 0.12, 전환율(CR)은 0.02에서 0.15, 전환당 수익(RPC)은 30에서 150, 품질 점수(QS)는 0.5에서 1.5 사이에서 무작위로 균등하게 추출.
- 광고주의 실제 가치를 로 정의.
- 유효 입찰가를 로 계산.
- 광고주를 유효 입찰가 기준으로 내림차순으로 정렬.
- 상위 3명에게 슬롯 1-3을 할당.
- 품질 조정 차가 지불 규칙을 사용하여 각 슬롯의 승자가 클릭당 비용(CPC)으로 (다음 광고주의 유효 입찰가 / 승자의 QS)를 지불하도록. (다음 광고주가 없는 경우 합리적인 예약 유효 입찰가를 사용).
- 시뮬레이션을 한 번 실행하고, 각 광고주에 대해 샘플링된 매개변수, 순위, 슬롯 할당을 출력하고, 각 승자에 대해 클릭당 지불 비용(CPC)을 계산. 마지막으로, 누가 각 슬롯을 차지하고 얼마의 CPC를 지불하는지 명확하게 기술.
import random
class Advertiser: def __init__(self, name, ctr, vr, rpc, qs): self.name = name self.ctr = ctr # 클릭률 (Click-Through Rate) self.vr = vr # 전환율 (Conversion Rate) self.rpc = rpc # 전환당 수익 (Revenue per Conversion) self.qs = qs # 품질 점수 (Quality Score) self.true_value = self.ctr * self.vr * self.rpc self.effective_bid = self.true_value * self.qs
advertisers = [ Advertiser(f"광고주 {ch}", ctr=random.uniform(0.02, 0.12), vr=random.uniform(0.02, 0.15), rpc=random.uniform(30, 150), qs=random.uniform(0.5, 1.5)) for ch in 'ABCDE']
sorted_ads = sorted(advertisers, key=lambda ad: ad.effective_bid, reverse=True)
for ads in sorted_ads: print(f"{ads.name}: CTR={ads.ctr:.4f}, VR={ads.vr:.4f}, RPC={ads.rpc:.2f}, QS={ads.qs:.4f}, " f"실제 가치={ads.true_value:.4f}, 유효 입찰가={ads.effective_bid:.4f}")
reserve = 0.2slots = 3print("\n경매 결과:")for i in range(slots): winner = sorted_ads[i] next_eff = sorted_ads[i + 1].effective_bid if i + 1 < len(sorted_ads) else reserve cpc = next_eff / winner.qs print(f"슬롯 {i + 1}: {winner.name} 승리, CPC = {cpc:.4f}")결과:
광고주 C: CTR=0.1055, VR=0.1369, RPC=139.81, QS=1.0041, 실제 가치=2.0188, 유효 입찰가=2.0270광고주 B: CTR=0.0879, VR=0.1193, RPC=107.26, QS=0.9813, 실제 가치=1.1244, 유효 입찰가=1.1034광고주 E: CTR=0.1052, VR=0.0470, RPC=84.23, QS=0.7098, 실제 가치=0.4164, 유효 입찰가=0.2956광고주 A: CTR=0.0584, VR=0.0910, RPC=50.90, QS=0.7391, 실제 가치=0.2707, 유효 입찰가=0.2001광고주 D: CTR=0.0881, VR=0.0289, RPC=52.56, QS=0.8695, 실제 가치=0.1340, 유효 입찰가=0.1165
경매 결과:슬롯 1: 광고주 C 승리, CPC = 1.0989슬롯 2: 광고주 B 승리, CPC = 0.3012슬롯 3: 광고주 E 승리, CPC = 0.2819- 슬롯 1은 광고주 C가 차지하며, CPC는 $1.0989를 지불합니다.
- 슬롯 2는 광고주 B가 차지하며, CPC는 $0.3012를 지불합니다.
- 슬롯 3은 광고주 E가 차지하며, CPC는 $0.2819를 지불합니다.
3-슬롯 GSP 경매
아래 나열된 5명의 광고주를 사용하여 3-슬롯 GSP 경매를 시뮬레이션하는 프로그램을 작성하세요. 각 광고주는 과거 성과 데이터와 입찰가를 가지고 있습니다:
- A (3200 노출, 210 클릭, 20 전환, RPC 1.40)
- B (2800 노출, 145 클릭, 12 전환, RPC 1.55)
- C (1500 노출, 120 클릭, 10 전환, RPC 1.10)
- D (4200 노출, 160 클릭, 14 전환, RPC 1.20)
- E (900 노출, 75 클릭, 6 전환, RPC 0.95)
각 광고주에 대해,
- 예상 클릭률(eCTR)을 계산.
- 전환율(CR)을 계산.
- 광고 순위를 로 정의.
- 상위 3명에게 슬롯 1-3을 할당.
- 각 승자의 가격을 GSP 규칙인 에 따라 책정. (다음 광고주가 없는 경우 예약 AdRank로 0.20 사용)
슬롯 1, 2, 3의 클릭 수를 각각 120, 90, 70으로 가정. 각 슬롯 승자에 대해 CPC, 총 비용, 수익, 그리고 이익을 출력.