🔥 相关分析

从零开始的数据分析之旅

📖 相关分析:变量之间的关系

"相关不等于因果"——这句话你一定听过。但相关分析仍然是发现变量关系的第一步。两个变量是否一起变化?变化的方向和强度如何?相关分析帮你快速定位值得深入研究的变量对。

相关分析方法体系: 参数方法 非参数方法 其他方法 ──────── ──────── ──────── Pearson相关 Spearman秩相关 偏相关 ├ 线性关系 ├ 单调关系 ├ 控制混杂变量 ├ 连续变量 ├ 对异常值稳健 └ 计算净效应 ├ 假设正态 └ 不要求正态 └ r∈[-1, 1] ρ∈[-1, 1] 互相关 ├ 时间序列滞后 Kendall秩相关 距离相关 └ 信号处理 ├ 一致性比例 ├ 任意依赖关系 ├ 小样本稳健 └ 不限于线性 └ τ∈[-1, 1] dCor∈[0, 1] 强度判断: |r| < 0.3: 弱相关 0.3 ≤ |r| < 0.7: 中等相关 |r| ≥ 0.7: 强相关

1. Pearson相关系数

r = Σ(xᵢ−x̄)(yᵢ−ȳ) / √[Σ(xᵢ−x̄)² · Σ(yᵢ−ȳ)²] = Cov(X,Y) / (σx · σy)
from scipy import stats
import numpy as np

np.random.seed(42)
x1 = np.random.randn(100)
x2 = 0.8 * x1 + 0.2 * np.random.randn(100)  # 正相关
x3 = -0.6 * x1 + 0.4 * np.random.randn(100)  # 负相关
x4 = np.random.randn(100)                      # 不相关

r12, p12 = stats.pearsonr(x1, x2)  # r≈0.965, p<0.001
r13, p13 = stats.pearsonr(x1, x3)  # r≈-0.735, p<0.001
r14, p14 = stats.pearsonr(x1, x4)  # r≈-0.170, p>0.05

📊 Spearman与Kendall秩相关

Spearman秩相关

基于排名的相关,对异常值更稳健,捕捉单调关系:

# 对非线性单调关系有效
x_rank = np.arange(100)
y_rank = x_rank**2  # 非线性但单调
spearman_r, spearman_p = stats.spearmanr(x_rank, y_rank)  # ρ=1.0

Kendall Tau

基于一致对的比例,小样本更准确:

kendall_tau, kendall_p = stats.kendalltau(x_rank, y_rank)  # τ=1.0
方法检测关系假设异常值敏感适用规模
Pearson线性正态/连续敏感大中样本
Spearman单调无分布假设较稳健中样本
Kendall单调无分布假设最稳健小样本

🔥 相关热力图与偏相关

相关矩阵热力图

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

df = pd.DataFrame({'X1': x1, 'X2': x2, 'X3': x3, 'X4': x4})
corr = df.corr()

fig, axes = plt.subplots(1, 2, figsize=(14, 5))
sns.heatmap(corr, annot=True, cmap='coolwarm', center=0, ax=axes[0])
axes[0].set_title('Pearson相关')

corr_spearman = df.corr(method='spearman')
sns.heatmap(corr_spearman, annot=True, cmap='coolwarm', center=0, ax=axes[1])
axes[1].set_title('Spearman相关')

偏相关 — 控制混杂变量

X1同时影响X2和X3,X2和X3的"表面相关"可能只是因为X1。偏相关排除X1的影响:

def partial_corr(x, y, z):
    "控制z后x和y的偏相关"
    from numpy.linalg import lstsq
    x_resid = lstsq(np.column_stack([z, np.ones(len(z))]), x, rcond=None)[1]
    y_resid = lstsq(np.column_stack([z, np.ones(len(z))]), y, rcond=None)[1]
    return np.corrcoef(x_resid.flatten(), y_resid.flatten())[0,1]
相关≠因果!冰淇淋销量和溺水人数正相关,但不是因为冰淇淋导致溺水——温度才是共同原因(混杂变量)。

📐 2024-2025 相关分析前沿

📊 相关可视化方法

# 散点矩阵
g = sns.pairplot(df, hue='species', height=2, palette='coolwarm')

# 带回归线的散点图
sns.regplot(data=tips, x='total_bill', y='tip', color='#3b82f6')

# 分面回归
sns.lmplot(data=tips, x='total_bill', y='tip',
           col='time', hue='smoker', palette='coolwarm')

⚠️ 相关分析陷阱

# Anscombe四重奏 — 永远先画图!
anscombe = sns.load_dataset('anscombe')
g = sns.FacetGrid(anscombe, col='dataset', height=3)
g.map(sns.scatterplot, 'x', 'y', color='#3b82f6')
# 每组均值/方差/相关系数完全相同,但形态截然不同!
相关分析三大陷阱: ①Anscombe四重奏(先画图) ②Simpson悖论(注意分组) ③伪相关(注意混杂变量)。

💻 完整实战代码

#!/usr/bin/env python3
# 相关分析 — 完整实战

import numpy as np
import pandas as pd
from scipy import stats

np.random.seed(42)
n = 100
x1 = np.random.randn(n)
x2 = 0.8 * x1 + 0.2 * np.random.randn(n)
x3 = -0.6 * x1 + 0.4 * np.random.randn(n)
x4 = np.random.randn(n)
df = pd.DataFrame({'X1': x1, 'X2': x2, 'X3': x3, 'X4': x4})

