Phương thức transpose () của NumPy hoán vị các trục của một mảng như thế nào?


81
In [28]: arr = np.arange(16).reshape((2, 2, 4))

In [29]: arr
Out[29]: 
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

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


In [32]: arr.transpose((1, 0, 2))
Out[32]: 
array([[[ 0,  1,  2,  3],
        [ 8,  9, 10, 11]],

       [[ 4,  5,  6,  7],
        [12, 13, 14, 15]]])

Khi chúng ta truyền một bộ số nguyên vào transpose()hàm, điều gì sẽ xảy ra?

Nói một cách cụ thể, đây là mảng 3D: NumPy biến đổi mảng như thế nào khi tôi vượt qua bộ ba trục (1, 0 ,2)? Bạn có thể giải thích dòng hoặc cột nào các số nguyên này tham chiếu đến không? Và số trục trong ngữ cảnh của NumPy là gì?



2
0là trục 1thứ nhất, 2là trục thứ hai, là trục thứ ba, v.v. ... axesTham số transposecung cấp thứ tự mới mà bạn muốn chúng sắp xếp, trong ví dụ của bạn: đầu tiên là thứ hai, sau đó là thứ nhất, sau đó là thứ ba.
Jaime

Trong màn hình 3d có các khối, hàng và cột. Chuyển vị của bạn đã thay đổi thứ tự của các khối và hàng, giữ nguyên các cột. Những gì từng là hàng thứ 2 của khối 1 trở thành hàng đầu tiên của khối 2.
hpaulj

Câu trả lời:


185

Để chuyển một mảng, NumPy chỉ cần hoán đổi thông tin hình dạng và khoảng cách cho mỗi trục. Đây là những bước tiến:

>>> arr.strides
(64, 32, 8)

>>> arr.transpose(1, 0, 2).strides
(32, 64, 8)

Lưu ý rằng hoạt động chuyển vị đã hoán đổi các bước cho trục 0 và trục 1. Độ dài của các trục này cũng được hoán đổi (cả hai độ dài đều có 2trong ví dụ này).

Không cần sao chép dữ liệu để điều này xảy ra; NumPy có thể đơn giản thay đổi cách nó nhìn vào bộ nhớ bên dưới để xây dựng mảng mới.


Hình dung những bước tiến

Giá trị khoảng cách biểu thị số byte phải được di chuyển trong bộ nhớ để đạt đến giá trị tiếp theo của trục của mảng.

Bây giờ, mảng 3D của chúng tôi arrtrông như thế này (với các trục được gắn nhãn):

nhập mô tả hình ảnh ở đây

Mảng này được lưu trữ trong một khối bộ nhớ liền kề ; về cơ bản nó là một chiều. Để diễn giải nó như một đối tượng 3D, NumPy phải nhảy qua một số byte không đổi nhất định để di chuyển dọc theo một trong ba trục:

nhập mô tả hình ảnh ở đây

Vì mỗi số nguyên chiếm 8 byte bộ nhớ (chúng tôi đang sử dụng kiểu int64), nên giá trị bước cho mỗi chiều gấp 8 lần số giá trị mà chúng ta cần nhảy. Ví dụ: để di chuyển dọc theo trục 1, bốn giá trị (32 byte) được nhảy và để di chuyển dọc theo trục 0, cần phải nhảy tám giá trị (64 byte).

Khi chúng ta viết, arr.transpose(1, 0, 2)chúng ta đang hoán đổi trục 0 và 1. Mảng được hoán vị trông như thế này:

nhập mô tả hình ảnh ở đây

Tất cả những gì NumPy cần làm là hoán đổi thông tin sải chân cho trục 0 và trục 1 (trục 2 không đổi). Bây giờ chúng ta phải nhảy xa hơn để di chuyển dọc theo trục 1 hơn trục 0:

nhập mô tả hình ảnh ở đây

Khái niệm cơ bản này hoạt động cho bất kỳ hoán vị nào của các trục của một mảng. Mã thực tế xử lý chuyển vị được viết bằng C và có thể được tìm thấy tại đây .


6
@Alex: cảm ơn! Những con số được đưa ra sử dụng draw.io .
Alex Riley

6

Như đã giải thích trong tài liệu :

Theo mặc định, hãy đảo ngược các kích thước, nếu không thì hoán vị các trục theo các giá trị đã cho.

Vì vậy, bạn có thể chuyển một tham số tùy chọn axesxác định thứ tự mới của thứ nguyên.

