相关系数矩阵是一个对称矩阵,其中每个元素表示两个变量之间的皮尔逊相关系数(Pearson correlation coefficient),通常用符号 r 表示。相关系数矩阵就是一次性把多个变量之间的“关联紧密程度”全都清晰地展示出来的工具。

 相关系数矩阵的本质是计算变量间的皮尔逊相关系数,公式为:

对于变量X和Y,相关系数

r = \frac{\text{Cov}(X,Y)}{\sqrt{\text{Var}(X)} \cdot \sqrt{\text{Var}(Y)}}

,其中:

\text{Cov}(X,Y):协方差,衡量两变量的总体误差;

\text{Var}(X):变量X的方差。

用 numpy 计算时,核心步骤是:

1. 对数据矩阵做中心化(每个变量减去自身均值);

2. 计算协方差矩阵;

3. 对协方差矩阵做标准化(除以变量标准差的乘积),得到相关系数矩阵。

矩阵的第 i 行第 j 列元素表示变量 X_i 和变量 X_j 之间的相关系数,取值范围在 [-1, 1] 之间:

相关系数值

含义

1

完全正线性相关

0

无线性相关

-1

完全负线性相关

矩阵形式如下:

对角线元素为 1(因为变量与自身完全相关)。

矩阵是对称的,即 r_{ij}=r_{ji}

举一个例子加以理解!

第一步:准备数据

创建一个虚拟的数据集,包含 5 名学生的三项指标:每日学习时间(小时)每日睡眠时长(小时) 和 期末考试分数

使用numpy:

import numpy as np

# 1. 数据准备(沿用学习时间、睡眠时长、考试分数数据)
data = {
    '学习时间(小时)': [2, 3, 5, 1, 4],
    '睡眠时长(小时)': [7, 6, 8, 5, 7],
    '考试分数': [65, 75, 90, 50, 85]
}
# 转为numpy二维矩阵(行=样本/学生,列=变量:学习时间、睡眠时长、考试分数)
data_matrix = np.column_stack((
    np.array(data['学习时间(小时)']),
    np.array(data['睡眠时长(小时)']),
    np.array(data['考试分数'])
))

使用pandas:

# 创建一个字典,键是变量名,值是数据列表
data = {
    '学习时间(小时)': [2, 3, 5, 1, 4],
    '睡眠时长(小时)': [7, 6, 8, 5, 7],
    '考试分数': [65, 75, 90, 50, 85]
}

# 使用字典创建一个DataFrame(可以理解为一个表格)
df = pd.DataFrame(data)

# 打印出我们的数据集,看看它长什么样
print("--- 我们的原始数据 ---")
print(df)

输出:

--- 我们的原始数据 ---
   学习时间(小时)  睡眠时长(小时)  考试分数
0           2           7      65
1           3           6      75
2           5           8      90
3           1           5      50
4           4           7      85

第二步:计算相关系数矩阵

使用numpy提供的现成的函数corrcoef()

# 2. 使用numpy的corrcoef函数计算相关系数矩阵
# rowvar=False:指定矩阵“列=变量”(默认rowvar=True,即“行=变量”,需手动调整)
corr_matrix = np.corrcoef(data_matrix, rowvar=False)

# 3. 输出结果
print("=== 基于np.corrcoef()的相关系数矩阵 ===")
# 保留4位小数,让结果更易读
print(np.round(corr_matrix, 4))
# 标注变量对应关系,避免混淆
print("\n变量说明:")
print("行/列1:学习时间(小时),行/列2:睡眠时长(小时),行/列3:考试分数")

输出:

=== 基于np.corrcoef()的相关系数矩阵 ===
[[1.      0.6402  0.9819]
 [0.6402  1.      0.7559]
 [0.9819  0.7559  1.    ]]

变量说明:
行/列1:学习时间(小时),行/列2:睡眠时长(小时),行/列3:考试分数

使用pandas 提供的现成的函数 corr()

