NumPyの多次元配列ndarrayは、データ入れ替えの操作も豊富にあります。transpose関数はそのうちの1つで、転置をするときや、軸のデータの順番を入れ替えるときに役に立ちます。

この記事では、transpose関数に焦点を当てて使い方を解説します。

軸のデータを入れ替えるとはどういうことか

多次元配列の軸と聞いて、何のことなんだろうと思った方もいるかもしれません。NumPyの多次元配列の形状表記は、タプルで(2, 3, 4)のように表記します。3行4列の行列であれば、(3, 4)と表記して第0軸が3、第1軸が4となります。

よく使用する転置の例で説明しましょう。転置はこの軸(axis)を入れ替えることに相当します。まずは、1次元のベクトルで考えてみます。

行ベクトルを転置すると列ベクトル、列ベクトルを転置すると行ベクトルになります。転置した行列やベクトルには t という添え字をつけることで元のものから転置したものであることを示します。

a = (a_1, a_2, \cdots, a_n), a^t = \begin{pmatrix} a_1 \\ a_2 \\ \vdots \\ a_n\\ \end{pmatrix}\\ b = \begin{pmatrix} b_1 \\ b_2 \\ \vdots \\ b_n\\ \end{pmatrix}, b^t = (b_1, b_2, \cdots, b_n)\

しかしながらNumPyでは、n次元ベクトルが行ベクトルであるか列ベクトルであるかの区別はしません。なので、ベクトルをtranspose関数で転置しても何も変わりません。

2次元配列以降からtranspose関数を使うことで中身が変わります。このとき、次のように行と列が反転します。

A = \begin{pmatrix} a_{11} & a_{12} \\ a_{21} & a_{22} \\ \end{pmatrix}\ , A^t = \begin{pmatrix} a_{11} & a_{21} \\ a_{12} & a_{22} \\ \end{pmatrix} \\ \\ \\ B = \begin{pmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ \end{pmatrix}, B^t = \begin{pmatrix} a_{11} & a_{21} \\ a_{12} & a_{22} \\ a_{13} & a_{23} \\ \end{pmatrix}\\

元の配列a の行と列を入れ替えることは、0軸と1軸を入れ替えることと同義です。その場合、次のような変換がなされます。

a(i, j) \rightarrow a'(j, i)

3次元にした場合も同様に、0軸と1軸を入れ替えた場合、次のような変換になります。

a(i, j, k) \rightarrow a'(j, i, k)

transpose

このような転置を行う関数は3通りあり、numpy.transposenumpy.ndarray.transposenumpy.ndarray.Tとがあります。

numpy.ndarray.transpose

numpy.ndarray.transposeのAPIドキュメントは以下の通りです。

numpy.ndarray.transpose(axes)

params:

パラメータ名 概要
axes intのタプルまたはn個並んだint (省略可能)
転置を行なった後の軸(axis)の入れ替え方を指定します。何も指定しなければ軸の順番が逆になった配列を返します。

returns:

指定された軸の入れ替え(転置)を行なった配列(ndarray)が返されます。

先程見たように1次元配列に対しては何も変化を及ぼしません。これは他の2つの関数についても同じことが言えます。

引数のaxesには、軸をどのように入れ替えるかを指定します。3次元配列の1軸と2軸を入れ替えたい場合は、(0, 2, 1)とします。0軸と2軸を入れ替えたい場合は、(2, 1, 0)と指定してください。

まずは2次元配列からtransposeの使用例を確認します。

In [1]: import numpy as np

In [2]: a = np.arange(12).reshape(3,4)

In [3]: a
Out[3]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [4]: a.transpose() # まずは何も引数を指定せずに転置。
Out[4]:
array([[ 0,  4,  8],
       [ 1,  5,  9],
       [ 2,  6, 10],
       [ 3,  7, 11]])

In [5]: a.transpose(1, 0) # 軸の順番を指定して見る。これは軸の順番を逆にしただけなので直前の操作の結果と同じ配列が返ってくる。
Out[5]:
array([[ 0,  4,  8],
       [ 1,  5,  9],
       [ 2,  6, 10],
       [ 3,  7, 11]])

In [6]: a.transpose((1, 0)) # タプルを指定することができます。
Out[6]:
array([[ 0,  4,  8],
       [ 1,  5,  9],
       [ 2,  6, 10],
       [ 3,  7, 11]])

In [7]: a.transpose(0, 1) # 元の順番のまま軸を指定すると配列に変化はない。
Out[7]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

1次元配列について見てみます。見た目がほとんど同じでもreshapeで形状変換することで転置を行うことは可能です。

In [8]: b = np.arange(6) # 今度は1次元配列を転置してみる。

In [9]: b
Out[9]: array([0, 1, 2, 3, 4, 5])

In [10]: b.transpose() # 特に変化は起こらない。
Out[10]: array([0, 1, 2, 3, 4, 5])

In [11]: b.shape # ここでbの`shape`を確認。軸が1つしかないことがわかる。
Out[11]: (6,)

In [12]: b = b.reshape((1,6)) # このように軸を2つに指定してやると転置ができるようになる。

In [13]: b
Out[13]: array([[0, 1, 2, 3, 4, 5]])

In [14]: b.transpose()
Out[14]:
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5]])

