NumPy:ブロードキャスティングの仕組み

NumPy では、形状の異なる配列同士でも計算ができることがあります。これをブロードキャスティングと呼びます。明示的にループを書かなくても、NumPy が自動的に配列の形状を揃えてくれる仕組みです。

基本的な例

配列とスカラー(単一の数値)の演算は、最も単純なブロードキャスティングです。

import numpy as np

a = np.array([1, 2, 3, 4, 5])
print(a * 2)  # [ 2  4  6  8 10]
print(a + 10) # [11 12 13 14 15]

スカラーが配列の各要素に「放送」されて、同じ形状になったかのように計算されます。

1次元配列と2次元配列

1次元配列と2次元配列の演算でも、ブロードキャスティングが働きます。

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

b = np.array([10, 20, 30])  # 3要素

print(a + b)
# [[11 22 33]
#  [14 25 36]]

1次元配列 b が各行に「放送」されて、2行3列の配列として扱われます。

ブロードキャスティングのルール

形状が異なる配列で計算するとき、NumPy は以下のルールで形状を揃えます。

ルール1:次元数を揃える

次元数が少ない配列の先頭に1を追加する。例:形状 (3,) は (1, 3) として扱われる

ルール2:サイズ1の次元を拡張

各次元で、サイズが1の方を相手のサイズに合わせる。サイズが1でも異なる場合はエラー

具体的に見てみましょう。

a = np.ones((3, 4))    # 形状 (3, 4)
b = np.array([1, 2, 3, 4])  # 形状 (4,)

# bは (1, 4) → (3, 4) に拡張される
print((a + b).shape)  # (3, 4)

列方向のブロードキャスト

列ベクトル(2次元で列が1)を使うと、列方向に放送されます。

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

b = np.array([[10],
              [20]])  # 形状 (2, 1)

print(a + b)
# [[11 12 13]
#  [24 25 26]]

reshape(-1, 1) で列ベクトルを作ると便利です。

b = np.array([10, 20]).reshape(-1, 1)
print(b.shape)  # (2, 1)

ブロードキャストできない例

両方のサイズが1でなく、かつ異なる場合はエラーになります。

a = np.ones((3, 4))  # 形状 (3, 4)
b = np.ones((3,))    # 形状 (3,) → (1, 3)

# (3, 4) と (1, 3) は列数が4と3で合わない
# print(a + b)  # ValueError

利点と注意点

利点

ループを書かずに済む。コードが簡潔になり、実行も高速

注意点

意図しないブロードキャストでバグになることも。形状をしっかり把握しておく

ブロードキャスティングを理解すると、NumPy の表現力が大きく広がります。最初は戸惑うかもしれませんが、形状の変化を意識しながら使ってみてください。