2016-11-30 4 views
0

У меня есть 3 Numpy массивов:Многошаговых операции линейной алгебры на нескольких Numpy массивов

import numpy 
arr_a = numpy.random.random((300, 300)) 
arr_b = numpy.random.random((300, 300)) 
arr_c = numpy.random.random((300, 300)) 

Я хочу создать 4-й массив (arr_d) от комбинации из 3-х массивов. Эти правила заключаются в следующем:

, если arr_a значение ячейки сетки> 0,2 и значение arr_b < 0,4 и arr_c> 0,6 затем заполнить arr_d с 1

, если arr_a значение ячейки сетки> 0,3 и значение arr_b < 0,5 и arr_c> 0.6 затем заполнить arr_d с 2

, если arr_a значение ячейки сетки> 0,1 и значение arr_b < 0,2 и arr_c> 0,5 затем заполнить arr_d с 3

Во всех остальных случаях заполнения arr_d с 4

Я могу сделать это с помощью вложенных циклов, но это очень медленно и не очень pythonic. Кроме того, это тестовый пример, реальные массивы имеют размер 1000 * 1000, поэтому я хочу, чтобы масштабируемое решение было желательно parallizable.

ответ

2

Использование чистого Python и для циклов - определенно не путь. Вы можете написать свою программу, используя операции массива в NumPy, эффективно выполняя цикл на C, значительно увеличивая код. Однако это создает новый массив для каждого из ваших правил, каждый из которых имеет тот же размер, что и ваши данные. Вместо этого вы можете использовать что-то вроде Numba, которое приходит, например. с распределением Anaconda Python. С Numba вы можете написать свой код с использованием циклов, но без штрафного времени (он компилирует ваш код для инструкций на машинах). Кроме того, никаких дополнительных больших массивов не требуется, что делает его намного более эффективным с точки зрения памяти, чем NumPy. Numba также происходит быстрее, так как этот пример показывает:

import numpy, numba, time 

def using_numpy(shape): 
    arr_a = numpy.random.random(shape) 
    arr_b = numpy.random.random(shape) 
    arr_c = numpy.random.random(shape) 
    mask1 = numpy.logical_and(numpy.logical_and((arr_a > 0.2), (arr_b < 0.4)), (arr_c > 0.6)) 
    mask2 = numpy.logical_and(numpy.logical_and((arr_a > 0.3), (arr_b < 0.5)), (arr_c > 0.6)) 
    mask3 = numpy.logical_and(numpy.logical_and((arr_a > 0.1), (arr_b < 0.2)), (arr_c > 0.5)) 
    result = numpy.ones(arr_a.shape)*4 
    result[mask1] = 1 
    result[mask2] = 2 
    result[mask3] = 3 
    return result 

@numba.jit 
def using_numba(shape): 
    arr_a = numpy.random.random(shape) 
    arr_b = numpy.random.random(shape) 
    arr_c = numpy.random.random(shape) 
    result = numpy.empty(shape) 
    for i in range(result.shape[0]): 
     for j in range(result.shape[1]): 
      if arr_a[i, j] > 0.2 and arr_b[i, j] < 0.4 and arr_c[i, j] > 0.6: 
       result[i, j] = 1 
      elif arr_a[i, j] > 0.3 and arr_b[i, j] < 0.5 and arr_c[i, j] > 0.6: 
       result[i, j] = 2 
      elif arr_a[i, j] > 0.1 and arr_b[i, j] < 0.2 and arr_c[i, j] > 0.5: 
       result[i, j] = 3 
      else: 
       result[i, j] = 4 
    return result 
# Compile the using_numba function 
using_numba((0, 0)) 

t0 = time.time() 
result = using_numpy((3000, 3000)) 
print('NumPy took', time.time() - t0, 'seconds') 

t0 = time.time() 
result = using_numba((3000, 3000)) 
print('Numba took', time.time() - t0, 'seconds') 

Здесь я использовал (3000, 3000) массивы. На моей машине использование NumPy занимает 0,47 секунды при использовании Numba занимает 0,29 секунды.

1

Один из способов будет использовать булевы карты

condition_1 = numpy.logical_and(numpy.logical_and((arr_a > 0.2), (arr_b < 0.4)), (arr_c > 0.6)) 
condition_2 = numpy.logical_and(numpy.logical_and((arr_a > 0.3), (arr_b < 0.5)), (arr_c > 0.6)) 
condition_3 = numpy.logical_and(numpy.logical_and((arr_a > 0.1), (arr_b < 0.2)), (arr_c > 0.5)) 
result = numpy.ones((300, 300)) * 4 
result[numpy.where(condition_3)] = 3 
result[numpy.where(condition_2)] = 2 
result[numpy.where(condition_1)] = 1 

Он избегает вложенных циклов, но выделяет три выделенных массивов и делает много лишних заданий. Должен быть более оптимальный подход ...

+0

Вы не должны использовать 'numpy.where' и просто использовать' result [condition_3] = 3' и т. Д. Это ускорит работу программы. Кроме того, вы используете 'np' вместо' numpy' в одном случае. –

+0

Спасибо, действительно, для меня это 0.71 сек с 'numpy.where' и 0.57 без –

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