9.

NumPy で多次元配列を 1 次元に変換する方法完全ガイド

編集
この記事の要点
  • arr.flatten() は常にコピーを返す(安全)
  • arr.ravel() は可能な限り view を返す(高速・省メモリ)
  • arr.reshape(-1) も同様に view を返す
  • C-order (行優先) がデフォルト、order="F" で列優先
  • 複数配列を結合して 1 次元化なら np.concatenate + reshape

flatten() と ravel() の違い

NumPy で多次元配列を 1 次元にする代表的な 2 つのメソッド:

import numpy as np

a = np.array([[1, 2, 3], [4, 5, 6]])
print(a.shape)    # (2, 3)

# 方法1: flatten(常にコピー)
b = a.flatten()
print(b)          # [1 2 3 4 5 6]
print(b.shape)    # (6,)
b[0] = 99
print(a[0, 0])    # 1 (元は変わらない)

# 方法2: ravel(可能なら view)
c = a.ravel()
print(c)          # [1 2 3 4 5 6]
c[0] = 99
print(a[0, 0])    # 99 (元も変わる!)
flatten()ravel()reshape(-1)
戻り値新しい配列(コピー)可能なら view可能なら view
メモリ使用2 倍同じ同じ
速度遅い(コピー発生)速い速い
元配列への影響なし(安全)あり(view 時)あり(view 時)
連続でない配列OKコピー発生コピー発生

reshape(-1) を使う方法

a = np.arange(24).reshape(2, 3, 4)
print(a.shape)     # (2, 3, 4)

# -1 は「残り全部」の意味
b = a.reshape(-1)
print(b.shape)     # (24,)
print(b)
# [ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]

# 多次元 → 別の多次元も可能
c = a.reshape(6, 4)
d = a.reshape(-1, 4)   # 行は自動計算

C-order と F-order

1 次元化のとき、要素を取り出す順序を指定できます:

a = np.array([[1, 2, 3],
              [4, 5, 6]])

# C-order(行優先、デフォルト)
print(a.flatten(order='C'))
# [1 2 3 4 5 6]   ← 行を順に並べる

# F-order(列優先、Fortran)
print(a.flatten(order='F'))
# [1 4 2 5 3 6]   ← 列を順に並べる

# K-order(メモリレイアウトに従う)
print(a.flatten(order='K'))
# C 配列なら C 順、F 配列なら F 順

# A-order(C 連続なら C、それ以外は F)
print(a.flatten(order='A'))
order意味用途
C行優先(NumPy デフォルト)Python / C と相性良
F列優先(Fortran)MATLAB / 線形代数で使用
Kメモリ順最速
A連続性優先あまり使われない

np.concatenate と np.stack

複数の配列を結合して 1 次元化する場合:

a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])

# concatenate: 既存の軸に沿って結合
c = np.concatenate([a.ravel(), b.ravel()])
# [1 2 3 4 5 6 7 8]

# または直接 reshape
c = np.concatenate([a, b], axis=None)
# axis=None で自動 1 次元化
# [1 2 3 4 5 6 7 8]

# np.hstack / np.vstack
d = np.hstack([a, b])    # 横方向(axis=1)
# [[1 2 5 6]
#  [3 4 7 8]]
e = np.vstack([a, b])    # 縦方向(axis=0)
# [[1 2] [3 4] [5 6] [7 8]]

Python のリスト内包表記との比較

import numpy as np

a = np.arange(1_000_000).reshape(1000, 1000)

# 方法1: Python ループ(遅い)
flat_py = [x for row in a for x in row]
# 約 200ms

# 方法2: numpy.ravel(速い)
flat_np = a.ravel()
# 約 0.001ms (20万倍速い)

# 速度差の理由:
# - Python ループは要素ごとに Python オブジェクト化
# - NumPy はメモリレイアウトをそのまま使う(コピー不要なら)

メモリ効率の違い

import numpy as np
import sys

a = np.arange(10_000_000)
print(a.nbytes / 1024 / 1024, "MB")   # 76 MB

# flatten はコピー → 倍の 152 MB を使う
b = a.flatten()

# ravel は view → 元と同じメモリ
c = a.ravel()
print(c.base is a)   # True(同じデータを共有)
print(b.base)        # None(独立)

view と copy の判定

ravel / reshape が view を返せないケースもあるので確認方法:

a = np.arange(12).reshape(3, 4)

b = a.ravel()
print(b.base is a)   # True (view)

# 連続でない配列(slice 等で抜き出した場合)
c = a[:, ::2]   # 1 つ飛ばしで列を抜く
print(c.flags.c_contiguous)   # False

d = c.ravel()
print(d.base is a)   # False (コピーになった)

# 明示的に view を強制
e = c.reshape(-1)
# これはエラーになる場合あり

# 確実に view を取りたいなら .ravel(order='K')
f = c.ravel(order='K')

PyTorch / TensorFlow の同等関数

NumPyPyTorchTensorFlow
arr.flatten()tensor.flatten()tf.reshape(t, [-1])
arr.ravel()tensor.view(-1)同上
arr.reshape(-1)tensor.reshape(-1)同上
arr.flatten(order="F")非対応非対応

機械学習での典型例

# CNN の出力を全結合層に通すとき
batch_size, channels, h, w = 32, 64, 7, 7
features = np.random.randn(batch_size, channels, h, w)

# (32, 64, 7, 7) → (32, 3136) に変換
flattened = features.reshape(batch_size, -1)
print(flattened.shape)   # (32, 3136)

# 画像 1 枚のピクセルベクトル化
image = np.random.randint(0, 256, (28, 28), dtype=np.uint8)
vector = image.flatten()   # shape (784,)

FAQ

Q: flatten した結果を変更しても元配列が変わる
A: flatten はコピーなので変わらないはず。ravelreshape(-1) なら view なので変わる。

Q: 巨大配列で flatten がメモリエラー
A: コピーが必要なので元の 2 倍メモリを要求する。ravel を使うか、ジェネレータで chunk 処理に切替。

Q: 順序を維持したまま列優先で取り出したい
A: .flatten(order="F") または .T.ravel()(転置 → ravel)。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 配列の作成
  2. 多次元配列の作成
  3. 要素の参照
  4. 要素の追加
  5. 要素の更新
  6. 要素の削除
  7. ブロードキャスト
  8. 多次元配列の構造の確認
  9. 多次元配列を1次元配列に変換
  10. 1次元配列を多次元配列に変換
  11. 要素の範囲指定
  12. 平均値の算出
  13. 行列を結合する方法