Pythonの数値計算ライブラリNumPyには、多次元配列を1次元配列に変換(平坦化)するためのflattenとravelという2つのメソッドがあります。どちらも似た機能を提供しますが、いくつかの違いがあります。この記事では、flattenとravelの基本的な使い方と概要を説明し、それらの違いと使い分けについて解説します。
1. flatten の概要と基本的な使い方
概要
ndarray.flatten()は、多次元配列のコピーを1次元配列として返します。元の配列は変更されません。
基本的な使い方
import numpy as np # 2次元配列を作成 arr2d = np.array([[1, 2, 3], [4, 5, 6]]) print(f"Original array:\n{arr2d}") # flattenを使って1次元化 (コピーが返される) arr1d_flatten = arr2d.flatten() print(f"flatten: {arr1d_flatten}") # flattenで作成した配列を変更しても、元の配列は変わらない arr1d_flatten[0] = 100 print(f"flatten (modified): {arr1d_flatten}") print(f"Original array after modification:\n{arr2d}")
出力
Original array: [[1 2 3] [4 5 6]] flatten: [1 2 3 4 5 6] flatten (modified): [100 2 3 4 5 6] Original array after modification: [[1 2 3] [4 5 6]]
メモリレイアウトの指定 (order)
order引数を使うと、多次元配列を1次元化する際のメモリ上の配置順序を指定できます。
'C'(C言語スタイル)を選ぶと行優先、'F'(Fortranスタイル)を選ぶと列優先になります。デフォルトは'C'です。
arr2d = np.array([[1, 2, 3], [4, 5, 6]]) arr1d_flatten_c = arr2d.flatten(order='C') # Cスタイル(行優先) デフォルト arr1d_flatten_f = arr2d.flatten(order='F') # Fortranスタイル(列優先) print(f"flatten (order='C'): {arr1d_flatten_c}") print(f"flatten (order='F'): {arr1d_flatten_f}")
出力
flatten (order='C'): [1 2 3 4 5 6] flatten (order='F'): [1 4 2 5 3 6]
2. ravel の概要と基本的な使い方
概要
ndarray.ravel()は、多次元配列を1次元配列として返します。flattenとは異なり、ravelは可能な限り元の配列のビューを返そうとします。(ビューとは、元の配列のデータを共有する別の配列のことです。ビューを変更すると、元の配列も変更されます。)
ただし、メモリレイアウトによってはコピーが返される場合もあります。
基本的な使い方
import numpy as np # 2次元配列を作成 arr2d = np.array([[1, 2, 3], [4, 5, 6]]) print(f"Original array:\n{arr2d}") # ravelを使って1次元化 (可能な限りビューが返される) arr1d_ravel = arr2d.ravel() print(f"ravel: {arr1d_ravel}") # ravelで作成した配列(ビュー)を変更すると、元の配列も変更される arr1d_ravel[0] = 100 print(f"ravel (modified): {arr1d_ravel}") print(f"Original array after modification:\n{arr2d}")
出力
Original array: [[1 2 3] [4 5 6]] ravel: [1 2 3 4 5 6] ravel (modified): [100 2 3 4 5 6] Original array after modification: [[100 2 3] [4 5 6]]
上記の例では、arr1d_ravel は arr2d のビューなので、arr1d_ravel への変更が arr2d にも反映されています。
メモリレイアウトの指定 (order)
flattenと同様に、order引数でメモリレイアウトを指定できます。
arr2d = np.array([[1, 2, 3], [4, 5, 6]]) arr1d_ravel_c = arr2d.ravel(order='C') # Cスタイル(行優先) デフォルト arr1d_ravel_f = arr2d.ravel(order='F') # Fortranスタイル(列優先) print(f"ravel (order='C'): {arr1d_ravel_c}") print(f"ravel (order='F'): {arr1d_ravel_f}")
出力
ravel (order='C'): [1 2 3 4 5 6] ravel (order='F'): [1 4 2 5 3 6]
order='F'を指定した場合や、配列がFortran順序で連続している場合など、ravelはビューではなくコピーを返すことがあります。
ビューが欲しいのかコピーが欲しいのか明確でない場合は、ravelの戻り値に対してbase属性をチェックすることで、それがビューなのかコピーなのかを判別できます。ビューであればbase属性は元の配列を指し、コピーであればNoneを返します。
arr = np.array([[1, 2], [3, 4]], order='F') arr1d_ravel = arr.ravel() print(arr1d_ravel.base is arr) # False コピーが返された print(arr1d_ravel.base is None) # False コピーの場合でもNoneとは限らない arr = np.array([[1, 2], [3, 4]], order='C') arr1d_ravel = arr.ravel() print(arr1d_ravel.base is arr) # True ビューが返された
flatten と ravel の違い
| 機能 | flatten |
ravel |
|---|---|---|
| 戻り値 | 常にコピーを返す | 可能な限りビューを返す(メモリレイアウトによってはコピーを返す) |
| 元の配列への影響 | 元の配列は変更されない | ビューが返された場合、ビューの変更は元の配列に影響する |
| メモリ使用量 | コピーを作成するため、メモリ使用量が増える可能性がある | ビューの場合はメモリ使用量が少ない。ただし、コピーが作成される場合もある |
| 速度 | コピーの作成に時間がかかる場合がある | 一般的にflattenより高速(特に大きな配列の場合) |
order引数 |
'C', 'F', 'A', 'K' |
'C', 'F', 'A', 'K' |
flatten と ravel の使い分け
flatten- 元の配列を変更したくない場合
- 1次元化された配列のコピーが必要な場合
ravel- メモリ効率を優先する場合(不要なコピーを避けたい場合)
- 1次元化された配列を通じて、元の配列も変更したい場合
- 速度が重要な場合(特に大きな配列)
まとめ
flattenとravelは、どちらもNumPy配列を1次元化するメソッドですが、flattenは常にコピーを返し、ravelは可能な限りビューを返します(ただし、メモリレイアウトによってはコピーを返すこともあります)。メモリ効率や処理速度を意識して使い分けることが重要です。元の配列を変更したくない場合はflatten、変更したい場合やメモリ効率を優先する場合はravelを使用します。
[PR]
現場で使える!NumPyデータ処理入門 機械学習・データサイエンスで役立つ高速処理手法 (AI & TECHNOLOGY) [ 吉田 拓真 ]
RとPythonで学ぶ[実践的]データサイエンス&機械学習【増補改訂版】 [ 有賀友紀、大橋俊介 ]
Pythonプログラミングパーフェクトマスター[最新Visual Studio Code対応 第4版] [ 金城俊哉 ]