Векторизовать итерацию по двум большим массивам numpy параллельно

У меня есть два больших массива типа numpy.core.memmap.memmap, называемых data и new_data, с> 7 миллионами элементов float32.

Мне нужно перебрать их обоих в одном и том же цикле, который я сейчас делаю так.

for i in range(0,len(data)):
  if new_data[i] == 0: continue
  combo = ( data[i], new_data[i] )
  if not combo in new_values_map: new_values_map[combo] = available_values.pop()
  data[i] = new_values_map[combo]

Однако это неоправданно медленно, поэтому я понимаю, что использование функций векторизации numpy - это путь.

Можно ли векторизовать с помощью индекса, чтобы векторизованный массив мог сравнивать свои элементы с соответствующим элементом в другом массиве?

Я думал о том, чтобы заархивировать два массива, но я думаю, что это приведет к необоснованным накладным расходам на подготовку?

Есть ли другой способ оптимизировать эту операцию?

Для контекста: цель состоит в том, чтобы эффективно объединить два массива так, чтобы каждая уникальная комбинация соответствующих значений между двумя массивами была представлена ​​другим значением в результирующем массиве, за исключением нулей в массиве new_data, которые игнорируются. Массивы представляют трехмерные растровые изображения.

РЕДАКТИРОВАТЬ: available_values — это набор значений, которые еще не использовались в data и сохраняются при вызовах этого цикла. new_values_map, с другой стороны, сбрасывается в пустой словарь перед каждым использованием этого цикла.

EDIT2: массив данных содержит только целые числа, то есть: он инициализируется нулями, а затем при каждом использовании этого цикла с другим new_data он заполняется дополнительными значениями, взятыми из available_values, который изначально представляет собой диапазон целых чисел. new_data теоретически может быть чем угодно.


person Nat    schedule 11.03.2013    source источник
comment
Я знаю, что это не то, о чем вы просите, но вы должны использовать xrange вместо range.   -  person Daniel Thaagaard Andreasen    schedule 11.03.2013
comment
спасибо, я новичок в python, так что это хорошо знать.   -  person Nat    schedule 11.03.2013
comment
Можете ли вы показать пример значений в data, new_data и available_values? Поскольку значения с плавающей запятой неточны, может быть лучше сначала преобразовать данные в целое число.   -  person HYRY    schedule 11.03.2013
comment
Я думаю, что проблема, с которой мы все сталкиваемся, заключается в том, что именно сопоставление от available_values к data является вашей основной проблемой векторизации. Как вы написали, вы, кажется, последовательно проходите каждое значение, выталкивая одно за раз и назначая его данным. Если это то, что вы делаете, вы можете сделать что-то вроде моего ответа. Если вы делаете что-то более сложное, нам нужно знать об этом, чтобы предложить любую разумную помощь.   -  person Henry Gomersall    schedule 11.03.2013
comment
Полезно ли знать, что значения извлекаются из набора только available_values в крошечной части времени? Для 99% итераций комбинация уже будет в словаре new_values_map, поэтому available_values не вызывается.   -  person Nat    schedule 11.03.2013
comment
Ага, понятно. Тогда вам нужно использовать другую структуру данных. Вы не можете избежать цикла, если используете словарь. Решение зависит от таких вещей, как количество различных значений combo; может ли он поместиться в 2D-массиве?   -  person Henry Gomersall    schedule 11.03.2013
comment
Что плохого в использовании словаря? Что может быть лучшим способом убедиться, что на протяжении этого цикла каждая уникальная комбинация соответствующих значений в data и new_data приводит к согласованному целочисленному значению по этому индексу data? (в идеале отбирать значения по порядку из пула available_values, который поддерживается глобально)   -  person Nat    schedule 11.03.2013


Ответы (3)


Отвечая на ваш вопрос о векторизации, ответ, вероятно, да, хотя вам нужно уточнить, что содержит available_values и как он используется, поскольку это является ядром векторизации.

Ваше решение, вероятно, будет выглядеть примерно так...

indices = new_data != 0

data[indices] = available_values

В этом случае, если available_values можно рассматривать как набор значений, в котором мы выделяем первое значение для первого значения в data, в котором new_data не равно 0, это должно работать, пока available_values является пустым массивом.

Допустим, new_data и data принимают значения от 0 до 255, тогда вы можете создать массив available_values с уникальными записями для каждой возможной пары значений в new_data и данных, как показано ниже:

available_data = numpy.array(xrange(0, 255*255)).reshape((255, 255))
indices = new_data != 0
data[indices] = available_data[data[indices], new_data[indices]]

Очевидно, что available_data может быть любым отображением, которое вы хотите. Вышеупомянутое должно быть очень быстрым, что бы ни было в available_data (особенно если вы создаете available_data только один раз).

person Henry Gomersall    schedule 11.03.2013

Python предоставляет мощные инструменты для обработки больших массивов данных: генераторы и итераторы

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

В случае обращения сразу к двум большим массивам можно

for item_a, item_b in izip(data, new_data):
   #... do you stuff here

izip создает итератор, который перебирает элементы ваших массивов в один раз, но он выбирает кусочки по мере необходимости, а не все сразу.

person Jakub M.    schedule 11.03.2013

Кажется, что заменив первые две строки цикла, получится:

for i in numpy.where(new_data != 0)[0]:
  combo = ( data[i], new_data[i] )
  if not combo in new_values_map: new_values_map[combo] = available_values.pop()
  data[i] = new_values_map[combo]

имеет желаемый эффект.

Таким образом, большая часть времени в цикле была потрачена на пропуск всего цикла при обнаружении нуля в new_data. Не очень понимаю, почему эти многочисленные нулевые итерации были такими дорогими, может быть, однажды я...

person Nat    schedule 11.03.2013
comment
Это все еще неправильный способ сделать это. Если вы используете массив numpy, вы хотите, если можете, перейти к нулевым циклам. - person Henry Gomersall; 11.03.2013