4

我有一些来自 HDF5 文件的事件数据:

>>> events
<class 'h5py._hl.dataset.Dataset'>

我得到这样的数组数据:

>>> events = events[:]

结构是这样的:

>>> type(events)
<type 'numpy.ndarray'>
>>> events.shape
(273856,)
>>> type(events[0])
<type 'numpy.void'>
>>> events[0]
(0, 30, 3523, 5352)
>>> # More information on structure 
>>> [type(e) for e in events[0]]    
[<type 'numpy.uint64'>, 
 <type 'numpy.uint32'>, 
 <type 'numpy.float64'>, 
 <type 'numpy.float64'>]   
>>> events.dtype 
[('start', '<u8'), 
 ('length', '<u4'), 
 ('mean', '<f8'), 
 ('variance', '<f8')]

我需要获取第一个字段小于某个值的特定事件的最大索引。蛮力方法是:

>>> for i, e in enumerate(events):
>>>     if e[0] >= val:
>>>         break

元组的第一个索引已排序,因此我可以进行二等分以加快速度:

>>> field1 = [row[0] for row in events]
>>> index = bisect.bisect_right(field1, val)

这显示了改进,但[row[0] for row in event]比我预期的要慢。关于如何解决这个问题的任何想法?

4

2 回答 2

4

是的,像您当前所做的那样迭代 numpy 数组相对较慢。通常,您会改用切片(创建视图,而不是将数据复制到列表中)。

看起来你有一个对象数组。这会使事情变得更慢。你真的需要一个对象数组吗?看起来所有的值都是ints。(这是一个“vlen”hdf5 数据集吗?)

对象数组有意义的用例是,如果events. 如果你不这样做,那么就没有理由使用一个。

如果您使用的是 2D 整数数组而不是元组对象数组,您只需执行以下操作:

field1 = events[:,0]

但是,在这种情况下,您可以这样做:(searchsorted使用二分法)

index = np.searchsorted(events[:,0], val)

编辑

啊! 好的,你有一个结构化数组。换句话说,它是一个数组(在这种情况下为一维),其中每个项目都是一个类似 C 的结构。从:

>>> events.dtype 
[('start', '<u8'), 
 ('length', '<u4'), 
 ('mean', '<f8'), 
 ('variance', '<f8')]

...我们可以看到第一个字段名为“start”。

因此,您只需要:

index = np.searchsorted(events["start"], val)

更一般地说,如果我们不知道该字段的名称,但知道它是某种结构化数组,那么您会这样做(将事情简化为切片步骤):

events[event.dtype.names[0]]

至于将所有内容转换为“普通”二维整数数组是否是一个好主意,这取决于您的用例。对于基本的切片和调用searchsorted,没有理由这样做。不应该(未经测试)有任何显着的速度增加。

根据您目前正在做的事情,我会保持原样。

然而,结构化数组通常处理起来很麻烦。

在很多情况下,结构化数组非常有用(例如,从磁盘读取某些二进制格式),但如果您想将其视为“类表”数组,您很快就会遇到痛点。您通常最好将列存储为单独的数组。(或者更好的是,将 apandas.DataFrame用于“表格”数据。)

如果您确实想将其转换为 2D 整数数组,请执行以下操作:

events = np.hstack([events[name] for name in events.dtype.names])

这将自动为新数组找到兼容的数据类型(int64在这种情况下),并将结构化数组的字段“堆叠”到二维数组中的列中。

调用events = events.astype(int)将有效地产生第一列。(这是因为每一项事件都是一个类似 C 的结构,并且astype按元素操作,因此每个结构都转换为单个 int。)

于 2014-01-17T17:56:34.043 回答
2

您可以使用numpy.searchsorted

>>> a = np.arange(10000).reshape(2500,4)
>>> np.searchsorted(a[:,0], 1000)
250

时间比较

>>> %timeit np.searchsorted(a[:,0], 1000)
100000 loops, best of 3: 11.7 µs per loop
>>> %timeit field1 = [row[0] for row in a];bisect.bisect_right(field1, 1000)
100 loops, best of 3: 2.63 ms per loop
于 2014-01-17T17:55:41.487 回答