HomeCourseModule 16 › User story: simple multi-touch attribution

User story: simple multi-touch attribution

Module 16 · Scenario: Sales & Marketing9 min readAdvanced

What you'll learn

  • Build a journey per customer
  • Try first-touch, last-touch, and linear attribution
  • Compare the answers

The data

touches = pd.read_csv("touches.csv", parse_dates=["ts"])
# user_id, ts, channel, conversion (bool), revenue

Build journeys

converters = touches.loc[touches["conversion"], "user_id"].unique()
j = (touches[touches["user_id"].isin(converters)]
        .sort_values(["user_id","ts"])
        .groupby("user_id")
        .agg(path=("channel", list),
             revenue=("revenue", "max")))

First-touch

j["first"] = j["path"].apply(lambda p: p[0])
first_touch = j.groupby("first")["revenue"].sum()

Last-touch

j["last"] = j["path"].apply(lambda p: p[-1])
last_touch = j.groupby("last")["revenue"].sum()

Linear (equal credit to every touch)

rows = []
for path, rev in zip(j["path"], j["revenue"]):
    share = rev / len(path)
    for c in path:
        rows.append({"channel": c, "credit": share})
linear = pd.DataFrame(rows).groupby("channel")["credit"].sum()

Compare

compare = pd.concat([first_touch.rename("first"),
                     last_touch.rename("last"),
                     linear.rename("linear")], axis=1).fillna(0).round(0)
compare.sort_values("linear", ascending=False)

Key takeaways

  • First-touch overrates discovery channels; last-touch overrates closing channels.
  • Linear is naive but a good "everyone gets credit" baseline.
  • Show all three side-by-side; the truth is usually somewhere in between.

Position-based (40/20/40)

Implement a position-based model: 40% to first, 40% to last, 20% split among the middle touches.

📹 Video walkthrough
A video walkthrough of this lesson will be embedded here. Until then, the written walkthrough above mirrors what the video will cover step-for-step.