この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:T
更新日時:2026-06-11 07:12:00

タイトル: NumPy 配列の範囲指定(スライス・多次元・Boolean / Fancy Index)
SEOタイトル: NumPy 配列スライス完全ガイド([start:stop:step] / 多次元 / Boolean / np.where)

この記事の要点
  • 1 次元は Python リストと同じ a[start:stop:step]
  • 多次元はカンマ区切り a[r1:r2, c1:c2]
  • NumPy スライスはビュー(参照)。書き換えると元配列も変わる。コピーは .copy()
  • Boolean Index a[a > 0] は条件抽出に必須。Fancy Index は整数配列で任意位置を取得
  • np.where(cond, x, y) = 条件分岐の代表格。np.where(cond) 単独はインデックス取得

1 次元配列のスライス

import numpy as np
a = np.array([10, 20, 30, 40, 50, 60, 70])

a[2]                     # 30 — 単一要素
a[2:5]                   # [30, 40, 50] — stop は含まない
a[:3]                    # [10, 20, 30]
a[3:]                    # [40, 50, 60, 70]
a[::2]                   # [10, 30, 50, 70] — step=2
a[::-1]                  # [70, 60, ..., 10] — 逆順
a[-3:]                   # [50, 60, 70] — 末尾 3 個

多次元配列のスライス

カンマで次元を区切ります。「行, 列」「行, 列, 奥行き」の順:

A = np.arange(24).reshape(4, 6)
# [[ 0  1  2  3  4  5]
#  [ 6  7  8  9 10 11]
#  [12 13 14 15 16 17]
#  [18 19 20 21 22 23]]

A[1, 2]                  # 8 — (行1, 列2)
A[1]                     # [6, 7, 8, 9, 10, 11] — 1 行全部
A[:, 2]                  # [2, 8, 14, 20] — 2 列目全部
A[1:3, 2:5]              # [[8, 9, 10], [14, 15, 16]] — 部分行列

# 全行 + 偶数列
A[:, ::2]                # [[0,2,4],[6,8,10],[12,14,16],[18,20,22]]

# ... (Ellipsis) で「残り全部」
B = np.arange(24).reshape(2, 3, 4)
B[..., 1]                # 最後の次元の 1 番目
B[0, ...]                # 1 枚目の全要素 = B[0]

スライスはビュー(参照)

★ Python リストとの最大の違い。NumPy スライスは新配列を作らずビューを返します。書き換えると元配列も変わります:

a = np.array([1, 2, 3, 4, 5])
b = a[1:4]               # b は a のビュー
b[0] = 999
print(a)                 # [1, 999, 3, 4, 5] ← 元も変わる!

# コピーを取りたい場合
b = a[1:4].copy()
b[0] = 888
print(a)                 # [1, 999, 3, 4, 5] — 不変

# ビューかコピーか確認
b = a[1:4]
print(b.base is a)       # True — ビュー

c = a[[0, 2, 4]]         # Fancy Index は常にコピー
print(c.base is a)       # False

Boolean Index(条件で抽出)

a = np.array([10, -5, 30, -2, 50])

# 正の値だけ
a[a > 0]                 # [10, 30, 50]

# 複合条件(& / | / ~ を使う。and/or は使えない)
a[(a > 0) & (a < 40)]    # [10, 30]
a[~(a > 0)]              # [-5, -2]

# 多次元でも
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
A[A > 4]                 # [5, 6, 7, 8, 9] — 1 次元化される

# 行ごとに条件
mask = A.sum(axis=1) > 10
A[mask]                  # 行和が 10 超の行のみ

# 値を条件で置換
a = np.array([10, -5, 30, -2, 50])
a[a < 0] = 0             # [10, 0, 30, 0, 50]

Fancy Indexing(整数配列でランダムアクセス)

a = np.array([100, 200, 300, 400, 500])

# 任意の順で取得
a[[0, 2, 4]]             # [100, 300, 500]
a[[2, 2, 0]]             # [300, 300, 100] — 重複可

# 2 次元配列
A = np.arange(20).reshape(4, 5)
A[[0, 2], [1, 3]]        # [A[0,1], A[2,3]] = [1, 13]

# 行を選んで列スライス
A[[0, 2], :]             # 0 行目と 2 行目
A[[0, 2]][:, [1, 3]]     # 0,2 行 × 1,3 列
A[np.ix_([0, 2], [1, 3])]   # 同じ意味

# ソート結果を別配列で利用
order = np.argsort(a)    # [0, 1, 2, 3, 4]
a[order]                 # ソート後の値

np.where: 条件分岐の主役

a = np.array([10, -5, 30, -2, 50])

# (1) cond, x, y 形式: 三項演算的
np.where(a > 0, a, 0)    # [10, 0, 30, 0, 50] — 負は 0 に
np.where(a > 0, 'pos', 'neg')   # 文字列も可

# (2) cond だけ: インデックスを返す
np.where(a > 0)          # (array([0, 2, 4]),)
idx = np.where(a > 0)[0]
print(idx)               # [0 2 4]

# 多次元
A = np.array([[1, -2], [-3, 4]])
np.where(A < 0, 0, A)    # 負を 0 に
row, col = np.where(A < 0)
# row=[0, 1] col=[1, 0] — 負の値の位置

各種インデックスの一覧

記法返り値ビュー/コピー
整数a[2]スカラー
スライスa[1:4]サブ配列ビュー
多次元スライスA[1:3, 2:5]サブ行列ビュー
Booleana[a>0]1 次元配列コピー
Fancya[[0,2,4]]サブ配列コピー
np.wherenp.where(c, x, y)条件選択新配列
EllipsisA[..., 1]軸省略ビュー

よくあるエラー

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

# ❌ Python の and/or は使えない
# A[(A > 2) and (A < 8)]
# → ValueError: The truth value of an array with more than one element is ambiguous

# ✅ & / | / ~ を使う
A[(A > 2) & (A < 8)]

# ❌ カッコ忘れ(演算子優先順位)
# A[A > 2 & A < 8]      # & が先に評価される
# ✅ 必ずカッコ
A[(A > 2) & (A < 8)]

# ❌ 形状違いの Fancy Index
# A[[0,1,2], [0,1]]     # shape mismatch
# ✅ np.ix_ で外積
A[np.ix_([0,1,2], [0,1])]

FAQ

Q: スライスを書き換えたら元が変わって困る
A: arr[1:4].copy() でコピーを取る。Pandas DataFrame でも同様。

Q: 大量の Boolean Index で遅い
A: np.nonzero(mask) でインデックス化、np.compress、または numba で JIT。

Q: 多次元で「対角成分」が欲しい
A: np.diag(A) または A[np.arange(n), np.arange(n)]