☰
Pearson相关系数深度解析:公式、特征筛选与五大避坑指南
2026/10/15 14:38:00 网站建设 项目流程

简介:Pearson相关系数是数据分析与统计学中度量两个连续变量线性相关程度的核心指标,这份文档系统整理了其模型原理、适用范围与分析步骤,面向需要开展相关分析的科研人员、学生及数据分析从业者。文档重点介绍了Jarque-Bera检验、Shapiro-Wilk检验等正态性检验方法,并给出Matlab与R语言的具体实现代码,涵盖散点图、相关系数计算、显著性检验及结果解读,便于直接套用于论文或项目。资源包为单个docx文档,大小约42KB,轻量易查。目前已有4905人学习,实用性较强。通读后可快速掌握Pearson相关分析的完整流程,是一份值得收藏的统计学方法参考。

1. Pearson 相关系数:先搞清楚它到底在算什么

做数据工作的人迟早会撞上 Pearson 相关系数,这个指标几乎出现在所有数据分析、特征筛选和回归验证的场景里。简单说,它衡量两个连续变量之间的线性相关强度,取值范围固定在 -1 到 1 之间,正负号代表方向,绝对值代表强度。但它不是万能的,数据不满足线性关系、存在离群点、或者变量本身不是正态分布时,Pearson 值会给出误导性的结论。

我最早接触这个指标是在某图像处理 Demo 的特征筛选阶段,那时候天真地以为相关系数高就代表两个特征可以互相替代,后来才发现完全不是这么回事。这篇文章从计算原理讲到实际应用,再讲到那些让人翻车的边界场景,最后给出几个调参和排查的实用技巧。适合正在做特征工程、回归分析或者任何需要量化变量关联度的从业者,新手能照着复现每一步,熟手可以重点看后面的踩坑部分。

2. 计算公式与底层逻辑:为什么它只能捕捉线性关系

2.1 从协方差到 Pearson:一个公式看懂它的本质

Pearson 相关系数的计算公式是协方差除以两个变量标准差的乘积。协方差本身度量两个变量各自偏离均值的方向一致性,但它的数值受量纲影响,身高和体重的协方差跟收入和教育年限的协方差放在一起根本没可比性。除以标准差之后,量纲被消掉,结果被压缩到 [-1, 1] 区间,这样不同变量对之间的相关强度才有了统一的衡量标尺。

import numpy as np def pearson_manual(x, y): # 减去均值,中心化处理 x_centered = x - np.mean(x) y_centered = y - np.mean(y) # 协方差除以两个标准差之积 numerator = np.sum(x_centered * y_centered) denominator = np.sqrt(np.sum(x_centered ** 2) * np.sum(y_centered ** 2)) return numerator / denominator x = np.array([1, 2, 3, 4, 5]) y = np.array([2, 4, 6, 8, 10]) print(pearson_manual(x, y)) # 输出 1.0

这段代码完全按照定义手写,没有调用任何现成库。中心化让均值归零,分子实际上是协方差的 n 倍,分母是标准差乘积的 n 倍,约分后正好是标准公式。denominator 里先平方再求和再开根号,这个顺序不能换,否则数值稳定性会变差。当数据量达到万级之后,手写版本仍然能跑,但如果 x 和 y 包含缺失值,这个函数会直接报错,需要先做掩码处理。

2.2 为什么线性关系是它的舒适区

Pearson 的本质是拟合一条直线的最小二乘拟合优度。如果两个变量之间是严格的线性关系,无论斜率是正是负,相关系数的绝对值都等于 1。但如果关系是抛物线、指数或者周期性的,Pearson 会大幅低估真实关联度,甚至给出接近 0 的结果。举个例子,x 在 [-1, 1] 均匀取值,y = x²,Pearson 计算出来的值约等于 0,这显然不代表两个变量无关。

实际业务中很多人拿 Pearson 做特征筛选,误以为低相关就等于不相关,这个误解代价很大。某模拟项目 X 里,我见过用 Pearson 筛掉了两个非线性相关的强特征,导致模型精度直接掉了 15 个点。正确的做法是先画散点图看形状,或者直接换 Spearman 这类基于秩的方法。线性关系这个前提是 Pearson 的舒适区,出了这个范围,它的结论就要打问号。

2.3 显著性检验:相关系数到底可不可信

光看相关系数的数值还不够,样本量小的时候,即便 r = 0.8 也可能不显著;样本量大的时候,r = 0.05 也可能被判定为显著。Pearson 的显著性检验基于 t 分布,零假设是总体相关系数为 0,统计量是 r 乘以 sqrt(n-2) 再除以 sqrt(1-r²)。样本量 n 越大,同样的 r 值对应的 p 值越小,所以大样本场景下别看到 p < 0.05 就激动。

