Polynomial distributed lags: how long does marketing keep working?

Most marketing does not work on the day you do it. An email is read on Tuesday, forwarded on Wednesday and acted on the following Sunday; a catalogue sits on a kitchen table for a fortnight; a trade ad is remembered when the budget meeting finally happens. If you only count the effect in the week it happened, you will undervalue every slow channel and overvalue every fast one, and your budget will drift towards paid search whether or not that is where the money is. This chapter is about the distributed lag model, which estimates how much of an action's effect arrives in each of the following weeks, and about the Almon polynomial restriction that makes it estimable on ordinary business data. I use Werkbank, a Rails SaaS for craft businesses, and 78 weeks of newsletter sends and trials to show how the lag curve is estimated, how to read its peak, decay and total, how to validate it on holdout weeks, and how it turned into a concrete decision to move from monthly to three weekly sends. This is part 5 of 21 of the Marketing Analytics series.

The newsletter that keeps working after you have forgotten it

Werkbank sends one newsletter a month to about 30,000 craft businesses: joiners, electricians, tilers, the people who run a van and a spreadsheet. Every send is followed by a bump in trial signups, and the founder, quite reasonably, looks at the trials on send day and the day after, divides by emails sent, and calls that the email conversion rate. It came to 0.2 percent. Not exciting. She was about to cut the newsletter to once a quarter to save the writer's time.

The problem is that the bump on send day is only the first instalment. A tiler reads the mail on Tuesday and forwards it to his partner who does the books; she opens a trial a week later, on a Sunday evening when the invoices are being done. Some of the effect arrives in week two, some in week three. Measured properly, the newsletter was worth about four trials per 1,000 emails, not two, and most of that arrived after the day the founder stopped counting. That is what a distributed lag model does: it tells you how much of a marketing action's effect arrives now, how much arrives later, and when it has finished arriving. Once you know that, you know when to send the next one.

Where this sits in the series

This is chapter 5 of 21 and we are in part two, dependent variable techniques, where a business outcome (trials, orders, bookings) is explained by things you control. The previous chapter on demand and price elasticity used ordinary regression where cause and effect happen in the same period. This chapter adds time: the cause happens in week 10 and the effect dribbles out over weeks 10 to 15. The next chapter on Poisson regression deals with a different problem, outcomes that are counts and cannot go negative. Later, in chapter 16 on media mix modelling and adstock, the lag idea comes back in a different costume.

One number for the email effect is the wrong shape

When you regress weekly trials on weekly emails sent, you get one coefficient: trials per 1,000 emails, in the same week. Every trial that happens in a later week because of that email is credited to whatever else happened in that later week, or to the intercept, or to noise. The coefficient is too small and your decision is wrong in a predictable direction: you underinvest in anything with a slow effect and overinvest in anything with a fast one.

The fix is not a smarter single number. The fix is to admit the effect is a curve over time, estimate the curve, and then summarise it with the numbers that matter: where it peaks, when it has died, and what it adds up to.

The distributed lag model

Write trials in week tt as yty_t and emails sent (in thousands) in week tt as xtx_t. A distributed lag model says this week's trials depend on this week's emails and on the emails of the previous LL weeks, each with its own weight:

yt=α+∑k=0Lβk xt−k+γ⊤zt+εty_t = \alpha + \sum_{k=0}^{L} \beta_k \, x_{t-k} + \gamma^\top z_t + \varepsilon_t

Here yty_t is the outcome in week tt, α\alpha is the baseline (trials that would happen with no email at all), βk\beta_k is the effect of 1,000 emails sent kk weeks ago on trials this week, LL is the lag length (how many weeks back you allow the effect to reach), ztz_t is a set of control variables such as paid search spend, holiday weeks and a trend, with their coefficients γ\gamma, and εt\varepsilon_t is the error. The set of weights β0,β1,…,βL\beta_0, \beta_1, \dots, \beta_L is the lag curve. It is the whole point of the exercise.

Three summaries of the curve do most of the work:

βtotal=∑k=0Lβk\beta_{\text{total}} = \sum_{k=0}^{L} \beta_k