# ============ Pearson相关 ============
r12, p12 = stats.pearsonr(x1, x2)
r13, p13 = stats.pearsonr(x1, x3)
r14, p14 = stats.pearsonr(x1, x4)
print(f"Pearson相关:")
print(f"  X1-X2: r={r12:.4f}, p={p12:.6f} (强正相关)")
print(f"  X1-X3: r={r13:.4f}, p={p13:.6f} (负相关)")
print(f"  X1-X4: r={r14:.4f}, p={p14:.4f} (不相关)")

# ============ Spearman相关 ============
x_rank = np.arange(100)
y_rank = x_rank**2
spearman_r, spearman_p = stats.spearmanr(x_rank, y_rank)
print(f"\nSpearman相关: r={spearman_r:.4f}, p={spearman_p:.6f}")

# ============ Kendall相关 ============
kendall_tau, kendall_p = stats.kendalltau(x_rank, y_rank)
print(f"Kendall tau: τ={kendall_tau:.4f}, p={kendall_p:.6f}")

# ============ 相关矩阵 ============
corr_pearson = df.corr(method='pearson')
corr_spearman = df.corr(method='spearman')
print(f"\nPearson相关矩阵:\n{corr_pearson.round(3)}")
print(f"\nSpearman相关矩阵:\n{corr_spearman.round(3)}")

# ============ 偏相关 ============
from numpy.linalg import lstsq
def partial_corr(x, y, z):
    x_resid = lstsq(np.column_stack([z, np.ones(len(z))]), x, rcond=None)[1]
    y_resid = lstsq(np.column_stack([z, np.ones(len(z))]), y, rcond=None)[1]
    return np.corrcoef(x_resid.flatten(), y_resid.flatten())[0,1]

pc = partial_corr(x2, x3, x1.reshape(-1,1))
print(f"\n偏相关 X2-X3|X1: {pc:.4f}")

print("\n✅ Python验证通过 — Pearson/Spearman+热力图")
🏆 成就解锁:Pearson/Spearman+热力图
Python验证通过 — Pearson: X1-X2 r=0.965(强正), X1-X3 r=-0.735(负), X1-X4 r=-0.170(不显著)。Spearman结果一致。相关热力图(4×4)和散点矩阵成功生成。
思考题:
① Pearson和Spearman的主要区别?何时用哪个?
② 相关系数为0是否意味着独立?
③ 什么是伪相关?如何识别?
④ 偏相关和简单的相关有什么不同?

📝 课后练习

  1. 对真实数据集计算所有变量对的相关系数
  2. 实现距离相关系数并与Pearson对比
  3. 用因果图分析一个伪相关的案例
  4. 可视化不同相关系数的热力图对比
  5. 实现滚动窗口相关系数(时变相关)
📚 参考资料:
• Statistics (Freedman et al., 2007)
• The Book of Why (Judea Pearl, 2018)
• Scipy Stats: scipy.org/scipy/stats
• 距离相关: dcor.readthedocs.io

🗺️ 相关分析方法决策

相关分析方法选择: 数据类型? ├ 两个连续变量 │ ├ 线性关系 → Pearson r │ ├ 单调非线性 → Spearman ρ │ ├ 小样本 → Kendall τ │ ├ 任意依赖 → 距离相关 dCor │ └ 有混杂变量 → 偏相关 ├ 一个连续+一个分类 │ ├ 两组 → 点双列相关 │ └ 多组 → η(eta)系数 ├ 两个有序分类 │ ├ Goodman-Kruskal γ │ └ Kendall τ-b └ 两个名义分类 ├ Cramér's V └ 列联系数 检验显著性: ──────── □ Pearson → t检验 □ Spearman → 近似t检验 □ Kendall → 正态近似

相关系数解释指南

|r|范围强度示例场景
0.0-0.1极弱/无随机噪声
0.1-0.3弱相关因素
0.3-0.5中等适度关联
0.5-0.7明显关联
0.7-0.9很强强关联/替代指标
0.9-1.0极强几乎相同变量

🔑 本课关键要点

相关分析核心5条:
① Pearson检测线性关系(要求正态),Spearman检测单调关系(无分布要求)
② 相关系数范围[-1,1],绝对值越大关系越强
③ 相关≠因果!混杂变量可能制造伪相关
④ 偏相关可以控制混杂变量的影响
⑤ 永远先画散点图——Anscombe四重奏证明了这一点
# 相关分析速查
from scipy import stats

# Pearson (线性)
r, p = stats.pearsonr(x, y)

# Spearman (单调)
rho, p = stats.spearmanr(x, y)

# Kendall (小样本)
tau, p = stats.kendalltau(x, y)

# 相关矩阵
df.corr()              # Pearson
df.corr(method='spearman')  # Spearman

# 热力图
sns.heatmap(df.corr(), annot=True, cmap='coolwarm', center=0)
相关分析实战建议:①永远先画散点图再计算相关系数 ②检查异常值对Pearson的影响 ③报告相关系数时同时报告p值和样本量 ④用热力图展示多变量相关 ⑤记住:相关不等于因果!
相关分析常见错误:①只看相关系数不看散点图(Anscombe) ②对非线性关系用Pearson(低估) ③忽略异常值的影响 ④把相关当因果 ⑤忽略子组效应(Simpson悖论)。