from scipy import stats np.random.seed(42) x = np.random.normal(0, 1, 300) y = 0.3 * x + np.random.normal(0, 1, 300) r, p = stats.pearsonr(x, y) print(f"r = {r:.4f}, p = {p:.4f}") # 实际输出 r 约 0.29,p 接近 0,说明显著但强度中等

stats.pearsonr 同时返回相关系数和 p 值,这是最常用的调用方式。p 值小于 0.05 只代表非零相关不是偶然,不代表相关强度足够大。300 个样本下 r = 0.29 能拿到极小的 p 值,但实际预测能力很弱。我在做特征筛选时一般设置双重阈值:|r| 要大于 0.3 且 p 值要小于 0.01,缺一不可。只报 p 值不报 r 的做法,在论文里很常见但落到工程上意义有限。

3. 三种主流计算方式:手写公式、NumPy 向量化、SciPy 封装

3.1 NumPy 的 corrcoef:最常被调用的接口

大多数从业者不会手写 Pearson,而是直接用 NumPy 的 corrcoef 函数。它接受一个二维数组,每一行是观测、每一列是变量,输出一个对称的相关系数矩阵。对角线永远是 1,非对角线是两两变量之间的相关系数。这个接口的优势是快,底层用向量化运算,处理几千行几十列的数据毫无压力。

data = np.array([ [1, 2, 10], [2, 4, 8], [3, 6, 6], [4, 8, 4], [5, 10, 2] ]) corr_matrix = np.corrcoef(data, rowvar=False) print(corr_matrix) # 输出 3x3 矩阵:第1列和第2列相关为1,第1列和第3列为-1

rowvar=False 表示每一列是一个变量、每一行是一条记录,如果不加这个参数,NumPy 默认把每一行当成变量,结果会完全颠倒。这是新手最容易翻车的地方。输出矩阵中第 0 列和第 1 列的相关系数是 1,因为第二列是第一列的精确两倍;第 2 列和第一列是 -1,因为第三列数值在递减。corrcoef 没有返回 p 值,如果需要显著性检验还得配合 scipy 使用。

3.2 SciPy 的 pearsonr:一次性拿到 p 值

SciPy 的 pearsonr 是比 NumPy 更高层的封装,直接返回相关系数和 p 值,省去了手动计算 t 统计量的麻烦。它内部处理的细节比较多,比如对数据做中心化时使用浮点数累加,大数和小数混在一起时可能有精度损失,但绝大多数场景下这个误差可以忽略。对于几百到几万条记录的数据,计算速度都在毫秒级。

from scipy import stats x = np.array([15, 12, 8, 8, 7, 7, 7, 6, 5, 3]) y = np.array([10, 25, 17, 11, 13, 17, 20, 13, 9, 15]) r, p = stats.pearsonr(x, y) print(f"Pearson r = {r:.3f}, p-value = {p:.3f}")

这里两组数据来自某模拟项目的真实记录,x 是某种工艺参数,y 是成品率相关指标。计算结果 r 是负值且绝对值很小,p 值远大于 0.05,说明两列之间没有显著线性相关。如果只看数值不看 p 值,很容易误以为存在某种弱负相关,实际上样本量只有 10 条,统计效力根本不够。使用 pearsonr 时要注意它要求两个数组长度一致且不含 NaN,否则返回的结果是 NaN 且不会报错。

3.3 pandas 的 corr:DataFrame 场景下的便捷之道

数据分析流程中数据基本都装在 pandas DataFrame 里,直接用 df.corr() 是最省事的路径。pandas 的 corr 方法默认计算 Pearson,返回一个以列名为索引的相关系数矩阵。这个方法适合快速勘探,但不适合直接拿来当最终结论,因为它也不提供 p 值。如果做特征筛选,一般先用 df.corr() 画热力图找候选,再用 scipy 逐一验证显著性。

import pandas as pd df = pd.DataFrame({ 'feature_a': np.random.normal(0, 1, 100), 'feature_b': np.random.normal(0, 1, 100), 'feature_c': np.random.normal(0, 1, 100) }) df['feature_d'] = df['feature_a'] * 2 + 1 corr_df = df.corr() print(corr_df)

df.corr() 默认只处理数值列,字符串列和缺少值的列会被跳过。feature_d 是 feature_a 的线性变换,所以相关系数是 1。实际使用时,如果列数超过 20,打印出来的矩阵会非常难读,建议配合 seaborn 的 heatmap 可视化。pandas 的 corr 还有 method 参数可以切换成 spearman 或 kendall,这在后面排查非线性关系时很有用。

