You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用无循环Numpy实现一维数组与递增序列的逐步滑动相关计算

无循环实现逐段皮尔逊相关系数计算

问题描述

给定一维数组,需要依次计算前2个、前3个……直至全部元素与对应长度的递增序列(如np.arange(k),k为当前段长度)的皮尔逊相关系数。原实现使用循环结合Numpy,现要求用更高效的无循环Numpy方法实现。

原循环代码:

import numpy as np

data = np.array([10,5,8,9,15,22,26,11,15,16,18,7,4,8,-2,-3,-4,-6,-2,0,10,0,5,8])
correl = np.zeros(data.shape)
for i in range(1, data.shape[0]):
     correl[i] = np.corrcoef(data[0: i+1], np.arange(i+1))[0, 1]
print(correl)

原输出:

[ 0.    -1.    -0.397  0.     0.607  0.799  0.88   0.64   0.581  0.556
  0.574  0.322  0.078 -0.02  -0.237 -0.383 -0.489 -0.572 -0.614 -0.634
 -0.568 -0.59  -0.573 -0.533]

高效无循环实现

利用皮尔逊相关系数的代数表达式,结合Numpy的累积求和函数np.cumsum实现全量向量化计算,避免循环开销:

import numpy as np

data = np.array([10,5,8,9,15,22,26,11,15,16,18,7,4,8,-2,-3,-4,-6,-2,0,10,0,5,8])
n = len(data)
y = np.arange(n)  # 对应各段的递增序列

# 计算各项累积和
sum_x = np.cumsum(data)
sum_y = np.cumsum(y)
sum_xy = np.cumsum(data * y)
sum_x2 = np.cumsum(data ** 2)
sum_y2 = np.cumsum(y ** 2)
k = np.arange(1, n+1)  # 各段的长度

# 计算相关系数的分子和分母
numerator = k * sum_xy - sum_x * sum_y
denominator_x = k * sum_x2 - sum_x ** 2
denominator_y = k * sum_y2 - sum_y ** 2
denominator = np.sqrt(denominator_x * denominator_y)

# 计算相关系数,处理k=1时分母为0的情况
correl = numerator / denominator
correl[0] = 0.0  # 对应原代码中第一个元素为0

# 保留三位小数以匹配原输出格式
print(np.round(correl, 3))

运行输出:

[ 0.    -1.    -0.397  0.     0.607  0.799  0.88   0.64   0.581  0.556
  0.574  0.322  0.078 -0.02  -0.237 -0.383 -0.489 -0.572 -0.614 -0.634
 -0.568 -0.59  -0.573 -0.533]

原理说明

皮尔逊相关系数可通过以下公式计算:
[
r = \frac{k\sum xy - \sum x \sum y}{\sqrt{(k\sum x^2 - (\sum x)^2)(k\sum y^2 - (\sum y)^2)}}
]
其中k为当前计算段的元素数量。

通过np.cumsum一次性计算所有前缀的累积和,再利用Numpy的广播特性完成向量化运算,相比循环实现,时间复杂度从O(n²)降至O(n),效率大幅提升,尤其适合处理大规模数组。

内容的提问来源于stack exchange,提问作者tibibou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 00:55:19