はじめに
ブロードキャスティングは、NumPy における基本的な概念であり、異なる形状の配列に対して要素ごとの算術演算を可能にします。この強力な機能により、明示的なループの必要がなくなり、より簡潔で計算効率の高いコードを作成できます。この実験では、ブロードキャスティングのルールを学び、Python スクリプトを作成・実行して実践的な例に適用します。
ブロードキャスティングは、NumPy における基本的な概念であり、異なる形状の配列に対して要素ごとの算術演算を可能にします。この強力な機能により、明示的なループの必要がなくなり、より簡潔で計算効率の高いコードを作成できます。この実験では、ブロードキャスティングのルールを学び、Python スクリプトを作成・実行して実践的な例に適用します。
ブロードキャスティングの最も単純な形式は、配列と単一の数値(スカラー)の間で演算を実行する場合に発生します。NumPy は、スカラーを配列の形状に合わせて自動的に「拡張」または「ブロードキャスト」します。
まず、画面左側のファイルエクスプローラーで broadcasting.py ファイルを見つけます。それをダブルクリックしてエディターで開きます。
次に、broadcasting.py の内容を以下のコードに置き換えます。このコードは、1 次元の NumPy 配列を作成し、それをスカラー値で乗算します。
import numpy as np
## Create a 1D array
a = np.array([1.0, 2.0, 3.0])
## Define a scalar
b = 2.0
## Multiply the array by the scalar
## The scalar 'b' is broadcast to the shape of 'a'
result = a * b
print("Array 'a':", a)
print("Scalar 'b':", b)
print("Result of a * b:", result)
結果を確認するには、スクリプトを実行する必要があります。画面下部のターミナルパネルにある + アイコンをクリックし、「Terminal」を選択してターミナルを開きます。次に、次のコマンドを実行します。
python broadcasting.py
配列 a の各要素が 2.0 で乗算された以下の出力が表示されるはずです。
Array 'a': [1. 2. 3.]
Scalar 'b': 2.0
Result of a * b: [2. 4. 6.]
ブロードキャスティングは、2 つの配列の形状が互換性がある場合にも機能します。互換性の一般的なルールは次のとおりです。2 つの配列の次元を右から左へ比較する場合、各次元のペアは等しいか、または一方の次元が 1 である必要があります。
1 次元配列を 2 次元配列に加算する例を見てみましょう。1 次元配列は、2 次元配列の各行にブロードキャストされます。
broadcasting.py ファイルを以下のコードに更新してください。
import numpy as np
## Create a 2D array (shape: 2, 3)
a = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
## Create a 1D array (shape: 3,)
b = np.array([10.0, 20.0, 30.0])
## Add the two arrays
## 'b' is broadcast to shape (2, 3) to match 'a'
## It becomes [[10. 20. 30.], [10. 20. 30.]] internally
result = a + b
print("Array 'a' (shape {}):\n{}".format(a.shape, a))
print("Array 'b' (shape {}): {}".format(b.shape, b))
print("Result of a + b:\n", result)
ターミナルでスクリプトを再度実行します。
python broadcasting.py
出力は、1 次元配列 b が 2 次元配列 a の各行に加えられたことを示しています。
Array 'a' (shape (2, 3)):
[[1. 2. 3.]
[4. 5. 6.]]
Array 'b' (shape (3,)): [10. 20. 30.]
Result of a + b:
[[11. 22. 33.]
[14. 25. 36.]]
配列の形状がルールに従って互換性がない場合、ブロードキャスティングは失敗します。これにより ValueError が発生します。これがいつ発生するかを理解することは、デバッグにとって非常に重要です。
不互換な形状を持つ操作を試してみましょう。ここでは、形状 (2, 3) の配列と形状 (2,) の配列を加算しようとします。NumPy は末尾の次元(3 と 2)を比較し、それらが等しくなく、かつどちらも 1 でないことを発見します。これによりエラーが発生します。
broadcasting.py ファイルを以下のコードを含むように変更してください。
import numpy as np
## Create a 2D array (shape: 2, 3)
a = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
## Create an incompatible 1D array (shape: 2,)
b = np.array([1.0, 2.0])
print("Array 'a' (shape {}):\n{}".format(a.shape, a))
print("Array 'b' (shape {}): {}".format(b.shape, b))
## This will raise a ValueError
try:
result = a + b
except ValueError as e:
print("\nError:", e)
ターミナルからスクリプトを実行します。
python broadcasting.py
予想どおり、プログラムは ValueError を捕捉し、形状が一致しないことを説明するエラーメッセージを出力します。これは、不互換な形状に対する正しく予期された動作です。
Array 'a' (shape (2, 3)):
[[1. 2. 3.]
[4. 5. 6.]]
Array 'b' (shape (2,)): [1. 2.]
Error: operands could not be broadcast together with shapes (2,3) (2,)
ブロードキャスティングを実践的な問題に適用してみましょう。ベクトル量子化(VQ)は、データ圧縮や分類で使用される技術です。その主要なステップは、「コードブック」から与えられた「観測」ベクトルに最も近い「コード」ベクトルを見つけることです。ブロードキャスティングにより、この計算が効率化されます。
観測(例:アスリートの体重と身長)と、異なるアスリートタイプを表すコードブックがあると想像してください。観測がどのタイプに最も近いかを見つけたいとします。
broadcasting.py のコードを以下に置き換えてください。
import numpy as np
## An observation vector (e.g., weight, height)
observation = np.array([111.0, 188.0])
## A codebook of vectors
codes = np.array([[102.0, 203.0],
[132.0, 193.0],
[45.0, 155.0],
[57.0, 173.0]])
## Use broadcasting to subtract the observation from all codes at once
## observation (2,) is broadcast to (4, 2)
diff = codes - observation
## Calculate the squared Euclidean distance
dist_sq = np.sum(diff**2, axis=-1)
## Find the index of the minimum distance
closest_index = np.argmin(dist_sq)
## Get the closest code from the codebook
closest_code = codes[closest_index]
print("Observation:", observation)
print("Codebook:\n", codes)
print("Distances squared:", dist_sq)
print("Closest code index:", closest_index)
print("Closest code:", closest_code)
ターミナルでスクリプトを実行します。
python broadcasting.py
出力には、観測から各コードまでの二乗距離が表示され、最も近い一致コードベクトルが特定されます。ブロードキャスティングのおかげで、この計算全体が明示的な Python ループなしで実行されました。
Observation: [111. 188.]
Codebook:
[[102. 203.]
[132. 193.]
[ 45. 155.]
[ 57. 173.]]
Distances squared: [ 306. 466. 5445. 3141.]
Closest code index: 0
Closest code: [102. 203.]
この実験では、NumPy のブロードキャスティングの基本を学びました。スカラー値を配列にブロードキャストする単純なケースから始め、互換性のある 2 つの配列間のブロードキャストに進み、エラーを発生させる互換性のない形状を認識する方法を学びました。最後に、ブロードキャスティングを実践的なベクトル量子化問題に適用し、数値計算のためにクリーンで効率的、かつループフリーなコードを書くためのその力を実証しました。ブロードキャスティングを習得することは、効果的でプロフェッショナルな NumPy コードを書くための重要なステップです。