Как ускорить фильтрацию / выбор массива Numpy? - PullRequest
0 голосов
/ 22 ноября 2018

У меня около 40 тыс. Строк, и я хочу протестировать все виды комбинаций выбора в строках.Под отбором я подразумеваю логические маски.Количество масок / фильтров составляет около 250 мм.

Текущий упрощенный код:

np_arr = np.random.randint(1, 40000, 40000)
results = np.empty(250000000)
filters = np.random.randint(1, size=(250000000, 40000))
for i in range(250000000):
    row_selection = np_arr[filters[i].astype(np.bool_)] # Select rows based on next filter
    # Performing simple calculations such as sum, prod, count on selected rows and saving to result
    results[i] = row_selection.sum() # Save simple calculation result to results array

Я пробовал Numba и Multiprocessing, но так как большая часть обработки находится в выборе фильтра, а невычисления, это не очень помогает.

Какой самый эффективный способ решить эту проблему?Есть ли способ распараллелить это?Насколько я вижу, мне нужно пройтись по каждому фильтру, чтобы затем индивидуально вычислить сумму, цену, количество и т. Д., Потому что я не могу применять фильтры параллельно (даже если вычисления после применения фильтров очень просты).

Ценю любые предложения по улучшению производительности / ускорению.

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Чтобы получить хорошую производительность в Numba, просто избегайте маскировки и, следовательно, очень дорогих копий массивов.Вы должны реализовать фильтры самостоятельно, но это не должно быть проблемой с фильтрами, которые вы упомянули.

Распараллеливание также очень легко сделать.

Пример

import numpy as np
import numba as nb

max_num = 250000 #250000000
max_num2 = 4000#40000
np_arr = np.random.randint(1, max_num2, max_num2)
filters = np.random.randint(low=0,high=2, size=(max_num, max_num2)).astype(np.bool_)

#Implement your functions like this, avoid masking
#Sum Filter
@nb.njit(fastmath=True)
def sum_filter(filter,arr):
  sum=0.
  for i in range(filter.shape[0]):
    if filter[i]==True:
      sum+=arr[i]
  return sum

#Implement your functions like this, avoid masking
#Prod Filter
@nb.njit(fastmath=True)
def prod_filter(filter,arr):
  prod=1.
  for i in range(filter.shape[0]):
    if filter[i]==True:
      prod*=arr[i]
  return sum

@nb.njit(parallel=True)
def main_func(np_arr,filters):
  results = np.empty(filters.shape[0])
  for i in nb.prange(max_num):
    results[i]=sum_filter(filters[i],np_arr)
    #results[i]=prod_filter(filters[i],np_arr)
  return results
0 голосов
/ 22 ноября 2018

Одним из способов улучшения является перемещение as_type за пределы цикла.В моих тестах это сократило время выполнения более чем наполовину.Для сравнения проверьте следующие два кода:

import numpy as np
import time

max_num = 250000 #250000000
max_num2 = 4000#40000
np_arr = np.random.randint(1, max_num2, max_num2)
results = np.empty(max_num)
filters = np.random.randint(1, size=(max_num, max_num2))
start = time.time()
for i in range(max_num):
    row_selection = np_arr[filters[i].astype(np.bool_)] # Select rows based on next filter
    # Performing simple calculations such as sum, prod, count on selected rows and saving to result
    results[i] = row_selection.sum() # Save simple calculation result to results array

end = time.time()
print(end - start)

занимает 2.12

, а

import numpy as np
import time

max_num = 250000 #250000000
max_num2 = 4000#40000
np_arr = np.random.randint(1, max_num2, max_num2)
results = np.empty(max_num)
filters = np.random.randint(1, size=(max_num, max_num2)).astype(np.bool_)
start = time.time()
for i in range(max_num):
    row_selection = np_arr[filters[i]] # Select rows based on next filter
    # Performing simple calculations such as sum, prod, count on selected rows and saving to result
    results[i] = row_selection.sum() # Save simple calculation result to results array

end = time.time()
print(end - start)

занимает 0.940

...