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

タイトル: 要素の更新
SEOタイトル: NumPy 配列要素の更新完全ガイド

この記事の要点
  • 単要素更新: arr[0] = 100 / 多次元は arr[1, 2] = 9
  • スライス代入: arr[1:3] = 0 でブロードキャスト
  • Boolean インデックス: arr[arr > 5] = 0 で条件一括更新
  • np.where(cond, x, y) で条件分岐 (新配列を返す、in-place ではない)
  • np.put / np.copyto / np.fill_diagonal / np.clip など便利関数
  • View と Copy の違い: スライスは View → 元配列も変わる、arr.copy() で独立
  • in-place vs new array: arr += 1 は in-place、arr = arr + 1 は新配列

単要素・スライスの更新

import numpy as np

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

# 1. 単要素更新
arr[0] = 100
# [100, 2, 3, 4, 5]

# 2. スライス代入 (右辺がスカラ → ブロードキャスト)
arr[1:3] = 0
# [100, 0, 0, 4, 5]

# 3. スライス代入 (右辺が配列)
arr[1:4] = [10, 20, 30]
# [100, 10, 20, 30, 5]

# 4. ステップ付きスライス
arr2 = np.arange(10)
arr2[::2] = -1   # 偶数 index を全部 -1
# [-1, 1, -1, 3, -1, 5, -1, 7, -1, 9]

# 5. 多次元配列
mat = np.zeros((3, 3))
mat[1, 2] = 5
mat[0, :] = [1, 2, 3]   # 1 行目を一括
mat[:, 1] = 9            # 2 列目を全部 9
# [[1, 9, 3],
#  [0, 9, 5],
#  [0, 9, 0]]

Boolean インデックス (条件一括更新)

NumPy 最大の武器。条件式から Boolean 配列を作って一括更新できます:

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

# 1. 条件で書き換え
arr[arr > 5] = 0
# [1, 5, 3, 0, 2, 0, 4]

# 2. 条件部分を計算
arr = np.array([1, 5, 3, 7, 2, 8, 4])
arr[arr > 5] = arr[arr > 5] * 10
# [1, 5, 3, 70, 2, 80, 4]

# 3. 複数条件 (& で and、| で or、~ で not。括弧必須)
arr = np.array([1, 5, 3, 7, 2, 8, 4])
arr[(arr > 3) & (arr < 8)] = 0
# [1, 0, 3, 0, 2, 8, 0]

# 4. 多次元
mat = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
mat[mat > 5] = -1
# [[1, 2, 3], [4, 5, -1], [-1, -1, -1]]

np.where: 条件分岐

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

# 1. 三項演算子的: cond なら x, でなければ y
result = np.where(arr > 5, 0, arr)
# arr 自体は変わらない (新配列を返す)
# [1, 5, 3, 0, 2, 0, 4]

# 2. 別配列との組合せ
a = np.array([1, 2, 3, 4, 5])
b = np.array([10, 20, 30, 40, 50])
result = np.where(a >= 3, b, a)
# [1, 2, 30, 40, 50]

# 3. np.where(cond) は条件を満たす index を返す
arr = np.array([1, 5, 3, 7, 2, 8, 4])
idx = np.where(arr > 5)
# (array([3, 5]),)
arr[idx] = -1

その他の更新系関数

関数用途
np.put1 次元インデックスで複数値代入np.put(arr, [0, 2], [99, 88])
np.copyto条件付き上書きnp.copyto(dst, src, where=mask)
np.fill_diagonal対角成分を一括設定np.fill_diagonal(mat, 0)
arr.fill(x)全要素を x にarr.fill(0)
np.clip範囲外を切り詰めnp.clip(arr, 0, 100)
arr.flat[i]1 次元インデックスで多次元アクセスmat.flat[5] = 99
# np.put
arr = np.arange(10)
np.put(arr, [0, 2, 4], [99, 88, 77])
# [99, 1, 88, 3, 77, 5, 6, 7, 8, 9]