# 使用 corr() 函数计算相关系数矩阵
# 默认计算的是 Pearson 相关系数,适用于衡量线性关系
correlation_matrix = df.corr()

# 打印结果
print("\n--- 相关系数矩阵 ---")
print(correlation_matrix)

输出:

--- 相关系数矩阵 ---
             学习时间(小时)  睡眠时长(小时)      考试分数
学习时间(小时)     1.000000     0.640184  0.981981
睡眠时长(小时)     0.640184     1.000000  0.755929
考试分数         0.981981     0.755929  1.000000

第三步:解读结果

1.对角线元素:你会看到对角线(从左上到右下)上的元素都是 1.000000。这是因为任何一个变量和它自己的相关系数永远是 1,这是完全正相关。

2.分析变量之间的关系

学习时间 vs 考试分数:相关系数是 0.98,非常接近 1。这表明学习时间和考试分数之间存在极强的正相关关系。这符合我们的常识:学习越努力,分数越高。

睡眠时长 vs 考试分数:相关系数是 0.76,也比较接近 1。这表明睡眠时长和考试分数之间存在较强的正相关关系。保证充足的睡眠似乎也对提高成绩有帮助。

学习时间 vs 睡眠时长:相关系数是 0.64,同样是正数。这表明学习时间和睡眠时长之间也存在一定的正相关关系。在这个例子里,学习时间长的学生,睡眠也相对充足,这可能是一个好习惯的体现。

总结一下:通过这个简单的矩阵,我们可以快速得出结论:对于这 5 名学生而言,学习时间是影响成绩最关键的因素,其次是睡眠。

拓展:三种常用的相关系数

pandas 的 corr() 函数默认使用的是 Pearson 相关系数,但你也可以通过 method 参数选择其他类型,它们适用于不同的数据情况。

相关系数类型

method 参数

适用场景

特点

Pearson

'pearson' (默认)

衡量两个变量线性关系的强度和方向。

要求数据近似服从正态分布,对异常值比较敏感。

Spearman

'spearman'

衡量两个变量单调关系的强度和方向(不一定是线性的)。

不要求正态分布,对异常值更稳健。适用于有序分类数据。

Kendall

'kendall'

与 Spearman 类似,也是衡量单调关系。

适用于样本量较小的情况。

如何切换使用?

# 计算 Spearman 相关系数矩阵
spearman_matrix = df.corr(method='spearman')
print("\n--- Spearman 相关系数矩阵 ---")
print(spearman_matrix)

在我们的例子中,由于关系基本是线性的,Pearson 和 Spearman 的结果会非常接近。

注意事项一:相关 ≠ 因果 (Correlation ≠ Causation)

相关 (Correlation):指的是两个变量一起变化的趋势。当一个变量增加时,另一个变量也倾向于增加(正相关)或减少(负相关)。它只描述了一种关系或伴随现象。

因果 (Causation):指的是一个变量直接导致了另一个变量的变化。它描述的是一种机制或原因和结果。

经典反例:冰淇淋销量 vs. 溺水人数

想象一下,我们收集了夏天三个月的数据,计算冰淇淋销量和溺水人数的相关系数,会发现它们之间存在很强的正相关(比如 r = 0.8)。

这是否意味着 “吃冰淇淋会导致溺水”?显然不是!

真正的原因是什么?

是第三个变量 ——“气温”。

当天气炎热时,人们更想吃冰淇淋,所以冰淇淋销量上升。

同时,天气炎热时,人们更想去游泳,游泳的人多了,溺水的风险和人数自然也会增加。

在这个例子中,冰淇淋销量和溺水人数都是结果,而气温才是它们共同的原因。这种被忽略的第三方变量,在统计学上称为混淆变量 (Confounding Variable)。

如何避免犯这个错误?

多问一个 “为什么”:当你发现两个变量高度相关时,不要轻易下结论,而是思考 “是否存在一个第三方变量同时影响了它们?”

