相关系数用来衡量两个变量之间线性或单调关系的强弱,取值范围从-1到1。很多初学者在调用pandas的corr()时只会使用默认参数,却忽略了皮尔逊与斯皮尔曼背后的假设差异。前者评估线性相关,后者评估单调相关,选错方法可能让结论完全失真。

皮尔逊与斯皮尔曼的差异到底在哪里
皮尔逊相关系数衡量的是两个连续变量之间的线性关系强度,公式基于原始数据的协方差除以各自标准差的乘积。它要求变量近似服从正态分布,且对异常值极其敏感。例如一组房价数据中混入一个录入错误的天价极值,皮尔逊系数可能被拉低或拉高,干扰你对真实趋势的判断。
斯皮尔曼相关系数则先对每个变量的数据进行排序,用排名值替代原始数值,再对排名值计算皮尔逊公式。因此它衡量的是两个变量之间单调关系的强度——只要一个变量增加时另一个变量总是增加(或总是减少),不论关系是直线还是曲线,斯皮尔曼系数都接近1或-1。这种基于秩的方法对异常值不敏感,也不要求数据服从正态分布,非常适合有序分类变量或存在明显离群点的场景。
两者的适用条件可以总结为:皮尔逊适合满足线性、连续、无显著离群点的数据;斯皮尔曼适合非线性但方向一致、含有离群点、或者数据本身就是等级顺序的情况。如果数据中存在强非线性关系,比如y=x^2在[0,1]区间内,皮尔逊系数可能只有0.9左右,而斯皮尔曼系数则接近1。
使用Pandas的corr()一行代码计算
Pandas的DataFrame对象自带corr()方法,通过method参数可以切换不同的相关系数类型。默认method=‘pearson’,也可以传入‘spearman’或‘kendall’。下面用一份模拟的考试成绩数据来演示如何同时计算两种系数。
import pandas as pd
import numpy as np
# 构造模拟数据:数学成绩、英语成绩和平时学习时长(小时)
data = {
'math_score': [85, 90, 78, 92, 88, 76, 95, 42, 89, 91],
'english_score': [82, 85, 75, 88, 86, 72, 90, 80, 87, 93],
'study_hours': [3.5, 4.0, 2.5, 4.2, 3.8, 2.0, 4.5, 1.5, 4.0, 4.3]
}
df = pd.DataFrame(data)
print(df.head())
调用corr()默认返回所有数值列两两之间的皮尔逊相关矩阵。下面的代码同时计算皮尔逊和斯皮尔曼相关矩阵,并打印输出。
pearson_corr = df.corr(method='pearson')
spearman_corr = df.corr(method='spearman')
print("皮尔逊相关矩阵:")
print(pearson_corr)
print("\n斯皮尔曼相关矩阵:")
print(spearman_corr)
从输出可以看到,每一行每一列的交点就是两个变量的相关系数。矩阵是对称的,对角线永远是1.0。上面模拟数据中math_score里故意放入了一个42分的低值,使得皮尔逊系数可能被拉低;而斯皮尔曼因为只关心排名,42分排名最后,不会像皮尔逊那样受到离群距离的严重影响。
如果你只关心某一对变量的相关系数,可以使用df['math_score'].corr(df['english_score'], method='pearson')的方式直接计算标量值。但corr()返回矩阵更方便后续画热力图。
实际分析中的关键注意点
相关系数大小不能直接说明关系显著。比如皮尔逊系数0.3在样本量为30和样本量为300时,统计显著性完全不同。Python中需要借助scipy.stats的pearsonr或spearmanr来计算p值,判断相关是否显著。下面的代码演示了对数学和英语成绩进行皮尔逊检验。
from scipy.stats import pearsonr, spearmanr
r_p, p_p = pearsonr(df['math_score'], df['english_score'])
r_s, p_s = spearmanr(df['math_score'], df['english_score'])
print(f"皮尔逊 r={r_p:.3f}, p={p_p:.4f}")
print(f"斯皮尔曼 r={r_s:.3f}, p={p_s:.4f}")
当p值小于0.05时,可以认为相关系数在统计上显著不为零。此外,即使相关系数很高,也不能直接推断因果关系,除非有实验设计或领域知识支撑。相关系数是对称的,交换两个变量位置结果不变。
数据预处理同样关键。corr()默认忽略缺失值,但如果某一列包含非数值类型,需要先转换或排除。在分析之前,建议检查数据的分布,使用seaborn的pairplot或热力图可以帮助直观判断。下面给出用seaborn绘制相关矩阵热力图的代码。
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(8, 6))
sns.heatmap(pearson_corr, annot=True, cmap='coolwarm', vmin=-1, vmax=1)
plt.title('Pearson Correlation Heatmap')
plt.show()
热力图中颜色越深表示相关性越强,标注的数字可以直接读取数值。当数据中存在非线性关系时,观察斯皮尔曼热力图与皮尔逊热力图的差异,能够发现被线性假设掩盖的单调关联。
理解corr()的底层实现有助于避免误解。皮尔逊计算的是cov(x,y)/(std(x)*std(y)),斯皮尔曼则先对每列做rank()变换再调用皮尔逊公式。如果数据中存在并列值,rank会默认采用平均排名,这可能导致斯皮尔曼系数略有偏差,但通常影响很小。Pandas内部使用numpy的相关系数计算,性能足以处理中等规模数据。
总结来看,进行相关性分析时应先明确研究目的是线性关系还是单调关系,然后选择对应的method参数。遇到异常值或非正态数据时优先考虑斯皮尔曼;只有确认数据满足线性假设时才使用默认的皮尔逊。配合显著性检验和可视化,才能得出可靠结论。