Krypf’s Diary

暇なときに書く

【Python】配列生成(初期化)時間まとめ

0 準備

型の確認.

type(None), type(0)
(NoneType, int)

適切なパラメータを設定する.

N = int(1e7)
M = int(1e4)

インポートも一応計測する.

%%timeit
import numpy as np
#112 ns ± 0.579 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

これはナノ秒なので考慮しなくて良い.

1 実行

1d配列

%timeit np.empty(N)
%timeit np.zeros(N)
%timeit np.ones(N)
%timeit np.zeros_like(np.empty(N))
%timeit np.ones_like(np.empty(N))
%timeit [None] * N
%timeit [0] * N
%timeit [None for i in range(N)]
%timeit [0 for i in range(N)]
'''
1.76 µs ± 32 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
11.3 ms ± 453 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
14.9 ms ± 182 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
19.9 ms ± 320 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
20.8 ms ± 931 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
35.9 ms ± 418 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
35.2 ms ± 489 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
417 ms ± 77.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
375 ms ± 15.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
'''

np.empty(N)が激烈に速い.ただし何が出力されるかその時々で異なるので速度は一定しないことに注意.100 μs ほどになることもあるが,それでも速い. また,0 と None は実行する順序を入れ替えたり%%timeitで独立のセルで実行したりすると,速度が逆転することがある.ということはどちらを使ってもほぼ同じ速度と見て差し支えない.

2d配列

%timeit np.empty([M,M])
%timeit np.zeros([M,M])
%timeit np.ones([M,M])
%timeit np.zeros_like(np.empty([M,M]))
%timeit np.ones_like(np.empty([M,M]))
%timeit [[None] * M] * M
%timeit [[0] * M] * M
%timeit [[None for j in range(M)] for i in range(M)]
%timeit [[0 for j in range(M)] for i in range(M)]
'''
3.58 µs ± 157 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
3.66 µs ± 51.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
378 ms ± 5.46 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
375 ms ± 3.22 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
384 ms ± 7.62 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
37.4 µs ± 1.08 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
37.4 µs ± 388 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
3.83 s ± 37.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
3.86 s ± 61.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
'''

やはりnp.empty([M,M])が速いがnp.zeros([M,M])も負けていない.意外に掛け算も善戦している.for 文は言わずもがな遅く,書き方の工夫もまだできるかもしれないが,初期化には使えない.

2 結果(表にまとめる)

1d配列

Code Mean Stdev Runs Loops
np.empty(N) 1.76 µs 32 ns 7 runs 1000000
np.zeros(N) 11.3 ms 453 µs 7 runs 100
np.ones(N) 14.9 ms 182 µs 7 runs 100
np.zeros_like(np.empty(N)) 19.9 ms 320 µs 7 runs 100
np.ones_like(np.empty(N)) 20.8 ms 931 µs 7 runs 10
[None] * N 35.9 ms 418 µs 7 runs 10
[0] * N 35.2 ms 489 µs 7 runs 10
[None for i in range(N)] 417 ms 77.7 ms 7 runs 1
[0 for i in range(N)] 375 ms 15.1 ms 7 runs 1

2d配列

Code Mean Stdev Runs Loops
np.empty([M,M]) 3.58 µs 157 ns 7 runs 100000
np.zeros([M,M]) 3.66 µs 51.5 ns 7 runs 100000
[[None] * M] * M 37.4 µs 1.08 µs 7 runs 10000
[[0] * M] * M 37.4 µs 388 ns 7 runs 10000
np.ones([M,M]) 378 ms 5.46 ms 7 runs 1
np.zeros_like(np.empty([M,M])) 375 ms 3.22 ms 7 runs 1
np.ones_like(np.empty([M,M])) 384 ms 7.62 ms 7 runs 1
[[None for j in range(M)] for i in range(M)] 3.83 s 37.5 ms 7 runs 1
[[0 for j in range(M)] for i in range(M)] 3.86 s 61.6 ms 7 runs 1

3 結論

配列生成だけならnp.empty(),初期化するならnp.zeros()が速い.

4 おまけ

np.empty_like も速い.

%timeit np.empty_like(np.empty(N))
%timeit np.empty_like(np.empty([M,M]))
'''
3.24 µs ± 59.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
7.1 µs ± 108 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
'''

参考記事

numpy.empty — NumPy v1.19 Manual

Notes: empty, unlike zeros, does not set the array values to zero, and may therefore be marginally faster. On the other hand, it requires the user to manually set all the values in the array, and should be used with caution. とある.

【NumPy入門 np.empty】要素を初期化せずに新しい配列を作る | 侍エンジニア塾ブログ(Samurai Blog) - プログラミング入門者向けサイト

【NumPy入門】配列の生成方法(1次元、2次元、高速化など) | 西住工房

NumPyで全要素を同じ値で初期化した配列ndarrayを生成 | note.nkmk.me

NumPyで空の配列ndarrayを生成するemptyとempty_like | note.nkmk.me

未初期化の配列を生成するnumpy.empty関数の使い方 - DeepAge