нарезка 3d массива numpy с индексом в виде массивов и изменение формы

#python #numpy #numpy-ndarray #numpy-slicing

Вопрос:

У меня есть 3d-массив формы (3, 5, 5). Мне нужно срезать, используя разные индексы вдоль 2-й и 3-й осей для каждого из 3 элементов

 ts = np.arange(25*3).reshape(3,5,5)
print(ts)
newr1 = np.array([1,0,2])
newr2 = np.array([3,2,4])

newc1 = np.array([1,2,0])
newc2 = np.array([3,4,2])

 

Я хочу что-то вроде ts[:, newr1:newr2, newc1:newc2] , но этот тип нарезки работает только для скалярных индексов. Результат должен выглядеть так, как показано ниже. Пожалуйста, посоветуйте

 array([[[ 6,  7,  8],
        [11, 12, 13],
        [16, 17, 18]],

       [[27, 28, 29],
        [32, 33, 34],
        [37, 38, 39]],

       [[60, 61, 62],
        [65, 66, 67],
        [70, 71, 72]]])
 

Комментарии:

1. Для индексирования не было бы векторизованного подхода, поскольку нет гарантии, что каждый подмассив будет возвращать данные с одинаковой формой.

2. Он должен был визуализировать выбор. Я думаю, вам нужно выразить это в виде итерации, объединения результатов или построения массивов индексирования. Это не basic индексация.

Ответ №1:

Ладно, мое любопытство взяло верх надо мной. Я найду ответ, даже если вы предоставили не так много информации, как следовало бы.

 In [10]: ts = np.arange(25*3).reshape(3,5,5)
    ...: print(ts)
    ...: newr1 = np.array([1,0,2])
    ...: newr2 = np.array([3,2,4])
    ...: 
    ...: newc1 = np.array([1,2,0])
    ...: newc2 = np.array([3,4,2])
    ...: 
[[[ 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 27 28 29]
  [30 31 32 33 34]
  [35 36 37 38 39]
  [40 41 42 43 44]
  [45 46 47 48 49]]

 [[50 51 52 53 54]
  [55 56 57 58 59]
  [60 61 62 63 64]
  [65 66 67 68 69]
  [70 71 72 73 74]]]
 

Я предполагаю, что то, чего ты хочешь, это:

 In [11]: for i in range(3):
    ...:     x = ts[i,newr1[i]:newr2[i],newc1[i]:newc2[i]]
    ...:     print(x)
    ...: 
[[ 6  7]
 [11 12]]
[[27 28]
 [32 33]]
[[60 61]
 [65 66]]
 

Хорошо, это близко, хотя вы неправильно обработали конечные точки срезов.

linspace способен генерировать «срезы/апельсины» для массивов входных данных:

 In [13]: np.linspace(newr1,newr2,3)
Out[13]: 
array([[1., 0., 2.],
       [2., 1., 3.],
       [3., 2., 4.]])
 

попытка использовать такие матрицы в качестве индекса приводит к ошибке:

 In [14]: I=np.linspace(newr1,newr2,3)
In [15]: J=np.linspace(newc1,newc2,3)
In [16]: ts[np.arange(3)[:,None,None], I[:,:,None], J[:,None,:]]
Traceback (most recent call last):
  File "<ipython-input-16-5bc9e51832b8>", line 1, in <module>
    ts[np.arange(3)[:,None,None], I[:,:,None], J[:,None,:]]
IndexError: arrays used as indices must be of integer (or boolean) type

In [17]: I=np.linspace(newr1,newr2,3).astype(int)
In [18]: J=np.linspace(newc1,newc2,3).astype(int)
In [19]: I
Out[19]: 
array([[1, 0, 2],
       [2, 1, 3],
       [3, 2, 4]])
In [20]: J
Out[20]: 
array([[1, 2, 0],
       [2, 3, 1],
       [3, 4, 2]])
 

После пары ошибок я пришел к:

 In [23]: ts[np.arange(3)[:,None,None], I.T[:,:,None], J.T[:,None,:]]
Out[23]: 
array([[[ 6,  7,  8],
        [11, 12, 13],
        [16, 17, 18]],

       [[27, 28, 29],
        [32, 33, 34],
        [37, 38, 39]],

       [[60, 61, 62],
        [65, 66, 67],
        [70, 71, 72]]])
 

Поэтому, если размеры срезов совпадают по «плоскостям», мы можем сделать этот выбор с помощью соответствующего набора массивов индексов.