Relationships
What moves together?.
Harbor Coffee is losing customers, and the founder wants to know why. Do loyalty members stay longer? Do frequent visitors leave less? A correlation table is a quick first look at what moves together. But beware. It's also the most misunderstood idea in all of data.

- Why are customers leaving?
- A first look at what moves together
- Often misunderstood
A correlation heatmap
Correlation runs from minus one to one. Near zero means no straight line link. We compute it for all pairs, and look closely at churn, the column for whether a customer left. Run it. Visits has a negative link with churn, so frequent visitors leave less. Loyalty is negative too. The heatmap shows all of the pairs at once, which is great for spotting patterns quickly.
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
df = pd.read_csv("customers.csv").drop_duplicates()
cols = ["age", "visits_per_month", "avg_spend", "loyalty", "churned"]
corr = df[cols].corr().round(2)
print(corr["churned"].sort_values().to_string())
plt.figure(figsize=(6, 4.5))
sns.heatmap(corr, annot=True, cmap="vlag", center=0)
plt.tight_layout(); plt.savefig("corr.png", dpi=110)visits_per_month -0.23 loyalty -0.11 avg_spend -0.04 age 0.01 churned 1.00
Correlation is not causation
Ice cream sales and drownings rise together. Does ice cream cause drowning? Of course not. Hot weather drives both. That's called a confounder. So, do loyalty cards keep customers? Or do people who already love Harbor Coffee just sign up for the card? Correlation can't tell you. Later, we'll learn how to answer that properly.
Comparing groups over time
Here's a chart for the founder. Monthly revenue, one line for each region. Seaborn's hue adds a line for each group automatically. Run it. You can see the summer dip, and the growth, and which regions lead. A good line chart can tell a whole story at a glance.
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
sales = pd.read_csv("sales.csv", parse_dates=["date"])
daily = sales.groupby(["date", "region"], as_index=False)["revenue"].sum()
daily["month"] = daily["date"].dt.to_period("M").dt.to_timestamp()
monthly = daily.groupby(["month", "region"], as_index=False)["revenue"].sum()
fig, ax = plt.subplots(figsize=(9, 4.5))
sns.lineplot(monthly, x="month", y="revenue", hue="region", ax=ax)
plt.tight_layout(); plt.savefig("regions.png", dpi=110)
print(monthly.groupby("region")["revenue"].mean().round(0).sort_values().to_string())region Americas 47591.0 Asia 58752.0 Africa 67896.0 Europe 94641.0
Summary
Correlations are clues, not proof. We've explored the data, and found patterns. But how do we know they're real? And how do we know they're not just luck? Next, statistics.
Key takeaways- Correlation: straight line links
- Confounders fool you
- Line charts tell stories