33

私は NumPy を学んでいますが、オペレーター*が実際に何をしているのかよくわかりません。なんらかの掛け算のように見えますが、どのように決定されるのかはわかりません。ipython から:

In [1]: import numpy as np

In [2]: a=np.array([[1,2,3]])

In [3]: b=np.array([[4],[5],[6]])

In [4]: a*b
Out[4]: 
array([[ 4,  8, 12],
       [ 5, 10, 15],
       [ 6, 12, 18]])

In [5]: b*a
Out[5]: 
array([[ 4,  8, 12],
       [ 5, 10, 15],
       [ 6, 12, 18]])

In [6]: b.dot(a)
Out[6]: 
array([[ 4,  8, 12],
       [ 5, 10, 15],
       [ 6, 12, 18]])

In [7]: a.dot(b)
Out[7]: array([[32]])

行列の乗算を行っているように見えますが、 をb乗算するだけaで、その逆ではありません。何が起こっている?

4

2 に答える 2

28

これは少し複雑で、ブロードキャストの概念と、すべての numpy 操作が要素ごとに行われるという事実に関係しています。

  1. aは 1 行 3 列bの 2D 配列で、1 列 3 行の 2D 配列です。
  2. a * bそれらを要素ごとに乗算しようとする場合 (これは、操作を除くすべての基本操作が要素単位であるため、numpy が実行しようとすることですdot)、すべての次元で一致するように配列をブロードキャストする必要があります。
  3. 最初の配列は 1x3 で、2 番目の配列は 3x1 であるため、ブロードキャスト ルールに従って 3x3 マトリックスにブロードキャストできます。それらは次のようになります。
a = [[1, 2, 3],
     [1, 2, 3],
     [1, 2, 3]]

b = [[4, 4, 4],
     [5, 5, 5],
     [6, 6, 6]]

そして今、Numpy はそれらを要素ごとに乗算し、結果を得ることができます:

[[ 4,  8, 12],
 [ 5, 10, 15],
 [ 6, 12, 18]]

演算を実行.dotすると、標準の行列乗算が実行されます。ドキュメントの詳細

于 2013-08-17T22:27:57.397 に答える
10

*要素ごとの乗算を行います。

配列の形状が異なるため、ブロードキャストルールが適用されます。

In [5]: a.shape
Out[5]: (1, 3)

In [6]: b.shape
Out[6]: (3, 1)

In [7]: (a * b).shape
Out[7]: (3, 3)
  1. 最大の ndim の入力配列よりも小さい ndim を持つすべての入力配列には、形状の先頭に 1 が追加されます (ここでは適用されません)。
  2. 出力形状の各次元のサイズは、その次元のすべての入力サイズの最大値です。
  3. 特定の次元のサイズがその次元の出力サイズと一致するか、値が正確に 1 の場合、入力を計算に使用できます。
  4. 入力の形状の次元サイズが 1 の場合、その次元の最初のデータ エントリが、その次元に沿ったすべての計算に使用されます。言い換えれば、ufunc のステッピング機構は単にその次元に沿ってステップしません (その次元のストライドは 0 になります)。

したがって、結果の形状は(および次元(3, 3)のサイズの最大値) である必要があり、乗算を実行している間、numpy は a の最初の次元と b の 2 番目の次元 (サイズは 1) を通過しません。ab

結果の要素は、ブロードキャストされたとの[i][j]要素の積に等しくなります。ab[i][j]

(a * b)[0][0] == a[0][0] * b[0][0]
(a * b)[0][1] == a[0][1] * b[0][0]  # (not stepping through b's second dimension)
(a * b)[0][2] == a[0][2] * b[0][0]
(a * b)[1][0] == a[0][0] * b[1][0]  # (not stepping through a's first dimension)

etc.
于 2013-08-17T22:28:00.163 に答える