# np.copyto + where (条件付き上書き)
dst = np.zeros(5)
src = np.array([1, 2, 3, 4, 5])
mask = np.array([True, False, True, False, True])
np.copyto(dst, src, where=mask)
# [1, 0, 3, 0, 5]

# np.fill_diagonal
mat = np.ones((3, 3))
np.fill_diagonal(mat, 0)
# [[0, 1, 1], [1, 0, 1], [1, 1, 0]]

# np.clip (min/max でクリップ)
arr = np.array([-3, -1, 5, 12, 100])
np.clip(arr, 0, 10)
# [0, 0, 5, 10, 10]

# flat: 多次元を 1 次元のように扱う
mat = np.arange(12).reshape(3, 4)
mat.flat[5] = 99
# [[0, 1, 2, 3], [4, 99, 6, 7], [8, 9, 10, 11]]

View と Copy の重要な違い

NumPy のスライスはView (参照) を返します。View を通じて更新すると元配列も変わる:

# View (元と連動)
arr = np.array([1, 2, 3, 4, 5])
sub = arr[1:4]      # View
sub[0] = 99
print(arr)          # [1, 99, 3, 4, 5]  ← 元も変わる!

# Copy (独立)
arr = np.array([1, 2, 3, 4, 5])
sub = arr[1:4].copy()
sub[0] = 99
print(arr)          # [1, 2, 3, 4, 5]  ← 元は変わらない

# Boolean インデックスは Copy
arr = np.array([1, 2, 3, 4, 5])
sub = arr[arr > 2]
sub[0] = 99
print(arr)          # [1, 2, 3, 4, 5]  ← 元は変わらない

# Fancy インデックスも Copy
arr = np.array([1, 2, 3, 4, 5])
sub = arr[[0, 2, 4]]
sub[0] = 99
print(arr)          # [1, 2, 3, 4, 5]

# View かどうか確認
print(sub.base is arr)    # True なら View

in-place vs 新配列 (メモリ効率)

# in-place (メモリ効率良)
arr = np.arange(1000000)
arr += 1                 # ← 既存メモリを書き換え
arr *= 2

# 新配列 (元残るがメモリ 2 倍消費)
arr = np.arange(1000000)
arr = arr + 1            # ← 新配列を作成して再代入
arr = arr * 2

# 巨大配列なら in-place が必須
# in-place 系の関数: np.add(a, b, out=a) など out= で指定可能
np.add(arr, 1, out=arr)
np.multiply(arr, 2, out=arr)

# 関数では out= 引数で結果書込先を指定
result = np.empty_like(arr)
np.sqrt(arr, out=result)

多次元での更新パターン

# 画像処理風: RGB のうち R チャンネルだけ更新
img = np.zeros((100, 100, 3), dtype=np.uint8)
img[:, :, 0] = 255       # R チャンネルを最大

# 矩形領域を一括塗りつぶし
img[20:50, 30:70, :] = [255, 0, 0]   # 赤い長方形

# 円形マスクで更新
y, x = np.ogrid[:100, :100]
mask = (x - 50)**2 + (y - 50)**2 <= 30**2
img[mask] = [0, 255, 0]   # 緑の円

# 行/列の挿入 (要 reshape)
mat = np.arange(9).reshape(3, 3)
# 1 行追加 → np.vstack
mat = np.vstack([mat, [10, 11, 12]])
# 1 列追加 → np.hstack
mat = np.hstack([mat, [[20], [21], [22], [23]]])

FAQ

Q: arr[arr > 5] = 0 はなぜ in-place?
A: Boolean インデックスでの代入 (left-hand side) は元配列を直接書き換えます。右辺 (取得) の Boolean インデックスは Copy を返します。

Q: スライスでの代入が元配列を変えないようにしたい
A: arr[1:4].copy() で明示的にコピー。または最初から copy で作る。

Q: np.where と Boolean インデックス、どちらを使う?
A: 「新配列が欲しい」なら np.where、「元配列を更新」なら Boolean インデックス代入。