Bringing your own problem · step 1 of 6
Start from the dataframe you already have
What does axiom need to know about your table?
Long format: one row per unit per period, a column for the treatment and a column for the outcome. That is the whole data requirement, and it is deliberately the shape almost everyone already has.
What axiom will not do is guess which column is which. A RoleMap names the unit, the time, the outcome and every treatment explicitly. Column-name conventions are how a spend column gets read as an outcome in somebody's third refactor, and the map is five lines against that.
step 1
import numpy as np
import pandas as pd
# Whatever produced your table. This one is 24 stores over 40 weeks:
# leaflet spend, and footfall that responds to it with diminishing
# returns. Substitute your own read_csv here -- nothing below cares.
rng = np.random.default_rng(7)
rows = []
for store in range(24):
base = 40.0 + rng.normal(0, 6) # stores differ
for week in range(40):
spend = float(max(0.0, rng.normal(300, 160)))
rows.append({
"store": f"s{store:02d}",
"week": week,
"leaflets": spend,
"footfall": base + 9.0 * spend / (spend + 250.0)
+ rng.normal(0, 2),
})
frame = pd.DataFrame(rows)
print(frame.head(3).to_string(index=False))
print(f"\n{len(frame)} rows, {frame['store'].nunique()} stores, "
f"{frame['week'].nunique()} weeks")
what it printed
store week leaflets footfall s00 0 347.799286 44.695300 s00 1 157.505306 42.576639 s00 2 141.336551 43.378141 960 rows, 24 stores, 40 weeks
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.