выборочная матрица суммы строк в numpy - PullRequest
2 голосов
/ 10 июля 2020

Есть ли эффективный numpy способ сделать следующее: Предположим, у меня есть матикс M размером R X C. Теперь предположим, что у меня есть другая матрица E, которая имеет форму R X a (где a - это просто некоторая константа a < C), которая содержит индексы строк M (и -1 для заполнения, т. Е. Каждый элемент E находится в {-1, 0, .., R-1}). Например,

M=array([[1, 2, 3],
         [4, 5, 6],
         [7, 8, 9]])

E = array([[ 0,  1],
           [ 2, -1],
           [-1,  0]])

Теперь, учитывая эти матрицы, я хочу сгенерировать третью матрицу P, где i-я строка P будет содержать сумму следующих строк M: E[i,:]. В примере P будет,

P[0,:] = M[0,:] + M[1,:]
P[1,:] = M[2,:]
P[2,:] = M[0,:]

Да, сделать это с помощью al oop довольно просто и легко, мне было интересно, есть ли какой-нибудь необычный numpy способ сделать это более эффективно (при условии, что я хочу сделать это с большими матрицами, например, 200 X 200.

Спасибо!

Ответы [ 3 ]

2 голосов
/ 10 июля 2020

Одним из способов было бы суммировать с индексированными в исходном массиве, а затем вычесть суммы, вызванные последними индексированными, на -1s -

out = M[E].sum(1) - M[-1]*(E==-1).sum(1)[:,None]

Другой способ - заполнить нулями в конце M, чтобы эти -1 индексировались в эти нули и, следовательно, не влияли на окончательную сумму после индексации -

M1 = np.vstack((M, np.zeros((1,M.shape[1]), dtype=M.dtype)))
out = M1[E].sum(1)

Если есть ровно один или меньше -1 на строку в E, мы можем оптимизировать дальше -

out = M[E].sum(1)
m = (E==-1).any(1)
out[m] -= M[-1]

Другой, основанный на тензорном умножении -

np.einsum('ij,kli->kj',M, (E[...,None]==np.arange(M.shape[1])))
1 голос
/ 10 июля 2020

Вероятно, не самый быстрый, но, возможно, образовательный: операцию, которую вы описываете, можно представить как матричное умножение с определенной матрицей смежности:

from scipy import sparse

# construct adjacency matrix
indices = E[E!=-1]
indptr = np.concatenate([[0],np.count_nonzero(E!=-1,axis=1).cumsum()])
data = np.ones_like(indptr)
aux = sparse.csr_matrix((data,indices,indptr))

# multiply
aux*M
# array([[5, 7, 9],
#        [7, 8, 9],
#        [1, 2, 3]], dtype=int64)
1 голос
/ 10 июля 2020

Вы можете проиндексировать M с помощью E и np.sum, где фактические индексы в E больше или равны 0. Для этого у нас есть параметр where:

np.sum(M[E], where=(E>=0)[...,None], axis=1)

array([[5, 7, 9],
       [7, 8, 9],
       [1, 2, 3]])

Где это есть:

M[E]
array([[[1, 2, 3],
        [4, 5, 6]],

       [[7, 8, 9],
        [7, 8, 9]],

       [[7, 8, 9],
        [1, 2, 3]]])

Добавляется по строкам:

(E>=0)[...,None]
array([[[ True],
        [ True]],

       [[ True],
        [False]],

       [[False],
        [ True]]])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...