Lesson 1 of 5

Correlation, Causation and Potential Outcomes

Riverside Books, a small online bookshop, emailed a $10 coupon to some of its customers. The next month, the customers who got a coupon spent far more than the ones who did not. Marketing wants to declare victory: the coupon works, send it to everyone.

Before they do, look at the pattern below. Each dot is a customer: how loyal they were last year (across the bottom) against what they spent this month (up the side). It is a strong, real correlation, and it is exactly the kind of picture that fools people. This whole lesson is about the hard question hiding inside it: when does a pattern like this actually mean one thing causes another?

By the end of this lesson you will be able to:

  • Explain why a correlation between two things does not prove that one causes the other
  • Define a causal effect honestly, using the potential-outcomes idea at the heart of modern causal inference
  • See, in real R, why the coupon's raw $18 "effect" is mostly an illusion, and how randomizing the coupon recovers its true $8 effect

Prerequisites: you can run R and take a mean, and you can read a scatterplot. Every new term is defined as it appears.

The pattern

The gap Riverside Books sees

Let us put real numbers on the story. We will build Riverside Books' customer records right here, because each lesson runs in its own fresh R session. Each row is one customer, with three things we observe: their loyalty last year (a score centered at 0, where positive means more engaged), whether marketing emailed them a coupon, and their spend the next month in dollars.

Because this is a simulation, we can also secretly store two extra columns, y0 and y1: the spend we would see for that customer without and with a coupon. Hold on to those, they are the whole trick of this lesson, and in real life you never get to see them.

RInteractive R
# Riverside Books: one row per customer. set.seed(2024) n <- 2000 loyalty <- round(rnorm(n), 2) # last year's engagement, centered at 0 y0 <- round(45 + 10 * loyalty + rnorm(n, 0, 5)) # dollars spent WITHOUT a coupon y1 <- y0 + 8 # WITH a coupon: a real +$8 for everyone coupon <- rbinom(n, 1, plogis(1.2 * loyalty)) # marketing emailed loyal customers more spend <- ifelse(coupon == 1, y1, y0) # you observe only ONE of y0, y1 per person books <- data.frame(loyalty, coupon, y0, y1, spend) round(tapply(books$spend, books$coupon, mean), 1) # average spend: no coupon vs coupon #> 0 1 #> 40.2 58.0

  

There it is, the pattern marketing noticed: customers who got a coupon spent about $58 on average, against $40 for those who did not, a gap of about $17.80. The two variables, "got a coupon" and "spend," clearly move together. In the language of the earlier EDA lessons they are correlated: knowing one tells you something about the other.

A correlation is just a measured association. For two numbers it is summarized by Pearson's \(r\),

\[ r = \frac{\sum_i (x_i - \bar x)(y_i - \bar y)}{\sqrt{\sum_i (x_i - \bar x)^2}\;\sqrt{\sum_i (y_i - \bar y)^2}} \]

where \(x_i\) and \(y_i\) are the two measurements for customer \(i\), and \(\bar x, \bar y\) are their averages. The \(r\) on the cover scatter is about 0.9. But \(r\), and the $17.80 gap, are both silent about one thing: why.