4 Pacing for Optimization
Warning
🚧 This chapter is a work in progress.
Maths: control theory (PID)!
Explain how pacing optimizes delivery (for different parties).
Use Observable to render example of multiplier changing over time?
import random
import matplotlib.pyplot as plt
# Constants
BUDGET = 1000.0 # Daily budget
TOTAL_MINUTES = 1440 # Minutes in a day
K_p = 0.8 # Proportional gain
K_i = 0.05 # Integral gain
K_d = 0.1 # Derivative gain
OPPORTUNITY_VALUE = 0.2 # $2 CPM is 200/1000 cents per impression
# the value and budget above need to be in same units, so assume cents
# Initialization
pickiness_level = 0.01 # Initial pickiness (how selective to be with ad opportunities)
previous_error = 0
integral_error = 0
spent = 0
# Data for plotting
opportunities_per_minute = []
pickiness_levels = []
actual_spend = []
target_spend = []
# Simulation loop
for minute in range(TOTAL_MINUTES):
# Simulate opportunities with smoother variation
if minute == 0:
opportunities = random.randint(10, 20) # Initial range
else:
# Limit changes to +/- 5 opportunities from previous minute
opportunities = max(5, min(25, opportunities_per_minute[-1] + random.randint(-5, 5)))
opportunities_per_minute.append(opportunities)
# Target spend per minute with linear (not opportunity based) pacing
target_spend_per_minute = BUDGET / TOTAL_MINUTES
target_spend.append(target_spend_per_minute * minute)
# Calculate overall pace
pace = spent / (target_spend_per_minute * minute) if minute > 0 else 0
# Calculate error
error = (1 - pace) / (1 + pace)
# PID control
derivative_error = (error - previous_error)
integral_error += error
new_pickiness_level = pickiness_level + (K_p * error + K_i * integral_error + K_d * derivative_error)
pickiness_levels.append(new_pickiness_level)
previous_error = error
# Simulate spending with fixed opportunity value
# if new_pickiness_level is between 0 and 1, then you are only winning a fraction of all opportunities per minute
spent_this_minute = opportunities * OPPORTUNITY_VALUE * new_pickiness_level
spent += spent_this_minute
actual_spend.append(spent)
# Plotting
plt.figure(figsize=(12, 8))
plt.subplot(3, 1, 1)
plt.plot(opportunities_per_minute)
plt.title("Ad Opportunities per Minute")
plt.subplot(3, 1, 2)
plt.plot(pickiness_levels)
plt.title("Adjusted Pickiness Level")
plt.subplot(3, 1, 3)
plt.plot(target_spend, label='Target Spend')
plt.plot(actual_spend, label='Actual Spend')
plt.title("Spending Over Time")
plt.legend()
plt.show()