Simultaneous equations: when marketing causes sales and sales cause marketing

TL;DR

Difficulty: Advanced

  • If the ad budget is set from sales and sales respond to ads, a single regression credits the ads with every good month. In the example it overstates the effect by 40%, and more data only makes it surer.
  • The reduced form writes both variables through outside drivers only. Ratios of its coefficients recover the true ad effect.
  • An equation is identified only if enough outside variables are excluded from it, and each exclusion is a claim about the world you must say out loud.
  • Two stage least squares replaces spend with the part the budget rule explains. Use a package, and check first stage F, overidentification, Wu Hausman and autocorrelation before trusting the number.
  • Written budget rules and cash limits make good instruments. Cost per click and competitor spend do not. A randomised holdout beats them all.

Most small companies set next month's advertising budget from this month's sales, and then ask a regression what the advertising did for sales. Using Vanlog, an invented SaaS for trades businesses in Galway, this chapter shows why that regression answers confidently and wrongly, and how the reduced form and two stage least squares recover the real effect, with working code and the checks to run before you trust the number. Part 11 of 21 of the Marketing Analytics series.

The founder who pays for his ads out of last month's invoices

Vanlog is the invented Rails SaaS from Galway that plays the software business in this series. It gives plumbers, carpenters and electricians one place for their calendar, their quotes and their invoices. Plans start at €29 a month, a new customer is worth roughly €600 in first year revenue, and Vanlog signs between 20 and 45 of them a month. The founder's advertising rule is simple and, on the face of it, sensible: next month's Google and Meta spend is 25% of this month's new bookings. Good month, more ads. Slow month, tighten the belt. Halfway through each month he looks at the dashboard and either tops the campaigns up or pauses them for a week.

After three years of this he asks me a fair question: what does one euro of advertising actually bring back? His agency had regressed monthly new bookings on ad spend and reported €2.10 of new business per euro spent, with a t statistic you could hang a coat on. Then they proposed doubling the budget. I did not doubt their arithmetic. I doubted the model, because at Vanlog ad spend does not simply cause bookings. Bookings cause ad spend. It is the founder's rule, written down in a spreadsheet.

When two variables cause each other, a single regression line is quietly wrong, in a direction you can predict. Here it flatters the ads by about 40%. Vanlog, its founder and every number in this chapter are made up so I can show each step. The numbers are illustrative. The mechanism is not.

Where this sits in the series

This is chapter 11 of 21 in my Marketing Analytics series and opens part three, the interrelationship techniques of chapters 11 to 14. Part two always had one outcome on the left and its causes on the right. Its last chapter, forecasting demand with autocorrelation, seasonality and honest error bands, taught that shocks linger from one month into the next, and that matters again here. Next comes principal components and factor analysis for marketers, where many variables move together without any one being the outcome. This chapter is the bridge: two outcomes, each also a cause.

Budget rules build feedback loops, and marketing is full of them

Simultaneity is the polite term for two variables determining each other within the same period. Marketing produces it constantly, through perfectly reasonable decisions. Budget as a share of revenue is the most common: sales set the spend, the spend moves sales. Price and quantity is the textbook case. Demand and supply set price and quantity together, so a regression of quantity on price cannot recover the demand curve on its own.1 Automated bidding is the newest: Google's Target ROAS strategy predicts the value of a possible conversion at every auction and sets bids to maximise conversion value,2 so bids rise where conversions are likely and conversions rise where bids are higher. The platform builds the loop for you at auction speed.

Here is the Vanlog loop. The dangerous step is the first, the shock nobody records, because it reaches ad spend through bookings.

How a booking shock reaches ad spendAn unrecorded shock lifts this month's bookings. The founder sees a strong month and tops up the campaigns, so ad spend rises in the same month. The 25% rule then raises next month's budget as well. A single regression sees high spend next to high bookings and credits the ads with the shock.An unrecorded shock lifts bookings thismonthBookings come in above what ads andorganic signups explainThe founder sees a strong month andtops up the campaigns mid monthAd spend rises in the same month as theshockThe 25% rule raises next month's budgettooThe regression sees high spend next tohigh bookings and credits the ads

Each box causes the next. Only the second and fourth show up in the data, side by side in one row, and nothing in the row says which caused which.

