Метод, который вы уже используете,
A[list1, :][:, list2]
, кажется, самый быстрый способ выбора нужных значений из матрицы запасных частей.См. Ниже для сравнения.
Однако, чтобы ответить на ваш вопрос о том, как выбрать значения из произвольных строк и столбцов A
с одним индексом , вам необходимо использовать так "расширенное индексирование" :
A[np.array(list1)[:,np.newaxis], np.array(list2)]
При расширенном индексировании, если arr1
и arr2
- это NDarrays, компонент (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)
выполнял все возможные индексы для результирующего массива формы (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())