Spearman相关系数

Spearman相关系数

斯皮尔曼相关系数,其对数据的分布要求较低,而且衡量的是两个变量之间的单调关系(即一个变量增加时,另一个变量也增加或减少,但不一定是线性关系)。因此,即使变量之间的关系是非线性的,只要关系是单调的,斯皮尔曼相关系数仍然可以有效地衡量它们之间的相关性。

计算方式

首先我们要计算排名,所谓排名就是将数据由大到小排列,然后给每个数据一个等级。最大是数等级就为1。但是,如果有相同的排名,我们就得给它们合理的排名,一般是取平均值。比如一组数1,2,2,4,5,那么它们的排名分别是1,2.5,2.5,4,5。基于这个排名我们再开始如下计算。


① 无结(无相同名次)时的公式

\[r_s = 1 - \frac{6 \sum_1^n d_i^{2}}{n(n^{2}-1)} \]

  • \(r_s\):斯皮尔曼相关系数
  • \(d_i\):第 \(i\) 对数据的等级差(两个变量对应观测值的等级之差)
  • \(n\):样本数量
  • \(\sum_1^n d_i^{2}\):所有等级差的平方和

② 存在“结”(相同名次)时的修正公式

\[r_s = \frac{\sum_1^n (R_i - \bar{R})(S_i - \bar{S})}{\sqrt{\sum_1^n (R_i - \bar{R})^{2} \sum_1^n (S_i - \bar{S})^{2}}} \]

  • \(R_i\):第一个变量的等级
  • \(S_i\):第二个变量的等级
  • \(\bar{R},\; \bar{S}\):两个变量等级的平均值

取值含义

取值范围: [-1, 1]

\(r_s\) 解释
+1 完全正单调相关(一个变量递增,另一个也严格递增)
−1 完全负单调相关(一个变量递增,另一个严格递减)
0 无单调相关关系

计算p值

我们还将计算P值来进一步反映相关性,在统计语言表达上,如果P值小于0.01,则称作0.01水平显著,则说明X对Y存在影响关系这件事至少有99%的把握,统计语言描述为X在0.01水平上呈现显著性。如果P值小于0.05(且大于或等于0.01),则称作在0.05水平上显著。反之,如果P值较大则说明显著性比较小。

Python代码

其中的计算数据来源某道数学建模题目。

import numpy as np
from scipy.stats import rankdata, t as tdist
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import zhplot

def spearman_manual(x, y, method='average'):
    """
    手动实现 Spearman 相关系数及其 p 值(双侧)
    参数
    ----
    x, y : 一维数组,长度相同
    method : rankdata 的并列值处理方式,默认 'average'

    返回
    ----
    rs : Spearman 相关系数
    p  : 双侧检验 p 值
    """
    x, y = np.asarray(x), np.asarray(y)
    if x.size != y.size:
        raise ValueError("x 与 y 长度必须相同")
    n = x.size
    if n < 3:                      # 自由度 n-2 >=1 才有意义
        return np.nan, np.nan

    # 1. 计算等级
    Rx = rankdata(x, method=method)
    Ry = rankdata(y, method=method)

    # 2. 检测是否有结
    ties = (len(np.unique(Rx)) != n) or (len(np.unique(Ry)) != n)

    # 3. 计算 rs
    if not ties:
        # 无结:经典公式
        d = Rx - Ry
        d2_sum = np.dot(d, d)
        rs = 1.0 - 6.0 * d2_sum / (n * (n**2 - 1))
    else:
        # 有结:等级后的 Pearson
        R_bar, S_bar = Rx.mean(), Ry.mean()
        numerator = np.sum((Rx - R_bar) * (Ry - S_bar))
        denominator = np.sqrt(np.sum((Rx - R_bar)**2) * np.sum((Ry - S_bar)**2))
        rs = numerator / denominator

    # 4. 计算双侧 p 值(t 检验,df = n-2)
    if abs(rs) >= 1.0:            # 防止除 0
        p = 0.0 if rs != 0 else 1.0
    else:
        t_stat = rs * np.sqrt((n - 2) / (1 - rs**2))
        p = 2 * tdist.sf(abs(t_stat), df=n - 2)

    return rs, p

# 输出结果
# 1. 读数据 -------------------------------------------------------------
data = np.loadtxt('B-附件1.csv', delimiter=',', dtype=float,
                  skiprows=2, encoding='utf-8', usecols=[1, 2, 3, 13, 14, 15, 16])

# 2. 变量名 -------------------------------------------------------------
x_names = ['X1', 'X2', 'X3']
y_names = ['Y1', 'Y2', 'Y3', 'Y4']

# 3. 计算并汇总 ---------------------------------------------------------
records = []
for i, xn in enumerate(x_names):
    for j, yn in enumerate(y_names):
        rs, p = spearman_manual(data[:, i], data[:, 3 + j])
        records.append({'X变量': xn, 'Y变量': yn,
                        '相关系数': rs, 'p值': p})

# 4. 输出表格 -----------------------------------------------------------
df = pd.DataFrame(records)
print(df)


# 绘制热力图
# 1. 把结果表 pivot 成 3×4 矩阵 -------------------------------
corr_mat = df.pivot(index='X变量', columns='Y变量', values='相关系数')

# 2. 画图 ------------------------------------------------------
plt.figure(figsize=(4, 3))                       
sns.heatmap(corr_mat,
            annot=True,
            fmt='.3f',
            cmap='coolwarm',
            annot_kws={'size': 20}) 
plt.title('Spearman 相关系数热力图',fontsize=25)
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.tight_layout()
plt.xlabel('')                               
plt.ylabel('')
plt.show()

输出结果

  X变量 Y变量      相关系数            p值
0   X1  Y1 -0.191580  1.611606e-01
1   X1  Y2  0.459110  4.224245e-04
2   X1  Y3 -0.530383  3.113766e-05
3   X1  Y4 -0.013273  9.233794e-01
4   X2  Y1  0.130301  3.430326e-01
5   X2  Y2  0.614357  6.067929e-07
6   X2  Y3  0.039024  7.772779e-01
7   X2  Y4 -0.572480  4.953330e-06
8   X3  Y1 -0.181354  1.851435e-01
9   X3  Y2  0.422558  1.310038e-03
10  X3  Y3 -0.241051  7.625124e-02
11  X3  Y4 -0.038841  7.782967e-01

绘制热力图

posted @ 2025-08-26 17:51  数理生风  阅读(86)  评论(0)    收藏  举报