Worked example: why a one month lag does not break the loop

A strict version of the rule uses last month's bookings, already in the books when this month's budget is set, so the loop should be broken within a month. Two things spoil it. First, the founder reacts mid month, so this month's bookings feed this month's spend. Second, the unobserved things that push bookings up tend to last longer than a month. An example: a competing scheduling app has a two week outage in late March, and trial users who were sitting on the fence convert. March bookings jump. The founder tops up in March. Some switchers were still deciding in April, so April's bookings are high as well, and April's budget, set from March, is high too. The shock sits inside last month's bookings and is still alive this month. That autocorrelation is why a lag alone does not save you.

Why the single regression is biased

Write the system down honestly. Two equations, one for each variable that is both cause and effect:

Rt=α0+α1At+α2St+α3Jt+utR_t = \alpha_0 + \alpha_1 A_t + \alpha_2 S_t + \alpha_3 J_t + u_t

Here RtR_t is new bookings in euro in month tt, AtA_t is ad spend in the same month, StS_t is the number of organic trial signups from the software directory listing and word of mouth, JtJ_t is a January indicator (one in January, zero otherwise, because trades businesses reorganise every January) and utu_t is everything else that moved bookings that month. α0\alpha_0 is the intercept, α2\alpha_2 and α3\alpha_3 are the effects of signups and January, and the number we want is α1\alpha_1: euro of new bookings per euro of ads. The regression itself is in Foundations: regression.

At=β0+β1Rt+β2Rt−1+β3Bt+vtA_t = \beta_0 + \beta_1 R_t + \beta_2 R_{t-1} + \beta_3 B_t + v_t

Here AtA_t and RtR_t are as before, β0\beta_0 is the intercept, β1\beta_1 is the founder's mid month reaction to this month's bookings, β2\beta_2 is the 25% rule applied to last month's bookings Rt−1R_{t-1}, β3\beta_3 is the effect of BtB_t, the cash balance at the start of the month (he does not top up when the account is thin), and vtv_t is his mood, his holidays and whatever else nudges the budget. Two equations at once are bookkeeping, see Foundations: matrices.

The competitor outage in March is a positive utu_t: bookings are higher than ads and signups would predict. The founder tops up, so AtA_t rises as well. The regression sees a high AtA_t next to a high RtR_t and hands the credit to the ads, every month. Formally, ordinary least squares (OLS) settles on

plim⁡ α^1OLS=α1+Cov⁡(A~t,ut)Var⁡(A~t)\operatorname{plim}\ \hat{\alpha}_1^{OLS} = \alpha_1 + \frac{\operatorname{Cov}(\tilde{A}_t, u_t)}{\operatorname{Var}(\tilde{A}_t)}

where plim⁡\operatorname{plim} is the probability limit, the value the estimate settles on as the sample grows without end, α^1OLS\hat{\alpha}_1^{OLS} is the OLS estimate of the ad effect, α1\alpha_1 the true effect, A~t\tilde{A}_t the part of ad spend that signups and January do not explain, Cov⁡(A~t,ut)\operatorname{Cov}(\tilde{A}_t, u_t) the covariance between that spend and the booking shock, and Var⁡(A~t)\operatorname{Var}(\tilde{A}_t) its variance. The second term is the simultaneity bias. The covariance is positive whenever β1>0\beta_1 > 0, because the shock travels into spend through the reaction. Covariance and variance are in Foundations: correlation and Foundations: spread.

The bias is zero when the founder never reacts within the month. It grows with the size of the booking shocks and shrinks as spend varies more for its own reasons, such as the rule and the cash position. Notice what is missing: the sample size.

Worked example: more data, same wrong answer

A simulation shows it. Take the Vanlog system with the 2SLS estimates from the worked example further down as the truth: a true ad effect of 1.50, a mid month reaction of 0.11 and the 25% rule. Draw 400 histories of 36 months, 400 of 360 months and 400 of 3,600 months, and estimate the ad effect both ways on each.