进行实验验证:在科学研究中,证明因果关系最可靠的方法是进行随机对照试验 (Randomized Controlled Trial)。例如,为了证明药物有效,你需要随机将病人分为两组,一组服药,一组不服(或服安慰剂),然后比较结果。

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

# 设置随机种子以保证结果可复现
np.random.seed(42)

# 1. 创建数据
# 假设我们有30天的数据
days = 30
# 气温:随机在25到35度之间
temperature = np.random.uniform(25, 35, days)
# 冰淇淋销量:气温越高,销量越高(加上一些随机波动)
ice_cream_sales = 5 * temperature + np.random.normal(0, 10, days)
# 溺水人数:气温越高,游泳的人越多,溺水人数也越多(加上一些随机波动)
drowning_cases = 0.8 * temperature + np.random.normal(0, 1, days)

# 创建DataFrame
df_causation = pd.DataFrame({
    '气温 (°C)': temperature,
    '冰淇淋销量': ice_cream_sales,
    '溺水人数': drowning_cases
})

# 2. 计算相关系数矩阵
print("--- 相关系数矩阵 ---")
print(df_causation.corr().round(3))

# 3. 可视化
plt.figure(figsize=(12, 5))

# 绘制冰淇淋销量 vs 气温
plt.subplot(1, 3, 1)
sns.scatterplot(data=df_causation, x='气温 (°C)', y='冰淇淋销量')
plt.title('冰淇淋销量 vs 气温')

# 绘制溺水人数 vs 气温
plt.subplot(1, 3, 2)
sns.scatterplot(data=df_causation, x='气温 (°C)', y='溺水人数')
plt.title('溺水人数 vs 气温')

# 绘制冰淇淋销量 vs 溺水人数(虚假相关)
plt.subplot(1, 3, 3)
sns.scatterplot(data=df_causation, x='冰淇淋销量', y='溺水人数')
plt.title('冰淇淋销量 vs 溺水人数')

plt.tight_layout()
plt.show()

输出:

相关系数矩阵:

--- 相关系数矩阵 ---
         气温 (°C)  冰淇淋销量   溺水人数
气温 (°C)    1.000  0.774  0.925
冰淇淋销量      0.774  1.000  0.748
溺水人数       0.925  0.748  1.000

冰淇淋销量、气温、溺水人数三者的关系图:

  • 冰淇淋销量 vs 气温:随着气温的升高,冰淇淋销量整体呈现上升趋势,体现了气温和冰淇淋销量的正相关关系,与相关系数矩阵里两者0.774的相关系数相呼应。
  • 溺水人数 vs 气温:随着气温升高,溺水人数明显上升,表明气温和溺水人数的强正相关,和相关系数0.925所反映的强关联一致。
  • 冰淇淋销量 vs 溺水人数:随着冰淇淋销量增加,溺水人数大致呈上升态势,体现出两者的正相关,和相关系数0.748相符。不过这只是线性相关表现,实际上冰淇淋销量增加并不会直接导致溺水人数增多,只是气温这个共同因素,使得气温高时冰淇淋销量和溺水人数都易增加,从而让两者呈现出相关关系。

总结:

Pandas 的 DataFrame.corr() 针对 DataFrame 的列(每列代表一个变量)操作,支持皮尔逊、斯皮尔曼、肯德尔等多种相关系数类型,能灵活处理缺失值,调用简单且结果以带变量名的 DataFrame 呈现,底层基于 NumPy 实现;而 NumPy 的 np.corrcoef() 针对数组操作,默认每行代表一个变量(可通过 rowvar=False 调整),仅支持皮尔逊相关系数,要求数组无缺失值,结果为无变量名的二维数组,在纯数组运算场景下效率较高。简言之,若处理结构化表格数据且需多样功能,选 DataFrame.corr();若为纯数组的皮尔逊相关系数运算,np.corrcoef() 更直接高效。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