8.

NumPy 多次元配列の構造確認完全ガイド (shape / ndim / dtype / reshape)

編集
この記事の要点
  • NumPy 配列の構造確認 4 大属性: shape / ndim / size / dtype
  • shape は次元ごとの長さの tuple、ndim は次元数、size は総要素数、dtype は要素の型
  • メモリサイズ確認: itemsize (1 要素のバイト数) × size = nbytes
  • 形状変換: reshape / flatten / ravel / transpose
  • メモリレイアウト: C 順 (行優先) がデフォルト、order="F" で Fortran 順 (列優先)

NumPy 配列の主要属性

NumPy ndarray はベクトル化計算と多次元データの基盤です。Broadcasting や行列演算でハマったとき、まず形状 (shape) を確認するのが鉄則です。

属性戻り値用途
arr.shapetuple各次元の長さ
arr.ndimint次元数
arr.sizeint総要素数
arr.dtypedtype要素の型 (int32, float64...)
arr.itemsizeint1 要素のバイト数
arr.nbytesint配列全体のバイト数
arr.flagsflagsメモリレイアウト (C/F 順) など
arr.stridestuple各軸を 1 進むのに必要なバイト数

具体例

import numpy as np

# 2 次元配列 (3 行 4 列)
arr = np.array([
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
])

arr.shape        # (3, 4)
arr.ndim         # 2
arr.size         # 12
arr.dtype        # dtype('int64')  (Windows では int32 のことも)
arr.itemsize     # 8 (int64 = 8 バイト)
arr.nbytes       # 96 (8 * 12)

# 3 次元配列 (バッチ画像)
imgs = np.zeros((32, 224, 224, 3), dtype=np.float32)
imgs.shape       # (32, 224, 224, 3)
imgs.ndim        # 4
imgs.size        # 32*224*224*3 = 4_816_896
imgs.nbytes      # 19_267_584 (約 19 MB)

np.info() / repr() でまとめて確認

np.info(arr)
# class:  ndarray
# shape:  (3, 4)
# strides:  (32, 8)
# itemsize:  8
# aligned:  True
# contiguous:  True
# fortran:  False
# data pointer: 0x...
# byteorder:  little
# byteswap:  False
# type: int64

print(repr(arr))
# array([[ 1,  2,  3,  4],
#        [ 5,  6,  7,  8],
#        [ 9, 10, 11, 12]])

dtype 一覧

dtypeサイズ範囲 / 説明
int8 / uint81 byte-128~127 / 0~255 (画像で頻出)
int16 / uint162 byte音声 PCM 等
int32 / uint324 byteWindows 規定の int
int64 / uint648 byteLinux 規定の int
float162 byte半精度 (GPU 推論)
float324 byte単精度 (深層学習標準)
float648 byte倍精度 (Python の float 相当)
complex64/1288/16 byte複素数
bool_1 byteTrue/False
object_Python オブジェクト (遅いので避ける)
<U1040 byteUnicode 文字列 (最大 10 文字)
# dtype 指定
arr = np.array([1, 2, 3], dtype=np.float32)
arr.dtype                 # dtype('float32')

# 型変換
arr2 = arr.astype(np.int8)

# よくあるバグ: float が混じると全体が float に
arr = np.array([1, 2, 3, 4.5])
arr.dtype                 # dtype('float64')   ← int じゃない!

形状変換

a = np.arange(12)
a.shape              # (12,)

# reshape (新しい view を返す)
b = a.reshape(3, 4)
b.shape              # (3, 4)

# -1 で自動推論 (1 つだけ可)
c = a.reshape(2, -1)         # (2, 6)
d = a.reshape(-1, 4)         # (3, 4)

# 平坦化
b.flatten()          # コピー (新規配列)
b.ravel()            # view (元と共有)

# 軸の入れ替え
img = np.zeros((224, 224, 3))   # H, W, C
img_chw = img.transpose(2, 0, 1)  # C, H, W (PyTorch 形式)
img.shape, img_chw.shape          # (224, 224, 3), (3, 224, 224)

# 次元追加
v = np.array([1, 2, 3])           # shape (3,)
v[:, None].shape                  # (3, 1)
v[None, :].shape                  # (1, 3)
np.expand_dims(v, axis=0).shape   # (1, 3)

Broadcasting の前提として shape を見る

NumPy の Broadcasting は末尾から各次元を比較し、同じか 1 なら適合します。事故を避けるには毎回 shape を確認します。

A = np.ones((3, 4))      # shape (3, 4)
B = np.ones(4)           # shape (4,)   → 末尾合致、(1, 4) に拡張
C = A + B                # shape (3, 4)

D = np.ones((3, 1))      # shape (3, 1)
E = A + D                # shape (3, 4)   ← 列方向に拡張

F = np.ones((3,))        # shape (3,)
# A + F  → ❌ ValueError: shape (3,) cannot broadcast with (3, 4)
# A.shape の末尾が 4 で、F は 3 なので不一致

メモリレイアウト (C 順 / F 順)

NumPy 配列はデフォルトでC 順 (行優先)。Fortran や MATLAB から移植したコードは F 順を期待することがあります。

arr_c = np.arange(12).reshape(3, 4)         # 規定で C 順
arr_f = np.arange(12).reshape(3, 4, order='F')

arr_c.flags['C_CONTIGUOUS']   # True
arr_c.flags['F_CONTIGUOUS']   # False

arr_c.strides                 # (32, 8)    行→列に進むのに 32 byte
arr_f.strides                 # (8, 24)    列方向に 8 byte

# transpose は基本 view (データは動かない)
arr_t = arr_c.T
arr_t.flags['C_CONTIGUOUS']   # False
arr_t.flags['F_CONTIGUOUS']   # True

list / Pandas との相互変換

# NumPy → Python list
arr.tolist()
# [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]

# Pandas DataFrame に
import pandas as pd
df = pd.DataFrame(arr, columns=['a', 'b', 'c', 'd'])
df.shape                  # (3, 4)
df.dtypes                 # int64 each

# DataFrame → NumPy
df.to_numpy()             # → ndarray
df.values                 # 旧 API (非推奨)

デバッグ Tips

# よくあるバグ調査の流れ
def debug_shape(name, arr):
    print(f"{name}: shape={arr.shape} ndim={arr.ndim} "
          f"dtype={arr.dtype} size={arr.size} nbytes={arr.nbytes}")

debug_shape('X', X)
debug_shape('W', W)
debug_shape('y', y)

# assert で形状を保証
def matmul(A, B):
    assert A.ndim == 2 and B.ndim == 2, f"need 2D, got {A.ndim}D and {B.ndim}D"
    assert A.shape[1] == B.shape[0], f"shape mismatch: {A.shape} @ {B.shape}"
    return A @ B

FAQ

Q: shapelen() の違いは?
A: len(arr) は最初の次元の長さ (= shape[0]) しか返しません。多次元は必ず shape

Q: メモリ使用量を減らしたい
A: 用途に応じて dtype を絞る。画像なら uint8、フラグなら bool。深層学習は float32 / float16 で十分なことが多い。

Q: shape が (N,)(N, 1) で何が違う?
A: 前者は 1 次元ベクトル、後者は 2 次元の列ベクトル。行列演算で動作が変わるため、Broadcasting の挙動を確認しながら使う。

編集
Post Share
子ページ

子ページはありません

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

最近更新/作成されたページ