Python / Numpy, как сделать внешний продукт из двух массивов 1-d [duplicate]

Давайте посмотрим на лес сначала, прежде чем смотреть на деревья.

Здесь есть много информативных ответов с большими подробностями, я не буду повторять ни одного из них. Ключ к программированию в JavaScript имеет сначала правильную ментальную модель общего исполнения.

  1. Ваша точка входа (ов) выполняется в результате события. Например, в браузер загружается тег сценария с кодом. (Соответственно, поэтому вам, возможно, придется заботиться о готовности страницы запускать ваш код, если он требует, чтобы элементы dom были сконструированы первыми и т. Д.)
  2. Ваш код выполняется до завершения, однако многие асинхронные вызовы, которые он делает, без выполнения каких-либо ваших обратных вызовов, включая запросы XHR, установку тайм-аутов, обработчиков событий dom и т. д. Каждый из этих обратных вызовов, ожидающих выполнения, будет находиться в очереди, ожидая, что их очередь будет запущена после других событий
  3. Каждый отдельный обратный вызов XHR-запроса, установленного таймаута или dom события после вызова будет завершен.

Хорошие новости заключается в том, что, если вы хорошо понимаете этот момент, вам никогда не придется беспокоиться о гоночных условиях. Прежде всего вы должны понимать, как вы хотите упорядочить свой код как по существу ответ на разные дискретные события, и как вы хотите объединить их в логическую последовательность. Вы можете использовать обещания или новые асинхронные / ожидающие более высокие уровни в качестве инструментов для этой цели, или вы можете откатывать свои собственные.

Но вы не должны использовать какие-либо тактические инструменты для решения проблемы, пока вам не понравится актуальная проблемная область. Нарисуйте карту этих зависимостей, чтобы знать, что нужно запускать, когда. Попытка ad-hoc подхода ко всем этим обратным вызовам просто не поможет вам.

8
задан thetna 7 January 2015 в 13:35
поделиться

3 ответа

На самом деле это не получается быстрее, это ваши варианты:

numpy.outer

>>> %timeit np.outer(a,b)
100 loops, best of 3: 9.79 ms per loop

numpy.einsum

>>> %timeit np.einsum('i,j->ij', a, b)
100 loops, best of 3: 16.6 ms per loop

numba

from numba.decorators import autojit

@autojit
def outer_numba(a, b):
    m = a.shape[0]
    n = b.shape[0]
    result = np.empty((m, n), dtype=np.float)
    for i in range(m):
        for j in range(n):
            result[i, j] = a[i]*b[j]
    return result

>>> %timeit outer_numba(a,b)
100 loops, best of 3: 9.77 ms per loop

попугай

from parakeet import jit

@jit
def outer_parakeet(a, b):
   ... same as numba

>>> %timeit outer_parakeet(a, b)
100 loops, best of 3: 11.6 ms per loop

cython

cimport numpy as np
import numpy as np
cimport cython
ctypedef np.float64_t DTYPE_t

@cython.boundscheck(False)
@cython.wraparound(False)
def outer_cython(np.ndarray[DTYPE_t, ndim=1] a, np.ndarray[DTYPE_t, ndim=1] b):
    cdef int m = a.shape[0]
    cdef int n = b.shape[0]
    cdef np.ndarray[DTYPE_t, ndim=2] result = np.empty((m, n), dtype=np.float64)
    for i in range(m):
        for j in range(n):
            result[i, j] = a[i]*b[j]
    return result

>>> %timeit outer_cython(a, b)
100 loops, best of 3: 10.1 ms per loop

theano

from theano import tensor as T
from theano import function

x = T.vector()
y = T.vector()

outer_theano = function([x, y], T.outer(x, y))

>>> %timeit outer_theano(a, b)
100 loops, best of 3: 17.4 ms per loop

pypy

# Same code as the `outer_numba` function
>>> timeit.timeit("outer_pypy(a,b)", number=100, setup="import numpy as np;a = np.random.rand(128,);b = np.random.rand(32000,);from test import outer_pypy;outer_pypy(a,b)")*1000 / 100.0
16.36 # ms

Выводы:

╔═══════════╦═══════════╦═════════╗
║  method   ║ time(ms)* ║ version ║
╠═══════════╬═══════════╬═════════╣
║ numba     ║ 9.77      ║ 0.16.0  ║
║ np.outer  ║ 9.79      ║ 1.9.1   ║
║ cython    ║ 10.1      ║ 0.21.2  ║
║ parakeet  ║ 11.6      ║ 0.23.2  ║
║ pypy      ║ 16.36     ║ 2.4.0   ║
║ np.einsum ║ 16.6      ║ 1.9.1   ║
║ theano    ║ 17.4      ║ 0.6.0   ║
╚═══════════╩═══════════╩═════════╝
* less time = faster
24
ответ дан elyase 26 August 2018 в 17:40
поделиться

Это должно быть так же просто, как использовать numpy.outer() : один вызов функции, который будет реализован в C для высокой производительности.

2
ответ дан Dietrich Epp 26 August 2018 в 17:40
поделиться
Ответ

@ elyase велик и справедливо принят. Вот еще одно предположение о том, что если вы можете использовать его, вы можете сделать вызов np.outer еще быстрее.

Вы говорите: «Я должен делать эту операцию несколько раз», поэтому возможно, что вы можете повторно использовать массив, который содержит внешний продукт, вместо того, чтобы каждый раз назначать новый. Это может дать хорошее повышение производительности.

Во-первых, некоторые случайные данные для работы с:

In [32]: a = np.random.randn(128)

In [33]: b = np.random.randn(32000)

Вот базовое время для np.outer (a, b) на моем компьютер:

In [34]: %timeit np.outer(a, b)
100 loops, best of 3: 5.52 ms per loop

Предположим, что мы будем повторять эту операцию несколько раз с массивами одинаковой формы. Создайте массив out, чтобы сохранить результат:

In [35]: out = np.empty((128, 32000))

Теперь используйте out в качестве третьего аргумента np.outer:

In [36]: %timeit np.outer(a, b, out)
100 loops, best of 3: 2.38 ms per loop

Итак, вы получаете приятное повышение производительности, если вы можете повторно использовать массив, который содержит внешний продукт.

Вы получаете аналогичную выгоду, если вы используете аргумент out в einsum и в функции cython, если вы добавляете третий аргумент для вывода вместо выделения его в функции с помощью np.empty. (Другие компилированные / закодированные коды в ответе @ elyase, вероятно, также выиграют от этого, но я попробовал только версию cython.)

Nota bene! Вышеприведенное преимущество может не реализуются на практике. Массив out подходит для кэша L3 моего процессора, и когда он используется в цикле, выполняемом командой timeit, он, вероятно, остается в кеше. На практике массив может быть перемещен из кеша между вызовами np.outer. В этом случае улучшение не так драматично, но по-прежнему должно быть по меньшей мере стоимость вызова np.empty(), то есть

In [53]: %timeit np.empty((128, 32000))
1000 loops, best of 3: 1.29 ms per loop
5
ответ дан Warren Weckesser 26 August 2018 в 17:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: