新解决方案
看了 Joe Kington 的回答后,我决定研究corrcoef() 代码并受到它的启发,进行了以下实现。
ms = data.mean(axis=1)[(slice(None,None,None),None)]
datam = data - ms
datass = np.sqrt(scipy.stats.ss(datam,axis=1))
for i in xrange(rows):
temp = np.dot(datam[i:],datam[i].T)
rs = temp / (datass[i:]*datass[i])
每次循环都会在第 i 行和第 i 行之间生成 Pearson 系数,直到最后一行。它非常快。它至少比单独使用 corrcoef() 快 1.5 倍,因为它不会冗余计算系数和其他一些事情。它也会更快,并且不会给您带来 50,000 行矩阵的内存问题,因为您可以选择存储每组 r 或在生成另一组之前处理它们。在不存储 r 的任何长期数据的情况下,我能够在一分钟内在我相当新的笔记本电脑上让上述代码在 50,000 x 10 组随机生成的数据上运行。
旧解决方案
首先,我不建议将 r 打印到屏幕上。对于 100 行(10 列),打印时间为 19.79 秒,而不使用代码则为 0.301 秒。如果您愿意,只需存储 r 并在以后使用它们,或者在进行过程中对它们进行一些处理,例如寻找一些最大的 r。
其次,您可以通过不重复计算某些数量来节省一些费用。 Pearson 系数是在 scipy 中使用一些您可以预先计算的量来计算的,而不是在每次使用行时计算。此外,您没有使用 p 值(pearsonr() 也返回了它,所以让我们也从头开始。使用以下代码:
r = np.zeros((rows,rows))
ms = data.mean(axis=1)
datam = np.zeros_like(data)
for i in xrange(rows):
datam[i] = data[i] - ms[i]
datass = scipy.stats.ss(datam,axis=1)
for i in xrange(rows):
for j in xrange(i,rows):
r_num = np.add.reduce(datam[i]*datam[j])
r_den = np.sqrt(datass[i]*datass[j])
r[i,j] = min((r_num / r_den), 1.0)
当我删除 p 值的东西时,我得到了比直接 scipy 代码大约 4.8 倍的加速 - 如果我将 p 值的东西留在那里,则加速了 8.8 倍(我使用了 10 列数百行)。我还检查了它确实给出了相同的结果。这并不是一个真正巨大的改进,但它可能会有所帮助。
最终,您遇到的问题是您正在计算 (50000)*(50001)/2 = 1,250,025,000 皮尔逊系数(如果我计算正确的话)。好多啊。顺便说一句,实际上没有必要自己计算每一行的 Pearson 系数(它将等于 1),但这只会使您免于计算 50,000 个 Pearson 系数。使用上面的代码,根据我在较小数据集上的结果,如果您的数据有 10 列,我预计大约需要 4 1/4 小时来完成计算。
您可以通过将上述代码导入 Cython 或类似的东西来获得一些改进。我希望如果幸运的话,你可能会比直接 Scipy 提高 10 倍。此外,根据 pyInTheSky 的建议,您可以进行一些多处理。