繁体   English   中英

切片ndarray的最快方法

[英]Fastest way to slice a ndarray

我有一些来自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]比我预期的要慢。 关于如何解决这个问题的任何想法?

是的,当你正在做的时,迭代numpy数组相对较慢。 通常,您将使用切片(创建视图,而不是将数据复制到列表中)。

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

对象数组有意义的用例是,如果events每个元素中有不同数量的项。 如果你不这样做,那么没有理由使用它。

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

field1 = events[:,0]

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

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

编辑

啊! 好的,你有一个结构化的数组 换句话说,它是一个数组(在这种情况下为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。)

你可以使用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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM