Numpy 如何计算一个非常大的相关矩阵

Numpy 如何计算一个非常大的相关矩阵,numpy,correlation,large-data,Numpy,Correlation,Large Data,我有一个观测值的np数组,其中z.shape是(100000,60)。我想高效地计算100000 x100000相关矩阵,然后将大于0.95的元素的坐标和值写入磁盘(这只是总数的一小部分) 我的暴力版本如下所示,但毫不奇怪,速度非常慢: for i1 in range(z.shape[0]): for i2 in range(i1+1): r = np.corrcoef(z[i1,:],z[i2,:])[0,1] if r > 0.95:

我有一个观测值的np数组,其中z.shape是(100000,60)。我想高效地计算100000 x100000相关矩阵,然后将大于0.95的元素的坐标和值写入磁盘(这只是总数的一小部分)

我的暴力版本如下所示,但毫不奇怪,速度非常慢:

for i1 in range(z.shape[0]):
    for i2 in range(i1+1):
        r = np.corrcoef(z[i1,:],z[i2,:])[0,1]
        if r > 0.95:
            file.write("%6d %6d %.3f\n" % (i1,i2,r))
我意识到使用np.corrcoef(z)在一次运算中可以更有效地计算相关矩阵本身,但是内存需求非常大。我也知道可以将数据集分解成块,一次计算相关矩阵的咬大小子部分,但编程和跟踪指数似乎不必要地复杂


是否有另一种方法(例如,使用memmap或pytables)既易于编码又不会对物理内存造成过多的需求?

根据我的粗略计算,您需要一个包含100000^2个元素的相关矩阵。假设是浮动的,它会占用大约40 GB的内存。
这可能不适合计算机内存,否则您可以使用
corrcoef
。 有一种基于特征向量的奇特方法,我现在找不到,它(必然)进入了复杂的范畴。。。 相反,依赖于这样一个事实,即对于零均值数据,协方差可以使用点积找到

z0 = z - mean(z, 1)[:, None]
cov = dot(z0, z0.T)
cov /= z.shape[-1]
这可以通过方差的标准化转化为相关性

sigma = std(z, 1)
corr = cov
corr /= sigma
corr /= sigma[:, None]
当然,内存使用仍然是一个问题。 您可以使用内存映射数组(确保已打开该数组进行读写)和
dot
out
参数来解决此问题(有关另一个示例,请参阅)


然后,您可以循环遍历生成的数组,并找到具有大相关系数的索引。(您可以使用
where(arr>0.95)
直接找到它们,但是比较将创建一个非常大的布尔数组,该数组可能适合内存,也可能不适合内存)。

根据我的粗略计算,您需要一个包含100000^2个元素的相关矩阵。假设是浮动的,它会占用大约40 GB的内存。
这可能不适合计算机内存,否则您可以使用
corrcoef
。 有一种基于特征向量的奇特方法,我现在找不到,它(必然)进入了复杂的范畴。。。 相反,依赖于这样一个事实,即对于零均值数据,协方差可以使用点积找到

z0 = z - mean(z, 1)[:, None]
cov = dot(z0, z0.T)
cov /= z.shape[-1]
这可以通过方差的标准化转化为相关性

sigma = std(z, 1)
corr = cov
corr /= sigma
corr /= sigma[:, None]
当然,内存使用仍然是一个问题。 您可以使用内存映射数组(确保已打开该数组进行读写)和
dot
out
参数来解决此问题(有关另一个示例,请参阅)

然后,您可以循环遍历生成的数组,并找到具有大相关系数的索引。(您可以使用
where(arr>0.95)
直接找到它们,但是比较将创建一个非常大的布尔数组,该数组可能适合内存,也可能不适合内存)。

您可以使用
metric=correlation
获得所有不带对称项的相关性。不幸的是,这仍然会给您留下大约5e10个可能会溢出内存的术语

您可以尝试重新格式化
KDTree
(理论上可以处理,因此可以处理相关距离)以过滤更高的相关性,但对于60维,这不太可能给您带来更多的加速

最好的办法可能是使用
scipy.space.distance.cdist(…,metric=correlation)
强制执行数据块,然后只保留每个块中的高相关性。一旦你知道你的内存可以处理多大的块而不会因计算机的内存结构而减慢速度,它应该比一次处理一个块快得多。

你可以使用
metric=correlation
来获得所有没有对称项的相关性。不幸的是,这仍然会给您留下大约5e10个可能会溢出内存的术语

您可以尝试重新格式化
KDTree
(理论上可以处理,因此可以处理相关距离)以过滤更高的相关性,但对于60维,这不太可能给您带来更多的加速


最好的办法可能是使用
scipy.space.distance.cdist(…,metric=correlation)
强制执行数据块,然后只保留每个块中的高相关性。一旦你知道你的内存可以处理多大的数据块而不会因计算机的内存结构而减慢速度,它应该比一次处理一个数据块快得多。

在试验了其他人提出的memmap解决方案后,我发现虽然它比我最初的方法(在我的Macbook上花了大约4天)快,这仍然需要很长时间(至少一天)——可能是由于对outputfile的逐元素写入效率低下。考虑到我需要多次计算,这是不可接受的

最后,最好的解决方案(对我来说)是登录AmazonWebServicesEC2门户,创建一个虚拟机实例(从一个配备了AnacondaPython的映像开始),内存容量超过120 GiB,上传输入数据文件,然后完全在核心内存中进行计算(使用矩阵乘法方法)。大约两分钟就完成了

作为参考,我使用的代码基本上是这样的:

import numpy as np
import pickle
import h5py

# read nparray, dimensions (102000, 60)

infile = open(r'file.dat', 'rb')
x = pickle.load(infile)
infile.close()     

# z-normalize the data -- first compute means and standard deviations
xave = np.average(x,axis=1)
xstd = np.std(x,axis=1)

# transpose for the sake of broadcasting (doesn't seem to work otherwise!)
ztrans = x.T - xave
ztrans /= xstd

# transpose back
z = ztrans.T

# compute correlation matrix - shape = (102000, 102000)
arr = np.matmul(z, z.T)   
arr /= z.shape[0]

# output to HDF5 file
with h5py.File('correlation_matrix.h5', 'w') as hf:
        hf.create_dataset("correlation",  data=arr)

在试验了其他人提出的memmap解决方案后,我发现虽然它比我最初的方法(在我的Macbook上花了大约4天)更快,但它仍然需要很长的时间(至少一天)——可能是由于对输出文件的逐元素写入效率低下。考虑到我需要多次计算,这是不可接受的

最后,最好的解决方案(对我来说)是登录亚马逊网络服务