chc.geo_world¶
Stability tier: experimental.
A geo media-mix world: each geo's KPI made by its own media, its effects drawn from a stated hierarchy, so a model fitted to it can be scored against the truth it was drawn from.
geos geos over weeks weeks. A geo's KPI a week is its base, moved by a season shared by
every geo, plus each channel's lift, plus what its neighbours' media lift in it, plus noise:
y_{g,t} = P_g b_g (1 + A sin(2 pi t / 52)) + sum_c m_{g,c,t} + o_{g,t} + e_{g,t}
- Per head. A channel's lift is the geo's population
P_gtimes a lift per head,m_{g,c,t} = P_g beta_{g,c} D_{c,t} h_c(a_{g,c,t} / P_g):athe geo's spend on the channel through its normalised geometric adstock,h_cthe channel's saturation curve with its scale in spend per head a week, andbeta_{g,c}the KPI per head a week at the curve's ceiling. A geo twice the size spending twice as much lifts twice as much. As achc.response.Channelthe lift is the curve with its scale timesP_gand the coefficientP_g beta_{g,c} D_{c,t}, whichGeoMediaWorld.cellsreturns forchc.allocation.allocate_geosto plan on. - The hierarchy.
log beta_{g,c} = log beta_c + tau_c z_{g,c}, thezstandard normal and independent across geos and channels:beta_cis the channel's national median andtau_cthe spread of the geos about it. A geo's base per headb_gand its population are log-normal about the mix's in the same way. - National media is bought nationally and allotted to the geos by population, so every geo
sees the same spend per head; its lift per head still differs by geo through
beta_{g,c}. - Spillover, an option: a geo's lift on the channels it buys itself also lifts each of its two
neighbours on a ring of the geos, in their order, by
spillover / 2of what it lifts at home. National media has no neighbour to spill to. - Drift, an option: each channel's lift moves with the weeks by a national factor
D_{c,t} = exp(d_{c,t}),da random walk from 0 with steps of standard deviationdrifta week. - The log's spend puts the confounding of
chc.mmmin: a geo's spend per head on a channel is the channel's mean times an intensity of the geo's, log-normal with log-SDspend_spread, times1 + policy sin(2 pi t / 52), a planner raising spend in the weeks the season raises the KPI, times a week's log-normal jitter of mean 1 and log-SDspend_noise. - Noise: each head's KPI a week independent with standard deviation
noise, so a geo's isnoise sqrt(P_g).
Every variate is drawn whatever the parameters, in one order, so two mixes that differ only in a parameter read the same variates at the same seed: common random numbers for a paired comparison.
HONEST SCOPE:
- The hierarchy is log-normal and independent across channels: no correlation between a geo's effects, no trend, one annual season that every geo shares.
- The neighbours are a ring of the geos in their order, not a geography.
- National media's spend per head is the same in every geo, so the geos hold no contrast in it: a model reads its effect from the weeks alone, as a model of the whole country does, and its spread over the geos from how each geo follows the same series. Only the channels a geo buys itself vary across the geos.
- The curves are JAX's. In double precision (
jax_enable_x64) the KPI is exact to rounding; in single, JAX's default, each lift is good to single precision.
MediaChannel
dataclass
¶
One channel of a GeoMediaMix, its parameters national.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
the channel's name. |
curve |
Saturation
|
its saturation per head, the scale in spend per head a week. |
effect |
float
|
the KPI per head a week at the curve's ceiling, the median over the geos. |
spread |
float
|
the log-SD of a geo's effect about the median. |
retention |
float
|
the share of its adstock a week keeps; the kernel is normalised. |
spend |
float
|
the log's mean spend per head a week. |
national |
bool
|
bought nationally and allotted to the geos by population. |
Raises:
| Type | Description |
|---|---|
TypeError
|
a curve that is not a |
ValueError
|
an effect or a spend not above 0, a negative spread, or a retention outside
|
GeoMediaMix
dataclass
¶
The parameters a world is drawn from; draw draws one.
Attributes:
| Name | Type | Description |
|---|---|---|
channels |
tuple[MediaChannel, ...]
|
the mix's channels. |
geos |
int
|
how many geos. |
weeks |
int
|
how many weeks of history. |
population |
float
|
a geo's median population. |
population_spread |
float
|
the log-SD of the populations about it. |
base |
float
|
the median geo's KPI per head a week before media and season. |
base_spread |
float
|
the log-SD of the geos' bases per head about it. |
season |
float
|
the annual season's amplitude, a share of the base, below 1. |
policy |
float
|
how far the log's spend rises with the season, between -1 and 1: the confounding. |
spend_spread |
float
|
the log-SD of a geo's spend per head on a channel about the channel's mean. |
spend_noise |
float
|
the log-SD of a week's spend about its plan. |
noise |
float
|
the standard deviation of one head's KPI a week. |
spillover |
float
|
what a geo's media lifts in its two neighbours together, a share of its lift at home; above 0 it needs three geos for the ring. |
drift |
float
|
the standard deviation a week of each channel's national random walk in the log of its lift. |
length |
int
|
each adstock kernel's length in weeks. |
Raises:
| Type | Description |
|---|---|
ValueError
|
on any parameter outside the ranges above, no channels, or two with one name. |
draw(seed)
¶
One world: its geos' populations and effects, the log's spend, and the KPI it made.
GeoMediaWorld
dataclass
¶
One draw of a GeoMediaMix: its geos, the media they ran and the KPI it made.
Arrays run geo by week by channel, the channels in the mix's order.
Attributes:
| Name | Type | Description |
|---|---|---|
mix |
GeoMediaMix
|
what the world was drawn from. |
population |
ndarray
|
|
effect |
ndarray
|
|
drift |
ndarray
|
|
spend |
ndarray
|
|
base |
ndarray
|
|
media |
ndarray
|
|
spilled |
ndarray
|
|
noise |
ndarray
|
|
kpi
property
¶
(geos, weeks): the base, every channel's lift, what spills in, and the noise.
shares
property
¶
(geos,) each geo's share of the population: what national media is allotted by.
cells(week=-1)
¶
Each geo's channels as chc.response.Channel, their lift at week's drift:
a row a geo, as chc.allocation.allocate_geos takes them. Spillover is not in
them.
lift(spend)
¶
(geos, weeks): what spend, geo by week by channel, lifts in each geo, at home and
from its neighbours, with nothing spent before the first week.