次は3次元配列について見ていきます。

In [17]: c = np.arange(24).reshape(4,3,2) # 4×3×2の3次元配列。ちなみに、axis = 0の要素数が4,axis = 1の要素数が3,axis = 2の要素数が2となっている。

In [15]: c
Out[15]:
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 [16]: c.transpose() # 引数を何も指定しないと軸の順番が逆になった(2,1,0)の配列を返す。
Out[16]:
array([[[ 0,  6, 12, 18],
        [ 2,  8, 14, 20],
        [ 4, 10, 16, 22]],

       [[ 1,  7, 13, 19],
        [ 3,  9, 15, 21],
        [ 5, 11, 17, 23]]])

In [17]: c.transpose(1, 0, 2) # 軸の順番を指定してみる。
Out[17]:
array([[[ 0,  1],
        [ 6,  7],
        [12, 13],
        [18, 19]],

       [[ 2,  3],
        [ 8,  9],
        [14, 15],
        [20, 21]],

       [[ 4,  5],
        [10, 11],
        [16, 17],
        [22, 23]]])

numpy.transpose

次はnumpy.transposeの方を見ていきましょう。基本的な使い方はnumpy.ndarray.transposeとほぼ同じです。第一引数に転置したい配列(ndarray)を指定すること以外は何も変更はありません。

APIドキュメントは以下の通りです。

numpy.transpose(a, axes = None)

params:

パラメータ名 概要
a array_like
(配列に相当するもの)
転置したい配列をここで指定します。
axes intのタプル (省略可能)初期値None
転置する際の軸の順番を指定します。

returns:

転置されたあとの配列(ndarray)が返されます。

ほとんど同じですが、こちらも使用方法を確認してみます。

In [18]: np.transpose(c) # 三次元配列のcを再び転置して見る。
Out[18]:
array([[[ 0,  6, 12, 18],
        [ 2,  8, 14, 20],
        [ 4, 10, 16, 22]],

       [[ 1,  7, 13, 19],
        [ 3,  9, 15, 21],
        [ 5, 11, 17, 23]]])

In [19]: c.shape
Out[19]: (4, 3, 2)

In [20]: np.transpose(c).shape
Out[20]: (2, 3, 4)

In [21]: np.transpose(c, (1,0,2)) # 軸の順番を指定。
Out[21]:
array([[[ 0,  1],
        [ 6,  7],
        [12, 13],
        [18, 19]],

       [[ 2,  3],
        [ 8,  9],
        [14, 15],
        [20, 21]],

       [[ 4,  5],
        [10, 11],
        [16, 17],
        [22, 23]]])

In [22]: np.transpose(c, (1,0,2)).shape # shapeを確認。
Out[22]: (3, 4, 2)

1次元配列でも確認しておきます。

In [23]: b
Out[23]: array([0, 1, 2, 3, 4, 5])

In [24]: np.transpose(b) # これは`numpy.ndarray.transpose`と同様転置しても変化がない。
Out[24]: array([0, 1, 2, 3, 4, 5])

In [25]: b = b.reshape((1, 6))

In [26]: b
Out[26]: array([[0, 1, 2, 3, 4, 5]])

In [27]: np.transpose(b) # `shape`を変化させれば転置できる。これも同様。
Out[27]:
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5]])

numpy.ndarray.T

最後にnumpy.ndarray.Tについて扱っていきます。これは引数を指定しないnumpy.ndarray.transposeです。プロパティのように使用することができます。

In [28]: a # 再び、a,b,cそれぞれについてTをつかって転置を行なっていきます。
Out[28]:
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])

In [29]: a.T
Out[29]:
array([[ 0,  4,  8],
       [ 1,  5,  9],
       [ 2,  6, 10],
       [ 3,  7, 11]])

In [30]: b
Out[30]: array([[0, 1, 2, 3, 4, 5]])

In [31]: b.T
Out[31]:
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5]])

In [32]: c
Out[32]:
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 [33]: c.T
Out[33]:
array([[[ 0,  6, 12, 18],
        [ 2,  8, 14, 20],
        [ 4, 10, 16, 22]],

       [[ 1,  7, 13, 19],
        [ 3,  9, 15, 21],
        [ 5, 11, 17, 23]]])

In [34]: a.transpose().shape == a.T.shape # それぞれの転置後のshapeを比較してみます。
Out[34]: True

In [35]: b.transpose().shape == b.T.shape
Out[35]: True

In [36]: c.transpose().shape == c.T.shape
Out[36]: True