Multicollinearity in marketing mix models: when channels move together

If two channels always rise and fall together, a model can fit sales perfectly and still have no idea how to split the credit. Here's how to spot it in your data, and the fixes that add information rather than decimal places.

Mike Taylor By Mike Taylor · Updated · 10 min read

Multicollinearity in a marketing mix model is when two or more channels (or a channel and a control) move together so closely that the regression can’t separate their effects. The model can still fit total sales very well, but the individual channel coefficients become unstable: they swing from one refresh to the next, swap places in the ROI ranking, or turn negative, because the data only pins down the combined effect, not how to split it.

I wrote a shorter explainer on multicollinearity a few years ago that covers the general regression idea. This page goes much further into what it means for MMM specifically, because in marketing data it’s the normal state of affairs rather than an occasional nuisance. In my experience nearly every marketing mix model has at least one pair of channels that were planned together and therefore moved together, and it’s the single most common reason a model’s ROIs look “wrong” to the people who run the channels. I’ll show you why it happens, how to measure it on your own data, and which fixes actually add information.

Why marketing channels move together

In a textbook regression the predictors vary independently, so the model gets to see what happens when one moves and the others don’t. Media plans are built the opposite way. A product launch gets TV, YouTube, paid social and a search budget increase in the same fortnight. Black Friday lifts everything at once. Budgets are often set as a total and then split by fixed percentages, so when the total goes up every channel goes up with it. Always-on channels hum along at a steady level and contribute almost no variation at all. And some channels are mechanically linked: TV drives branded searches, so brand search spend rises whenever TV is on air.

Seasonality makes it worse, because most channels follow the same calendar as demand, which means they’re correlated with each other and with the confounders you’re trying to control for. Google’s researchers listed “correlated input variables” among the core data limitations of MMM in Chan and Perry’s 2017 paper, alongside the limited amount and range of data, and those three problems feed each other: two or three years of weekly data is only 104 to 156 rows, and if the channels in those rows never moved independently, there’s simply no information about their separate effects to find.

An accurate fit can support incompatible attributions

The course lesson on separating linked channels starts with an extreme case that makes the problem obvious. Imagine search and social always increase together, by exactly the same amounts, and the true model is that search returns $2 per $1 and social $1. Since the two spends are identical every week, the model only ever sees their sum, and any pair of coefficients that adds to 3 predicts sales perfectly: 2 and 1, or 3 and 0, or 5 and −2. A perfectly fitted sales line hasn’t chosen the correct channel story; it has chosen one of infinitely many stories that fit equally well.

Real data is rarely that extreme, but the same thing happens in a milder form whenever the correlation is high. In the formula for the variance of a coefficient, correlation with the other predictors appears as a multiplier on the uncertainty:

Var⁡(β^j)=σ2(n−1)Var⁡(xj)⋅11−Rj2\operatorname{Var}(\hat\beta_j) = \frac{\sigma^2}{(n-1)\operatorname{Var}(x_j)} \cdot \frac{1}{1 - R_j^2}

where Rj2R_j^2 is the R² from regressing channel jj on all the other predictors. The second fraction is the variance inflation factor (VIF). With two channels correlated at 0.9, Rj2R_j^2 = 0.81 and the VIF is about 5.3, so the standard error is 5.3\sqrt{5.3} ≈ 2.3 times larger than it would be if the channels varied independently. At 0.95 it’s 10.3 and about 3.2 times. Nothing is biased, in the sense that the estimates are still right on average across many hypothetical datasets, but you only get one dataset, and the one you have can land a long way from the truth.

The simulator below makes that concrete. It draws 200 datasets from exactly the same process, fits a regression to each, and plots every pair of estimated returns. Start at a correlation of 0.9, then drag it up to 0.99 and down to 0.3.

Interactive
Two channels that are always on together

Search and social are generated with a correlation you choose. The widget draws 200 fresh datasets from the same process, fits a regression to each, and plots every pair of estimated returns. The truth never changes: search earns $2.00 per $1 and social $1.00.

VIF (each channel)
–
Condition number
–
Median R²
–
Search estimate, 90% of runs
–
Runs ranking social above search
–
Runs with a negative return
–

Each dataset: weekly spend around $10,000 per channel (standard deviation $2,500), sales = 20,000 + 2.0 × search + 1.0 × social + noise. Ordinary least squares on each of 200 seeded resamples. VIF and condition number are for the first resample. Synthetic data.

At high correlation the cloud stretches into a long diagonal ridge along the line where search plus social equals 3. That ridge is the whole story of multicollinearity in one picture: the data knows the total very precisely (every point sits close to the line) but has almost no information about where along the line the truth sits. The R² is nearly identical in every run, so nothing in the fit statistics tells you which run you happened to get. Notice too that adding weeks helps, but slowly, because more rows of the same linked pattern mostly confirm the total again: going from 104 to 260 weeks narrows the range of search estimates by less than half, while cutting the correlation from 0.9 to 0.3 does better with the original 104 weeks. Reducing the correlation beats adding data, which is the most useful practical lesson on this page.