The total effect is the sum of the weights: how many trials 1,000 emails eventually produce, across all the weeks in which they produce anything. The peak lag is the kk with the largest βk\beta_k. And the mean lag,

kˉ=∑k=0Lk βk∑k=0Lβk\bar{k} = \frac{\sum_{k=0}^{L} k \, \beta_k}{\sum_{k=0}^{L} \beta_k}

is the average delay between sending and effect, weighted by how much effect arrives in each week. For Werkbank it comes out at about a week and a half.

Why unrestricted lags fall apart

The obvious approach is to put xt,xt−1,…,xt−Lx_t, x_{t-1}, \dots, x_{t-L} into an ordinary regression and read off the coefficients. I have done this on Werkbank's 78 weeks and I show the result below because it is instructive. The numbers throughout are illustrative, but the pattern is exactly what you will see on real data.

Lag kkUnrestricted βk\beta_kStd. errorReads as
01.310.62plausible
10.420.88too low, noisy
22.050.91too high
3minus 0.660.87emails destroy trials?
41.170.83a second peak?
5minus 0.080.61zero, probably
Total4.211.38fine, oddly

Two things went wrong. First, there are too many parameters: six lag weights plus controls from 73 usable weeks (78 minus the 5 lost to lags). Second, and worse, the lagged variables are nearly copies of each other. Werkbank sends on a fixed monthly rhythm, so a week with a big xtx_t is followed with great regularity by a big xt−4x_{t-4} or xt−5x_{t-5} four or five weeks later, and lags 0 and 4 become almost indistinguishable to the regression. That is collinearity, and its symptom is exactly this: individual coefficients that swing wildly and change sign, wide standard errors, and a total that is oddly stable because the errors cancel. The total is right and every individual number is useless.

There is an irony here I point out to every client with a rigid send calendar: a perfectly regular cadence is easy to run and almost impossible to measure. A little irregularity in the send dates is a gift to whoever has to analyse them.

The Almon trick: make the weights follow a curve

Shirley Almon's idea from the 1960s is simple and still the cleanest fix I know. Instead of estimating six free weights, assume the weights lie on a smooth low order polynomial in the lag:

βk=a0+a1k+a2k2+⋯+apkp=∑j=0pajkj\beta_k = a_0 + a_1 k + a_2 k^2 + \dots + a_p k^p = \sum_{j=0}^{p} a_j k^j

Here kk is the lag in weeks, pp is the degree of the polynomial (2 or 3 in practice) and the aja_j are the polynomial's coefficients. Instead of L+1L+1 weights you estimate p+1p+1 coefficients, and the weights are recovered from them. A quadratic can describe a hump; a cubic can describe a quick rise, a hump and a long tail, which is the shape most marketing effects have.

The clever part is that this is still ordinary least squares. Substitute the polynomial into the lag model and swap the order of the sums:

yt=α+∑j=0paj(∑k=0Lkj xt−k)+γ⊤zt+εt=α+∑j=0paj wjt+γ⊤zt+εty_t = \alpha + \sum_{j=0}^{p} a_j \left( \sum_{k=0}^{L} k^j \, x_{t-k} \right) + \gamma^\top z_t + \varepsilon_t = \alpha + \sum_{j=0}^{p} a_j \, w_{jt} + \gamma^\top z_t + \varepsilon_t

Each wjt=∑kkjxt−kw_{jt} = \sum_k k^j x_{t-k} is a new constructed variable: w0tw_{0t} is the plain sum of the last L+1L+1 weeks of emails, w1tw_{1t} is the same sum with each week weighted by its lag, w2tw_{2t} weighted by the lag squared, and so on. You build these four columns in a spreadsheet or three lines of code, regress yty_t on them and the controls, and the aja_j fall out. Then βk\beta_k for each kk is just the polynomial evaluated at kk.

What you have bought is stability: the six weights now share four parameters, so they cannot flip sign from one lag to the next. What you have paid is an assumption: that the true curve is smooth. For emails, catalogues and most advertising that is a very good assumption. For a flash sale with a hard deadline it is not, and I say so in the pitfalls.

Choosing the lag length and the degree

Two decisions, and neither should be made by staring at p values alone.

