我试图弄清楚如何在scipy稀疏数组(csc格式)上有效地执行以下操作:
元素伪代码:
try:
M[i,j] /= (V[i] + V[j])
except ZeroDivisionError:
pass # leave at old value
注意,这使得零元素为0,因此不增加输入矩阵M
的密度。
对于稠密矩阵有一个简单的方法:
# V is a ndarray of shape (N), all values finite and >= 0.0
# M is a ndarray of shape (N,N), all values finite
rows_plus_cols = V[:, np.newaxis] + V[np.newaxis, :]
M = np.divide(M, rows_plus_cols, out=M, where=(rows_plus_cols != 0))
不幸的是,这种方法似乎不适用于稀疏矩阵,因为rows_plus_cols
的中间计算会导致大小为(N,N)
的密集矩阵。
典型的输入M可以是100 k乘100 k,具有~ 1 M个非零条目。显然,在实现一个完整的密集矩阵是不明智的政权。出于测试目的,以下是“足够接近”典型输入:
n = 100000
d = 10
# a.k.a. "mostly nonzero, but not always"
V = np.maximum((np.random.normal(size=n)+2), 0)
M = scipy.sparse.coo_array((np.random.normal(size=n*d), np.random.randint(n, size=(2, n*d))), shape=(n,n)).tocsc()
M.sum_duplicates()
M.prune()
M.sort_indices()
小问题:scipy稀疏数组似乎不允许使用where
子句进行元素级除法。可以解决,但这不是主要问题。我知道您可以使用M.data
访问scipy csc数组的底层数据点;我看不出如何在不具体化稠密矩阵的情况下进行作为坐标的函数的元素级计算。
建议?
1条答案
按热度按时间vfwfrxfs1#
这里有一种使用
coo_array
的方法。在这个例子中,
M
是一个8x8coo_array
,V
是一个长度为8的一维NumPy数组。如果M
可能有重复的条目,则应在执行以下操作之前调用M.sum_duplicates()
。首先将分母形成为
V[M.row] + V[M.col]
,并将任何出现的0替换为1,因此不是除以0,这些位置的值保持不变:我们将新数组命名为
Q
。Q_data
将是Q
的data
数组:使用与
M
相同的形状和相同的行和列索引,用Q_data
创建一个新的coo_array
:执行密集版本的计算,以验证其是否按预期工作:
你可以将ipython会话的第112、113、115和117行打包成一个函数。