JavaScriptを有効にしてください

NumPyのemptyで空(長さ0)の配列を作る

 ·   4 min read

はじめに

NumPyのempty関数を用いて、np.empty(0), np.empty([0, 0]), …とすることで、空の(要素を持たない)任意の次元の配列を作成できる。本記事では、空の配列の作り方、使い方について簡単に考察する。

環境

ソフトウェア バージョン
NumPy 1.19

本記事では、以下の通りライブラリをインポートしていることを前提とする。

1
import numpy as np

np.emptyについて

np.emptyは中身を初期化せずに配列を作成する関数である。主な引数は次の通り。

1
np.empty(shape, dtype=float)

shapeは配列の形状を決める引数であり、

  • int
  • intを格納するタプル
  • intを格納するリスト

のいずれかをとる。

dtypeは配列の数値の型を決める引数であり、

  • int
  • float
  • np.float32
  • np.int8

などを指定する(デフォルトはfloat)。

要素数が5つの1次元配列を生成するには、shape5、または(5)、または[5]とする。ただし、配列の中身は変わる場合がある。

1
2
3
4
5
6
>>> np.empty(5)
array([0.  , 0.25, 0.5 , 0.75, 1.  ])
>>> np.empty((5))
array([0.  , 0.25, 0.5 , 0.75, 1.  ])
>>> np.empty([5])
array([0.  , 0.25, 0.5 , 0.75, 1.  ])

要素数が2×3の2次元配列を生成するには、shape(2, 3)、または[2, 3]とする。

1
2
3
4
5
6
>>> np.empty((2, 3))
array([[0.93137112, 0.92761264, 0.98531337],
       [0.28813119, 0.49620105, 0.41308828]])
>>> np.empty([2, 3])
array([[0.93137112, 0.92761264, 0.98531337],
       [0.28813119, 0.49620105, 0.41308828]])

np.empty()は、中身が全て0の配列を生成するnp.zeros()や、中身が全て1の配列を生成するnp.ones()と比較すると、配列を高速に生成できる利点がある。

空の配列の生成

冒頭に記したように、np.empty()shape0[0, 0], …とすると、任意の次元の空の配列を生成できる。

1次元配列の場合

1
2
3
4
5
>>> a1 = np.empty(0)
>>> a1
array([], dtype=float64)
>>> a1.ndim # 次元数
1

2次元配列の場合

1
2
3
4
5
>>> a2 = np.empty([0, 0])
>>> a2
array([], shape=(0, 0), dtype=float64)
>>> a2.ndim # 次元数
2

同様に、

  • np.empty([0, 0, 0])で3次元の空の配列
  • np.empty([0, 0, 0, 0])で4次元の空の配列

がそれぞれ生成できる。

なお、np.zeros()関数やnp.ones()関数を使って、

  • np.zeros(0)
  • np.ones([0, 0])

としても、同様に空の配列を作成できる。しかし、関数名と異なり要素に0や1を含まない配列が生成されて紛らわしいため、np.empty()関数を使うべきだと個人的に思う。

空の配列の使い方

空の配列は、「配列を結合したいが、最終的に得られる配列のサイズが分からない場合」、あるいは「計算の規模が小さく、かつプログラムの可読性を重視したい場合」に用いるべきである。

配列を逐次的に結合すると、その都度メモリを確保する必要があるため、実行速度が低下する。
そのため、最終的な配列のサイズが分かっている場合には、初めに必要なサイズの配列を確保して、逐次的に配列を代入した方が速く実行できる。

比較のため、配列を結合する関数stack()と、最初に配列を確保する関数substitute()を作成した。両者とも、長さが1000で要素が全て1の配列を返す。関数stack()では長さ1の配列を1000回結合し、関数substitute()では最初に確保した配列に長さ1の配列を1000回代入している。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def stack():
    a = np.empty(0)
    for i in range(1000):
        a = np.hstack([a, np.array(1)])
    return a
        
def substitute():
    a = np.empty(1000)
    for i in range(1000):
        a[i] = np.array(1)
    return a

IPythonの%timeitマジックコマンドで実行速度を測定する。

1
2
3
4
>>> %timeit stack()
5.93 ms ± 147 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
>>> %timeit substitute()
436 µs ± 17.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

stack()関数とsubstitute()関数の平均実行時間はそれぞれ5.93ミリ秒と0.436ミリ秒であり、substitute()の方が約14倍高速である。すなわち、処理速度を重視する場合、最初に配列を確保した方が良い。

参考

numpy.empty — NumPy v1.19 Manual

シェアする

Helve
WRITTEN BY
Helve
関西在住、電機メーカ勤務のエンジニア。X(旧Twitter)で新着記事を配信中です

サイト内検索