OLS and 2SLS estimates by sample sizeSimulated Vanlog system with a true ad effect of 1.50. The average OLS estimate is 2.04 at 36 months, 2.12 at 360 months and 2.13 at 3,600 months. The median 2SLS estimate is 1.43, 1.50 and 1.50. The true value is 1.50 throughout.Estimated € of bookings per € of ads€0€0.6€1.3€1.9€2.536 months360 months3,600 monthsOLS, average2SLS, medianTrue effect€ per €Length of the history

The horizontal axis is the length of the history, the vertical axis the estimated euro of bookings per euro of ads. OLS sits near €2.10 at every length, while its spread across the runs falls from 0.29 at 36 months to 0.02 at 3,600: ever surer of a number 40% too high. Two stage least squares lands on the true 1.50, with a spread of 0.45 at 36 months that shrinks the same way. More data makes a biased estimator more confidently wrong.

Unbiased, consistent, efficient: three different virtues

An estimator is unbiased if, across many repeated samples, it lands on the true value on average. It is consistent if it converges to the true value as the sample grows. It is efficient if, among estimators of its class, it has the smallest variance. The idea of a sample estimate varying around the truth is in Foundations: sampling.

An example: a kitchen scale that always reads 200 grams heavy, to the gram, is precise and biased. A scale that wobbles by 20 grams either way but averages right is unbiased and inefficient. Weigh 500 grams of flour on each a hundred times: the first says 700 every time, the second anything from 480 to 520, averaging 500. You would rather bake with the second, and so would your accountant.

Under simultaneity, OLS is neither unbiased nor consistent, just very efficient at estimating the wrong thing. Two stage least squares (2SLS), which this chapter builds, is consistent but not unbiased in small samples, and less efficient: its standard errors are wider, sometimes a lot. A precise wrong number for a fuzzy right one, and in marketing you take that trade every time. "1.50, plausibly between 0.5 and 2.5" is a better basis for a budget decision than "2.10 plus or minus 0.6" around a centre that is not there. I have written before about how correlation dresses up as causation. Simultaneity is that problem with the arrow pointing both ways.

The reduced form: what the outside drivers alone can tell you

Substitute the spend equation into the booking equation and the other way round, then collect terms. Both endogenous variables (the ones the system itself determines, bookings and spend) end up expressed only through the exogenous ones, decided outside the system:

Rt=π10+π11St+π12Jt+π13Rt−1+π14Bt+ε1tR_t = \pi_{10} + \pi_{11} S_t + \pi_{12} J_t + \pi_{13} R_{t-1} + \pi_{14} B_t + \varepsilon_{1t}

Here RtR_t, StS_t, JtJ_t, Rt−1R_{t-1} and BtB_t mean what they meant above, π10\pi_{10} is the intercept, π11\pi_{11} to π14\pi_{14} are the total effects of each outside driver on bookings once the loop has run its course, and ε1t\varepsilon_{1t} is a mixture of the two shocks utu_t and vtv_t. See Foundations: regression.

At=π20+π21St+π22Jt+π23Rt−1+π24Bt+ε2tA_t = \pi_{20} + \pi_{21} S_t + \pi_{22} J_t + \pi_{23} R_{t-1} + \pi_{24} B_t + \varepsilon_{2t}

Here AtA_t is ad spend, π20\pi_{20} the intercept, π21\pi_{21} to π24\pi_{24} the total effects of the same drivers on spend, and ε2t\varepsilon_{2t} another mixture of utu_t and vtv_t. Both right hand sides contain only exogenous variables, so each equation can be estimated by ordinary least squares without embarrassment (Foundations: regression). Each π\pi is a knot of structural coefficients, for instance

π13=α1β21−α1β1,π23=β21−α1β1\pi_{13} = \frac{\alpha_1 \beta_2}{1 - \alpha_1 \beta_1}, \qquad \pi_{23} = \frac{\beta_2}{1 - \alpha_1 \beta_1}

where π13\pi_{13} and π23\pi_{23} are the effects of last month's bookings on this month's bookings and spend, α1\alpha_1 is the ad effect, β1\beta_1 the mid month reaction and β2\beta_2 the 25% rule, and the denominator 1−α1β11 - \alpha_1 \beta_1 is the loop's amplification, which must be positive for the system to settle. Fractions like these are in Foundations: ratios and rates.

