Python 大型二维numpy阵列中相同元素的高效成对计算

Python 大型二维numpy阵列中相同元素的高效成对计算,python,arrays,numpy,scipy,sparse-matrix,Python,Arrays,Numpy,Scipy,Sparse Matrix,我有一个2D numpy数组,它有几十万行和大约一千列(假设它是一个N=200000,p=1000的nxp数组)。这里的目标是计算每对行向量之间相同元素的数量,理想情况下使用numpy数组魔术,不需要我在199999*100000这样的行向量对上执行循环。由于存储200000 x 200000阵列可能不可行,因此输出可能采用Nx3稀疏坐标格式,例如,如果输入格式为: 5 12 14 200 0 45223 7 12 14 0 200 60000 7 6 23 0 0 45223

我有一个2D numpy数组,它有几十万行和大约一千列(假设它是一个N=200000,p=1000的nxp数组)。这里的目标是计算每对行向量之间相同元素的数量,理想情况下使用numpy数组魔术,不需要我在199999*100000这样的行向量对上执行循环。由于存储200000 x 200000阵列可能不可行,因此输出可能采用Nx3稀疏坐标格式,例如,如果输入格式为:

5 12 14 200   0 45223
7 12 14   0 200 60000
7  6 23   0   0 45223
5  6 14 200   0 45223
得到的(密集的)NxN矩阵M将是(不考虑对角元素):

这样,假设基于0的索引,Mij包含初始行i和初始行j之间相同元素的数量。 因此,预期的稀疏输出当量为:

0 1 2
0 2 2
0 3 4
1 2 2 
1 3 1
2 3 3
实现这一点的一种幼稚而低效的方法是:

import itertools
import numpy as np

def pairwise_identical_elements(small_matrix):
    n, p = small_matrix.shape
    coordinates = itertools.combinations(range(n), 2)
    sparse_coordinate_matrix = []
    for row1, row2 in itertools.combinations(small_matrix, 2):
        idx1, idx2 = next(coordinates)
        count = p - np.count_nonzero(row1 - row2)
        sparse_coordinate_matrix.append([idx1, idx2, count])
    return sparse_coordinate_matrix
我已经研究了距离度量实现,比如scipy和sklearn中的Jaccard相似性,但是它们都假设输入行向量必须是二进制的。我还尝试添加第三维以使条目成为二进制(例如,条目“9”变为零向量,第9位为1),但存在明显的内存问题(条目“45223”需要第三维拉伸那么多元素)

是否有一个高效、可扩展和/或pythonic的解决方案使用numpy或scipy,而我却错过了


编辑:在深入研究scipy之后,我发现了一些与我尝试做的事情非常匹配的东西,即汉明度量。然而,它以“压缩”形式返回输出,由于我们试图避免转换为全密集数组以节省内存,问题可能会变成:如何将压缩距离矩阵转换为稀疏距离矩阵?

如评论中所述,scipy的“hamming”是解决此问题的最简单有效方法,考虑到空间和cpu时间

您将无法比它的内存效率更高。
事实上,当编写成“稀疏”格式时,您需要一个
(N*(N-1)/2,3)
矩阵,而不是
N*(N-1)/2
向量,该向量由
pdist

返回。请归纳一些代码,让我们更多地了解您的意图,我添加了一个小片段,以一种天真的方式实现了我正在尝试的操作。假设输入是一个标准的numpy数组。那么这里的桩在哪里呢?空间复杂性?或者关于时间?内存是一个明显的问题(因为python在处理太多对象时往往会崩溃),但是任何与scipy.sparse.distance模块中前面提到的pdist函数数量级相同的运行时都可以。@lurena您能解释一下问题中的示例吗,因为对示例输入运行函数会得到不同的输出
import itertools
import numpy as np

def pairwise_identical_elements(small_matrix):
    n, p = small_matrix.shape
    coordinates = itertools.combinations(range(n), 2)
    sparse_coordinate_matrix = []
    for row1, row2 in itertools.combinations(small_matrix, 2):
        idx1, idx2 = next(coordinates)
        count = p - np.count_nonzero(row1 - row2)
        sparse_coordinate_matrix.append([idx1, idx2, count])
    return sparse_coordinate_matrix