Как эффективно управлять большим массивом NumPy - PullRequest
0 голосов
/ 27 октября 2018

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

Заранее спасибо, пожалуйста, найдите мои коды ниже:

N = 1000000000
rand = np.random.rand(N)
beta = np.zeros(N)
for i in range(0, N):
    if rand[i] < 0.5:
        beta[i] = 2.0*rand[i]
    else:
        beta[i] = 1.0/(2.0*(1.0-rand[i]))

Ответы [ 3 ]

0 голосов
/ 27 октября 2018

N = 1000000000 вызвало MemoryError для меня. Сокращение до 100 для минимального примера. Вы можете использовать подпрограмму np.where .

В обоих случаях, по сути, вы перебираете массив и применяете функцию. Однако , np.where использует намного более быстрый цикл (в основном это скомпилированный код), в то время как ваш цикл "python" интерпретируется и, таким образом, действительно медленен для большого N.

Вот пример реализации.

N = 100
rand = np.random.rand(N)
beta = np.where(rand < 0.5,  2.0 * rand, 1.0/(2.0*(1.0-rand))
0 голосов
/ 27 октября 2018

Как уже отмечалось в других ответах, почти всегда следует избегать (и можно) избегать итерации по элементам массива numpy в цикле Python.В большинстве случаев переход от цикла Python к операции с массивом дает ускорение ~ 100x.

Однако, если производительность абсолютно критична, вы часто можете выжать еще один фактор между 2x и 10x (по моему опыту)используя Cython .Вот пример:

%%cython
cimport numpy as np
import numpy as np
cimport cython
from cython cimport floating

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
cpdef np.ndarray[floating, ndim=1] beta(np.ndarray[floating, ndim=1] arr):
    cdef:
        Py_ssize_t i
        Py_ssize_t N = arr.shape[0]
        np.ndarray[floating, ndim=1] result = np.zeros(N)

    for i in range(N):
        if arr[i] < 0.5:
            result[i] = 2.0*arr[i]
        else:
            result[i] = 1.0/(2.0*(1.0-arr[i]))

    return result

Тогда вы бы назвали его beta(rand).Как вы можете видеть, это позволяет использовать исходную структуру цикла, но теперь использовать эффективный типизированный нативный код.Я получаю ускорение примерно в 2,5 раза по сравнению с np.where.

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

0 голосов
/ 27 октября 2018

Вы в основном теряете эффективность numpy, выполняя обработку в Python.Идея NumPy заключается в обработке элементов в Bulk , так как он имеет алгоритмы эффективности на C ++ за кулисами, которые выполняют фактическую обработку.Вы можете видеть конец numpy more в Python как «интерфейс».

Теперь, чтобы ответить на ваш вопрос, мы можем сначала создать массив случайных чисел от 0 до 2, умножив его уже на 2:

rand = 2.0 * np.random.rand(N)

далее мы можем использовать np.where(..) [numpy-doc] , который действует как условный селектор: здесь мы передаем три «массива»: первыйодин представляет собой массив логических значений, который кодирует истинность «условия», второй представляет собой массив значений для заполнения в случае, если соответствующее условие истинно, и третье значение представляет собой массив значений для подключения в случае, если условиеложно, поэтому мы можем написать это как:

N = 1000000000
rand = 2 * np.random.rand(N)
beta = np.where(rand < 1.0, rand, 1.0 / (2.0 - rand))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...