Skip to content

Retail and consumer goodsBI, AI and ML for the business

Bought together: market basket analysis

Receipts show which products are bought together, but they stay in the till system. In Muvia a Python function computes the support, confidence and lift of every pair each night, and the dashboard says what to do with them: bundled promotions, neighbours on the shelf, suggestions at the till.

Illustrative scenario: it describes a typical case, not a customer project.

Receipts know what goes together. Nobody reads them.

Every day the tills record thousands of receipts, and each one holds a valuable fact: which products the same person put in the same basket. That fact usually stays in the till system, and bundled promotions are decided on gut feeling.

Counting pairs over a few months of receipts is not hard. The hard part is doing it again every night, telling the pairs that truly go together from the ones made of best-sellers, and getting the result to the people who decide promotions and shelves.

Who it's for
Category managers and marketing, store and layout managers, whoever runs the loyalty programme.
Loyalty-card receipts from an SFTP folder, the product range from the ERP on SQL Server and the promotion plan in Excel flow into Muvia, where a Python function computes the association rules every night; out come the rules table, a dashboard with the lift map, recommendations per item and Athena's answers.

In Muvia, step by step

Real product screens, recorded on a project with sample data.

1 of 5

The video · Receipts show which products are bought together, but they stay in the till system. In Muvia a Python function computes the support, confidence and lift of every pair each night, and the dashboard says what to do with them: bundled promotions, neighbours on the shelf, suggestions at the till.

What you get

Promotions built on real baskets
Bundled promotions start from the pairs customers really buy together, not from gut feeling.
Lift, not just frequency
Lift tells the pairs that seek each other apart from the ones made of best-sellers.
Rules that stay fresh
The flow rebuilds the rules every night on the new receipts, so they follow the season and the range on their own.
An action for every rule
Bundled promotion, shelf neighbour or suggestion at the till: whoever runs the store knows what to do tomorrow.

For the technical team

How it is built in Muvia

  1. 1

    Load the receipts

    The till files arrive every night in an SFTP folder and are appended to the same table: one receipt per row, with the loyalty card and the items. The product range is copied from the ERP on SQL Server.

  2. 2

    Write the rules in Python

    A Python function counts the pairs of items on the same receipt and computes support, confidence and lift; the minimum thresholds are parameters. Athena can draft the code, and a trial run writes nothing.

  3. 3

    Schedule the recomputation

    A flow runs the function every night and writes the rules, the map and the recommendations to managed tables. Dashboards and notebooks read them like any other data.

  4. 4

    Build the dashboard

    The lift map shows the families of the basket; a flow chart shows who buys one item and what they buy on later visits; every strong rule carries its recommended action.

  5. 5

    Ask Athena

    Which pairs should go into a bundled promotion? Athena reads the rules, saves the query in the Lab and answers in one sentence.

Python function

from collections import Counter
from itertools import combinations

import pandas as pd

def transform(inputs, params, ctx):
    min_support = params["min_support_pct"] / 100
    min_lift = params["min_lift"]
    baskets = inputs["rows"]["item_codes"].str.split("|").map(lambda c: sorted(set(c)))
    n = len(baskets)
    singles, pairs = Counter(), Counter()
    for basket in baskets:
        singles.update(basket)
        pairs.update(combinations(basket, 2))
    rules = []
    for (a, b), k in pairs.items():
        lift = k * n / (singles[a] * singles[b])
        if k / n >= min_support and lift >= min_lift:
            rules.append({"item": a, "bought_with": b,
                          "support_pct": round(100 * k / n, 2),
                          "confidence_pct": round(100 * k / singles[a], 1),
                          "lift": round(lift, 2)})
    out = pd.DataFrame(rules).sort_values("lift", ascending=False)
    ctx.logger.info("rules found: %d over %d receipts", len(out), n)
    return {"rows": out}
Association rules: support, confidence and lift for every pair on the same receipt. The flow runs it every night.
The data it needs
  • Receipts with the loyalty card and the items bought, from the till files
  • Product range with items and departments, from the ERP on SQL Server
  • The season's promotion plan, from an Excel file
Parts of Muvia used

Bring us a question you can't answer today.

We start from a real question your business has and walk the path from source to dashboard with your systems, not a demo dataset.