Lag length LL. Start generous. If you think the effect is gone in four weeks, fit with eight. Look at the tail weights: if β6,β7,β8\beta_6, \beta_7, \beta_8 are indistinguishable from zero and the curve has flattened, cut back to where it has died and refit. Compare the fits with an information criterion such as AIC or BIC, which reward fit but penalise parameters; pick the shortest LL that is not clearly worse. Too short an LL is the expensive mistake: the late effect is silently pushed into the intercept and the total is understated.

Degree pp. Fit degree 2 and degree 3 and compare. If the cubic's a3a_3 is significant and the curve has a visibly different shape, keep it. If not, the quadratic is fine. I very rarely go above 3 with weekly marketing data; a quartic on 78 weeks is fitting noise. Also test the restriction itself: the Almon model imposes L−pL - p linear restrictions on the unrestricted lags, so an F test between the two tells you whether the polynomial is too rigid. If it rejects at the one percent level, look at the residuals before believing either model.

Endpoint restrictions (forcing βL+1=0\beta_{L+1} = 0 or β−1=0\beta_{-1} = 0) are available and sometimes sensible. I use the far endpoint when the tail is clearly zero; I never force the near end, because an instant effect is real for email.

Werkbank's lag curve, week by week

Same 78 weeks, same controls, L=5L = 5 and p=3p = 3, chosen by the recipe above. The estimated polynomial coefficients were a0=0.92a_0 = 0.92, a1=0.83a_1 = 0.83, a2=−0.47a_2 = -0.47 and a3=0.054a_3 = 0.054. Evaluating the cubic at each lag gives the curve:

Lag kk (weeks after send)Almon βk\beta_k (trials per 1,000 emails)Std. errorCumulativeShare of total
00.920.210.9221%
11.340.192.2653%
21.140.173.4079%
30.650.164.0594%
40.180.154.2398%
50.070.194.30100%
Total4.300.54

Reading it line by line. Lag 0: in the week of the send, 1,000 emails produce 0.92 extra trials, about a fifth of everything they will ever produce. This is the number the founder was measuring, and she was measuring it correctly; it was just the wrong number. Lag 1: the following week is the peak, 1.34 trials per 1,000. Half of the total effect has arrived by the end of week 1. Lag 2 is still strong at 1.14; by the end of it four fifths of the effect is in. Lag 3 at 0.65 is the last week that matters commercially. Lags 4 and 5 are small, and their standard errors are about as large as the estimates, so I read them as "close to zero, could be nothing". The total is 4.30 trials per 1,000 emails, with a standard error of 0.54, so a 95 percent interval of roughly 3.2 to 5.4. On a 30,000 email send that is about 129 trials per campaign, give or take 30.

Compare the unrestricted table: same total within noise, but now the shape is readable. Peak at one week, commercially dead after three, nothing after five.

The Almon lag curve for the Werkbank newsletter. Lag 0 is the send week; the peak is one week later; effectively nothing arrives after week 4.

And the cumulative view, which is the one that drives the cadence decision:

By the end of week 3, 94 percent of a send's effect has arrived. Weeks 4 and 5 add the last 6 percent.

One warning about totals and averages. 4.30 per 1,000 is the average effect at the volumes and frequencies Werkbank has actually run. It is not a promise about the 18th send of the year if you move to a higher cadence. That is a marginal question, and marginal ROI is not average ROI; I come back to it below.

From lag curve to send cadence

Now the decision the founder actually faced. Under the monthly calendar a send lands every four to five weeks. The curve says the effect is 94 percent delivered after three weeks and 98 percent after four. So in a five week month, the list sits for one to two weeks producing essentially nothing from email. That is the gap.

Move to a three week cadence and each new send lands just as the previous one has spent 94 percent of its effect. There is very little overlap, so you are not stacking a fresh message on top of one the reader has not finished responding to, and there is no idle fortnight. Twelve sends a year become about seventeen. If each send kept its full effect of roughly 129 trials, email would deliver about 2,200 trials a year instead of 1,550, an extra 650.

