axiom

Bringing your own problem · step 2 of 6

Say what the columns mean

Why does a column need a dimension and a unit?

A Treatment and an Outcome are not labels. They carry a dimension and a unit, and those travel with every number derived from them — into the estimand, into the transfer ledger, onto the report.

This is what stops dollars being added to visits four steps later, in a function nobody is reading at the time. D.currency and D.outcome are different dimensions, and axiom refuses the arithmetic that would mix them rather than returning a number with no meaning.

step 2
from axiom.core import D, Outcome, Treatment
from axiom.data import Panel, RoleMap

leaflets = Treatment(
    name="leaflets",
    dimension=D.currency,
    unit="USD/store-week",
    description="leaflet spend delivered to the store's catchment",
)
footfall = Outcome(
    name="footfall",
    dimension=D.outcome,
    unit="visits/week",
    description="counted entries through the door",
    aggregation="mean",
)

roles = RoleMap(
    unit="store",
    time="week",
    outcome=("footfall", footfall),
    treatments={"leaflets": leaflets},
)
panel = Panel(frame, roles)

print(f"unit column      : {roles.unit}")
print(f"time column      : {roles.time}")
print(f"outcome column   : {roles.outcome[0]}  [{footfall.dimension}]")
print(f"treatment columns: {list(roles.treatments)}  "
      f"[{leaflets.dimension}]")
print()
print(f"the two dimensions are different objects: "
      f"{D.currency != D.outcome}")
what it printed
unit column      : store
time column      : week
outcome column   : footfall  [Y]
treatment columns: ['leaflets']  [$]

the two dimensions are different objects: True

Every line above was captured by running this code at build time. The steps share one namespace, so the code on this page is the code you would type after the steps before it.