3. 相关系数计算与解读
在环境数据分析中,我们经常需要回答“两个变量之间到底有没有关系、关系有多强、是正还是负”这类问题。散点图能给出直观印象,但无法给出可比较、可检验的数值。相关系数正是把这种关系压缩成一个标准化指标的工具。本节围绕两个最常用的系数——Pearson 与 Spearman——讲清楚它们的适用条件、计算方式、结果解读,以及如何用热力图把整张相关矩阵一次看清。
先分清两种“相关”的含义
Pearson 相关系数衡量的是线性关系的强度和方向,定义为两变量协方差除以各自标准差的乘积,取值在 −1 到 1 之间。它假设变量近似服从正态分布、关系大致呈直线、且对异常值敏感。Spearman 相关系数则是先把每个变量的观测值转成秩(排名),再对秩计算 Pearson 系数,因此它衡量的是单调关系:只要一个变量增大时另一个变量总体上也增大(或减小),即使关系是弯曲的,Spearman 也能捕捉到。
环境数据里这两种情形都很常见。例如 PM2.5 与能见度往往近似线性负相关,适合 Pearson;而气温与臭氧浓度常呈非线性单调上升,用 Spearman 更稳妥。判断时可以先看散点图形状,再决定主用哪个系数,并把两个系数都算出来对照——若两者差异很大,往往提示存在非线性或异常值。
用 pandas 一步算出相关矩阵
pandas 的 DataFrame.corr() 默认就是 Pearson,通过 method 参数可切换为 'spearman' 或 'kendall'。它会对所有数值列两两计算,返回一个对称矩阵,对角线恒为 1。下面用一份模拟的城市空气质量日数据演示(数据为教学示例,非实测):
import pandas as pd
import numpy as np
# 构造示例数据:pm25、temp、humidity、o3、wind
rng = np.random.default_rng(42)
n = 200
temp = rng.normal(22, 6, n)
humidity = 80 - 0.8 * temp + rng.normal(0, 8, n)
wind = rng.gamma(2, 1.2, n)
pm25 = 60 - 1.5 * wind + 0.4 * humidity + rng.normal(0, 10, n)
o3 = 30 + 2.2 * temp + rng.normal(0, 12, n)
df = pd.DataFrame({
"pm25": pm25, "temp": temp,
"humidity": humidity, "o3": o3, "wind": wind
})
pearson = df.corr(method="pearson")
spearman = df.corr(method="spearman")
print(pearson.round(2))
print(spearman.round(2))
运行后你会得到两张 5×5 矩阵。以示例数据为例,pm25 与 wind 的 Pearson 系数约为 −0.55,说明风速越大 PM2.5 越低,中等偏强的负线性关系;o3 与 temp 的 Pearson 约为 0.74,而 Spearman 可能略高,提示温度与臭氧的单调上升关系比纯线性更明显。这些数值是示例构造下的合理结果,实际数据需以真实计算为准。
用 scipy 获取系数与显著性
pandas 只给系数,不给 p 值。若样本量不大或需要判断“相关是否显著异于零”,应使用 scipy.stats 的 pearsonr 与 spearmanr,它们同时返回系数和双侧检验的 p 值:
from scipy.stats import pearsonr, spearmanr
r, p = pearsonr(df["pm25"], df["wind"])
print(f"Pearson r={r:.3f}, p={p:.4f}")
rho, p2 = spearmanr(df["o3"], df["temp"])
print(f"Spearman rho={rho:.3f}, p={p2:.4f}")
解读时要把系数大小和 p 值一起看:p 值小只说明“不太可能是偶然”,并不代表关系强;样本很大时,微弱的 0.1 也可能显著。因此报告时应写成“r = −0.55,p < 0.001,中等负相关”,而不是只写“显著相关”。另外,相关系数只能说明统计关联,不能直接当作因果证据——温度与臭氧相关,背后可能是日照这一共同驱动因素。
用热力图把相关矩阵可视化
矩阵数字多了不易扫读,热力图用颜色编码系数,能一眼看出成簇的高相关变量。常用 seaborn 的 heatmap,配合 annot=True 显示数值、vmin=-1, vmax=1 固定色标范围,保证不同图之间可比:
import seaborn as sns
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei"] # 中文显示
plt.rcParams["axes.unicode_minus"] = False
plt.figure(figsize=(7, 5.5))
sns.heatmap(pearson, annot=True, fmt=".2f",
cmap="RdBu_r", vmin=-1, vmax=1,
square=True, linewidths=0.5)
plt.title("环境变量 Pearson 相关矩阵")
plt.tight_layout()
plt.show()
读图时注意三点:一是颜色方向,RdBu_r 中红色为正、蓝色为负,务必在图注中说明;二是矩阵对称,只需看下三角;三是若某对变量系数接近 ±1,要警惕共线性,后续做回归时应考虑剔除或合并。下图概括了从原始数据到相关结论的完整判断路径与关键分支:
实操中容易踩的坑
第一,缺失值处理。corr() 默认按列成对删除缺失(pairwise),不同变量对可能基于不同样本量,导致矩阵内部不完全可比;若数据缺失较多,建议先统一删除或插补,并在报告中说明。第二,异常值。一个极端点就能把 Pearson 拉偏,可先画箱线图或计算 Spearman 对照,若两者差距悬殊,优先怀疑异常值。第三,量纲无关但分布有关。Pearson 对偏态分布敏感,环境浓度数据常右偏,必要时先做对数变换再算。第四,多重比较。一次算几十对系数,总会有几对“碰巧显著”,应结合业务重要性筛选,而非只看 p 值。
把上述流程固化成习惯:先看散点与分布,再同时算 Pearson 和 Spearman,用 scipy 补 p 值,最后用固定色标的热力图呈现并标注方向约定。这样得到的相关分析既有数值依据,也有可视化支撑,能为后续的回归建模和变量筛选提供可靠起点。