Skip to content

Channel order mismatch between media and media_spend can silently produce incorrect spend attribution #1644

Description

@h30s

Description

While looking through the validation flow, I noticed a case where media and media_spend can contain the same channel names but in a different order, and the model appears to accept the input without raising an error.

For example:

  • media: ["Search", "TV"]
  • media_spend: ["TV", "Search"]

This can realistically happen when impressions and spend data come from separate exports that are sorted differently.

Relevant Code

  • meridian/data/input_data.py - _check_dim_match
  • meridian/data/input_data.py - _validate_dimensions
  • meridian/data/input_data_builder.py - _validate_channels_consistency
  • meridian/model/media.py - build_media_tensors

Why This Happens

In the direct InputData path, validation appears to check only that dimensions have matching sizes:

_check_dim_match(constants.MEDIA_CHANNEL, [self.media, self.media_spend])

_check_dim_match() verifies dimension lengths but does not verify coordinate values or ordering.

For xarray inputs, channel validation currently compares sets of channel names:

set(...)

This ensures the same channels exist, but it does not ensure they appear in the same order.

Later, during model construction, both arrays are converted to backend tensors:

media = backend.to_tensor(input_data.media, ...)
aggregated_media_spend = backend.to_tensor(
    input_data.aggregate_media_spend(...),
    ...
)

At this point the coordinate labels are no longer available, so the tensors rely entirely on positional ordering.

Potential Impact

If channel ordering differs between execution and spend inputs, media effects for one channel may be paired with spend from another channel.

This could affect:

  • ROI and mROI calculations
  • Prior calibration
  • Response curves
  • Budget optimization recommendations

The outputs may still look reasonable, making the issue difficult to detect.

Suggested Fix

Consider validating exact coordinate equality instead of only checking dimension lengths or set equality.

Examples:

  • media.media_channel should exactly match media_spend.media_channel
  • reach.rf_channel, frequency.rf_channel, and rf_spend.rf_channel should exactly match
  • organic_reach.organic_rf_channel and organic_frequency.organic_rf_channel should exactly match

It may also be worth validating time-coordinate alignment for datasets where the documentation expects matching time dimensions.

Alternatively, spend arrays could be automatically reindexed to the execution array's channel order before tensor conversion.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions