Scipy:来自数组的稀疏指标矩阵

时间:2019-02-16 09:04:07

标签: python numpy scipy sparse-matrix indicator

从一个或两个数组Ia,b其中I[i,j]==True来计算稀疏布尔矩阵a[i]==b[j]的最有效方法是什么?以下是快速但内存效率低的方法:

I = a[:,None]==b

以下是缓慢的过程,但在创建过程中仍然内存不足:

I = csr((a[:,None]==b),shape=(len(a),len(b)))

以下内容至少给出了行,col以便更好地进行csr_matrix初始化,但是它仍然会创建完整的密集矩阵并且同样慢:

z = np.argwhere((a[:,None]==b))

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

一种实现方法是首先使用a来标识bset共有的所有不同元素。如果ab中的值没有太多不同的可能性,这应该会很好地工作。这样一来,只需要遍历不同的值(在变量values中),并使用np.argwhere来标识这些值出现在ab中的索引。然后可以使用np.repeatnp.tile构造稀疏矩阵的2D索引:

import numpy as np
from scipy import sparse

a = np.random.randint(0, 10, size=(400,))
b = np.random.randint(0, 10, size=(300,))

## matrix generation after OP
I1 = sparse.csr_matrix((a[:,None]==b),shape=(len(a),len(b)))

##identifying all values that occur both in a and b:
values = set(np.unique(a)) & set(np.unique(b))

##here we collect the indices in a and b where the respective values are the same:
rows, cols = [], []

##looping over the common values, finding their indices in a and b, and
##generating the 2D indices of the sparse matrix with np.repeat and np.tile
for value in values:
    x = np.argwhere(a==value).ravel()
    y = np.argwhere(b==value).ravel()    
    rows.append(np.repeat(x, len(x)))
    cols.append(np.tile(y, len(y)))

##concatenating the indices for different values and generating a 1D vector
##of True values for final matrix generation
rows = np.hstack(rows)
cols = np.hstack(cols)
data = np.ones(len(rows),dtype=bool)

##generating sparse matrix
I3 = sparse.csr_matrix( (data,(rows,cols)), shape=(len(a),len(b)) )

##checking that the matrix was generated correctly:
print((I1 != I3).nnz==0)

用于生成csr矩阵的语法取自documentation。稀疏矩阵相等性的检验来自this post

旧答案

我对性能一无所知,但至少您可以避免使用简单的生成器表达式来构造完整的密集矩阵。这里的一些代码使用两个1d随机整数的arras首先以OP发布的方式生成稀疏矩阵,然后使用生成器表达式测试所有元素的相等性:

import numpy as np
from scipy import sparse

a = np.random.randint(0, 10, size=(400,))
b = np.random.randint(0, 10, size=(300,))

## matrix generation after OP
I1 = sparse.csr_matrix((a[:,None]==b),shape=(len(a),len(b)))

## matrix generation using generator
data, rows, cols = zip(
    *((True, i, j) for i,A in enumerate(a) for j,B in enumerate(b) if A==B)
)
I2 = sparse.csr_matrix((data, (rows, cols)), shape=(len(a), len(b)))

##testing that matrices are equal
## from https://stackoverflow.com/a/30685839/2454357
print((I1 != I2).nnz==0)  ## --> True

我认为没有办法绕过双循环,理想情况下,将其推入numpy,但至少使用生成器,这些循环在某种程度上已得到优化...

答案 1 :(得分:0)

您可以使用容忍度较小的numpy.isclose

docker-compose -f docker-compose.production.yml up

pandas.DataFrame.eq

np.isclose(a,b)

请注意,这将返回a.eq(b) True的数组。