#python #arrays #numpy #numpy-slicing
#python #массивы #numpy #numpy-нарезка
Вопрос:
Как я могу вырезать numpy
массив за пределы его формы, чтобы значения в массиве повторялись без необходимости сохранять весь массив в памяти? Вот что я хотел бы сделать:
x = numpy.array([[1, 2], [3, 4]])
x[0:3, 0:3]
->
[[1, 2, 1, 2],
[3, 4, 3, 4],
[1, 2, 1, 2],
[3, 4, 3, 4]]
Я знаю о numpy.repeat
и numpy.tile
, но оба они создают копию массива, и я хотел бы нарезать мой массив, как x[1238123:1238143,5328932:5328941]
без необходимости создавать миллионы копий меньшего массива.
Комментарии:
1. Не могли бы вы объяснить, почему? Я имею в виду, если вы знаете, что массив повторяется и период, который он повторяет, зачем вам обращаться к нему с
1238123:1238143,5328932:5328941
конкретно?2. В любом случае, может
x[(x.shape[0] - 1) % 1238123: (x.shape[0] - 1) % 1238143, (x.shape[1] - 1) % 5328932: (x.shape[1] - 1) % 5328941]
быть тем, что вы ищете? Если это так, это может быть обернуто в функцию или с помощью подклассаnp.ndarray
Ответ №1:
С strides
помощью хитростей мы можем создать представление 4d:
In [18]: x = numpy.array([[1, 2], [3, 4]])
In [19]: as_strided = np.lib.stride_tricks.as_strided
In [20]: X = as_strided(x, shape=(2,2,2,2), strides=(0,16,0,8))
In [21]: X
Out[21]:
array([[[[1, 2],
[1, 2]],
[[3, 4],
[3, 4]]],
[[[1, 2],
[1, 2]],
[[3, 4],
[3, 4]]]])
Которое может быть преобразовано в желаемый массив:
In [22]: X.reshape(4,4)
Out[22]:
array([[1, 2, 1, 2],
[3, 4, 3, 4],
[1, 2, 1, 2],
[3, 4, 3, 4]])
Но это изменение формы создаст копию X
.
Этот (2,2) массив может использоваться в вычислениях как (1,1,2,2) массив, который при необходимости расширяется до (2,2,2,2):
In [25]: x[None,None,:,:]
Out[25]:
array([[[[1, 2],
[3, 4]]]])
In [26]: np.broadcast_to(x,(2,2,2,2))
Out[26]:
array([[[[1, 2],
[3, 4]],
[[1, 2],
[3, 4]]],
[[[1, 2],
[3, 4]],
[[1, 2],
[3, 4]]]])
Таким образом, трансляция позволяет нам использовать представление массива в более крупных вычислениях.
Ответ №2:
Массивы NumPy этого не поддерживают. Массив должен иметь последовательный шаг в каждом измерении, а в массиве, который вы хотите, этого не будет.
Вы могли бы реализовать свой собственный пользовательский тип для результата, но он не будет работать со скоростью NumPy и не будет напрямую совместим с NumPy — в лучшем случае, любая функция NumPy, которую вы пытались вызвать, должна была бы сначала создать реальный массив из вашего объекта.
Если вашему варианту использования нужны только небольшие фрагменты, как в вашем x[1238123:1238143,5328932:5328941]
примере, вам, вероятно, лучше всего настроить конечные точки фрагмента до эквивалентных меньших значений, затем разбить на плитки и срезать.
Ответ №3:
Используйте numpy.ndarray.take
дважды для 2D-массива (тройной для 3D-массива и т.д.). Каждый раз вы должны указывать другую ось. Для случая, который вам требовался:
x.take(range(0, 4), mode='wrap', axis = 0).take(range(0, 4), mode='wrap', axis = 1)
что привело бы к
array([[1, 2, 1, 2],
[3, 4, 3, 4],
[1, 2, 1, 2],
[3, 4, 3, 4]])