How to detect multicollinearity in your MMM data

There are three checks I’d run on any model’s inputs, and they take minutes.

Correlation matrix

The pairwise correlation matrix is the obvious first look, and correlations above about 0.8 between channels deserve attention. Its weakness is that it only sees pairs. If TV is roughly the sum of YouTube and display, each pairwise correlation can look moderate while TV is almost perfectly predictable from the other two together.

Variance inflation factor

The VIF catches those combinations because it regresses each predictor on all the others at once. The usual rules of thumb treat a VIF above 5 as worth checking and above 10 as serious, but I’d read it through its square root rather than as a pass/fail test: a VIF of 9 means that channel’s standard error is three times what it would be with independent variation, and you can decide whether that’s tolerable given how big the effect is. Remember to calculate VIFs on the variables as they enter the model, after adstock transformation, since adstock smooths spend and often increases the correlations.

Condition number

The condition number summarizes the whole design matrix in one figure: the square root of the ratio of the largest to the smallest eigenvalue of the predictors’ correlation matrix. If it’s large, some combination of the predictors barely varies, and the eigenvector behind the smallest eigenvalue tells you which columns are tied together. Belsley, Kuh and Welsch, whose 1980 book on regression diagnostics popularised the measure, suggested that condition indices of 30 or more signal a serious problem, though their version scales the columns differently and includes the intercept, so it runs higher than the correlation-based version used here. On the correlation-based scale I use in the calculator below, two channels correlated at 0.9 give a condition number of about 4.4 and at 0.95 about 6.2, so I treat anything above 5 as a reason to look closely and above 10 as serious.

You can run all three checks on your own data below. Paste a CSV with one column per channel (and any controls you plan to use), or load the practice dataset or a linked-channels example. The outcome column is unticked automatically if it’s called revenue or sales.

Interactive
VIF calculator for your own media data

Paste a CSV with a header row (weekly spend or impressions per channel, plus any controls). Choose the predictors you plan to put in the model; the outcome column should be left out.

VIF = 1 / (1 − R²) from regressing each predictor on all the others, with an intercept. Condition number = √(largest / smallest eigenvalue) of the predictors' correlation matrix. Nothing you paste leaves your browser. Practice data is Vexpower synthetic data.

The practice dataset is a useful contrast: its three channels have VIFs of about 1.0, because they were generated with independent variation, and that’s what a design with good separating information looks like. The linked-channels example is closer to a real media plan, with YouTube bought as a fixed share of TV, and the VIF for those two shows the problem immediately. If you’d rather run the same checks in Python, or need them in a notebook, the script below prints the correlation matrix, VIFs, condition number and the columns tied together in the weakest direction.

py
Multicollinearity check (Python)python vif-check.py my_data.csv --outcome revenue. Defaults to the practice CSV. Needs numpy and pandas.
Download

What multicollinearity does and doesn’t break

It’s worth being precise here, because multicollinearity gets blamed for things it doesn’t do. It doesn’t make the model’s predictions of total sales worse, as long as future weeks keep the same relationship between the channels; that’s why R² and MAPE look fine. It doesn’t bias the coefficients in the statistical sense. And it doesn’t affect channels that aren’t part of the correlated group.

What it does break is everything that depends on the split. Channel ROIs and contributions become unreliable, and a refresh with a few extra weeks of data can move them a lot. Signs can flip, which is where the classic “Facebook has a negative ROI” result comes from. Worst of all, budget optimization can amplify the noise: an optimizer reads the coefficients literally, so if search happens to land at 3.5 and social at −0.5 on this refresh, it will move everything into search, which is a recommendation the data never supported. In my experience, this is the most expensive consequence of multicollinearity, because the output looks like a confident plan rather than an uncertain estimate.

How to fix multicollinearity in a marketing mix model

The fixes fall into two groups, and the distinction matters. Some add new information that separates the channels. Others make the estimates stable by adding assumptions. Both are legitimate, but only the first kind can tell you something the data didn’t already know.

Fixes that add information

  • Run an experiment on one of the channels. A geo-lift test or platform lift study gives you an estimate of one channel’s effect that doesn’t depend on the correlation. Once one point on the ridge is pinned down, the other channel’s share follows from the well-identified total. Calibrating MMM with experiments explains how to feed the result into the model.
  • Vary spend deliberately. Changing the media plan so channels move independently for a few weeks (pausing one while holding the other steady, or flighting them on different schedules) creates exactly the variation the model is missing. It’s cheaper than people think, because it doesn’t have to be a formal test to help the model.
  • Use geographic variation. If spend differs across regions in different proportions, a geo-level model has many more independent combinations to learn from than a single national time series.
  • Use informative priors. In a Bayesian MMM, a prior on each channel’s ROI from past experiments or benchmarks tells the model where on the ridge it’s plausible to be. This is information, but it’s information from outside the dataset, so the prior deserves as much scrutiny as the data.

