Correlation and the shape of data
Covariance and correlation, curves, outliers and common causes, rank correlation, skew and kurtosis.
Create a free account Try part of it here
Why it matters
"Customers who view more pages spend more." "Longer prompts get better answers." Claims like these are correlations, and they drive product decisions every week. Correlation is easy to compute and easy to misread: it misses curved relationships, one odd point can create or destroy it, and two things can move together only because something else drives both. This lesson builds correlation from the variance you know, then looks at the shape of data, because skewed and heavy-tailed numbers (order values, response times, token counts) break the averages people report.
What you'll be able to do
- Compute covariance and correlation, and say why correlation is the one to compare
- Spot the three ways correlation misleads: curves, outliers and a hidden common cause
- Use rank (Spearman) correlation when a relationship is steady but not straight
- Describe a distribution's shape with skew and kurtosis, and choose the median when tails are long
What it covers
- Covariance: moving together
- Correlation: covariance without units
- Find the bug: correlation without the means
- Three ways correlation misleads
- When the groups disagree with the whole
- Rank correlation for steady but curved relationships
- The shape of a distribution: skew and kurtosis
- Working with long tails
Show the answer
Warm weather drives both, so they move together
A third thing, the weather, pushes both up and down. Two series moving together says nothing about one causing the other.
Covariance: moving together
You know variance: the average squared distance from the mean. Covariance does the same for two variables at once, multiplying their distances from their means instead of squaring one:
In plain words: each pair of values votes positive when both sit on the same side of their averages, and negative when they sit on opposite sides.
When both are above their means together, or below together, the products are positive and the covariance is positive. When one is high while the other is low, it's negative. Near zero means no straight-line tendency.
import statistics as st tents = [12, 15, 22, 30, 41, 38, 25, 14] sunscreen = [40, 52, 70, 95, 130, 118, 80, 45] # bottles print("covariance:", round(st.covariance(tents, sunscreen), 1)) cases = [s / 12 for s in sunscreen] # the same sales, counted in cases of 12 print("in cases:", round(st.covariance(tents, cases), 2))
Same sales, two very different covariances: its size depends on the units, so "368.6" alone means nothing.
Correlation: covariance without units
Divide the covariance by both standard deviations and the units cancel. That's the correlation , always between -1 and 1:
means the points sit on a rising straight line, on a falling one, and 0 means no straight-line relationship. Because units cancel, correlations can be compared across very different pairs of measurements.
There's a neat link to the embeddings lessons: subtract each variable's mean, and the correlation is exactly the cosine similarity of the two centered vectors. Correlation is cosine similarity after centering.
Squaring gives a useful reading: is the share of the variation in one variable that a straight line on the other accounts for. A correlation of 0.5 sounds strong, yet the line explains only a quarter of the variation; three quarters comes from everything else.
Show the answer
About 9%
r² = 0.3² = 0.09. A correlation of 0.3 is real but weak: most of the differences in scores come from other things.
import statistics as st tents = [12, 15, 22, 30, 41, 38, 25, 14] bottles = [40, 52, 70, 95, 130, 118, 80, 45] cases = [b / 12 for b in bottles] print(round(st.correlation(tents, bottles), 3), round(st.correlation(tents, cases), 3))
Show the answer
0.999 0.999
Rescaling one variable changes its covariance but not the correlation: the standard deviation shrinks by the same factor and cancels it out.
Find the bug: correlation without the means
correlation(xs, ys) should return Pearson's r, but it says [1, 2, 3] and [3, 2, 1] are positively related, when one goes down exactly as the other goes up. It's computing cosine similarity of the raw values. Fix it.
import math def correlation(xs, ys): num = sum(x * y for x, y in zip(xs, ys)) den = math.sqrt(sum(x * x for x in xs) * sum(y * y for y in ys)) return num / den print(round(correlation([1, 2, 3], [3, 2, 1]), 3))
Write a sentence or two, then compare it with a good answer in the lesson.
Three ways correlation misleads
Curves. Correlation measures straight-line relationships only. Satisfaction that rises with delivery speed up to a point and then doesn't change, or a U shape, can have a correlation near zero while one variable almost fully determines the other. Always plot before you trust .
Outliers. One extreme point can create a strong correlation out of noise, or wipe out a real one, because distances from the mean are squared in spirit. The cell below adds a single unusual week to six unrelated ones.
import statistics as st visits = [1, 2, 3, 4, 5, 6] orders = [3, 1, 4, 1, 5, 2] print("six weeks:", round(st.correlation(visits, orders), 3)) print("plus one launch week:", round(st.correlation(visits + [30], orders + [30]), 3))
A common cause. Tents and sunscreen correlate because of weather; page views and spending may both be driven by how much someone already wanted to buy. Only an experiment, changing one thing on purpose and watching the other, shows cause, which is why the A/B tests lesson matters.
import statistics as st x = list(range(11)) y = [(v - 5) ** 2 for v in x] print(round(st.correlation(x, y), 3))
Show the answer
0.0
y is completely determined by x, but in a U shape: the falling half and the rising half cancel. Correlation 0 means no straight-line relationship, not no relationship.
A straight-line fit with R², which for one variable is the correlation squared. Drag a single point far from the others.
When the groups disagree with the whole
A fourth trap catches experienced analysts. Within every group, a relationship can point one way while the pooled data points the other: Simpson's paradox. Suppose that in both of the shop's warehouses, faster packing comes with fewer complaints. But the busy city warehouse packs fast and gets many complaints from its sheer volume of awkward orders, while the small rural one packs slowly and gets few. Pool the two and "faster packing" seems to go with "more complaints".
The pooled correlation isn't wrong arithmetic; it's answering a different question, mixing the effect of packing speed with the difference between warehouses. When groups differ a lot, compute the relationship within each group before trusting the total.
Show the answer
The fast warehouse also gets more complaints
The busy warehouse is both faster and gets more complaints, so pooling mixes the warehouse difference into the speed relationship. Within each warehouse, the real pattern shows.
Write a sentence or two, then compare it with a good answer in the lesson.
Rank correlation for steady but curved relationships
Often you only care whether one thing goes up when the other does, not whether the line is straight. Spearman's rank correlation replaces each value by its rank (1st, 2nd, 3rd...) and correlates the ranks. Any relationship that always rises gets 1, however curved, and one huge value can't dominate, because its rank is just "the largest".
import statistics as st prompt_words = [1, 2, 3, 4, 5, 6, 7, 8] cost = [1, 2, 3, 4, 5, 6, 7, 100] print("Pearson:", round(st.correlation(prompt_words, cost), 3)) print("Spearman:", round(st.correlation(prompt_words, cost, method="ranked"), 3))
Pearson is pulled around by the single 100; Spearman sees a perfectly steady rise. Use Spearman for ratings, rankings and anything with long tails, and Pearson when you expect a straight line.
Show the answer
The square root of the variance
Variance is the average squared distance from the mean; its square root, the standard deviation, is back in the data's own units.
The shape of a distribution: skew and kurtosis
The mean and standard deviation describe a distribution well only when it's roughly symmetric. Two more numbers describe the shape.
Skew measures lopsidedness. Order values, response times, salaries and token counts are right-skewed: most values are modest, a few are huge, and the long tail drags the mean far above the median. Report the median (and percentiles such as the 90th) for skewed data, and consider analyzing the logarithm, which often makes it close to symmetric.
Kurtosis measures how heavy the tails are: how often extreme values turn up compared with a normal distribution. High kurtosis means rare but large surprises, the kind that break averages, alerts and capacity plans built on "typical" days. Here are the shop's order values for one morning:
import statistics as st orders = [18, 22, 25, 25, 30, 34, 41, 48, 60, 95, 240, 610] mean, sd = st.mean(orders), st.pstdev(orders) skew = sum(((x - mean) / sd) ** 3 for x in orders) / len(orders) kurtosis = sum(((x - mean) / sd) ** 4 for x in orders) / len(orders) - 3 print("mean", round(mean, 1), "median", st.median(orders)) print("skew", round(skew, 2), "excess kurtosis", round(kurtosis, 2))
A skew of 2.45 and excess kurtosis of 4.72 say clearly: long right tail, and rare large orders. A normal distribution scores 0 on both.
Show the answer
The median, 37.5
Ten of the twelve orders are below 100; the mean sits above almost all of them because of two large ones. For skewed data, the median describes the typical case.
Working with long tails
Long tails are everywhere in AI products. A few long conversations use most of the tokens, a few slow requests set how long users wait, and a few heavy customers produce most of the cost. Three habits help.
Report percentiles alongside the median: the 50th, 90th and 99th percentiles of response time say far more than the mean. Analyze on a log scale when values span orders of magnitude, so a model or a chart isn't dominated by the largest few. And look at the tail itself, because that's often where the money and the complaints are: the top 1% of conversations by cost deserves its own report.
Show the answer
The median, with the 90th and 99th percentiles
The median shows a typical conversation and the percentiles show how heavy the tail is, which is where most of the cost hides. The mean blends the two into a number that describes neither.
Write a sentence or two, then compare it with a good answer in the lesson.
Practice what you just read
- 4 code examples you can edit and run
- a practice exercise that checks your code
- a 5-question quiz
- 6 review cards for spaced repetition
Try a quiz question
Why compare correlations rather than covariances?