この記事では、NumPyのflatten関数について紹介します!
flattenという関数、他の様々なプログラミング言語に実装されている機能で、「多次元配列を一次元配列に変換する」という機能を持ちます。
例えばこの関数は、「二次元配列として表現されている画像データを一次元配列に変換してSVMに入力する」などの場面で活躍します。
この記事の要点は
- flattenは多次元配列を一次元配列に変換する関数である
- flattenは出力に新しい配列を作るので、その分だけnp.ravelより遅い
の二点です。
この解説にピンと来なかった方、この記事でflattenについて勉強しましょう!
ndarray.flattenの使い方
※この記事のコードは、jupyter notebookやjuputer labを使って書かれています。
コードを試すときは是非これらを使ってみてください。
flattenはndarray(np.array)のメソッドです。
似た機能をもつravelと違い、np.ravel/ndarray.ravelのように関数もメソッドもあるというわけではないので、ここだけ注意です。
# コード In [1]: import numpy as np
# コード In [2]: a = np.arange(12).reshape(4,-1) # Jupyterではprint関数を使わなくても、変数の中身を確認できますよ! a
# 出力結果 Out [2]: array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11]])
さて、flattenは多次元配列を一次元配列に変換してくれる関数です。
使い方は簡単、ndarrayオブジェクト.flatten()とすればOK!
# コード In [3]: b = a.flatten()
# コード In [4]: print("a: original") print(a) print("\nb") # 改行してから"b"という文字をprintします。 print(b)
# 出力結果 [4]: a: original [[ 0 1 2] [ 3 4 5] [ 6 7 8] [ 9 10 11]] b [ 0 1 2 3 4 5 6 7 8 9 10 11]
flattenとravelの違い
flattenは元の配列のコピーを返す関数
np.ravel関数も同じように多次元配列を一次元配列に変換してくれました。
ですがravelは変換後の配列の要素を変更すると、元の配列の要素も変わってしまいましたね。
flattenの返り値は新しい配列なので、そのようなことが無いのがravelとの違いです。
# コード In [5]: b[0] = 100
# コード In [6]: print("a: original") print(a) print("\nb") print(b)
# 出力結果 [6]: a: original [[ 0 1 2] [ 3 4 5] [ 6 7 8] [ 9 10 11]] b [100 1 2 3 4 5 6 7 8 9 10 11]
bの先頭要素を変更しましたが、aの先頭要素は変わっていませんね。
これがravel関数だとaの先頭要素も変わってしまいます。
flattenはravelより遅い
flattenは新しい配列を作るので、元の配列へのビューを返すだけのravelより動作が遅いことが知られています。
# コード In [7]: c = np.arange(10000).reshape(10,100,10)
# コード In [8]: # %%timeitコマンドでセル内のコードの実行時間を計測できます! %%timeit c.flatten()
# 出力結果 [8]: 2.4 µs ± 29.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
# コード In [9]: %%timeit c.ravel()
# 出力結果 [9]: 162 ns ± 2.15 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
機械学習などの実装において、元の配列を残して起きたい場合はflatten, 元の配列をそのまま使ってもいい場合はravelなどの使い分けをすることで、高速化できそうですね。
まとめ
この記事では、多次元配列を一次元配列に変換するメソッド、ndarray.flattenについて紹介しました。
ravelとの違い、わかっていただけたでしょうか。
新しい配列を作るかどうか、というのは非常に大きな違いです。
これらをしっかり理解して、flattenを機械学習や科学計算の実装の際に役立ててくれると嬉しいです!