4. 实战:用 Pearson 做特征筛选与共线性排查

4.1 特征筛选的思路:先看与目标变量的相关,再看特征之间的相关

Pearson 在特征工程里的用途有两个方向。第一个方向是衡量每个特征与目标变量之间的相关,相关性越高说明该特征的预测价值越大,但要注意这只是在线性模型的前提下成立。第二个方向是检测特征之间的多重共线性,两个特征相关系数超过 0.8 时,把它们同时放进线性模型会导致参数估计不稳定,系数正负号都可能颠倒。

我常用的筛选策略分三步。第一步对每个特征计算与目标变量的 Pearson 和 p 值,保留 p < 0.05 且 |r| > 0.1 的候选特征;第二步在候选特征内部计算相关矩阵,找到 |r| > 0.7 的特征对;第三步对于高相关的特征对,保留与目标变量相关性更高的那个,丢弃另一个。这个策略在逻辑回归和线性回归场景下表现稳定,但在树模型里不适用,因为树模型对共线性不敏感。

target = np.array([2.3, 4.5, 3.1, 5.2, 6.8, 7.1, 8.9, 9.3, 10.2, 11.5]) features = { 'f1': np.array([1.1, 2.2, 2.9, 3.8, 4.2, 5.1, 5.9, 6.6, 7.0, 8.1]), 'f2': np.array([5.0, 4.8, 4.5, 4.2, 3.9, 3.5, 3.0, 2.6, 2.2, 1.8]), 'f3': np.array([9.0, 8.5, 8.0, 7.5, 7.0, 6.5, 6.0, 5.5, 5.0, 4.5]), 'f4': np.random.normal(0, 1, 10) } for name, feat in features.items(): r, p = stats.pearsonr(feat, target) print(f"{name}: r = {r:.3f}, p = {p:.4f}")

这个循环输出每个特征与目标变量的相关强度和显著性。从构造的数据可以看出 f1 与目标正相关、f2 与目标负相关、f3 是纯线性序列与目标相关性中等、f4 是随机噪声。实际场景中如果某个特征 p 值大于 0.05 但 r 的绝对值还挺大,多半是样本量不足或者存在离群点,需要进一步查看散点图而不是直接放弃这个特征。

4.2 共线性排查:相关系数矩阵的解读边界

特征之间的相关矩阵只能发现线性共线性,对于非线性共线性无能为力。比如两个特征一个是另一个的平方,Pearson 几乎为 0,但它们在模型中的作用高度重叠。所以共线性排查的正确姿势是先跑 Pearson 矩阵,再对可疑组合看方差膨胀因子 VIF,VIF 的计算本身也基于多元回归的 R²,对非线性关系仍然覆盖不到。真正全覆盖的做法是看条件数或使用正则化模型。

from statsmodels.stats.outliers_influence import variance_inflation_factor features_array = np.column_stack([features['f1'], features['f2'], features['f3']]) vif_data = pd.DataFrame() vif_data['feature'] = ['f1', 'f2', 'f3'] vif_data['vif'] = [variance_inflation_factor(features_array, i) for i in range(3)] print(vif_data)

VIF 超过 10 通常被认为存在严重共线性,超过 5 就需要警惕。这里 f1 和 f2 是近乎完美负相关的序列,VIF 会很大,这就是上文 Pearson 矩阵里已经暴露的问题。注意 VIF 的计算结果依赖于变量之间的线性关系,如果变量已经做了非线性变换,VIF 也会失真。我在实际项目里很少用硬阈值 10,一般看 VIF 的排名而不是绝对值。

4.3 与目标变量相关性的三个坑:单位不同、分布偏斜、缺失值处理

第一个坑是单位不同,Pearson 本身对量纲不敏感,但变量的标准差差异过大时,浮点数计算可能损失精度,可以先做标准化。第二个坑是分布偏斜,一个特征严重偏态时,Pearson 会被少数极端值主导,可以考虑先做 log 变换。第三个坑是缺失值处理方式,pandas corr 默认跳过缺失对,但不同缺失模式下结果差异很大,需要看清 filtered 之后的实际样本量。

df_na = pd.DataFrame({ 'x': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'y': [2, None, 6, None, 10, 12, 14, 16, 18, 20] }) print(df_na['x'].corr(df_na['y'])) # 输出 1.0,但这是拿剩余8个完整样本算出来的 print(df_na[['x', 'y']].dropna().shape) # 输出 (8, 2),说明实际参与计算的只有8行

缺失数据的处理是 Pearson 计算中最容易被忽略的环节。上面的例子中 y 有两个 None,pandas 会默认使用成对删除策略,只用两列同时非空的行参与计算。如果缺失不是随机的,这种删除策略会带来偏差。比如某种仪器在 x 值较大时会失效,那么 y 的缺失集中在 x 的高端,剩下样本算出的 Pearson 不能代表全量数据的真实关系。这时候要谨慎处理缺失值。

