2016-10-31 2 views
2

Я хотел бы использовать что-то вроде np.dot или (желательно) np.einsum для эффективной работы с ними, но с альтернативным ufunc вместо np.multiply. Например, рассмотрим эти два массива:numpy dot или einsum с произвольным оператором

>>> a 
array([[0, 1], 
     [1, 1], 
     [1, 0]]) 
>>> b 
array([[0, 0], 
     [1, 0], 
     [1, 0], 
     [0, 0]]) 

Теперь предположим, что я хочу, чтобы подсчитать количество элементов в каждой строке a равной соответствующих элементов в каждой строке b. Я хотел бы быть в состоянии сделать эквивалент следующего (примечание: ниже выход изготовлен, но значения то, что я ожидал увидеть):

>>> np.dot(a, b.T, ufunc=np.equal) 
array([[1, 0, 0, 1], 
     [0, 1, 1, 0], 
     [1, 2, 2, 1]]) 

Есть ли способ сделать это?

+0

Будут ли массивы всегда иметь '' '' '' '' '' '' '' только? – Divakar

+0

В моем конкретном случае, да. Но мне интересен и ответ на более общий случай. – bogatron

ответ

3

Вы можете использовать вещанию от ответа Divakar вместе с numexpr:

numexpr.evaluate('sum(1*(a == b), axis=2)', {'a': a[:,None]}) 

1*() является a workaround. Я подтвердил это не выделяет большой временный массив.

+0

И я думал, что нарезка не поддерживается с помощью 'numexpr', это хорошо! – Divakar

+0

Ну, это просто аргумент 'local_dict', нарезание происходит еще в Python :-) – user6758673

+0

Я думаю, что это будет работать лучше всего, поскольку оно позволяет избежать временного хранения массива. Upvote для @Divakar для изящного решения только для numpy. – bogatron

2

Вы можете использовать broadcasting для такого подсчета матч проблема -

(a[:,None] == b).sum(2) 

Пример выполнения -

In [36]: a 
Out[36]: 
array([[0, 1], 
     [1, 1], 
     [1, 0]]) 

In [37]: b 
Out[37]: 
array([[0, 0], 
     [1, 0], 
     [1, 0], 
     [0, 0]]) 

In [38]: (a[:,None] == b).sum(2) 
Out[38]: 
array([[1, 0, 0, 1], 
     [0, 1, 1, 0], 
     [1, 2, 2, 1]]) 

Если вы действительно хотите использовать np.einsum и np.equal, вот способ формовать ранее подход к дать нам желаемый результат -

np.einsum('ijk->ij',np.equal(a[:,None],b).astype(int)) 
+0

Это дает ожидаемый результат. Единственным недостатком является временное хранилище для '(a [:, None] == b)' и 'np.equal (a [:, None], b)'. В примере промежуточный массив имеет форму '(3, 4, 2)', но на практике последнее измерение может быть большим, и именно поэтому я надеялся его избежать. – bogatron

+0

@bogatron Что было бы типичными формами 'a' и' b' для фактического использования? – Divakar

+0

Первое измерение каждого массива составляет около 10 ** 5. Второе измерение (по которому происходит суммирование) будет либо 64, либо 128. – bogatron

1

Существует старая проблема в numpy github с просьбой обобщить einsum, что позволит использовать другие функции. Текущая версия просто реализует сумму продуктов. Насколько я знаю, никто этого не предпринял.

Несколько лет назад я исправил einsum, установив обработку обозначения «...». Поэтому я имею хорошее представление о том, как это реализовано; и, возможно, адаптировать мой эмулятор Python/cython для добавления этой функции. Фактический код einsum написан на c.

Я предполагаю, что если вам не нравится подход Дивакара, вам придется написать свою собственную версию с помощью cython.

+0

Принимаемый ответ делает то, что мне нужно, но было бы замечательно видеть, что 'einsum' поддерживает эту функцию. Я нашел, что он работает намного быстрее, чем альтернативные решения для многочисленных операций. – bogatron

Смежные вопросы