Python 不同大小数组的Numpy高效索引
看看这段代码:Python 不同大小数组的Numpy高效索引,python,arrays,numpy,Python,Arrays,Numpy,看看这段代码: import numpy as np a = np.random.random(10) indicies = [ np.array([1, 4, 3]), np.array([2, 5, 8, 7, 3]), np.array([1, 2]), np.array([3, 2, 1]) ] result = np.zeros(2) result[0] = a[indicies[0]].sum() result[1] = a[indicies[2
import numpy as np
a = np.random.random(10)
indicies = [
np.array([1, 4, 3]),
np.array([2, 5, 8, 7, 3]),
np.array([1, 2]),
np.array([3, 2, 1])
]
result = np.zeros(2)
result[0] = a[indicies[0]].sum()
result[1] = a[indicies[2]].sum()
有没有办法更有效地获得结果
?在我的例子中,a
是一个非常大的数组
换句话说,我想从具有多个不同大小索引数组的
a
中选择元素,然后在一次操作中对它们求和,产生一个数组。如果数组a非常大,则在循环时,如果索引数组包含多个索引数组,则可能会出现内存问题
要避免此问题,请使用迭代器而不是列表:
indices = iter(indices)
然后循环遍历迭代器。使用
a
和标记列表:
In [280]: [a[i].sum() for i in indicies]
Out[280]:
[1.3986792680307709,
2.6354365193743732,
0.83324677494990895,
1.8195179021311731]
当然可以将其包装在np.array()
中
对于标记的子集
项目,使用:
In [281]: [a[indicies[i]].sum() for i in [0,2]]
Out[281]: [1.3986792680307709, 0.83324677494990895]
一条评论指出,标记
来自邻接矩阵,可能是稀疏的
我可以通过以下方式重新创建这样的阵列:
In [289]: A=np.zeros((4,10),int)
In [290]: for i in range(4): A[i,indicies[i]]=1
In [291]: A
Out[291]:
array([[0, 1, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 1, 0, 1, 1, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 0, 0, 0, 0, 0, 0]])
并使用矩阵积(np.dot
)进行选择和求和:
In [292]: A.dot(a)
Out[292]: array([ 1.39867927, 2.63543652, 0.83324677, 1.8195179 ])
A[[0,2],:]。点(A)
将使用行的子集
稀疏矩阵版本具有行索引列表:
In [294]: Al=sparse.lil_matrix(A)
In [295]: Al.rows
Out[295]: array([[1, 3, 4], [2, 3, 5, 7, 8], [1, 2], [1, 2, 3]], dtype=object)
和一个矩阵积,它给出了相同的数字:
In [296]: Al*a
Out[296]: array([ 1.39867927, 2.63543652, 0.83324677, 1.8195179 ])
那么,对已经加载到RAM中的对象调用iter
将如何帮助减少内存消耗呢?此外,如果您只是对索引中的某些内容执行:代码>,Python将隐式地为您执行iter(索引)
。索引的来源是什么?对于您的问题,可能有一些非常优雅的解决方案,它们是二进制邻接矩阵的非零元素(行或列,因为矩阵是对称的,所以不重要)。还有另一种解决方案,如果邻接矩阵是A
,可以这样写:(A[[0,2][:,无]*A[[0,2],:])。sum(axis=1)
,但我不确定这是否更有效。如果用稀疏矩阵替换A
,那么它甚至不起作用。换句话说,对于节点子集(在示例[0,2]),对其所有相邻节点的数组a
中的值求和)Scipy sparse执行类似于矩阵乘法的行求和。因此,A.dot(A)
可能是工作结果[1]和索引[2]-1和2的组合正确吗?为了清楚起见,这意味着我想要两个索引数组的结果,它们恰好是第0和第2个,所以将它们放在结果数组的位置0和1。可能是任何人。这只是一个随机的例子。我确实也想到了a[[0,2],:].dot(a)
,但我认为这不太好,因为a
矩阵是NxN
并且N
很大。然后我试着用稀疏矩阵来做,但没能让它工作。现在我意识到,*
实际上是稀疏矩阵的点积,它与2D密集阵列不同,而2D密集阵列实际上是一个正态乘法。奇怪的因此,执行A1[[0,2],:]*a
是可行的。在MATLAB中*
是矩阵乘法,而*
是元素乘法。稀疏矩阵是在复制MATLAB的np.matrix
上建模的。较新的python添加了@
以供矩阵乘法使用。显然*
重载为类型np.matrix
的矩阵乘法和类型np.array
的元素乘法。应该知道:)