データの処理をする時にnumpy arrayをいじる時が度々あります。
データ量が多くなるとデータ処理のパフォーマンスを考えざるを得なくなります。
色々パフォーマンスチューニングのポイントがありますが、
その中で影響の大きい一つが、numpyのデータをcopyしてるかどうかになります。
例えば、下記の例を見ましょう。
a = np.zeros(10000000)
# 1. copyせずに元データを書き換え
a *= 2
# 2. 元データをcopyし作業
b = a * 2
2 は implicit copy が行われているので、1 より何倍も遅くなります。
実際に速度を測ってみると、
%%timeit a = np.zeros(10000000)
a *= 2
# 結果
# 100 loops, best of 3: 5.86 ms per loop
%%timeit a = np.zeros(10000000)
b = a * 2
# 結果
# 10 loops, best of 3: 22.4 ms per loop
ご覧の通り、約3~4倍遅くなります。
この copy しているかどうかを判断するためには、そのnumpy arrayの base arrayを確認する必要があります。
下記は私がよく使う関数です。
def get_data_base(arr):
# 与えられた numpy arrayの実データになる base array を返す
base = arr
while isinstance(base.base, np.ndarray):
base = base.base
return base
def arrays_share_data(x, y):
# 二つの numpy array が同じベースなのかを判別する
return get_data_base(x) is get_data_base(y)
上記の関数を使うと、二つのarrayが同じベースを持っているのかを確認できます。
例えば、下記のように同じ処理に見えますが、パフォーマンスの差が出る処理を確認できます。
a = np.arange(3)
# array([0, 1, 2])
b = a.flatten()
# array([0, 1, 2])
c = a.ravel()
# array([0, 1, 2])
arrays_share_data(a, b)
# False
arrays_share_data(a, c)
# True
他の例として、全然違う形に見えてもベースが同じの場合もあります。
a = np.arange(3)
# array([0, 1, 2])
b = a[1:]
# array([1, 2])
arrays_share_data(a, b)
# True
データが増えれば増えるほど、こんな小さいことが大きく影響が出てきます。
特に機械学習のモデルを学習してる時に loop処理のたびに numpy arrayを
transposeしたり、flattenしたりすると限りなく遅くなる場合が多いです。気をつけましょう。
もっと詳しい情報が知りたい方は、初心者にも分かりやすいこの本をおすすめします。
http://ipython-books.github.io/