効率的な計算のための NumPy ブロードキャスティング

NumPyBeginner
オンラインで実践に進む

はじめに

ブロードキャスティングは、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 つの配列の形状が互換性がある場合にも機能します。互換性の一般的なルールは次のとおりです。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 は末尾の次元(32)を比較し、それらが等しくなく、かつどちらも 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 コードを書くための重要なステップです。