我有来自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]
比我预期的要慢。关于如何解决这个问题的任何想法?
答案 0 :(得分:4)
是的,当你正在做的时,迭代numpy数组相对较慢。通常,您将使用切片(创建视图,而不是将数据复制到列表中)。
看起来你有一个对象数组。这会让事情变得更慢。你真的需要一个对象数组吗?看起来所有值都是int
s。 (这是“vlen”hdf5数据集吗?)
对象数组有意义的用例是events
的每个元素中有不同数量的项。如果不这样做,则没有理由使用它。
如果您使用的是int数组而不是元组的对象数组,那么您只需:
field1 = events[:,0]
但是,在这种情况下,您可以这样做:(searchsorted
使用二分法)
index = np.searchsorted(events[:,0], val)
修改强>
啊!好的,你有一个structured array。换句话说,它是一个数组(在这种情况下为1D),其中每个项是一个类似C的结构。从:
>>> events.dtype
[('start', '<u8'),
('length', '<u4'),
('mean', '<f8'),
('variance', '<f8')]
...我们可以看到第一个字段名为“start”。
因此,您只想:
index = np.searchsorted(events["start"], val)
更一般地说,如果我们不知道该字段的名称,但知道它是某种结构化数组,那么你就可以了(将事情简化为切片步骤):
events[event.dtype.names[0]]
至于将所有内容转换为“普通”2D整数数组是一个好主意,这取决于您的用例。对于基本切片和调用searchsorted
,没有理由。不应该(未经测试)任何显着的速度增加。
根据你目前所做的事情,我只是保持原样。
但是,结构化数组通常很难处理。
有很多情况下结构化数组非常有用(例如从磁盘读取某些二进制格式),但如果你想把它想象成“类似表”的数组,你很快就会遇到痛点。您通常最好将列存储为单独的数组。 (或者更好的是,使用pandas.DataFrame
表示“表格”数据。)
如果您确实想将其转换为2D数组,请执行以下操作:
events = np.hstack([events[name] for name in events.dtype.names])
这将自动为新数组找到兼容的数据类型(在本例中为int64
),并将结构化数组的字段“堆叠”为2D数组中的列。
调用events = events.astype(int)
实际上只会产生第一列。 (这是因为事件的每个项都是类似C的结构,而astype
是按元素运行的,因此每个结构都转换为单个int。)
答案 1 :(得分: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