I do not believe the full 650, and I told her so. The model was estimated on monthly sends and knows nothing about what happens to open rates and unsubscribes at a higher frequency. Werkbank did have two sends spaced two weeks apart for a product launch in weeks 22 and 24, and the unsubscribe rate on the second was roughly double the usual. That is one observation, not evidence, but it is a warning. So the memo said: expected gain 260 to 650 trials a year, the low end assuming each extra send delivers only 60 percent of the current effect, with the risk on the unsubscribe side. And it said how to find out: split the list at random, half on three weekly, half on monthly, run it for twelve weeks and compare trials, unsubscribes and revenue. The split test is the correct tool for the part the model cannot see, and I have written a complete guide to marketing testing methods if you want the design details.

Why not fortnightly? Because at two weeks the previous send is only 79 percent through, the overlap is meaningful, and the one piece of frequency evidence we had pointed the wrong way. Three weeks is where the curve, the evidence and the writer's calendar agreed.

Where adstock fits in

If you have met adstock in media mix modelling, you have met a distributed lag with a very strict shape. Adstock assumes the effect decays geometrically: βk=β0λk\beta_k = \beta_0 \lambda^k with a single retention rate λ\lambda between 0 and 1. The effect is largest immediately and shrinks by the same proportion every week. One parameter for the whole curve is wonderfully economical with twelve channels and 156 weeks, and wrong whenever the peak is not at lag 0. Werkbank's peak is at lag 1; a geometric decay cannot produce that hump and would put too much weight on the send week and too little on the following two. The Almon polynomial is the more flexible cousin: a few parameters, any smooth shape.

How to run it yourself

Data you need: one row per week, at least 60 weeks and preferably 100 or more, with the outcome (trials, orders, enquiries), the marketing action in a sensible unit (thousands of emails, catalogue copies, pounds of spend), and the controls that also move the outcome: paid search spend, price changes, holiday and school break flags, a linear trend, perhaps a launch dummy. Weekly is the right grain for email; daily is too noisy and monthly hides the curve entirely.

The steps, as I run them:

The estimation loop. Most of the time goes into the weekly table and the controls, not the regression.

In Python with statsmodels it is short:

import numpy as np, pandas as pd, statsmodels.api as sm

L, p = 5, 3                                  # lag length, polynomial degree
x = df["emails_k"]                           # emails sent per week, in thousands
for j in range(p + 1):                       # Almon columns w_j = sum_k k^j x_{t-k}
    df[f"w{j}"] = sum((k ** j) * x.shift(k) for k in range(L + 1))
cols = [f"w{j}" for j in range(p + 1)] + ["paid_search", "holiday", "trend"]
X = sm.add_constant(df[cols])
fit = sm.OLS(df["trials"], X, missing="drop").fit(cov_type="HAC", cov_kwds={"maxlags": 4})
a = fit.params[[f"w{j}" for j in range(p + 1)]].to_numpy()
beta = np.array([sum(a[j] * k ** j for j in range(p + 1)) for k in range(L + 1)])
print(np.round(beta, 2), "total:", round(beta.sum(), 2))

The HAC standard errors matter: weekly residuals are autocorrelated, and plain OLS standard errors will flatter you. Check the residual autocorrelation; if it is strong, add a lagged outcome or model the errors, and treat the total's interval with more suspicion.

Before you trust it, hold out. Fit on the first 66 weeks, forecast the last 12, compare:

WeekEmails (000s)Actual trialsForecastError
6731101956%
680981046%
69091943%
70086807%
71064686%
722997925%
730931008%
74099936%
75072777%
763090956%
7701081035%
78089946%

Mean absolute percentage error about 6 percent, against 14 percent for a seasonal baseline that ignores email. More importantly, look at the shape: weeks 68 and 73, one week after a send, are the high weeks in both actual and forecast, and week 71, four weeks after, is the trough in both. The model has the timing right, which is the thing you are going to act on.

How long does this take? With a clean weekly table, an afternoon. Building the weekly table from a mail platform export, an analytics export and a finance sheet, and agreeing what counts as a trial, is a week.

Pitfalls