Now look at the ratio: π13/π23=α1\pi_{13} / \pi_{23} = \alpha_1. The effect of last month's bookings on this month's bookings, divided by its effect on this month's spend, is the effect of spend on bookings. The budget rule moves spend for a reason that has nothing to do with this month's shock, so whatever bookings do in response is the ad effect, cleanly. That is the whole idea of an instrument. The same works for cash: π14/π24=α1\pi_{14} / \pi_{24} = \alpha_1 as well. With two excluded variables, Rt−1R_{t-1} and BtB_t, you get two such ratios and have to reconcile them, which is what two stage least squares does in an organised way.

Worked example: recovering 1.50 from the ratios

Take the example's structural values: α1=1.50\alpha_1 = 1.50, β1=0.11\beta_1 = 0.11, β2=0.24\beta_2 = 0.24 and β3=0.014\beta_3 = 0.014.

  • The amplification: 1−1.50×0.11=1−0.165=0.8351 - 1.50 \times 0.11 = 1 - 0.165 = 0.835.
  • Last month's bookings on this month's spend: π23=0.24/0.835=0.2874\pi_{23} = 0.24 / 0.835 = 0.2874.
  • Last month's bookings on this month's bookings: π13=1.50×0.24/0.835=0.36/0.835=0.4311\pi_{13} = 1.50 \times 0.24 / 0.835 = 0.36 / 0.835 = 0.4311.
  • The ratio: 0.4311/0.2874=1.500.4311 / 0.2874 = 1.50.
  • Cash, the same way: π24=0.014/0.835=0.01677\pi_{24} = 0.014 / 0.835 = 0.01677, π14=1.50×0.014/0.835=0.02515\pi_{14} = 1.50 \times 0.014 / 0.835 = 0.02515, and 0.02515/0.01677=1.500.02515 / 0.01677 = 1.50.

Every €1 of last month's bookings adds about 29 cent to this month's ads and 43 cent to this month's bookings. The 43 cent arrives only because of the 29 cent, so a euro of ads is worth about €1.50. In real data the two ratios never agree exactly, and how far apart they are is a test in its own right.

Identification: can the data even tell the two directions apart?

With only RtR_t and AtA_t you have a cloud of points and no way of knowing which line through it is the booking equation and which the spend equation. The system is unidentified, and no amount of data fixes it. What identifies an equation is a variable that is excluded from it and present elsewhere in the system. The order condition says it as a count. For each equation, the number of exogenous variables excluded from it must be at least the number of endogenous variables on its right hand side:

K−k≥m−1K - k \geq m - 1

where KK is the number of exogenous variables in the whole system, kk the number of them in the equation you want to estimate, and mm the number of endogenous variables in that equation, including the one on the left. With more excluded variables than needed the equation is overidentified, with exactly enough it is exactly identified, and with fewer it is underidentified and cannot be estimated.3 The count is the same bookkeeping as in Foundations: matrices.

Worked example: counting the Vanlog system

The system has four exogenous variables: StS_t, JtJ_t, Rt−1R_{t-1} and BtB_t. So K=4K = 4.

  • The booking equation contains StS_t and JtJ_t, so k=2k = 2 and K−k=2K - k = 2. It has two endogenous variables, RtR_t and AtA_t, so m−1=1m - 1 = 1. Since 2≥12 \geq 1 it is identified, in fact overidentified by one, which is good news because it lets us test the two instruments against each other.
  • The spend equation contains Rt−1R_{t-1} and BtB_t and excludes StS_t and JtJ_t, so again K−k=2K - k = 2 against m−1=1m - 1 = 1. Overidentified by one as well.

The order condition is necessary but not sufficient. The rank condition behind it says the excluded variables must actually move spend (β2\beta_2 or β3\beta_3 not zero), which in practice is the first stage F statistic below.

The deeper point is not statistical. "Excluded" is a claim about the world, and here there are two. The first says the opening cash balance does not itself change how many carpenters buy scheduling software this month, other than through the ads it pays for. The second says last month's bookings reach this month's bookings only through the budget, once organic signups, which carry the word of mouth, are in the equation. Both are statements about carpenters, not about data, and you have to say them out loud. The example also treats organic signups as exogenous. If the ads spill over into searches for the brand name and show up as "organic", that assumption fails too. If a colleague laughs at any of these, find a different instrument.

