numpy: эффективные выборочные многомерные операции (частичные операции) - PullRequest
0 голосов
/ 21 июня 2020

Есть ли способ в numpy выполнять операции частично по некоторым измерениям? Например, скажем, у меня есть 2 матрицы форм a = (MxN), b = (NxK) и третья, в которой я хочу сохранить скалярное произведение a и b, например c = (MxK). Если мне просто нужен скалярный продукт, я могу просто сделать:

c = a.dot(b)

Теперь предположим, что я хотел бы заполнить c теми же результатами, но только частично - например, только для индекса 0 по измерению M. Использование a python для l oop:

for msel in [0]:
    c[msel,:] = a[msel].dot(b)

Или, может быть, например, добавление матрицы b в матрицу a размером MxN, но только для индексов 0,2 по измерению N:

# Full add would be: a+=b
for nsel in [0,2]:
    a[:,nsel] += b[:,nsel]

Извините, если я здесь немного расплывчат, в настоящее время мне в основном нужна такая функциональность для операций с точкой и сложением, но я думал сформулировать вопрос в надежде, что, возможно, есть что-то вроде этого относительно общего c то numpy предложений, о которых я не знаю.

Обновление: похоже, это работает, как ожидалось:

import numpy as np

a = np.array([[0,1,2],
              [3,4,5]])
b = np.array([[0,1],
              [3,4],
              [5,6]])
c = np.zeros((2,2))

#c = a.dot(b)
#for d in [0]:
#  c[d,:] = a[d].dot(b)
cond=[True, False]
c[cond,:] = a[cond,:].dot(b) # <--- what I was searching for for dot
print(c)

a=np.ones((2,3))
b=np.ones((2,3))

#a+=b
#for d in [0,2]:
#  a[:,d] += b[:,d]
cond=[True, False, True]
a[:,cond] += b[:,cond] # <--- what I was searching for for add
print(a)

Интересно, если за кулисами (C код ) numpy действительно исследует только необходимые размеры и оставляет нетронутыми все остальное. Было бы здорово!

1 Ответ

0 голосов
/ 21 июня 2020

Я новичок с numpy, синтаксис индексации, вероятно, хорошо известен опытным пользователям. Тем не менее, для таких новичков, как я, я только что подтвердил, что приведенный выше синтаксис (см. Рассматриваемое обновление) делает именно то, что мне нужно, и эффективно. Кроме того, есть поддержка выбора индекса как с помощью логической маски, так и с помощью списков индексов.

Фрагмент кода:

import numpy as np
import timeit

a = np.ones((1000, 2000))
b = np.ones((2000, 1000))
c = np.zeros((1000, 1000))

# Prepare dimensions selection (list)
dims=np.arange(0,500,2)
# Prepare dimensions selection (conditions)
cond=np.full((1000), False)
cond[dims] = True

def full_dot(): c = a.dot(b)
def dot_by_dims(): c[dims,:] = a[dims,:].dot(b)
def dot_by_cond(): c[cond,:] = a[cond,:].dot(b)
def dot_by_pyfor():
    for d in dims:
        c[d,:] = a[d,:].dot(b)

print('Full dot time: {} seconds'.format(timeit.Timer(full_dot).timeit(number=100)))
print('Dot partial python for time: {} seconds'.format(timeit.Timer(dot_by_pyfor).timeit(number=100)))
print('Dot partial by dims time: {} seconds'.format(timeit.Timer(dot_by_dims).timeit(number=100)))
print('Dot partial by cond time: {} seconds'.format(timeit.Timer(dot_by_cond).timeit(number=100)))

Вывод:

Full dot time: 4.831596400000002 seconds
Dot partial python for time: 12.7231105 seconds
Dot partial by dims time: 1.4666931999999946 seconds
Dot partial by cond time: 1.5701424000000017 seconds

( использование classi c python for примерно на 8,5X медленнее , чем синтаксис numpy! Даже в 2,6 раза медленнее, чем точка с точкой, хотя он делает только частичную точку ...)

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