Как пороговые векторы [u, v] в двумерном массиве numpy? - PullRequest
3 голосов
/ 18 мая 2019

Я написал пороговую функцию TH (arr, threshold), которая принимает двумерный массив векторов [u, v] и устанавливает u и v в 0, если они оба имеют абсолютное значение ниже указанного порога.

Функция состоит из 2 циклов for и выполняет свою работу, но требует больших вычислительных ресурсов (я запускаю ее на больших наборах данных).

Примеры:

[u, v] -> Выход (порог = 1)

[2, 2] -> [2, 2]

[2, .1] -> [2, .1]

[. 1, .1] -> [0, 0]

Какие другие методы / функцииМогу ли я использовать для более эффективного решения этой проблемы (используя списки или другие методы)?

Вот код:

import numpy as np
import time
start = time.time()

def TH(arr, threshold):
    for idx, value in enumerate(arr):
        for i, item in enumerate(value):
            if np.abs(item[0]) < threshold and np.abs(item[1]) < threshold:
                arr[idx][i][0] = 0.0
                arr[idx][i][1] = 0.0
    return arr

a = np.array([[[.5,.8], [3,4], [3,.1]],
              [[0,2], [.5,.5], [.3,3]],
              [[.4,.4], [.1,.1], [.5,5]]])

a = TH(a, threshold = 1)
print(a)

end = time.time()
print("Run time: ", end-start)

Вывод:

[[[0.  0. ]
  [3.  4. ]
  [3.  0.1]]

 [[0.  2. ]
  [0.  0. ]
  [0.3 3. ]]

 [[0.  0. ]
  [0.  0. ]
  [0.5 5. ]]]

Run time:  0.0009984970092773438

1 Ответ

2 голосов
/ 18 мая 2019

Просто нарежьте два элемента вдоль последней оси и выполните те же операции векторизованным способом, чтобы получить маску, и, наконец, внесите маску в указатель во входной массив, чтобы присвоить 0s -

mask = (np.abs(arr[...,0]) < threshold) & (np.abs(arr[...,1]) < threshold)
arr[mask] = 0

Обратите внимание, что arr[...,0] - это еще один способ поставить arr[:,:,0], и он предназначен для нарезки общего ndarray вдоль последней оси.Аналогично, для arr[...,1].

В качестве альтернативы предварительно вычислите абсолютные значения и используйте их для сравнения с threshold и найдите совпадения all с последней осью, чтобы получить ту же маску -

ab = np.abs(arr)
mask = (ab < threshold).all(-1)

Или используйте тот же метод нарезки после вычисления абсолютных значений -

mask = (ab[...,0] < threshold) & (ab[...,1] < threshold)

Для больших массивов мы также можем использовать numexpr module -

import numexpr as ne

m0 = ne.evaluate('abs(arr)<threshold')
mask = m0[...,0] & m0[...,1]

Сроки -

In [209]: arr = np.random.rand(1080,1920,2)

In [210]: threshold = 1

In [211]: %timeit (np.abs(arr[...,0])<threshold) & (np.abs(arr[...,1])<threshold)
100 loops, best of 3: 10.2 ms per loop

In [212]: %timeit np.abs(arr).all(1)
10 loops, best of 3: 34.5 ms per loop

In [213]: %%timeit
     ...: ab = np.abs(arr)
     ...: (ab[...,0] < threshold) & (ab[...,1] < threshold)
     ...: 
100 loops, best of 3: 11 ms per loop

In [214]: %%timeit
     ...: m0 = ne.evaluate('abs(arr)<threshold')
     ...: m0[...,0] & m0[...,1]
     ...: 
100 loops, best of 3: 4.79 ms per loop
...