概要(ブロードキャストは「形が違っても自然に計算させる」仕組み)
NumPy のブロードキャストは、形状(shape)が違う配列どうしの演算を可能にする仕組みです。ポイントは「末尾の次元から見て、同じ長さか長さ1なら合わせられる」「長さ1の次元は自動的に“伸びる”」「実データを複製せずに仮想拡張で高速」。初心者は「shape を確認→合わせたい軸に長さ1の次元を足す→そのまま演算する」型を覚えると、for ループを書かずにスッと解決できます。
基本の使い方(ここが重要)
スカラーと配列の演算(全要素に同じ値を適用)
import numpy as np
x = np.array([1, 2, 3])
print(x + 10) # → [11 12 13]
print(x * 2) # → [2 4 6]
Pythonスカラーは自動で全要素に“伸びる”ので、配列全体へ一括で適用できます。
行列と行ベクトル(列方向に伸びる)
import numpy as np
M = np.array([[1, 2, 3],
[4, 5, 6]]) # shape=(2,3)
v = np.array([10, 20, 30]) # shape=(3,)
print(M + v)
# 各行の3列へ [10,20,30] が足される
Python末尾の次元が一致しているので、列方向へ自動拡張されて加算されます。
行列と列ベクトル(行方向に伸びる)
import numpy as np
M = np.array([[1, 2, 3],
[4, 5, 6]]) # shape=(2,3)
u = np.array([100, 200]).reshape(2, 1) # shape=(2,1)
print(M + u)
# 1行目に100、2行目に200を各列へ足す
Python長さ1の次元は“伸びる”ので、行方向に拡張されて計算されます。
ブロードキャストのルール(形合わせの考え方を深掘り)
ルールの要約(末尾から見て整合性チェック)
- 次元数をそろえる: 次元の少ない配列は、先頭側に長さ1の次元があるとみなされます(仮想的に追加される)。
- 各次元の整合性: 対応する次元で「サイズが同じ」または「どちらかが1」ならOK。両方とも1以外で違うならNG。
- 拡張の仕方: サイズ1の次元は、相手のサイズに合わせて仮想的に繰り返される(メモリコピーはしない)。
形を意図的に合わせるテクニック(np.newaxis / reshape)
import numpy as np
x = np.array([1, 2, 3]) # shape=(3,)
col = x[:, np.newaxis] # shape=(3,1) 列ベクトル化
row = x[np.newaxis, :] # shape=(1,3) 行ベクトル化
M = np.arange(9).reshape(3, 3) # shape=(3,3)
print(M + col) # 各行に [1,2,3] を縦方向で足す
print(M + row) # 各列に [1,2,3] を横方向で足す
Pythonnp.newaxis は「次元を1つ増やす」ための最短手。reshape(…, 1) でも同じ効果が得られます。
典型パターン(前処理・正規化・距離計算)
列方向・行方向の標準化(平均0・分散1)
import numpy as np
X = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0]]) # shape=(3,3)
# 列方向(各列の平均と標準偏差)
mu = X.mean(axis=0) # shape=(3,)
sigma = X.std(axis=0) # shape=(3,)
Z = (X - mu) / sigma # 列ごとに標準化
# 行方向(各行の平均と標準偏差)
mu_row = X.mean(axis=1)[:, None] # shape=(3,1)
sigma_row = X.std(axis=1)[:, None]
Z_row = (X - mu_row) / sigma_row
Python平均・標準偏差の shape を「列なら (n,)」「行なら (n,1)」に合わせるだけで、一括標準化できます。
min-max 正規化(0〜1へ)
import numpy as np
X = np.array([[10.0, 20.0, 30.0],
[15.0, 25.0, 35.0]])
mn = X.min(axis=0) # 各列の最小
mx = X.max(axis=0) # 各列の最大
Y = (X - mn) / (mx - mn)
Python列ごとの最小・最大を列ベクトル形にすると、配列全体を一発でスケーリングできます。
すべての組み合わせ距離(行どうしの差の二乗和)
import numpy as np
A = np.array([[1.0, 2.0], [3.0, 4.0]]) # shape=(2,2)
B = np.array([[5.0, 6.0], [7.0, 8.0]]) # shape=(2,2)
# A の各行と B の各行のユークリッド距離を 2x2 で出す
diff = A[:, None, :] - B[None, :, :] # shape=(2,2,2)
dist2 = (diff ** 2).sum(axis=2) # 各行の二乗和 → shape=(2,2)
print(dist2)
Python[:, None, :] や [None, :, :] で「行数を交差させる軸」を増やすのがコツ。二次元の距離行列がループ無しに作れます。
よくある落とし穴(形不一致・意図しない拡張・keepdims)
両方が1以外でサイズが違うとエラー
import numpy as np
A = np.ones((2, 3))
B = np.ones((4, 3))
# A + B # 2 と 4(行)が合わない → エラー
Python「どちらかが1」か「同じ長さ」でない軸は合わせられません。足りない側に長さ1の次元を足す発想を持つと回避できます。
意図しない方向へ拡張される(軸の取り違え)
import numpy as np
X = np.arange(6).reshape(2, 3) # (2行,3列)
v = np.array([10, 20]) # (2,)
# X + v は「列方向」に合わない(3 と 2 が不一致)
# 行方向に足したいなら v を (2,1) にする
print(X + v[:, None]) # 行方向の拡張で意図通り
Python「どの軸で合わせたいか」を shape で表現する癖をつけると、取り違えが消えます。
集計後の形が変わって困る(keepdims を使う)
import numpy as np
X = np.arange(6).reshape(2, 3)
col_sum = X.sum(axis=0) # shape=(3,)
# そのままだと (2,3) と (3,) のブロードキャストになる(列方向)
# 行方向に合わせたい等、軸を明示したいときは keepdims
col_sum_keep = X.sum(axis=0, keepdims=True) # shape=(1,3)
print(X - col_sum_keep) # 明快に列方向で拡張
Pythonkeepdims=True は「集計後もその軸を長さ1で残す」。拡張方向を明示できて安全です。
例題で身につける(定番から一歩先まで)
例題1:列ごとの標準化(列方向)
import numpy as np
X = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0]])
mu = X.mean(axis=0)
sd = X.std(axis=0)
Z = (X - mu) / sd
print(Z.round(2))
Python例題2:行ごとのセンタリング(行方向)
import numpy as np
X = np.array([[10.0, 11.0, 12.0],
[20.0, 21.0, 22.0]])
row_mean = X.mean(axis=1)[:, None] # (2,1)
Xc = X - row_mean
print(Xc)
Python例題3:列オフセットの一括加算
import numpy as np
M = np.array([[1, 2, 3],
[4, 5, 6]])
offs = np.array([10, 20, 30]) # (3,)
print(M + offs)
Python例題4:全組み合わせの差分二乗和(距離行列)
import numpy as np
A = np.array([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]]) # 3点
B = np.array([[1.0, 1.0], [2.0, 0.0]]) # 2点
d = A[:, None, :] - B[None, :, :] # (3,2,2)
dist2 = (d ** 2).sum(axis=2) # (3,2)
print(dist2)
Pythonまとめ
ブロードキャストの核は「末尾の次元から見て、同じ長さか長さ1なら合わせられる」「長さ1の次元は自動拡張」「実データは複製しない」。shape を常に確認し、合わせたい方向に長さ1の次元を追加(np.newaxis や reshape)する型を身につけると、ループなしで前処理・正規化・距離計算まで一気に書けます。keepdims で集計後の形を整え、軸の取り違えをなくす。これを体に入れれば、初心者でも短く、速く、壊れない数値計算が自然に書けるようになります。
