Как получить элементы deque через индексы? - PullRequest
0 голосов
/ 23 июня 2018

У меня есть следующий объект deque:

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 не поддерживает этот тип операции индексации.Как я могу легко (и эффективно) получить список элементов в idx из test?

EDIT -

Больше информации о моей первоначальной цели.У меня есть список трехмерных массивов, т.е. (N, H,W,3), и в режиме реального времени я перемещаю новый 3D-массив в список N, т.е. новый массив размером (H,W,3) перемещается (как очередь) всписок из N.

Было бы неплохо иметь для всех простой массив формы (N, H,W,3), но я не мог понять, как получить эффективную функциональность очереди, поэтому я выбрал deque.

1 Ответ

0 голосов
/ 24 июня 2018

Чтобы непосредственно ответить на ваш вопрос, вы индексируете деку с повторяющимися индексами так же, как вы делаете список - [test[i] for i in idx].Но случайный поиск deque равен O(n) (что может иметь большее значение для больших запросов), и если вы захотите выполнить индексирование в стиле NumPy, вы не сможете.Из вашего описания проблемы также звучит так, будто вы ищете кольцевой буфер.

Так что вместо deque вообще, может быть, лучше (и более эффективно для больших размеров deque) придерживаться NumPy.

Теперь вы можете катить свой собственный класс интерфейса кольцевого буфера типа deque вокруг ndarray, который управляет размером буфера, индексами влево / вправо и т. Д. Или Эрик Вайзер уже выпустил 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.]]])>

Вы получаете минимальный интерфейс deque с append, extend, pop и левой версией.Вы также можете использовать индексирование 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...