numpy
には、配列ndarray
を生成するための様々な関数があります。
0
、1
で埋め尽くされた配列を生成する関数zeros
, ones
や
その派生形full
, empty
について紹介します。
これらの関数は、配列の初期化に使用することが多い非常に重要な関数です。
配列ndarray
の基本はこちらをチェック!
zeros系統:形状を指定して配列生成
これらの関数は、引数で配列の形状を指定すると、それぞれ
zeros()
:0
ones()
:1
full(val)
:val
empty()
:初期化されていない数値
で埋め尽くされた配列を生成します。
配列の形状shape
は、
- 一次元配列:整数のリテラル ⇒ 例:
1
や2
など - 二次元以上の配列:整数のタプル ⇒ 例:
(2, 2)
、(2, 2, 3)
など
で与えます。
以下では、各関数についてサンプルコード付きで解説します。
zeros(shape) ⇒ 0で初期化
0
で初期化された形状shape
の配列を生成します。
import numpy as np
a = np.zeros(5)
# a → array([0., 0., 0., 0., 0.])
A = np.zeros((2, 3))
# A → array([[0., 0., 0.],
# [0., 0., 0.]])
my_shape = (2, 2)
B = np.zeros(my_shape)
# B → array([[0., 0.],
# [0., 0.]])
形状の指定は
- 一次元配列の形状:整数値のリテラルで指定
- 二次元以上の配列の形状:タプルで指定
という点に注意しましょう。
次のように、二次元以上の配列を生成するときに、整数を連続して渡すとエラーになります。
C = np.zeros(2, 3)
# TypeError: data type not understood
私の場合、特に理由がなければ、zeros()
で初期化します。
作成した配列は後ほど、0
以外の値に書き換えて使用することが多いと思います。
書き換え忘れがあった場合、0
で初期化しておいた方がわずかですが気づきやすいことがあります。例えば、zero divideで気づけたりします。
ones(shape) ⇒ 1で初期化
1
で初期化された形状shape
の配列を生成します。
# ones(shape)
a = np.ones(5)
# a → array([1., 1., 1., 1., 1.])
A = np.ones((2, 3))
# A → array([[1., 1., 1.],
# [1., 1., 1.]])
my_shape = (2, 2)
B = np.ones(my_shape)
# B → array([[1., 1.],
# [1., 1.]])
形状の指定は
- 一次元配列の形状:整数値のリテラルで指定
- 二次元以上の配列の形状:タプルで指定
という点に注意しましょう。
次のように、二次元以上の配列を生成するときに、整数を連続して渡すとエラーになります。
C = np.zeros(2, 3)
# TypeError: data type not understood
full(val, shape) ⇒ valで初期化
1
で初期化された形状shape
の配列を生成します。
やりがちなタイプミスですが、fulls()
ではなくて、full()
なので注意しましょう。
a = np.full(5, 3)
# a → array([3, 3, 3, 3, 3])
A = np.full((2, 3), 0.1)
# A → array([[0.1, 0.1, 0.1],
# [0.1, 0.1, 0.1]])
my_shape = (2, 2)
B = np.full(my_shape, -2)
# B → array([[-2, -2],
# [-2, -2]])
ones()
で配列を生成して、val
をかけても同じ結果になりますが、full()
の方が僅かに速いです。
私の実行環境で、マジックコマンド%timeit
で比較してみます。
val = 0.1
X = np.ones(3)*val
# X → array([0.1, 0.1, 0.1])
# 2.4 µs ± 21.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Y = np.full(3, val)
# Y → array([0.1, 0.1, 0.1])
# 1.85 µs ± 36.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
少しだけ速いですね…
形状の指定は
- 一次元配列の形状:整数値のリテラルで指定
- 二次元以上の配列の形状:タプルで指定
という点に注意しましょう。
次のように、二次元以上の配列を生成するときに、整数を連続して渡すとエラーになります。
C = np.ones(2, 3, 0.5)
# TypeError: data type not understood
empty(shape) ⇒ 初期化なし
empty()
は、初期化されていない数値で配列を生成します。
初期値として、そのときたまたまメモリに残っていた値が使用されます。
a = np.empty(3)
# a → array([6.95216240e-310, 1.07193797e-311, 6.95218871e-310])
A = np.empty((2, 2))
# A → array([[4.67296746e-307, 1.69121096e-306],
# [7.56597770e-307, 1.89146896e-307]])
一見、empty()
には使い道がなさそうですが、初期化しない分だけzeros()
などより僅かに速いです。
私の実行環境で、マジックコマンド%timeit
で比較してみます。
X = np.zeros(3)
# X → array([0., 0., 0.])
# 570 ns ± 17.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Y = np.empty(3)
# Y → array([ 6.95216299e-310, 5.55977121e-312, -0.00000000e+000])
# 555 ns ± 0.951 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
empty()
の方が僅かに速いです…。
この僅かな速度差のために初期化忘れの危険があるempty()
を使用した方がいいのかは疑問ですが…。
zeros_like系統:既存配列と同じ形状の配列生成
スクリプトを書く際には、zeros()
よりもzeros_like()
系統で初期化することの方が多いかもしれません。
zeros_like()
では、引数に既存の配列を与えると、既存配列と同じ形状の配列を生成します。
初期値はそれぞれ
zeros_like()
:0
ones_like ()
:1
full_like (val)
:val
empty_like ()
:初期化されていない数値
で埋め尽くされた配列を生成します。
同じ形状の配列を複数作成する際には、1つ目をzeros()
系統で作成して、2つ以降をzeros_like()
系統にすることが多いと思います。
既存配列としては、
ndarray
- リスト
- タプル
等いわゆるarray_like
を与えることができます。
zeros_like(array) ⇒ 0で初期化
array
で与えた配列と同じ形状の配列を、0
で初期化して作成します。
A = np.zeros((2,2))
# A → array([[0., 0.],
# [0., 0.]])
B = np.zeros_like(A)
# B → array([[0., 0.],
# [0., 0.]])
ones_like(array) ⇒ 1で初期化
array
で与えた配列と同じ形状の配列を、1
で初期化して作成します。
A = np.zeros((2,2))
# A → array([[0., 0.],
# [0., 0.]])
B = np.ones_like(A)
# B → array([[1., 1.],
# [1., 1.]])
ones_full(array, val) ⇒ valで初期化
array
で与えた配列と同じ形状の配列を、val
で初期化して作成します。
A = np.zeros((2,2))
# A → array([[0., 0.],
# [0., 0.]])
B = np.full_like(A, 0.5)
# B → array([[0.5, 0.5],
# [0.5, 0.5]])
empty_like(array) ⇒ 初期化なし
array
で与えた配列と同じ形状の配列を、初期化せずに生成します。
初期値として、そのときたまたまメモリに残っていた値が使用されます。
A = np.zeros((2,2))
# A → array([[0., 0.],
# [0., 0.]])
B = np.empty_like(A)
# B → array([[2.23754644e-312, 2.05210913e-307],
# [3.32653424e-111, 1.13477778e+118]])
【応用】zeros, onesで真偽値配列を生成
生成する配列要素の型をdtype
で指定することができます(デフォルトfloat64
)。
dtype=bool
とすると、真偽値boolean
の配列を作成できます。
True
とFalse
から構成される、マスク式の初期化に便利です。
zeros(shape, dtype=bool)
→False
で初期化ones(shape, dtype=bool)
→True
で初期化
mask = np.zeros((2,2), dtype=bool)
# mask → array([[False, False],
# [False, False]])
mask = np.ones((2,2), dtype=bool)
# mask → array([[ True, True],
# [ True, True]])
おわりに
他にもnumpy
の記事を書いていますのでぜひ見てみてください!