Ненужный рулон в нескольких размерах

Мне нужно сдвинуть трехмерный массив на 3D-вектор смещения для алгоритма. На данный момент я использую этот (допустимо очень уродливый) метод:

shiftedArray = np.roll(np.roll(np.roll(arrayToShift, shift[0], axis=0) , shift[1], axis=1), shift[2], axis=2) 

Что работает, но означает, что я называю 3 рулона! (58% моего времени алгоритма расходуется на них, согласно моему профилированию)

Из документов Numpy.roll:

Параметры:
shift: int

ось: int, необязательно

Нет упоминания о параметрах массива в параметре … Значит, у меня не может быть многомерной прокатки?

Я думал, что могу просто назвать такую ​​функцию (звучит как вещь, которую нужно делать с помощью Numpy):

 np.roll(arrayToShift,3DshiftVector,axis=(0,1,2)) 

Может быть, с плоской версией моего массива? но как я могу вычислить вектор сдвига? и этот сдвиг действительно то же самое?

Я удивлен, что не нашел для этого легкого решения, поскольку я думал, что это будет довольно обычная вещь (хорошо, не так, но …)

Итак, как мы – относительно – эффективно сдвигаем ndarray на N-мерный вектор?

4 Solutions collect form web for “Ненужный рулон в нескольких размерах”

Я думаю, что scipy.ndimage.interpolation.shift сделает то, что вы хотите, из документов

shift: float или sequence, необязательный

Сдвиг по осям. Если поплавок, сдвиг одинаков для каждой оси. Если последовательность, сдвиг должен содержать одно значение для каждой оси.

Это означает, что вы можете сделать следующее,

 from scipy.ndimage.interpolation import shift import numpy as np arrayToShift = np.reshape([i for i in range(27)],(3,3,3)) print('Before shift') print(arrayToShift) shiftVector = (1,2,3) shiftedarray = shift(arrayToShift,shift=shiftVector,mode='wrap') print('After shift') print(shiftedarray) 

Который дает,

 Before shift [[[ 0 1 2] [ 3 4 5] [ 6 7 8]] [[ 9 10 11] [12 13 14] [15 16 17]] [[18 19 20] [21 22 23] [24 25 26]]] After shift [[[16 17 16] [13 14 13] [10 11 10]] [[ 7 8 7] [ 4 5 4] [ 1 2 1]] [[16 17 16] [13 14 13] [10 11 10]]] 

Теоретически использование scipy.ndimage.interpolation.shift как описано @Ed Smith, должно работать, но из-за открытой ошибки ( https://github.com/scipy/scipy/issues/1323 ) она не дает результат, эквивалентный нескольким вызовам np.roll .


ОБНОВЛЕНИЕ : возможность добавления нескольких numpy.roll в numpy.roll в numpy версии 1.12.0. Вот двухмерный пример, в котором первая ось прокатывается по одной позиции, а вторая ось свертывается в три положения:

 In [7]: x = np.arange(20).reshape(4,5) In [8]: x Out[8]: array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) In [9]: numpy.roll(x, [1, 3], axis=(0, 1)) Out[9]: array([[17, 18, 19, 15, 16], [ 2, 3, 4, 0, 1], [ 7, 8, 9, 5, 6], [12, 13, 14, 10, 11]]) 

Это делает код ниже устаревшим. Я оставлю его там для потомства.


Нижеприведенный код определяет функцию, которую я вызываю multiroll которая делает то, что вы хотите. Вот пример, в котором он применяется к массиву с формой (500, 500, 500):

 In [64]: x = np.random.randn(500, 500, 500) In [65]: shift = [10, 15, 20] 

Используйте несколько вызовов для np.roll для генерации ожидаемого результата:

 In [66]: yroll3 = np.roll(np.roll(np.roll(x, shift[0], axis=0), shift[1], axis=1), shift[2], axis=2) 

Сгенерируйте сдвинутый массив, используя multiroll :

 In [67]: ymulti = multiroll(x, shift) 

Убедитесь, что мы получили ожидаемый результат:

 In [68]: np.all(yroll3 == ymulti) Out[68]: True 

Для такого размера массива, делающего три вызова np.roll , почти в три раза медленнее, чем вызов multiroll :

 In [69]: %timeit yroll3 = np.roll(np.roll(np.roll(x, shift[0], axis=0), shift[1], axis=1), shift[2], axis=2) 1 loops, best of 3: 1.34 s per loop In [70]: %timeit ymulti = multiroll(x, shift) 1 loops, best of 3: 474 ms per loop 

