您已经使用的方法,
A[list1, :][:, list2]
似乎是从备用矩阵中选择所需值的最快方法。请参阅下面的基准。
但是,要回答有关如何A
使用单个索引从任意行和列中选择值的问题,您需要使用所谓的“高级索引”:
A[np.array(list1)[:,np.newaxis], np.array(list2)]
使用高级索引,if arr1
and arr2
are NDarrays,equals的(i,j)
组成部分A[arr1, arr2]
A[arr1[i,j], arr2[i,j]]
因此,您会希望对所有人都arr1[i,j]
平等,并且
对所有人都平等。list1[i]
j
arr2[i,j]
list2[j]
i
这可以通过设置 , 和 借助广播(见下文)来安排
。arr1 = np.array(list1)[:,np.newaxis]
arr2 = np.array(list2)
的形状是
arr1
广播的(len(list1), 1)
形状,因为新的轴会在需要时自动添加到左侧。arr2
(len(list2), )
(1, len(list2))
每个数组都可以进一步广播成形(len(list1),len(list2))
。这正是我们想要
A[arr1[i,j],arr2[i,j]]
理解的,因为我们想要(i,j)
遍历所有可能的索引以获取 shape 的结果数组(len(list1),len(list2))
。
这是一个测试用例的微基准,表明这A[list1, :][:, list2]
是最快的选择:
In [32]: %timeit orig(A, list1, list2)
10 loops, best of 3: 110 ms per loop
In [34]: %timeit using_listener(A, list1, list2)
1 loop, best of 3: 1.29 s per loop
In [33]: %timeit using_advanced_indexing(A, list1, list2)
1 loop, best of 3: 1.8 s per loop
这是我用于基准测试的设置:
import numpy as np
import scipy.sparse as sparse
import random
random.seed(1)
def setup(N):
A = sparse.rand(N, N, .1, format='lil')
list1 = np.random.choice(N, size=N//10, replace=False).tolist()
list2 = np.random.choice(N, size=N//20, replace=False).tolist()
return A, list1, list2
def orig(A, list1, list2):
return A[list1, :][:, list2]
def using_advanced_indexing(A, list1, list2):
B = A.tocsc() # or `.tocsr()`
B = B[np.array(list1)[:, np.newaxis], np.array(list2)]
return B
def using_listener(A, list1, list2):
"""https://stackoverflow.com/a/26592783/190597 (listener)"""
B = A.tocsr()[list1, :].tocsc()[:, list2]
return B
N = 10000
A, list1, list2 = setup(N)
B = orig(A, list1, list2)
C = using_advanced_indexing(A, list1, list2)
D = using_listener(A, list1, list2)
assert np.allclose(B.toarray(), C.toarray())
assert np.allclose(B.toarray(), D.toarray())