Ellipsis(...)の解説

はじめに

Pythonの3点リーダー(...)の意味について解説します。

機械学習のベストセラー「ゼロから作るDeep Learning」の2作目「2 自然言語処理編」にも多用されてる記法です。

結論

numpy.nadarrayにおける残りの軸を表します。

numpy.ndarrayのスライスの復習

軸の話をわかりやすくするために、

  • 第1軸のサイズが1
  • 第2軸のサイズが2
  • 第3軸のサイズが3
  • 第4軸のサイズが4

であるようなndarrayAを考える。

1
2
3
4
>>> import numpy as np
>>> A = np.random.rand(1,2,3,4)
>>> A.shape
(1, 2, 3, 4)

今後もこのAを、様々にスライスしshapeを確認します。

第1軸の0番目についてスライスをしたい時は以下のようにします。

1
2
>>> a[0].shape
(2, 3, 4)

では、第2軸の0番目についてスライスをしたい時は?

1
2
>>> a[:,0].shape
(1, 3, 4)

このようにコロンを入れます。

では、第1軸と第4軸の0番目についてスライスをしたい時は?

1
2
>>> a[0,:,:,0].shape
(2, 3)

複数の:の省略としての用法

では、以下のような6次元配列の、第6軸の0番目についてスライスをしたい時は?

1
2
3
>>> B = np.random.rand(1,2,3,4,5,6)
>>> B[:,:,:,:,:,0].shape
(1, 2, 3, 4, 5)

なんだか、コロンが多くて大変です。

こういった場面でElipsisを使えます。

1
2
>>> B[...,0].shape
(1, 2, 3, 4, 5)

先ほどのコードと全く同じ動きです。

つまり、指定していない軸で、全て:を指定したかのように動作します。

1
2
>>> B[[:,0,...,0].shape
(1, 3, 4, 5)

とても便利ですね。

ndarrayのdeep copyに便利

これは、応用テクニックですが、deep copyに利用できます。

  1. Bを書き換えると、Aも書き換わる

    1
    2
    3
    4
    5
    6
    7
    A = np.ones((2,3))
    B = np.zeros((2,3))
    B = A
    B *= 2
    A
    array([[2., 2., 2.],
    [2., 2., 2.]])
  2. Bを書き換えても、Aも変わらない

    1
    2
    3
    4
    5
    6
    7
    A = np.ones((2,3))
    B = np.zeros((2,3))
    B[:,:] = A
    B *= 2
    A
    array([[1., 1., 1.],
    [1., 1., 1.]])
  3. Bを書き換えても、Aも変わらない

    1
    2
    3
    4
    5
    6
    7
    A = np.ones((2,3))
    B = np.zeros((2,3))
    B[...] = A
    B *= 2
    A
    array([[1., 1., 1.],
    [1., 1., 1.]])

    ellipsisを使うとndarrayの次元数を気にせず使えるので、楽です。