计算相关系数矩阵
相关系数矩阵是一个对称矩阵,其中每个元素表示两个变量之间的皮尔逊相关系数(Pearson correlation coefficient),通常用符号 r 表示。相关系数矩阵就是一次性把多个变量之间的“关联紧密程度”全都清晰地展示出来的工具。
相关系数矩阵的本质是计算变量间的皮尔逊相关系数,公式为:
对于变量X和Y,相关系数
,其中:
:协方差,衡量两变量的总体误差;
:变量X的方差。
用 numpy 计算时,核心步骤是:
1. 对数据矩阵做中心化(每个变量减去自身均值);
2. 计算协方差矩阵;
3. 对协方差矩阵做标准化(除以变量标准差的乘积),得到相关系数矩阵。

矩阵的第 i 行第 j 列元素表示变量 X_i 和变量 X_j 之间的相关系数,取值范围在 [-1, 1] 之间:
|
相关系数值 |
含义 |
|
1 |
完全正线性相关 |
|
0 |
无线性相关 |
|
-1 |
完全负线性相关 |
矩阵形式如下:

对角线元素为 1(因为变量与自身完全相关)。
矩阵是对称的,即
举一个例子加以理解!
第一步:准备数据
创建一个虚拟的数据集,包含 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() 更直接高效。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)