Regular cadence, collinear lags. I said it above and I will say it again because it is the most common reason the unrestricted model fails and the Almon model is silently misspecified: if you always send on the first Tuesday, lag 0 and lag 4 or 5 are nearly the same variable. Vary the send date by a week now and then.

Smoothness is an assumption. The polynomial cannot draw a cliff. A flash sale that ends on Sunday has an effect that is large for six days and exactly zero on Monday; a cubic will smear that into the following week and invent a tail that is not there. For hard deadline promotions, use short unrestricted lags at daily grain, or model the deadline explicitly.

Something else changed that week. Werkbank's biggest trial week in the sample was not an email week; it was the week a trade magazine ran a review. If that is not in the controls, the model will try to explain it with whatever email was nearby and the lag curve gets a phantom bump. Keep a log of everything that happened, and put the big ones in as dummies.

Reverse timing. Marketers send when they expect demand: before the busy season, after a product launch. If sends are timed to anticipated trials, the lag model will credit email with trials that were coming anyway. Controls for seasonality help; an honest holdout helps more; a randomised send timing test settles it.

Weekly boundaries. A Thursday send puts three days of lag 0 in the send week and four in the following week, so the "peak at lag 1" is partly a calendar artefact. If you send on a fixed weekday, define your analysis weeks to start on that weekday. It sounds pedantic; it moves the peak.

How I do this for clients

The deliverable is a lag curve you can act on, not a regression printout. I need a weekly export from your email or campaign tool (sends, opens, unsubscribes), the outcome from your product or shop database (trials, orders, enquiries) and whatever else you spent money on week by week, plus a calendar of launches, price changes and anything unusual. Sixty weeks is the floor; if you have less, I will say so and we will talk about what can honestly be learned from it.

It starts with a free workshop where we agree the question (for Werkbank it was "how often should we send?"), the outcome that counts, and where the data lives. Then I do two weeks of real work at my own risk: the weekly table, the model, the holdout, and a first draft of the curve. If the data cannot support the answer, you hear that at the end of the two weeks and owe nothing.

What you get is a one page decision memo with a number and a risk (for Werkbank: 4.3 trials per 1,000 emails with its interval, the three weekly recommendation, the expected gain and the unsubscribe risk), the fitted model as a notebook you own and can rerun each quarter, and a small dashboard that answers one question: how much of last month's trials did email deliver, and when. If you want the split test run and read as well, that is part of my performance marketing work; the modelling itself sits under data science. Pricing is on the pricing page in plain terms: a fixed fee for the modelling, and for ongoing growth work a commission based option where I earn when the trials turn into revenue.

Questions to ask whoever measures your marketing

  • How many weeks after a send do you keep counting its effect, and why that number?
  • Can you show me the lag curve, not just a conversion rate, for our last twelve campaigns?
  • What controls are in the model, and is the trade press review from March in there?
  • Did you hold out the last quarter and forecast it before telling me the model works?
  • What is the confidence interval on the total effect, and would the decision change at the low end?
  • Is our send calendar so regular that the lags cannot be separated, and should we vary it?
  • Does the cadence recommendation account for fatigue and unsubscribes, or only for the curve?

This series is inspired by Mike Grigsby's Marketing Analytics (Kogan Page). The explanations, examples and numbers here are my own.

If you have a year or more of weekly sends and outcomes and have never seen the lag curve behind them, send me the two exports and I will tell you what can honestly be learned from them. The first conversation is a free workshop where we agree the question, the outcome that counts and where the data lives. After that I do two weeks of real work at my own risk before you commit to anything. If the data cannot support an answer, you hear that plainly. If it can, you get a curve, a number with its error margin and a cadence you can defend to your team. Book the workshop and bring the awkward question.

1%of every invoice goes to a UK charity you pick.

A donation, never sponsorship. You choose the cause at onboarding.

The story behind the pledge →

Stay ahead of your competition.

The latest innovative products and services, straight to your inbox before your competitors hear about them.

Get up to 5% off your first six months: 1% per topic you pick, the full 5% when you take everything. Limited offer · ends 31 December 2026.

New clients only. Terms apply.

* Up to 5% off your first six monthly invoices, new clients only. Full terms.

Questions about pricing, contracts or how we work together?

Read the FAQ