Two stage least squares, step by step

Stage one: regress AtA_t on every exogenous variable in the system, meaning StS_t, JtJ_t, Rt−1R_{t-1} and BtB_t, and keep the fitted values A^t\hat{A}_t. They are the part of ad spend explained by the budget rule, the cash position and the calendar, none of which knows about this month's booking shock. Stage two: regress RtR_t on A^t\hat{A}_t, StS_t and JtJ_t. The coefficient on A^t\hat{A}_t is the two stage least squares estimate of α1\alpha_1. In matrix form the whole thing is one line:

θ^2SLS=(X′PZX)−1X′PZy,PZ=Z(Z′Z)−1Z′\hat{\theta}_{2SLS} = (X' P_Z X)^{-1} X' P_Z y, \qquad P_Z = Z (Z'Z)^{-1} Z'

Here θ^2SLS\hat{\theta}_{2SLS} is the vector of estimated coefficients of the booking equation, yy is the vector of monthly bookings, XX holds the regressors of the booking equation (a constant, AtA_t, StS_t, JtJ_t), ZZ holds all the exogenous variables plus the constant, the prime ′' turns a matrix on its side (the transpose), the power −1-1 is the matrix inverse, and PZP_Z is the projection onto the space spanned by the instruments. Multiplying XX by PZP_Z replaces the spend column with its first stage fit and leaves the exogenous columns as they were, because they are already in ZZ. Matrix multiplication is explained in Foundations: matrices.

One practical warning. If you run the two stages by hand as two separate regressions, the coefficients are right but the standard errors printed after stage two are wrong, because they do not account for the fitted spend being an estimate itself.1 Every serious package corrects this. Use one.

Two stage least squares as a procedureCollect all exogenous variables. Stage one regresses ad spend on them. If the first stage F is below 10 the instruments are weak and you stop. Otherwise keep fitted ad spend and run stage two on it with the controls, letting a package correct the standard errors. If the overidentification test fails, one instrument is wrong and you go back. If it passes, write the decision memo with the number and its band.Collect every exogenous variable in thesystemStage one: regress ad spend on all ofthemFirst stage F above 10?noNo: weak instruments, stop and rethinkyesYes: keep the fitted ad spendStage two: regress bookings on fittedspend and the controlsLet the package correct the standarderrorsDoes the overidentification testpass?noNo: one instrument is wrong, go backyesYes: decision memo with the number andits band

The procedure as I actually run it, top to bottom, including the two exits where you go back rather than forward.

Worked example: the Vanlog numbers, line by line

36 months of Vanlog data. Over the period the business averaged €18,400 of new bookings a month, €4,600 of ad spend, 31 organic trial signups and an opening cash balance around €41,000. The booking equation, estimated both ways:

TermOLS estimateOLS std error2SLS estimate2SLS std error
Intercept (€)5,5701,4807,8301,930
Ad spend (€ of bookings per € spent)2.100.311.500.52
Organic trial signups (€ per signup)962811234
January (€)2,3009402,4101,060
R squared0.710.64
First stage F on the two instruments18.4
Sargan test of overidentification, p value0.41

Reading it from the top. The intercept, a month with no ads, signups or January, is larger under 2SLS because ads are given less credit, so more of the baseline stays in the baseline. Both versions pass through the averages: under 2SLS, 7,830+1.50×4,600+112×31+2,410/12=7,830+6,900+3,472+201≈18,4007{,}830 + 1.50 \times 4{,}600 + 112 \times 31 + 2{,}410 / 12 = 7{,}830 + 6{,}900 + 3{,}472 + 201 \approx 18{,}400.

The ad row is the headline: €2.10 per euro under OLS, €1.50 under 2SLS, so the single equation overstated the effect by 2.10/1.50−1=40%2.10 / 1.50 - 1 = 40\%. The standard error nearly doubled, from 0.31 to 0.52. That is the efficiency we gave up. A 95% band is 1.50±1.96×0.521.50 \pm 1.96 \times 0.52, roughly 0.5 to 2.5, and I would rather have that around the right centre than 2.10±1.96×0.312.10 \pm 1.96 \times 0.31, roughly 1.5 to 2.7, around the wrong one. Bands are explained in Foundations: confidence intervals.

Organic signups gain a little, €96 to €112, because some revenue OLS gave the ads belonged to the organic channel, busy in the same months. January barely moves: nothing in the feedback loop is about the calendar.

The bottom three rows are the checks. R squared falls under 2SLS, as it should: 2SLS does not maximise fit, and a higher R squared is no evidence for OLS. The first stage F of 18.4 says the two instruments explain enough of the variation in spend to be useful. The usual rule of thumb is that anything under 10 is weak.4 The Sargan test asks whether the two instruments tell the same story about α1\alpha_1, which is the two ratios from the reduced form agreeing. A p value of 0.41 means they do, within noise. Had it been 0.01, one of them would be lying and I would have had to decide which. The p value itself is explained in Foundations: hypothesis tests.

The second equation tells you whether the model understood the business:

TermOLS estimate2SLS estimate
Intercept (€)minus 3,250minus 2,410
Bookings this month (€ of spend per €)0.210.11
Bookings last month (€ of spend per €)0.190.24
Opening cash balance (€ of spend per €)0.0120.014

OLS claims the founder reacts to the current month with 21 cent of extra spend per euro of bookings. 2SLS says 11 cent, much closer to what he describes as "a modest top up if it is going well". The 25% rule shows up as 0.24 under 2SLS, almost exactly the stated policy, while OLS put it at 0.19 because it had handed part of the rule's credit to the same month. Cash matters a little: about €1.40 of extra spend per €100 in the account. The negative intercept looks odd and is not: the top up and the cash effect work around a normal month, adding above it and pausing below it, and at the averages the equation gives −2,410+0.11×18,400+0.24×18,400+0.014×41,000≈4,600-2{,}410 + 0.11 \times 18{,}400 + 0.24 \times 18{,}400 + 0.014 \times 41{,}000 \approx 4{,}600. When the estimated system reproduces the rules the founder actually follows, I start trusting the estimated effect of the rules.

So the founder does not double the budget. At €1.50 of first year bookings per euro and an assumed 80% gross margin, a euro of ads returns 1.50×0.80=1.201.50 \times 0.80 = 1.20, so €1.20 of contribution in year one. Fine, but not the licence to print money that 2.10 implied. And a linear model says nothing about whether the next euro earns as much as the average one, see Foundations: marginal versus average. He steps it up by 30% and runs a geographic holdout on Meta to check the 1.50 against something that needs no instrument. I have written about five ways to prove a campaign actually worked. A holdout is the first of them, and an estimate from observational data is a hypothesis for the holdout, not a substitute.

How to run it yourself

You need monthly data (weekly if you have the volume, with more care about seasonality), at least 36 periods, ideally 60. For each period: the outcome, spend by channel, the exogenous drivers of the outcome you can measure (organic signups, calendar indicators, price changes), and the inputs to the budget decision as they were actually used (the lagged outcome, cash, the annual plan). Write the budget rule down before you look at any regression output. If nobody can, interview whoever sets the budget for 20 minutes. The rule exists even if it is a habit.

In Python the whole estimation is a few lines with the linearmodels package:

import pandas as pd
from linearmodels.iv import IV2SLS

df = pd.read_csv("vanlog_monthly.csv", parse_dates=["month"]).set_index("month")
df["bookings_lag1"] = df["bookings"].shift(1)
df["jan"] = (df.index.month == 1).astype(int)
df = df.dropna()

model = IV2SLS(
    dependent=df["bookings"],
    exog=df[["organic_signups", "jan"]].assign(const=1.0),
    endog=df["ad_spend"],
    instruments=df[["bookings_lag1", "opening_cash"]],
)
res = model.fit(cov_type="kernel")   # HAC standard errors for monthly data
print(res.summary)
print(res.first_stage)                # partial F for ad_spend
print(res.sargan)                     # overidentification test
print(res.wu_hausman())               # does 2SLS actually differ from OLS?

The kernel option gives standard errors that allow for heteroskedasticity and autocorrelation (HAC), which monthly data need.5 first_stage, sargan and wu_hausman are the diagnostics the results object provides.6 One detail: linearmodels reports the partial first stage statistic as a chi squared, so divide it by the number of instruments, two here, to get roughly the F statistic the rule of 10 refers to. Where the errors are badly behaved, Hansen's J test is the robust cousin of the Sargan test, available from the IVGMM estimator as j_stat.7 The code runs as shown on a simulated 36 month file and prints all four parts.

In R the same model is one call to ivreg with the instruments listed after a vertical bar.1 Whatever the tool, the checks before you trust the number are the same five:

  1. First stage F above 10.
  2. The overidentification test not rejecting.
  3. The Wu Hausman test rejecting. It asks whether spend can be treated as exogenous, in effect whether OLS and 2SLS differ by more than noise. If not, keep the simpler model.
  4. No residual autocorrelation, or HAC standard errors and a longer lag if there is.
  5. A plot of fitted spend against actual spend, so you can see how much of the variation the instruments explain.

Time: a week to assemble and clean the data, a day for the model, and a week of arguing about instruments, which is the week that matters.

Finding instruments in marketing data

The instrument question is where most attempts die, so here is what works, roughly in the order I reach for it.

  1. Written budget rules are the best instruments there are, because the rule is a mechanical link between something in the past and spend today, and you can read the exclusion restriction off the spreadsheet: lagged revenue, lagged margin, a share of last quarter's cash flow.
  2. Financial constraints: opening cash, card limits, a financial year budget that resets in January, the quarter end freeze the finance director imposes.
  3. Platform accidents: an account suspension, a tracking outage that left automated bidding blind for three weeks, a policy change that disapproved half the creatives.
  4. With regional data, reach caps can leave a single national campaign with uneven local exposure. That unevenness is an instrument only if you can argue it is unrelated to local demand.
  5. People: the founder's holiday, an agency handover, a parental leave cover who did not touch the campaigns.

Now the ones that look like instruments and are not. The cost per click index in your category seems ideal, since you did not choose it. But it changes what a euro of spend buys, so it reaches bookings directly and belongs in the outcome equation, as the worked example below shows. Competitors' spend affects your demand directly. Weather affects both spend and demand for most seasonal businesses. Above all of these sits the one instrument that needs no argument: a randomised holdout. If you can switch spend off in a random set of regions or weeks, do that, and use this chapter to make sense of the years when you did not.

Worked example: testing an instrument by saying it out loud

Vanlog's bookkeeper suggests a third instrument: the monthly Google cost per click for "job management software". Say the exclusion out loud: "the cost per click changes bookings only through how much the founder spends." It does not. At a fixed budget a higher cost per click buys fewer clicks and fewer trials, so it moves bookings with spend unchanged. It fails before any data is loaded. The founder's two weeks in Kerry each August pass the test: "The founder being on holiday changes bookings only because nobody tops up the campaigns." That is plausible for a business whose customers do not know or care where he is, as long as nothing else at Vanlog stops while he is away.

Pitfalls

Weak instruments. When the first stage F is low, 2SLS is biased towards OLS, the very thing you were trying to escape, and with many weak instruments it drifts right back to the OLS answer.8 Its sampling distribution is wide and oddly shaped, so the reported standard errors understate how little you know.4 The honest response is to find better instruments or to say that the data cannot answer the question.

Instruments that fail exclusion. These are worse, because nothing in the output warns you. The overidentification test compares instruments with each other. If they are all wrong in the same direction it passes happily. The only protection is the argument you make in plain language about why this variable cannot reach the outcome except through spend, and the willingness to lose that argument.

Lingering shocks. They poison lagged instruments. If the booking residuals are autocorrelated, last month's bookings carry this month's shock and the instrument is contaminated. The opening cash balance, built from last month's takings, carries it too. Check the residual autocorrelation as in the previous chapter, and see whether the estimate holds up with a two month lag. If it moves a lot, say so in the memo.

Small samples. They give wide bands, and the temptation is to trim instruments or controls until the band looks presentable. Resist it. 36 months is thin, the wide band is the result, and "between 0.5 and 2.5" is something a decision maker can act on. "1.50" after you quietly removed an instrument is not.

The shape of the response. 2SLS fixes the direction of causation, not the shape of the response. If ad effects saturate, a linear system overstates the return at high spend even after the simultaneity is dealt with. And the system is the business as it was run: if the founder changes his rule next year, the spend equation changes and so does the identification strategy. Re estimate when the rules change, and treat the number as a working figure, not a constant of nature.

How I do this for clients

The data I ask for is unglamorous: three to five years of monthly outcomes from the accounting system, spend by channel, whatever exogenous drivers you can export, and the budget rule as it was actually applied, informal parts included.

It starts with the free workshop, where we draw your feedback loop on a whiteboard and list every rule and habit that sets spend. Then two weeks of real work on me, before you commit to anything: I assemble the system, test the instruments, run the checks above and come back with a first estimate and an honest statement of whether the data can support it.

What you get is a model in your own repository (it runs without me, and the terms for code and models are in the analytics and data science terms), a two page decision memo with one number, its band and the biggest risk to it, and a small dashboard that answers one question: what is a euro of advertising worth this quarter, and how sure are we. Where it makes sense I also propose a budget rule that keeps the data readable in future, typically a planned holdout or a step change committed in advance, because the best instrument is one you designed. This is Data Science work at its core, and it pairs naturally with Performance Marketing if you want the same person to run the campaigns and be accountable for the number. The fees are on the pricing page. No vanity metrics, and every number comes with its error margin attached.

Questions to ask whoever built your marketing model

  • Is there anything in our business, written or habitual, that sets marketing spend from sales? If yes, how did the model account for it?
  • Did the model treat spend as something that happened to us, or as something we chose in response to results?
  • What are the instruments, and would a sceptical colleague accept that they cannot reach sales except through spend?
  • What is the first stage F, and what happens to the estimate if the weakest instrument is dropped?
  • How far did the answer move between the single equation and the system?
  • What is the band around the number, and does the recommendation survive the bottom of it?
  • Have we tested the estimate against a holdout since, and when will we?

The series is inspired by Mike Grigsby's Marketing Analytics.9 The explanations, examples and numbers here are my own.

Footnotes

  1. Christoph Hanck, Martin Arnold, Alexander Gerber and Martin Schmelzer, Introduction to Econometrics with R, section 12.1 The IV estimator with a single regressor and a single instrument, https://www.econometrics-with-r.org/12.1-TIVEWASRAASI.html

  2. Google, About Target ROAS bidding, Google Ads Help, https://support.google.com/google-ads/answer/6268637

  3. Christoph Hanck, Martin Arnold, Alexander Gerber and Martin Schmelzer, Introduction to Econometrics with R, section 12.2 The general IV regression model, https://www.econometrics-with-r.org/12.2-TGIVRM.html

  4. Christoph Hanck, Martin Arnold, Alexander Gerber and Martin Schmelzer, Introduction to Econometrics with R, section 12.3 Checking instrument validity, Key Concept 12.5, https://www.econometrics-with-r.org/12.3-civ.html

  5. Kevin Sheppard, linearmodels documentation, IV2SLS.fit (covariance estimators), https://bashtage.github.io/linearmodels/iv/iv/linearmodels.iv.model.IV2SLS.fit.html

  6. Kevin Sheppard, linearmodels documentation, IVResults (first_stage, sargan, wu_hausman), https://bashtage.github.io/linearmodels/iv/iv/linearmodels.iv.results.IVResults.html

  7. Kevin Sheppard, linearmodels documentation, IVGMMResults (j_stat), https://bashtage.github.io/linearmodels/iv/iv/linearmodels.iv.results.IVGMMResults.html

  8. Douglas Staiger and James H. Stock, Instrumental variables regression with weak instruments, NBER Technical Working Paper 151, 1994, https://www.nber.org/papers/t0151

  9. Mike Grigsby, Marketing Analytics: A Practical Guide to Improving Consumer Insights Using Data Techniques, Kogan Page, 2022, ISBN 9781398608191, https://www.netgalley.co.uk/catalog/book/267990

If your ad budget is set from last quarter's results and someone has handed you a return on ad spend from a regression, I would like to see it. Bring the monthly numbers and the budget rule as you actually apply it to the free workshop, and we will draw the loop together and see whether the data can answer the question at all. The first two weeks of work are on me, and you get an honest number with its band, not a flattering one.