Fixes that add assumptions

  • Regularise the coefficients. Ridge regression, which Robyn uses, shrinks correlated coefficients towards each other and towards zero, which stops them flying apart. It makes the estimates stable without making them right: on the ridge, it tends to split the credit more evenly between the linked channels than the truth might.
  • Combine the channels. If YouTube is always bought as a share of TV, model “TV + YouTube video” as one channel. You lose the split, but you report a number the data supports instead of one it doesn’t.
  • Add business constraints. Robyn’s DECOMP.RSSD objective prefers models whose effect shares stay close to spend shares, and sign constraints stop coefficients going negative. These rule out the most implausible parts of the ridge, but they’re opinions about the answer, so say so when you report it.

There’s one tempting fix I’d avoid, which is dropping one of the correlated channels because its estimate looks awkward. If the channel really affects sales, its effect doesn’t disappear; it moves into whatever it was correlated with, usually the other channel or the baseline. The table looks tidier and the interpretation gets worse.

What I’d do in practice

When I find correlated channels in a model, I start by asking why they move together, since the answer usually points to the fix. If they’re planned together because of how the budget is split, a few weeks of deliberately varied spend will help more than any statistical technique. If one causes the other (TV and brand search), the problem is really a causal one, and the confounding variables guide is the place to start. If they’re both seasonal, better seasonality controls may separate them from demand even if not from each other.

Then I report the uncertainty honestly. A stable total contribution beside unstable channel contributions is a reason to investigate, not a reason to hide the uncertainty, and I’d rather show a combined ROI with a tight range than two separate ROIs with ranges that overlap zero. The pillar guide to marketing mix modeling has more on reading model output, and the Vexpower MMM course includes the attribution puzzle from the course lesson, where you can watch incompatible channel stories produce the same sales line.

Downloads

py
Multicollinearity check (Python)Correlation matrix, VIF and condition number for any CSV of model inputs; defaults to the practice dataset.
Download
csv
Practice weekly dataset (CSV)104 synthetic weeks of revenue, three channels and a promotion flag.
Download

Frequently asked questions

What is multicollinearity in a marketing mix model?

Multicollinearity is when two or more media channels or controls move together so closely that the regression cannot tell their effects apart. The model can still fit sales well, but the individual channel coefficients become unstable and can change sharply, or even turn negative, with small changes to the data.

What VIF is too high for marketing mix modeling?

A common rule of thumb treats a variance inflation factor above 5 as worth checking and above 10 as serious. The square root of the VIF tells you how much the coefficient's standard error is inflated, so a VIF of 9 means the uncertainty is three times what it would be with independent variation.

Does multicollinearity affect model accuracy?

Usually not much. Correlated channels mostly affect how the credit is split between them, not how well the model predicts total sales, which is why an MMM can have a high R squared and implausible ROIs at the same time.

How do you fix multicollinearity in MMM?

Add information that separates the channels: experiments on one of them, informative priors, deliberate changes to the media plan so channels vary independently, or geographic variation. Ridge regression and grouping channels make the estimates stable, but they do it by making assumptions rather than by learning more from the data.

Should I drop a correlated channel from my MMM?

Usually not. Removing a channel that really affects sales pushes its effect into whichever variable it moved with, so the remaining channel looks better than it is. Grouping the two into one combined channel is a more honest option if you can't separate them.

References

  1. Belsley, Kuh & Welsch (1980), Regression Diagnostics: Identifying Influential Data and Sources of Collinearity, Wiley Condition index diagnostics; the 30+ rule of thumb as documented in the olsrr package.
  2. Chan & Perry (2017), Challenges and Opportunities in Media Mix Modeling, Google Correlated input variables listed among MMM data limitations.
  3. Robyn documentation: features (ridge regression, DECOMP.RSSD) How Robyn regularises and selects models.
  4. Google Meridian documentation Bayesian MMM with ROI priors.
  5. Hoerl & Kennard (1970), Ridge Regression: Biased Estimation for Nonorthogonal Problems, Technometrics The original ridge regression paper, written for exactly this problem.
Mike Taylor
Mike Taylor

I've built marketing mix models for Monzo Bank, Booking.com, Time Out, The AA and others, advised Google, Appsflyer and Recast on MMM, and teach marketing mix modeling on LinkedIn Learning. Before that I co-founded a 50-person growth marketing agency. I write the Vexpower MMM course.

Keep reading

Learn MMM by doing itThe Vexpower course walks through thirty lessons on one invented brand, with simulators, Python labs and a decision case you can defend.
See the course