【问题标题】:How to get deque elements via indices?如何通过索引获取双端队列元素?
【发布时间】:2018-12-02 22:10:48
【问题描述】:

我有以下双端队列对象:

test = deque([np.zeros((4,1,1))+0.5] * 25)

所以有 25 个某种形状的数组,我将在对象中追加,在另一端弹出旧的,等等。

在某些时候,我会想在我的双端队列中选择一个元素子集:

>>> idx = np.round(np.linspace(0, 20, 4, dtype='int'))
>>> idx
array([ 0,  6, 13, 20])

所以我想要这些指标。我试过了:

>>> test[idx]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: only integer scalar arrays can be converted to a scalar index

也许 deque 不支持这种类型的索引操作。如何轻松(有效)从test 获取idx 中的元素列表?

编辑——

关于我最初目标的更多信息。我有一个 3D numpy 数组的列表,即(N, H,W,3),并且我正在实时将一个新的 3D 数组转移到 N 的列表中,即一个大小为 (H,W,3) 的新数组被转移(像一个队列一样)到N 的列表。

如果所有东西都有一个形状为 (N, H,W,3) 的 numpy 数组会很好,但我不知道如何获得有效的队列功能,所以我选择了 deque

【问题讨论】:

  • @miradulo 这似乎行得通——但这会有效吗?
  • 这是在 Python 中使用一堆索引来索引双端队列的方法,这通常很慢。我不知道你在这里的工作总体上是否有效。我以前从未见过有人使用 NumPy 数组的双端队列.. 并且会认为向您的 NumPy 数组添加维度,固定大小并完全避免这种情况(如果可能的话)将是有效的做法。
  • 我最初的想法是添加一个numpy数组索引并使用np.roll,但是发现这样做非常慢而不是使用deque。接受其他想法。
  • 使用双端队列访问索引是O(n),不像list。 Python 必须遵循 n 个链接才能到达对象。
  • @JDS 如果您添加了一些关于您实际解决的问题的信息,那么建议一个有效的解决方案会容易得多。

标签: python arrays numpy queue deque


【解决方案1】:

要直接回答您的问题,您可以像使用列表一样使用可迭代的索引来索引双端队列 - [test[i] for i in idx]。但是双端队列随机查找是O(n)(对于较大的双端队列可能更重要),如果你想对双端队列进行 NumPy 风格的索引,你将无法做到。从您的问题描述中,听起来您正在寻找一个环形缓冲区。

因此,完全不用双端队列,坚持使用 NumPy 可能是一个更好的主意(并且对于更大的双端队列更有效)。

现在您可以围绕管理缓冲区大小、左/右索引等的 ndarray 滚动您自己的类似双端队列的环形缓冲区接口类。或者 Eric Weiser 已经发布了 numpy_ringbuffer,这似乎非常适合你的问题。

演示

In [83]: from numpy_ringbuffer import RingBuffer

In [84]: # RingBuffer w/ capacity 3, extra dimensions (2, 2)
    ...: r = RingBuffer(capacity=3, dtype=(float, (2, 2)))

In [85]: # fill our buffer up
    ...: r.extendleft(np.arange(12, dtype=float).reshape(3, 2, 2))

In [86]: r.is_full
Out[86]: True

In [87]: r
Out[87]: 
<RingBuffer of array([[[ 0.,  1.],
        [ 2.,  3.]],

       [[ 4.,  5.],
        [ 6.,  7.]],

       [[ 8.,  9.],
        [10., 11.]]])>

In [88]: r.appendleft(np.arange(12, 16).reshape(2, 2))

In [89]: r
Out[89]: 
<RingBuffer of array([[[12., 13.],
        [14., 15.]],

       [[ 0.,  1.],
        [ 2.,  3.]],

       [[ 4.,  5.],
        [ 6.,  7.]]])>

您将获得带有appendextendpop 和左侧版本的最小双端队列接口。您还可以在底层数组上使用 NumPy 索引。

In [90]: r[[0, 2]]
Out[90]: 
array([[[12., 13.],
        [14., 15.]],

       [[ 4.,  5.],
        [ 6.,  7.]]])

与 NumPy 中类似双端队列的操作的幼稚方法相比,它会快得多,因为它只是尽可能地操纵左/右索引。

In [91]: arr = np.random.randn(10**7).reshape(10**5, 10, 10)

In [92]: r = RingBuffer(capacity=arr.shape[0],
    ...:                dtype=(float, arr.shape[1:]))
    ...:                

In [93]: %%timeit r.extendleft(arr); s = np.random.randn(10, 10)
    ...: r.appendleft(s)
    ...: r.append(s)
    ...: 
4.08 µs ± 66.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [94]: %%timeit A=arr.copy(); s = np.random.randn(10, 10)
    ...: A[1:] = A[:-1]
    ...: A[0] = s
    ...: A[:-1] = A[1:]
    ...: A[-1] = s
    ...: 
91.5 ms ± 231 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

【讨论】:

    猜你喜欢
    • 2020-07-06
    • 2023-03-28
    • 2013-12-03
    • 2011-01-18
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多