Ví dụ: chuyển đổi hai kích thước đầu tiên của mảng pixel VGA RGB:

 >>> x = np.ones((480, 640, 3))
 >>> np.transpose(x, (1, 0, 2)).shape
 (640, 480, 3)

1
Hi, cảm ơn bạn cho câu trả lời của bạn. Tuy nhiên, tôi vẫn không thể hiểu vấn đề này, như bạn có thể thấy, hình dạng của arr là (2,2,4) và arr.transpose (1,0,2) cũng là (2,2,4). đây là mảng 3-d, làm thế nào để biến đổi mảng khi tôi truyền (1,0,2), bạn có thể giải thích hàng hoặc cột mà 1,0,2 đề cập đến? Và số trục là gì?
Frank Hu

1
@FrankHu hình dung trong không gian 3d, vì vậy quay trục x, y là những gì đã xảy ra ở đây. (1,0,2) đã được chuyển đổi từ (0,1,2), do đó, 2 trục đầu tiên được chuyển đổi. 0 là chỉ số của trục. Say, x, y, z bản đồ để 0,1,2
CodeFarmer

5

Trong ký hiệu C, mảng của bạn sẽ là:

int arr[2][2][4]

là một mảng 3D có 2 mảng 2D. Mỗi mảng 2D đó có 2 mảng 1D, mỗi mảng 1D đó có 4 phần tử.

Vì vậy, bạn có ba chiều. Các trục là 0, 1, 2, với các kích thước 2, 2, 4. Đây chính xác là cách numpy xử lý các trục của mảng N chiều.

Vì vậy, arr.transpose((1, 0, 2))sẽ lấy trục 1 và đặt nó ở vị trí 0, trục 0 và đặt nó ở vị trí 1, và trục 2 và để nó ở vị trí 2. Bạn đang hoán vị các trục một cách hiệu quả:

0 -\/-> 0
1 -/\-> 1
2 ----> 2

Nói cách khác 1 -> 0, 0 -> 1, 2 -> 2,. Các trục đích luôn có thứ tự, vì vậy tất cả những gì bạn cần là chỉ định các trục nguồn. Đọc ra khỏi tuple theo thứ tự: (1, 0, 2).

Trong trường hợp này, kích thước mảng mới của bạn lại là thứ nguyên [2][2][4], chỉ vì trục 0 và 1 có cùng kích thước (2).

Thú vị hơn là một chuyển vị (2, 1, 0)cung cấp cho bạn một mảng [4][2][2].

0 -\ /--> 0
1 --X---> 1
2 -/ \--> 2

Nói cách khác 2 -> 0, 1 -> 1, 0 -> 2,. Đọc ra khỏi tuple theo thứ tự: (2, 1, 0).

>>> arr.transpose((2,1,0))
array([[[ 0,  8],
        [ 4, 12]],

       [[ 1,  9],
        [ 5, 13]],

       [[ 2, 10],
        [ 6, 14]],

       [[ 3, 11],
        [ 7, 15]]])

Bạn đã kết thúc với một int[4][2][2].

Có thể bạn sẽ hiểu rõ hơn nếu tất cả các kích thước đều có kích thước khác nhau, vì vậy bạn có thể biết từng trục đã đi đâu.

Tại sao lại là yếu tố bên trong đầu tiên [0, 8]? Bởi vì nếu bạn hình dung mảng 3D của mình như hai tờ giấy 08được xếp thẳng hàng, một trên một tờ giấy và một trên tờ giấy kia, cả hai đều ở phía trên bên trái. Bằng cách chuyển đổi, (2, 1, 0)bạn đang nói rằng bạn muốn hướng của giấy sang giấy bây giờ di chuyển dọc theo giấy từ trái sang phải và hướng từ trái sang phải bây giờ đi từ giấy sang giấy. Bạn có 4 phần tử đi từ trái sang phải, vì vậy bây giờ bạn có bốn mảnh giấy thay thế. Và bạn đã có 2 giấy tờ, vì vậy bây giờ bạn có 2 yếu tố đi từ trái sang phải.

Xin lỗi vì nghệ thuật ASCII khủng khiếp. ¯\_(ツ)_/¯


Tôi có đúng khi nghĩ rằng tuple bạn đưa cho transpose()không phải là một hoán vị toán học hay bất cứ điều gì? Nó thực sự chỉ là hướng dẫn nói "làm cho các trục bây giờ ở các vị trí này"? Ví dụ: .transpose(p, q, r, s)bạn đang nói "đặt trục plà 0, qlà 1, r2 và s3"? Hoặc nhìn thấy một cách khác b = a.transpose(axes)có nghĩa là b.shape == tuple(a.shape[i] for i in axes)?
Tim

