Python, PyTables - использование поиска в ядре
У меня есть файлы HDF5 с несколькими группами, где каждая группа содержит набор данных с>= 25 миллионами строк. На каждом временном шаге моделирования каждый агент выводит других агентов, которые он / она обнаружил на этом временном шаге. В сценарии ~2000 агентов и тысячи временных шагов; O(n^2) характер вывода объясняет огромное количество строк.
Что меня интересует в подсчете, так это количество уникальных наблюдений по категориям. Например, агенты принадлежат стороне, красный, синий или зеленый. Я хочу сделать двумерную таблицу, где строка i, столбец j это количество агентов в категории j
которые были обнаружены по крайней мере одним агентом в категории i. (Я использую Стороны в этом примере кода, но мы могли бы классифицировать агентов и другими способами, такими как оружие, которое у них есть, или датчики, которые они несут.)
Вот пример выходной таблицы; обратите внимание, что симуляция не дает сине-голубых ощущений, потому что занимает тонну места, и мы не заинтересованы в них. То же самое для зеленого, зеленого)
blue green red
blue 0 492 186
green 1075 0 186
red 451 498 26
Столбцы
- тик - шаг по времени
- sensingAgentId - идентификатор агента, выполняющего распознавание
- sensedAgentId - идентификатор распознаваемого агента
- detRange - расстояние в метрах между двумя агентами
- senseType - перечислимый тип для того, какой тип определения был выполнен
Вот код, который я сейчас использую для этого:
def createHeatmap():
h5file = openFile("someFile.h5")
run0 = h5file.root.run0.detections
# A dictionary of dictionaries, {'blue': {'blue':0, 'red':0, ...}
classHeat = emptyDict(sides)
# Interested in Per Category Unique Detections
seenClass = {}
# Initially each side has seen no one
for theSide in sides:
seenClass[theSide] = []
# In-kernel search filtering out many rows in file; in this instance 25,789,825 rows
# are filtered to 4,409,176
classifications = run0.where('senseType == 3')
# Iterate and filter
for row in classifications:
sensedId = row['sensedAgentId']
# side is a function that returns the string representation of the side of agent
# with that id.
sensedSide = side(sensedId)
sensingSide = side(row['sensingAgentId'])
# The side has already seen this agent before; ignore it
if sensedId in seenClass[sensingSide]:
continue
else:
classHeat[sensingSide][sensedSide] += 1
seenClass[sensingSide].append(sensedId)
return classHeat
Примечание: у меня есть фон Java, поэтому я прошу прощения, если это не Pythonic. Пожалуйста, укажите это и предложите способы улучшить этот код, я хотел бы стать более опытным с Python.
Теперь, это очень медленно: для выполнения этой итерации и проверки членства требуется приблизительно 50 секунд, и это с наиболее ограниченным набором критериев членства (другие типы обнаружения имеют намного больше строк для итерации).
Мой вопрос: возможно ли перенести работу из Python в поисковый запрос в ядре? Если так, то как? Есть ли какое-то явно очевидное ускорение, которое мне не хватает? Мне нужно иметь возможность запускать эту функцию для каждого прогона в наборе прогонов (~30) и для нескольких наборов критериев (~5), поэтому было бы здорово, если бы это можно было ускорить.
Последнее замечание: я пытался использовать psyco, но это едва имело значение.
1 ответ
Если у вас N=~2 тыс. Агентов, я предлагаю поместить все наблюдения в массив размером NxN. Это легко помещается в памяти (около 16 мегабайт для целых чисел). Просто храните 1 там, где произошло прицеливание.
Предположим, что у вас есть массив sightings
, Первая координата - Sensing, вторая - Sensed. Предположим, у вас также есть массивы 1-го индекса, в которых перечислены агенты, с какой стороны. Вы можете получить количество наблюдений стороны B стороной A таким образом:
sideAseesB = sightings[sideAindices, sideBindices]
sideAseesBcount = numpy.logical_or.reduce(sideAseesB, axis=0).sum()
Возможно, вам нужно использовать sightings.take(sideAindices, axis=0).take(sideBindices, axis=1)
на первом этапе, но я сомневаюсь в этом.