LoginSignup
2
4

More than 3 years have passed since last update.

Numpyのtransposeメソッドと「転置・軸」を自分なりにわかりやすく解釈してみた

Last updated at Posted at 2019-08-25

1.【概要】

O'Reilly Japanのゼロから作るDeep Learningを読んでいて、numpyのtransposeメソッドの動き(特に3次元配列以上の時の動き)が難しく理解に手間取ったので、自分用のメモも兼ねて記載します。

【対象レベル】

・numpy初心者(transposeメソッドを利用したことが無い、転置・軸の概念がわからない)

2. 【transposeメソッドとは】

Pythonライブラリのnumpyに含まれている、配列加工用のメソッドです。
※numpy.transposeとnumpy.ndarray.transposeがありますが、今回は後者が対象です。

  
リファレンスの概要から、重要そうな部分だけ和訳すると下記のようになります。(Google翻訳&意訳)

軸を転置した配列のビューを返します。
・1次元配列に使用した場合、転置されたベクトルは単純に同じベクトルであるため、このメソッドは効果がありません。
・2次元配列に使用した場合、これは標準の行列転置です。
・n次元配列に使用した場合、軸が指定されていれば、その順序が軸の並べ替え方法を示します。
numpy.ndarray.transpose 公式リファレンス(英語)

2.1 2次元配列にtransposeを使用した場合

リファレンスにて、1次元配列はtransposeを使っても意味が無いと記載されているので、
まずは2次元配列の場合の動き(行列転置)から見ていきます。

【そもそも転置とは??】

m 行 n 列の行列 A に対して A の (i, j) 要素と (j, i) 要素を入れ替えた n 行 m 列の行列、つまり対角線で成分を折り返した行列のことである。
Wikipediaより

要は下記のように配列の縦と横を入れ替える行為です。
※Jupyter NotebookやGoogle colaboratoryにそのまま貼り付けて動かせるようになっています。


#Numpyのインポート
import numpy as np

#randintメソッドで0~9までのランダムな値で、size引数に記載の形状の配列を生成
Array=np.random.randint(10,size=(2,3))
print("2×3の配列")
print(Array)

#2次元配列に対しtransposeを実行し、転置する(3×2になる)
print(Array.transpose())
#---------------コードここまで----------------

#【実行結果】
#・2×3の配列
[[2 5 2]
 [6 1 1]]

#・上記配列を転置(3×2になる)
[[2 6]
 [5 1]
 [2 1]]

ここまでは特に問題ないかと思います。

2.2 n次元配列にtransposeを使用した場合

では本題のn次元配列(3次元以上の配列)の場合の動き(軸の並び変え)を見ていきます。
先ほどのリファレンスを見返すと、n次元配列は下記のように記載されています。

・n次元配列に使用した場合、軸が指定されていれば、その順序が軸の並べ替え方法を示します。

【軸とは??】

指摘を恐れず個人的な解釈を述べると、
軸=配列要素を表すときのインデックス(Array[1,2]の「1,2」の部分)のことだと言えます。
そしてこの軸の順番を並べ変える=「配列の各要素の位置を配列のインデックス基準で変更する」ということになります。

実際にコードを実行してみましょう。

#Numpyのインポート
import numpy as np

#randintメソッドで0~9までのランダムな値で、size引数に記載の形状の配列を作成
Array=np.random.randint(10,size=(2,3,4))
print("【2×3×4の3次元配列】\n")
print(Array)

#transposeメソッドで並び替え
print(Array.transpose(1,0,2))
#---------------コードここまで----------------

#【実行結果】

[[[4 8 1 6]
  [2 3 8 5]
  [9 1 0 6]]

 [[0 1 7 0]
  [9 6 4 9]
  [4 6 9 5]]]


#【transpose(1,0,2)を実行し、上記配列を並び替え(インデックスの0番目、1番目を入れ替え)】
#・配列の形状:2×3×4 → 3×2×4 
#  ※インデックス0番目(第0軸)の「2」と1番目(第1軸)の「3」が入れ替わっている

#・要素の位置:全要素が形状同様に入れ替わり(例 [2,1]の値[0,1,7,0]が[1,2]に移動)
#  ※入れ替わっていないものは、元々インデックスの0番目と1番目が同じ値で、入れ替えても変わらないもの。(インデックスが[1,1,2]の値など)

[[[4 8 1 6]
  [0 1 7 0]]

 [[2 3 8 5]
  [9 6 4 9]]

 [[9 1 0 6]
  [4 6 9 5]]]

  

【reshapeメソッドと何が違う??】

同じようなメソッドにreshapeもありますが、
reshapeの場合は、あくまで配列の形状が変わるだけで、transposeのように配列の要素の位置は変わりません。

つまり、最初に生成した配列を1次元配列一行で表現したものと比較すると下記のようになります。
・reshapeメソッド:最初に生成した配列と同じ
・transposeメソッド:最初に生成した配列と要素の順番が違う

試しにreshapeした場合と、transposeした場合とで比べてみましょう。

#Numpyのインポート
import numpy as np

#randintメソッドで0~9までのランダムな値で、size引数に記載の形状の配列を作成
Array=np.random.randint(10,size=(2,3,4))

#reshapeメソッドで形状変形(2×3×4 → 3×2×4)
Array_reshape=(Array.reshape(3,2,4))

#transposeメソッドで形状変形と共に並び替え(2×3×4 → 3×2×4)
Array_transpose=(Array.transpose(1,0,2))


#flattenメソッドで配列を1次元に直して比較
print("\n\n【検証:flattenで配列を1次元に直して比較】")

print("・最初に生成した配列")
print(Array.flatten())

print("\n・reshapeメソッドで形状だけを変えた配列 (最初に生成した配列と「同じ」順に要素が並んでいる)")
print(Array_reshape.flatten())

print("\n・transposeメソッドで形状と要素の位置を変えた配列 (最初に生成した配列と「違う」順に要素が並んでいる)")
print(Array_transpose.flatten())
#---------------コードここまで----------------

#【実行結果】

#【検証:flattenで配列を1次元に直して比較】
#・最初に生成した配列
[4 4 1 6 5 5 3 8 5 1 2 9 2 5 5 7 7 4 2 8 7 9 6 3]

#・reshapeメソッドで形状だけを変えた配列 (最初に生成した配列と「同じ」順に要素が並んでいる)
[4 4 1 6 5 5 3 8 5 1 2 9 2 5 5 7 7 4 2 8 7 9 6 3]

#・transposeメソッドで形状と要素の位置を変えた配列 (最初に生成した配列と「違う」順に要素が並んでいる)
[4 4 1 6 2 5 5 7 5 5 3 8 7 4 2 8 5 1 2 9 7 9 6 3]

3.【結論】

reshapeは配列の「形状」を変えますが、「要素の並び順」は変わりません。
しかし、transposeはreshapeのように配列の「形状」を変えると共に「要素の並び順」も入れ替えます。
  
(注意:reshapeのように任意の形状の配列は作れません。あくまで各次元の要素数を並び替えるだけです。)

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4