Ý tưởng về việc hoán đổi trục với nghệ thuật ASCII làm rõ sự hiểu biết của tôi. Cảm ơn rất nhiều
K_inverse 17/09/19

0

Có vẻ như câu hỏi và ví dụ bắt nguồn từ cuốn sách Python để phân tích dữ liệu của Wes McKinney. Tính năng transposenày được đề cập trong Chương 4.1. Chuyển đổi mảng và hoán đổi trục .

Đối với mảng có chiều cao hơn, transposesẽ chấp nhận một bộ số trục để hoán vị các trục (để uốn tâm thêm).

Ở đây "permute" có nghĩa là "sắp xếp lại", nên sắp xếp lại thứ tự các trục.

Các số trong .transpose(1, 0, 2)xác định thứ tự của các trục được thay đổi như thế nào so với ban đầu. Bằng cách sử dụng .transpose(1, 0, 2), chúng tôi có nghĩa là, "Thay đổi chiếc rìu thứ nhất bằng chiếc rìu thứ hai." Nếu chúng ta sử dụng .transpose(0, 1, 2), mảng sẽ giữ nguyên vì không có gì thay đổi; nó là thứ tự mặc định.

Ví dụ trong cuốn sách với một (2, 2, 4)mảng có kích thước không rõ ràng lắm vì trục thứ nhất và thứ hai có cùng kích thước. Vì vậy, kết quả cuối cùng dường như không thay đổi ngoại trừ việc sắp xếp lại các hàng arr[0, 1]arr[1, 0].

Nếu chúng ta thử một ví dụ khác với mảng 3 chiều với mỗi chiều có kích thước khác nhau, phần sắp xếp lại trở nên rõ ràng hơn.

In [2]: x = np.arange(24).reshape(2, 3, 4)

In [3]: x
Out[3]: 
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]]])

In [4]: x.transpose(1, 0, 2)
Out[4]: 
array([[[ 0,  1,  2,  3],
        [12, 13, 14, 15]],

       [[ 4,  5,  6,  7],
        [16, 17, 18, 19]],

       [[ 8,  9, 10, 11],
        [20, 21, 22, 23]]])

Ở đây, kích thước mảng ban đầu là (2, 3, 4). Chúng tôi đã thay đổi thứ 1 và thứ 2, vì vậy nó có (3, 2, 4)kích thước. Nếu chúng ta quan sát kỹ hơn để xem việc sắp xếp lại chính xác đã diễn ra như thế nào; các mảng số dường như đã thay đổi theo một mô hình cụ thể. Sử dụng phép tương tự trên giấy của @ RobertB , nếu chúng ta lấy 2 phần số và viết từng phần một trên các trang tính, sau đó lấy một hàng từ mỗi trang tính để tạo một chiều của mảng, bây giờ chúng ta sẽ có một mảng có kích thước 3x2x4 , tính từ lớp ngoài cùng đến lớp trong cùng.

[ 0,  1,  2,  3] \ [12, 13, 14, 15]

[ 4,  5,  6,  7] \ [16, 17, 18, 19]

[ 8,  9, 10, 11] \ [20, 21, 22, 23]

Có thể là một ý tưởng hay khi chơi với các mảng có kích thước khác nhau và thay đổi các trục khác nhau để có được trực giác tốt hơn về cách hoạt động của nó.


-3

Để tóm tắt a.transpose () [i, j, k] = a [k, j, i]

a = np.array( range(24), int).reshape((2,3,4))
a.shape gives (2,3,4)
a.transpose().shape gives (4,3,2)  shape tuple is reversed.

khi nào thì một tham số tuple được truyền vào, các trục được hoán vị theo tuple. Ví dụ

a = np.array (range (24), int) .reshape ((2,3,4))

a [i, j, k] bằng a.transpose ((2,0,1)) [k, i, j]

trục 0 chiếm vị trí thứ 2

trục 1 chiếm vị trí thứ 3

Trục 2 câu chuyện vị trí thứ nhất

tất nhiên, chúng ta cần chú ý rằng các giá trị trong tham số tuple được truyền để chuyển vị là duy nhất và trong phạm vi (số trục)


Bạn chưa giải quyết câu hỏi của OP, đó là điều gì sẽ xảy ra khi bạn chuyển vị với các trục được chỉ định .
Robert B

thêm câu trả lời cho câu hỏi khi các trục được chỉ định.
Raghu Ram
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.