NumPy: столбец точечный продукт - PullRequest
14 голосов
/ 03 июня 2011

Учитывая массив 2D numpy, мне нужно вычислить скалярное произведение каждого столбца с самим собой и сохранить результат в одномерном массиве. Следующие работы:

In [45]: A = np.array([[1,2,3,4],[5,6,7,8]])

In [46]: np.array([np.dot(A[:,i], A[:,i]) for i in xrange(A.shape[1])])
Out[46]: array([26, 40, 58, 80])

Есть ли простой способ избежать цикла Python? Вышесказанное - едва ли конец света, но если для этого есть примитив numpy, я бы хотел его использовать.

edit На практике матрица имеет много строк и относительно мало столбцов. Поэтому я не слишком заинтересован в создании временных массивов размером больше O(A.shape[1]). Я также не могу изменить A на месте.

Ответы [ 3 ]

19 голосов
/ 03 июня 2011

Как насчет:

>>> A = np.array([[1,2,3,4],[5,6,7,8]])
>>> (A*A).sum(axis=0)
array([26, 40, 58, 80])

РЕДАКТИРОВАТЬ: Хм, хорошо, вы не хотите промежуточных крупных объектов.Может быть:

>>> from numpy.core.umath_tests import inner1d
>>> A = np.array([[1,2,3,4],[5,6,7,8]])
>>> inner1d(A.T, A.T)
array([26, 40, 58, 80])

, что в любом случае кажется немного быстрее.Это должно делать то, что вам нужно, за кулисами, так как AT - это представление (которое не создает свою собственную копию, IIUC), а inner1d кажется зацикливанием так, как нужно.* ОЧЕНЬ ПОБЕДЕННОЕ ОБНОВЛЕНИЕ: Другая альтернатива будет использовать np.einsum:

>>> A = np.array([[1,2,3,4],[5,6,7,8]])
>>> np.einsum('ij,ij->j', A, A)
array([26, 40, 58, 80])
>>> timeit np.einsum('ij,ij->j', A, A)
100000 loops, best of 3: 3.65 us per loop
>>> timeit inner1d(A.T, A.T)
100000 loops, best of 3: 5.02 us per loop
>>> A = np.random.randint(0, 100, (2, 100000))
>>> timeit np.einsum('ij,ij->j', A, A)
1000 loops, best of 3: 363 us per loop
>>> timeit inner1d(A.T, A.T)
1000 loops, best of 3: 848 us per loop
>>> (np.einsum('ij,ij->j', A, A) == inner1d(A.T, A.T)).all()
True
2 голосов
/ 03 июня 2011

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

np.sum(np.square(A),0);

(я не совсем уверен насчет второго параметра функции sum, который определяет ось вдольчто взять сумму, и у меня в настоящее время нет numpy. Может быть, вам придется экспериментировать :) ...)

EDIT

Глядя на * 1011Пост * DSM , похоже, вы должны использовать axis=0.Использование функции square может быть немного более производительным, чем использование A*A.

0 голосов
/ 07 мая 2014

В линейной алгебре точечное произведение строки i на строку j является i, j-й записью AA ^ T.Аналогично, произведение точек столбца i на столбец j является i-й записью (A ^ T) A.

Поэтому, если вы хотите получить произведение точек каждого вектора столбца A на себя, вы можете использоватьColDot = np.dot(np.transpose(A), A).diagonal().С другой стороны, если вы хотите получить произведение точек каждой строки на себя, вы можете использовать RowDot = np.dot(A, np.transpose(A)).diagonal().

Обе строки возвращают массив.

...