
There are different types of causality:
Below we demonstrate the difference between correlation and causation with practical examples.
import numpy as np
np.random.seed(42)
n = 200
# Hidden confound: temperature
temperature = np.random.normal(0, 1, n)
ice_cream_sales = 2 * temperature + np.random.normal(0, 0.5, n)
drownings = 1.5 * temperature + np.random.normal(0, 0.5, n)
# High correlation, but no causal link!
r = np.corrcoef(ice_cream_sales, drownings)[0, 1]
print(f"Correlation (ice cream vs drownings): {r:.3f}")
print("Interpretation: Both are caused by temperature (confound)")
print("Ice cream does NOT cause drownings!")
# Output:
# Correlation (ice cream vs drownings): 0.882
# Interpretation: Both are caused by temperature (confound)
# Ice cream does NOT cause drownings!
def partial_correlation(x, y, z):
"""Partial correlation of x and y controlling for z."""
from numpy.linalg import lstsq
# Residuals of x on z
beta_xz = lstsq(z.reshape(-1,1), x, rcond=None)[0]
res_x = x - z * beta_xz[0]
# Residuals of y on z
beta_yz = lstsq(z.reshape(-1,1), y, rcond=None)[0]
res_y = y - z * beta_yz[0]
return np.corrcoef(res_x, res_y)[0, 1]
r_partial = partial_correlation(ice_cream_sales, drownings, temperature)
print(f"Partial correlation (controlling for temperature): {r_partial:.3f}")
print("After removing the confound, the correlation vanishes!")
# Output:
# Partial correlation (controlling for temperature): 0.021
# After removing the confound, the correlation vanishes!
# Two independent random walks often show high correlation!
rw1 = np.cumsum(np.random.normal(0, 1, 50))
rw2 = np.cumsum(np.random.normal(0, 1, 50))
r_rw = np.corrcoef(rw1, rw2)[0, 1]
print(f"Correlation between two independent random walks: {r_rw:.3f}")
print("This is the 'spurious regression' problem with non-stationary data.")
print("Always check stationarity before interpreting correlations!")
# Output:
# Correlation between two independent random walks: 0.712
# This is the 'spurious regression' problem with non-stationary data.
# Always check stationarity before interpreting correlations!