プロジェクトのgithubアドレス:bitcarmanlee easy-algorithm-interview-and-practice
誰もがスターを付け、メッセージを残し、一緒に学び、進歩することを歓迎します
1.ブロードキャスト(ブロードキャスト)メカニズム
numpyでのブロードキャストは非常に一般的であり、その使用法は、異なる形状のndarrayに対して対応する数値計算を実行するときに、対応する形状に一致するように小さいndarrayを大きいndarrayにブロードキャストして、2つが異なる形状を持っているように見せることです。対応する数値演算を実行できます。
2.放送ルール
1.最大のndimの入力配列よりも小さいndimを持つすべての入力配列には、形状の前に1が付いています。
2.出力形状の各次元のサイズは、その次元のすべての入力サイズの最大値です。
3.特定の次元の入力がその次元の出力サイズと一致するか、値が正確に1である場合、入力を計算に使用できます。
4.入力の形状のディメンションサイズが1の場合、そのディメンションの最初のデータエントリが、そのディメンションに沿ったすべての計算に使用されます。言い換えると、ufuncのステッピング機構は、単にその次元に沿ってステップすることはありません(その次元のストライドは0になります)。
変換は
1です。すべての入力配列を配列の最長の形状に揃え、形状の不十分な部分
を前面に1を追加して埋めます。2。出力配列の形状は、の各軸の最大値です。入力配列の形状
3.。入力配列の軸の長さと出力配列の対応する軸の長さが同じであるか、その長さが1の場合、この配列を計算に使用でき
ます。そうでない場合、エラーが発生します。入力配列の軸の長さは1で、この軸を計算するときにこの軸の最初の値のセットを使用します
上記の説明は実際にはかなり抽象的なものです。いくつかの例を通して理解しましょう。
3.ケース分析
まず、ブロードキャストの最も簡単な方法である、スカラーでのベクトルの操作を見てみましょう。
import numpy as np
def t1():
array = np.arange(5)
print("array is: ", array)
array = array * 4
print("after broadcast, array is: ", array)
操作の結果は次のとおりです。
array is: [0 1 2 3 4]
after broadcast, array is: [ 0 4 8 12 16]
これについては何も言うことはありません。より一般的な要素ごとの計算方法は、基本的に、配列の各位置に4を掛けることです。計算プロセスは、スカラー4を5 * 1の次元にブロードキャストすることとして理解できます。
def t2():
array = np.arange(12).reshape(4, 3)
print("array is: ", array)
print(array.mean(0))
print(array.mean(0).shape)
print(array.mean(1))
print(array.mean(1).shape)
array = array - array.mean(0)
print("after broadcast, array is: ", array)
array = array - array.mean(1)
print("after broadcast, array is: ", array)
出力結果は次のとおりです。
array is: [[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
[4.5 5.5 6.5]
(3,)
[ 1. 4. 7. 10.]
(4,)
after broadcast, array is: [[-4.5 -4.5 -4.5]
[-1.5 -1.5 -1.5]
[ 1.5 1.5 1.5]
[ 4.5 4.5 4.5]]
Traceback (most recent call last):
File "/Users/wanglei/wanglei/code/python/tfpractice/basic/Broadcast.py", line 81, in <module>
t2()
File "/Users/wanglei/wanglei/code/python/tfpractice/basic/Broadcast.py", line 29, in t2
array = array - array.mean(1)
ValueError: operands could not be broadcast together with shapes (4,3) (4,)
上記のコードでは、mean(0)の次元は(3、)です。次元(4、3)の配列で操作する場合、mean(0)の最後の次元は3であり、これはの最後の次元と同じです。 (4,3)。なので、スムーズに放送できます。ただし、mean(1)の次元は(4、)であり、(4,3)の最後の次元と等しくないため、ブロードキャストできません。
def t3():
array = np.arange(12).reshape(4, 3)
print("array is: ", array)
print(array.mean(0))
print(array.mean(0).shape)
print(array.mean(1))
print(array.mean(1).shape)
array = array - array.mean(0).reshape(1, 3)
print("after broadcast, array is: ", array)
結果は以下のとおりです。
array is: [[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
[4.5 5.5 6.5]
(3,)
[ 1. 4. 7. 10.]
(4,)
after broadcast, array is: [[-4.5 -4.5 -4.5]
[-1.5 -1.5 -1.5]
[ 1.5 1.5 1.5]
[ 4.5 4.5 4.5]]
def t4():
array = np.arange(12).reshape(4, 3)
print("array is: ", array)
print(array.mean(1).reshape(4, 1))
array = array - array.mean(1).reshape(4, 1)
print("after broadcast, array is: ", array)
結果は以下のとおりです。
array is: [[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
[[ 1.]
[ 4.]
[ 7.]
[10.]]
after broadcast, array is: [[-1. 0. 1.]
[-1. 0. 1.]
[-1. 0. 1.]
[-1. 0. 1.]]
mean(1)を(4,1)に変形すると、配列(4、3)の次元と比較して、最初の次元は同じで、2番目の次元は1であるため、スムーズにブロードキャストできます。
def t5():
array = np.arange(24).reshape(2, 3, 4)
print("in the beginning, array is: ", array)
arrayb = np.arange(12).reshape(3, 4)
print("arrayb is: ", arrayb)
array = array - arrayb
print("after broadcast, array is: ", array)
運転結果
in the beginning, array is: [[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
arrayb is: [[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
after broadcast, array is: [[[ 0 0 0 0]
[ 0 0 0 0]
[ 0 0 0 0]]
[[12 12 12 12]
[12 12 12 12]
[12 12 12 12]]]
上記の配列の次元は(2、3、4)であり、arraybの次元は(3、4)であるため、ブロードキャストする場合、shape [0]の次元をコピーするのと同じです。
def t6():
array = np.arange(24).reshape(2, 3, 4)
print("in the beginning, array is: ", array)
arrayb = np.arange(8).reshape(2, 1, 4)
print("arrayb is: ", arrayb)
array = array - arrayb
print("after broadcast, array is: ", array)
def t7():
array = np.arange(24).reshape(2, 3, 4)
print("in the beginning, array is: ", array)
arrayb = np.arange(6).reshape(2, 3, 1)
print("arrayb is: ", arrayb)
array = array - arrayb
print("after broadcast, array is: ", array)
操作の結果は次のとおりです。
in the beginning, array is: [[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
arrayb is: [[[0 1 2 3]]
[[4 5 6 7]]]
after broadcast, array is: [[[ 0 0 0 0]
[ 4 4 4 4]
[ 8 8 8 8]]
[[ 8 8 8 8]
[12 12 12 12]
[16 16 16 16]]]
in the beginning, array is: [[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
arrayb is: [[[0]
[1]
[2]]
[[3]
[4]
[5]]]
after broadcast, array is: [[[ 0 1 2 3]
[ 3 4 5 6]
[ 6 7 8 9]]
[[ 9 10 11 12]
[12 13 14 15]
[15 16 17 18]]]
上記の2つの方法は、それぞれ形状[1]と形状[2]の寸法でブロードキャストされます。
4.まとめ
上記の例を組み合わせて、ブロードキャストの基本原則を要約し
ます。1.2つのアレイの次元を最後から比較します。
2.ディメンションが等しいか、値の1つが1の場合、ブロードキャスト可能であると見なされます。
3.ディメンションが欠落している場合は、無視できます。
4.ブロードキャストは、欠落しているディメンションまたは1のディメンションで実行されます。