Вот определение multiroll :

 from itertools import product import numpy as np def multiroll(x, shift, axis=None): """Roll an array along each axis. Parameters ---------- x : array_like Array to be rolled. shift : sequence of int Number of indices by which to shift each axis. axis : sequence of int, optional The axes to be rolled. If not given, all axes is assumed, and len(shift) must equal the number of dimensions of x. Returns ------- y : numpy array, with the same type and size as x The rolled array. Notes ----- The length of x along each axis must be positive. The function does not handle arrays that have axes with length 0. See Also -------- numpy.roll Example ------- Here's a two-dimensional array: >>> x = np.arange(20).reshape(4,5) >>> x array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) Roll the first axis one step and the second axis three steps: >>> multiroll(x, [1, 3]) array([[17, 18, 19, 15, 16], [ 2, 3, 4, 0, 1], [ 7, 8, 9, 5, 6], [12, 13, 14, 10, 11]]) That's equivalent to: >>> np.roll(np.roll(x, 1, axis=0), 3, axis=1) array([[17, 18, 19, 15, 16], [ 2, 3, 4, 0, 1], [ 7, 8, 9, 5, 6], [12, 13, 14, 10, 11]]) Not all the axes must be rolled. The following uses the `axis` argument to roll just the second axis: >>> multiroll(x, [2], axis=[1]) array([[ 3, 4, 0, 1, 2], [ 8, 9, 5, 6, 7], [13, 14, 10, 11, 12], [18, 19, 15, 16, 17]]) which is equivalent to: >>> np.roll(x, 2, axis=1) array([[ 3, 4, 0, 1, 2], [ 8, 9, 5, 6, 7], [13, 14, 10, 11, 12], [18, 19, 15, 16, 17]]) """ x = np.asarray(x) if axis is None: if len(shift) != x.ndim: raise ValueError("The array has %d axes, but len(shift) is only " "%d. When 'axis' is not given, a shift must be " "provided for all axes." % (x.ndim, len(shift))) axis = range(x.ndim) else: # axis does not have to contain all the axes. Here we append the # missing axes to axis, and for each missing axis, append 0 to shift. missing_axes = set(range(x.ndim)) - set(axis) num_missing = len(missing_axes) axis = tuple(axis) + tuple(missing_axes) shift = tuple(shift) + (0,)*num_missing # Use mod to convert all shifts to be values between 0 and the length # of the corresponding axis. shift = [s % x.shape[ax] for s, ax in zip(shift, axis)] # Reorder the values in shift to correspond to axes 0, 1, ..., x.ndim-1. shift = np.take(shift, np.argsort(axis)) # Create the output array, and copy the shifted blocks from x to y. y = np.empty_like(x) src_slices = [(slice(n-shft, n), slice(0, n-shft)) for shft, n in zip(shift, x.shape)] dst_slices = [(slice(0, shft), slice(shft, n)) for shft, n in zip(shift, x.shape)] src_blks = product(*src_slices) dst_blks = product(*dst_slices) for src_blk, dst_blk in zip(src_blks, dst_blks): y[dst_blk] = x[src_blk] return y 

Я считаю, что roll медленный, потому что свернутый массив не может быть выражен как представление исходных данных в виде операции среза или изменения формы. Таким образом, данные копируются каждый раз. Для справки см. https://scipy-lectures.github.io/advanced/advanced_numpy/#life-of-ndarray

Что может стоить попробовать сначала обработать ваш массив (с режимом «wrap»), а затем использовать срезы в заполненном массиве, чтобы получить shiftedArray : http://docs.scipy.org/doc/numpy/reference/generated/numpy. pad.html

можно использовать режим wrap и я думаю, что он не меняет массив в памяти.

Вот реализация с использованием входов @ EdSmith:

 arrayToShift = np.reshape([i for i in range(27)],(3,3,3)) shiftVector = np.array((1,2,3)) ind = 3-shiftVector np.take(np.take(np.take(arrayToShift,range(ind[0],ind[0]+3),axis=0,mode='wrap'),range(ind[1],ind[1]+3),axis=1,mode='wrap'),range(ind[2],ind[2]+3),axis=2,mode='wrap') 

который дает то же самое, что и OP:

 np.roll(np.roll(np.roll(arrayToShift, shift[0], axis=0) , shift[1], axis=1),shift[2], axis=2) 

дает:

 array([[[21, 22, 23], [24, 25, 26], [18, 19, 20]], [[ 3, 4, 5], [ 6, 7, 8], [ 0, 1, 2]], [[12, 13, 14], [15, 16, 17], [ 9, 10, 11]]]) 
  • Python: массив с разделителем numpy
  • Извлечение и преобразование данных в numpy
  • Обозначение фрагмента Python с запятой / списком
  • Передача массива numpy в Cython
  • Как добавить один colobar, который будет отображать данные из двух разных подплат
  • Обрезка многомерных массивов
  • Понимание того, как массивы numpy размещаются в памяти
  • Файл HDF5, созданный с помощью h5py, не может быть открыт h5py
  •  
    Interesting Posts for Van-Lav

    Python: как подавлять отчеты о регистрации из сторонних библиотек?

    Как получить информацию «в реальном времени» из подпроцесса. Открыть в python (2.5)

    Как остановить скрипт Python, но продолжать перевод интерпретатора

    Получение прилагательного из наречия в nltk или другой библиотеке НЛП

    автоматически обновлять скрипт python

    Как предотвратить совместимость устройств Django с существующими данными

    Сортировка счетчика частоты слов с использованием python

    Eclipse PyDev: установка контрольных точек в источнике сайтов-пакетов

    Pythonic способ проверить: все элементы оцениваются в False -OR- все элементы оцениваются в True

    Проверка подлинности Django с пользовательской моделью с идентификатором электронной почты как уникальным ключом

    Как изменить имя произвольных столбцов в pandas df с помощью лямбда-функции?

    подгонка экспоненциального распада без первоначального угадывания

    .csv между каждой буквой на выходе

    Capture стандартный вывод для ребенка Python, порожденный внешним пакетом

    Как сделать api-вызов, требующий входа в web2py?

    Python - лучший язык программирования в мире.