Làm cách nào để lấy các phần tử từ ma trận 3D bằng cách sử dụng các chỉ số cụ thể trong numpy?

Aug 15 2020
  • Tôi có ma trận 3D, trong ví dụ dưới đây là ma trận (5, 4, 2): data_matrix
  • Tôi có một mảng chỉ mục khác của hình dạng (5, 4) trong đó mỗi hàng của mảng đại diện cho vị trí phần tử: indx_array

Tôi không biết làm thế nào tôi có thể lấy được required_output. Tôi đang cố gắng sắp xếp (1,2) phần tử của mỗi hàng dựa trênindx_array

Tôi không muốn sử dụng cho các vòng lặp!

data_matrix = np.array([
    [[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]]
])

indx_array = np.array([[3,2,1,0], [0,1,2,3], [1,0,3,2], [0,3,1,2], [1,2,3,0]])


# I want following result:
required_output = [
    [[6, 7], [4, 5], [2, 3], [0, 1]]
    [[8, 9], [10, 11], [12, 13], [14, 15]]
    [[18, 19], [16, 17], [22, 23], [20, 21]]
    [[24, 25], [30, 31], [26, 27], [28, 29]]
    [[34, 35], [36, 37], [38, 39], [32, 33]]
]

EDIT: Đã cập nhật indx_arrayđể minh họa tốt hơn tình hình.

Trả lời

3 hpaulj Aug 15 2020 at 21:43
  • Numpy: Lập chỉ mục
    • Numpy: Lập chỉ mục các mảng đa chiều
In [637]: data_matrix.shape                                                                          
Out[637]: (5, 4, 2)
In [638]: indx_array.shape                                                                           
Out[638]: (5, 4)

Bạn cần lập chỉ mục nâng cao trên 2 thứ nguyên đầu tiên. Mảng thứ nguyên đầu tiên cần phát sóng với thứ hai (5,4). Để làm điều đó, tôi thực hiện (5,1) arange:

In [639]: data_matrix[np.arange(5)[:,None], indx_array]                                              
Out[639]: 
array([[[ 6,  7],
        [ 4,  5],
        [ 2,  3],
        [ 0,  1]],

       [[ 8,  9],
        [10, 11],
        [12, 13],
        [14, 15]],

       [[18, 19],
        [16, 17],
        [22, 23],
        [20, 21]],

       [[24, 25],
        [30, 31],
        [26, 27],
        [28, 29]],

       [[34, 35],
        [36, 37],
        [38, 39],
        [32, 33]]])

Đối chiếu chỉ mục (5,1) của tôi với chỉ mục được chấp nhận _x(là (5,4) được làm nghiêng):

In [640]: np.arange(5)[:,None]                                                                       
Out[640]: 
array([[0],
       [1],
       [2],
       [3],
       [4]])
In [641]: _x = np.repeat(np.arange(indx_array.shape[0]),indx_array.shape[1])                         
In [643]: _x                                                                                         
Out[643]: array([0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4])

Với việc phát sóng _xkhông cần lặp lại, (5,4); (5,1) là đủ.

Việc phát sóng thực hiện một sự lặp lại ảo. Điều này có thể được minh họa bằng broadcast_tohàm:

In [648]: np.broadcast_to(np.arange(5)[:,None],(5,4))                                                
Out[648]: 
array([[0, 0, 0, 0],
       [1, 1, 1, 1],
       [2, 2, 2, 2],
       [3, 3, 3, 3],
       [4, 4, 4, 4]])
In [649]: _.strides                                                                                  
Out[649]: (8, 0)

Đó là 0những bước đi lặp lại mà không cần tạo bản sao. as_stridedstride_trickschức năng hữu ích nhất , đặc biệt khi làm những việc như di chuyển cửa sổ. Thông thường, chúng tôi chỉ để phát sóng tự động làm công việc mà không cần lo lắng quá nhiều về cách thức.

4 RichardNemeth Aug 15 2020 at 21:14

Có thể được thực hiện với một chút bàn giao của mảng chỉ mục.

import numpy as np

_x = np.repeat(np.arange(indx_array.shape[0]),indx_array.shape[1])
_y = indx_array.ravel()

output = data_matrix[_x, _y].reshape(data_matrix.shape)

kết quả là mảng numpy dự kiến

array([[[ 6,  7],
        [ 4,  5],
        [ 2,  3],
        [ 0,  1]],

       [[ 8,  9],
        [10, 11],
        [12, 13],
        [14, 15]],

       [[18, 19],
        [16, 17],
        [22, 23],
        [20, 21]],

       [[24, 25],
        [30, 31],
        [26, 27],
        [28, 29]],

       [[34, 35],
        [36, 37],
        [38, 39],
        [32, 33]]])