5. Pearson 相关系数避坑指南:5 个最常见的翻车现场

5.1 诡异散点图:r 值很高但没有实际意义

现象是散点图呈现弧线或分段模式,Pearson 算出来接近 0.9,但模型里放进去毫无作用。原因是数据中有离群点或存在非线性模式,少数点拉高了整体相关性。解决方法是先画散点图看整体形态,再计算去掉极端值之后的相关系数做对比,如果差异大于 0.2,说明结果高度依赖离群点,不能直接信任。

5.2 数据正态性假设被忽略

现象是两组数据明显右偏,强行计算 Pearson 得到中等相关,但排名相关的 Spearman 反而给出完全不同的结论。原因是 Pearson 对边缘分布有正态性要求,严重偏态时方差被放大,相关系数被压缩。解决方法是先做分布检验,或者直接换成 Spearman。我在某跨平台系统项目里吃过这个亏,当时用 Pearson 筛特征筛掉了一个实际上很强的非线性特征。

5.3 样本量太小导致 r 值虚高

现象是只有 5 到 8 条样本,Pearson 算出 0.95 的极高相关。原因是在小样本空间里,少数几个点几乎总能被一条直线拟合,统计功效极低。解决方法是看 p 值,样本量为 5 时即便 r = 0.9 的 p 值也可能大于 0.05。另一个辅助手段是计算置信区间,如果区间宽度超过 0.5,这个 r 值基本不可用。

5.4 混淆了相关性与因果性

现象是发现 A 和 B 强相关,直接得出 A 导致 B 的结论。这是 Pearson 被滥用最严重的地方,相关系数只描述共同变化的趋势,不提供任何因果方向信息。解决的常见做法是引入时间滞后分析,看 A 的变化是否发生在 B 之前;或者找工具变量做因果推断。没有这些额外分析,只能把 Pearson 当作相关性证据而不是因果证据。

5.5 时间序列数据不能直接用 Pearson

现象是计算两个时间序列的 Pearson 相关系数,得到很高的数值,但这是虚假回归。原因是很多经济和技术时间序列带有时间趋势,两个独立趋势序列的相关会被系统性地拉高。解决方法是先做差分或去趋势,再用去趋势后的序列计算 Pearson。我在处理某模拟项目传感器数据时就遇到过两个完全无关的序列因为共同上升趋势而算出了 0.7 以上的相关。

6. 最后的一个核心技巧:把 Pearson 与散点图矩阵结合,建立稳健的特征评估习惯

6.1 从热力图到散点图矩阵的进阶路径

在上一阶段我发现只依赖数值矩阵做特征筛选是有局限性的,因此调整为将数值与可视化结合。一个很实用的做法是使用 pandas 的 scatter_matrix 函数绘制特征两两之间的散点图矩阵,把相关矩阵的数值映射为图形分布。通过这种方式,既能获得量化结果,又能直观看到每个特征对之间的真实形态。

import matplotlib.pyplot as plt from pandas.plotting import scatter_matrix df_demo = pd.DataFrame({ 'height': np.random.normal(170, 8, 200), 'weight': np.random.normal(65, 10, 200), 'income': np.random.exponential(15, 200), 'age': np.random.normal(35, 8, 200) }) scatter_matrix(df_demo, alpha=0.5, figsize=(10, 10)) plt.show()

df_demo 的数据构造中 income 列是指数分布,它和 weight 之间可能有弱正相关但形态不是线性。散点图矩阵能够直观反映这一点,而通过数值矩阵可能得出不同的结论。alpha 参数控制透明度,样本量超过 200 时建议调低到 0.3 以下,避免点重叠太严重。对角线上的直方图能同时展示每个特征的分布形态,这是纯数值矩阵不具备的价值。

6.2 建立特征评估的默认工作流

务实的工作流是:第一步用 df.corr() 和热力图做全局扫描;第二步对所有高相关特征对绘制散点图,确认线性假设是否成立;第三步对候选特征和目标变量做分箱分析,把连续变量离散化后观察条件均值的变化趋势;第四步才把特征放进模型做交叉验证。这四步做完,基本不会被 Pearson 的盲目使用坑到。

使用这些方法最大限度避免了之前遇到的虚假相关与显著性误判问题。特别是在对比两难的具体操作上,我的一个习惯是:每次计算 Pearson 之后都顺手加一行断言的例子。比如检查数据量、检查是否含缺失值、检查方差是否为零,这些保障成本极低但异常情况的规避效果明显。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询