1

我有多个组的 HDF5 文件,其中每个组包含一个 >= 2500 万行的数据集。在模拟的每个时间步,每个智能体输出他/她在该时间步感应到的其他智能体。场景中有大约 2000 个代理和数千个时间步长;输出的 O(n^2) 特性解释了巨大的行数。

我感兴趣的是按类别计算的独特目击次数。例如,代理属于一侧,红色、蓝色或绿色。我想制作一个二维表,其中第 i 行,第 j 列是类别j中至少一个类别 i 中的代理感知到的类别中的代理数量。(我在此代码示例中使用 Sides,但我们也可以通过其他方式对代理进行分类,例如根据他们拥有的武器或他们携带的传感器。)

这是一个示例输出表;请注意,模拟不会输出蓝色/蓝色的感觉,因为它需要大量的空间而且我们对它们不感兴趣。绿绿相同)

      blue     green      red
blue  0      492       186
green 1075    0     186
red   451    498      26

列是

  1. 滴答时间步长
  2. senseAgentId - 进行传感的代理的 ID
  3. sensedAgentId - 被感知代理的 ID
  4. detRange - 两个代理之间的距离(以米为单位)
  5. 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,但这几乎没有什么不同。

4

1 回答 1

2

如果您有 N=~2k 代理,我建议将所有目击事件放入一个大小为 NxN 的 numpy 数组中。这很容易放入内存中(整数约为 16 兆)。只要在发生目击事件的地方存储一个 1。

假设您有一个数组sightings。第一个坐标是 Sensing,第二个是 Sensed。假设您还有一维索引数组,列出了哪些代理在哪一侧。您可以通过这种方式获得 A 面的 B 面目击次数:

sideAseesB = sightings[sideAindices, sideBindices]
sideAseesBcount = numpy.logical_or.reduce(sideAseesB, axis=0).sum()

您可能需要sightings.take(sideAindices, axis=0).take(sideBindices, axis=1)在第一步中使用,但我对此表示怀疑。

于 2009-12-31T20:57:20.647 回答