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:
where is the R² from regressing channel on all the other predictors. The second fraction is the variance inflation factor (VIF). With two channels correlated at 0.9, = 0.81 and the VIF is about 5.3, so the standard error is ≈ 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.
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.
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.
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.
