gpt4 book ai didi

python - numpy:有效地添加矩阵的行

转载 作者:太空宇宙 更新时间:2023-11-03 14:59:04 25 4
gpt4 key购买 nike

我有一个矩阵。

mat = array([
[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]
])

我想获得某些索引处的行总和:例如。

ixs = np.array([0,2,0,0,0,1,1])

我知道我可以将答案计算为:

mat[ixs].sum(axis=0)
> array([16, 23, 30, 37])

问题是 ixs 可能很长,我不想用所有的内存来创建中间产品 mat[ixs],只能用 sum 再次减少它。

我也知道我可以简单地计算索引并改用乘法。

np.bincount(ixs, minlength=mat.shape[0).dot(mat)
> array([16, 23, 30, 37])

但如果我的 ixs 稀疏,那将是昂贵的。

我知道 scipy 的稀疏矩阵,我想我可以使用它们,但我更喜欢纯 numpy 解决方案,因为稀疏矩阵在各种方面受到限制(例如只有二维)

那么,在这种情况下,是否有一种纯粹的 numpy 方法来合并索引和归约?

结论:

感谢 Divakar 和 hpaulj 非常详尽的回复。 “稀疏”是指 range(w.shape[0]) 中的大部分值不在 ixs 中。使用这个新定义(以及更真实的数据大小,我重新运行 Divakar 测试,添加了一些新功能:

rng = np.random.RandomState(1234)
mat = rng.randn(1000, 500)
ixs = rng.choice(rng.randint(mat.shape[0], size=mat.shape[0]/10), size=1000)

# Divakar's solutions
In[42]: %timeit org_indexing_app(mat, ixs)
1000 loops, best of 3: 1.82 ms per loop
In[43]: %timeit org_bincount_app(mat, ixs)
The slowest run took 4.07 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 177 µs per loop
In[44]: %timeit indexing_modified_app(mat, ixs)
1000 loops, best of 3: 1.81 ms per loop
In[45]: %timeit bincount_modified_app(mat, ixs)
1000 loops, best of 3: 258 µs per loop
In[46]: %timeit simply_indexing_app(mat, ixs)
1000 loops, best of 3: 1.86 ms per loop
In[47]: %timeit take_app(mat, ixs)
1000 loops, best of 3: 1.82 ms per loop
In[48]: %timeit unq_mask_einsum_app(mat, ixs)
10 loops, best of 3: 58.2 ms per loop
# hpaulj's solutions
In[53]: %timeit hpauljs_sparse_solution(mat, ixs)
The slowest run took 9.34 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 3: 524 µs per loop
%timeit hpauljs_second_sparse_solution(mat, ixs)
100 loops, best of 3: 9.91 ms per loop
# Sparse version of original bincount solution (see below):
In[60]: %timeit sparse_bincount(mat, ixs)
10000 loops, best of 3: 71.7 µs per loop

赢家在这种情况下是 bincount 解决方案的稀疏版本。

def sparse_bincount(mat, ixs):
x = np.bincount(ixs)
nonzeros, = np.nonzero(x)
x[nonzeros].dot(mat[nonzeros])

最佳答案

bincount 的替代方法是 add.at:

In [193]: mat
Out[193]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
In [194]: ixs
Out[194]: array([0, 2, 0, 0, 0, 1, 1])

In [195]: J = np.zeros(mat.shape[0],int)
In [196]: np.add.at(J, ixs, 1)
In [197]: J
Out[197]: array([4, 2, 1])

In [198]: np.dot(J, mat)
Out[198]: array([16, 23, 30, 37])

关于稀疏性,我假设 ixs 可能不包含所有行,例如,没有 0 的 ixs:

In [199]: ixs = np.array([2,1,1])
In [200]: J=np.zeros(mat.shape[0],int)
In [201]: np.add.at(J, ixs, 1)
In [202]: J
Out[202]: array([0, 2, 1])
In [203]: np.dot(J, mat)
Out[203]: array([16, 19, 22, 25])

J 仍然具有 mat.shape[0] 形状。但是 add.at 应该随着 ixs 的长度缩放。

一个稀疏的解决方案看起来像:

ixs 中创建一个稀疏矩阵,如下所示:

In [204]: I
Out[204]:
array([[1, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 1, 1],
[0, 1, 0, 0, 0, 0, 0]])

对行求和; sparse 使用矩阵乘法来做到这一点,例如:

In [205]: np.dot(I, np.ones((7,),int))
Out[205]: array([4, 2, 1])

然后做我们的点:

In [206]: np.dot(np.dot(I, np.ones((7,),int)), mat)
Out[206]: array([16, 23, 30, 37])

或者在稀疏代码中:

In [225]: J = sparse.coo_matrix((np.ones_like(ixs,int),(np.arange(ixs.shape[0]), ixs)))
In [226]: J.A
Out[226]:
array([[1, 0, 0],
[0, 0, 1],
[1, 0, 0],
[1, 0, 0],
[1, 0, 0],
[0, 1, 0],
[0, 1, 0]])
In [227]: J.sum(axis=0)*mat
Out[227]: matrix([[16, 23, 30, 37]])

稀疏,当从 coo 转换为 csr 时,会对重复项求和。我可以利用它

In [229]: J = sparse.coo_matrix((np.ones_like(ixs,int), (np.zeros_like(ixs,int), ixs)))
In [230]: J
Out[230]:
<1x3 sparse matrix of type '<class 'numpy.int32'>'
with 7 stored elements in COOrdinate format>
In [231]: J.A
Out[231]: array([[4, 2, 1]])
In [232]: J*mat
Out[232]: array([[16, 23, 30, 37]], dtype=int32)

关于python - numpy:有效地添加矩阵的行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39964555/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com