web-dev-qa-db-ja.com

NumPy MatrixとArrayクラスの乗算の違いは何ですか?

Numpyのドキュメントでは、行列を操作するために行列の代わりに配列を使用することを推奨しています。ただし、オクターブ(最近まで使用していた)とは異なり、*は行列乗算を実行しないため、関数matrixmultipy()を使用する必要があります。これにより、コードが非常に読みにくくなると思います。

誰かが私の意見を共有し、解決策を見つけましたか?

128
elexhobby

matrixクラスの使用を避ける主な理由は、a)本質的に2次元であり、b)「通常の」numpy配列と比較して追加のオーバーヘッドがあることです。あなたがしているのが線形代数だけなら、どうしてもマトリックスクラスを自由に使用してください...個人的には、それが価値があるよりももっと厄介だと思います。

配列の場合(Python 3.5より前)、dotの代わりに matrixmultiply を使用します。

例えば。

import numpy as np
x = np.arange(9).reshape((3,3))
y = np.arange(3)

print np.dot(x,y)

または、numpyの新しいバージョンでは、単にx.dot(y)を使用します

個人的には、行列乗算を意味する*演算子よりもはるかに読みやすいと思います...

Python 3.5の配列の場合は、x @ yを使用します。

126
Joe Kington

NumPyarraysに対する操作とNumPymatrix

  • NumPy行列は、NumPy配列のサブクラス

  • NumPyarray操作はelement-wise(一度ブロードキャストが考慮される)

  • NumPymatrix演算は線形代数の通常の規則に従います

説明するためのコードスニペット:

>>> from numpy import linalg as LA
>>> import numpy as NP

>>> a1 = NP.matrix("4 3 5; 6 7 8; 1 3 13; 7 21 9")
>>> a1
matrix([[ 4,  3,  5],
        [ 6,  7,  8],
        [ 1,  3, 13],
        [ 7, 21,  9]])

>>> a2 = NP.matrix("7 8 15; 5 3 11; 7 4 9; 6 15 4")
>>> a2
matrix([[ 7,  8, 15],
        [ 5,  3, 11],
        [ 7,  4,  9],
        [ 6, 15,  4]])

>>> a1.shape
(4, 3)

>>> a2.shape
(4, 3)

>>> a2t = a2.T
>>> a2t.shape
(3, 4)

>>> a1 * a2t         # same as NP.dot(a1, a2t) 
matrix([[127,  84,  85,  89],
        [218, 139, 142, 173],
        [226, 157, 136, 103],
        [352, 197, 214, 393]])

ただし、これらの2つのNumPy行列が配列に変換されると、この操作は失敗します。

>>> a1 = NP.array(a1)
>>> a2t = NP.array(a2t)

>>> a1 * a2t
Traceback (most recent call last):
   File "<pyshell#277>", line 1, in <module>
   a1 * a2t
   ValueError: operands could not be broadcast together with shapes (4,3) (3,4) 

ただし、NP.dot構文を使用すると、arrays;この演算は、行列乗算のように機能します。

>> NP.dot(a1, a2t)
array([[127,  84,  85,  89],
       [218, 139, 142, 173],
       [226, 157, 136, 103],
       [352, 197, 214, 393]])

numPyマトリックスが必要になりましたか?つまり、線形代数計算にはNumPy配列で十分でしょう(正しい構文、つまりNP.dotを知っている場合)。

ルールは、引数(配列)が与えられた線形代数演算と互換性のある形状(m x n)を持っている場合は大丈夫、そうでなければNumPyがスローするということです。

私が遭遇した唯一の例外(他の可能性が高い)は逆行列の計算です。

以下は、純粋な線形代数演算(実際には、Numpyの線形代数モジュールから)を呼び出し、NumPy配列で渡されたスニペットです。

determinant配列の:

>>> m = NP.random.randint(0, 10, 16).reshape(4, 4)
>>> m
array([[6, 2, 5, 2],
       [8, 5, 1, 6],
       [5, 9, 7, 5],
       [0, 5, 6, 7]])

>>> type(m)
<type 'numpy.ndarray'>

>>> md = LA.det(m)
>>> md
1772.9999999999995

固有ベクトル/固有値ペア:

>>> LA.eig(m)
(array([ 19.703+0.j   ,   0.097+4.198j,   0.097-4.198j,   5.103+0.j   ]), 
array([[-0.374+0.j   , -0.091+0.278j, -0.091-0.278j, -0.574+0.j   ],
       [-0.446+0.j   ,  0.671+0.j   ,  0.671+0.j   , -0.084+0.j   ],
       [-0.654+0.j   , -0.239-0.476j, -0.239+0.476j, -0.181+0.j   ],
       [-0.484+0.j   , -0.387+0.178j, -0.387-0.178j,  0.794+0.j   ]]))

行列norm

>>>> LA.norm(m)
22.0227

qr分解

>>> LA.qr(a1)
(array([[ 0.5,  0.5,  0.5],
        [ 0.5,  0.5, -0.5],
        [ 0.5, -0.5,  0.5],
        [ 0.5, -0.5, -0.5]]), 
 array([[ 6.,  6.,  6.],
        [ 0.,  0.,  0.],
        [ 0.,  0.,  0.]]))

マトリックスrank

>>> m = NP.random.Rand(40).reshape(8, 5)
>>> m
array([[ 0.545,  0.459,  0.601,  0.34 ,  0.778],
       [ 0.799,  0.047,  0.699,  0.907,  0.381],
       [ 0.004,  0.136,  0.819,  0.647,  0.892],
       [ 0.062,  0.389,  0.183,  0.289,  0.809],
       [ 0.539,  0.213,  0.805,  0.61 ,  0.677],
       [ 0.269,  0.071,  0.377,  0.25 ,  0.692],
       [ 0.274,  0.206,  0.655,  0.062,  0.229],
       [ 0.397,  0.115,  0.083,  0.19 ,  0.701]])
>>> LA.matrix_rank(m)
5

マトリックスcondition

>>> a1 = NP.random.randint(1, 10, 12).reshape(4, 3)
>>> LA.cond(a1)
5.7093446189400954

inversionはNumPymatrixが必要です:

>>> a1 = NP.matrix(a1)
>>> type(a1)
<class 'numpy.matrixlib.defmatrix.matrix'>

>>> a1.I
matrix([[ 0.028,  0.028,  0.028,  0.028],
        [ 0.028,  0.028,  0.028,  0.028],
        [ 0.028,  0.028,  0.028,  0.028]])
>>> a1 = NP.array(a1)
>>> a1.I

Traceback (most recent call last):
   File "<pyshell#230>", line 1, in <module>
   a1.I
   AttributeError: 'numpy.ndarray' object has no attribute 'I'

しかしMoore-Penrose pseudoinverseはうまく動作するようです

>>> LA.pinv(m)
matrix([[ 0.314,  0.407, -1.008, -0.553,  0.131,  0.373,  0.217,  0.785],
        [ 1.393,  0.084, -0.605,  1.777, -0.054, -1.658,  0.069, -1.203],
        [-0.042, -0.355,  0.494, -0.729,  0.292,  0.252,  1.079, -0.432],
        [-0.18 ,  1.068,  0.396,  0.895, -0.003, -0.896, -1.115, -0.666],
        [-0.224, -0.479,  0.303, -0.079, -0.066,  0.872, -0.175,  0.901]])

>>> m = NP.array(m)

>>> LA.pinv(m)
array([[ 0.314,  0.407, -1.008, -0.553,  0.131,  0.373,  0.217,  0.785],
       [ 1.393,  0.084, -0.605,  1.777, -0.054, -1.658,  0.069, -1.203],
       [-0.042, -0.355,  0.494, -0.729,  0.292,  0.252,  1.079, -0.432],
       [-0.18 ,  1.068,  0.396,  0.895, -0.003, -0.896, -1.115, -0.666],
       [-0.224, -0.479,  0.303, -0.079, -0.066,  0.872, -0.175,  0.901]])
81
doug

3.5では、Python最後に 行列乗算演算子を取得しました 。構文はa @ bです。

19
Petr Viktorin

行列を扱う場合と同様に、配列を扱う場合、ドット演算子が異なる答えを与える状況があります。たとえば、次のことを想定します。

>>> a=numpy.array([1, 2, 3])
>>> b=numpy.array([1, 2, 3])

それらを行列に変換しましょう:

>>> am=numpy.mat(a)
>>> bm=numpy.mat(b)

これで、2つのケースの異なる出力を確認できます。

>>> print numpy.dot(a.T, b)
14
>>> print am.T*bm
[[1.  2.  3.]
 [2.  4.  6.]
 [3.  6.  9.]]
15
Jadiel de Armas

http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html からの参照

...、numpy.matrixクラスの使用はdiscouraged 、2Dnumpy.ndarrayオブジェクトでは達成できないものは何も追加しないため、confusionどのクラスが使用されているか。例えば、

>>> import numpy as np
>>> from scipy import linalg
>>> A = np.array([[1,2],[3,4]])
>>> A
    array([[1, 2],
           [3, 4]])
>>> linalg.inv(A)
array([[-2. ,  1. ],
      [ 1.5, -0.5]])
>>> b = np.array([[5,6]]) #2D array
>>> b
array([[5, 6]])
>>> b.T
array([[5],
      [6]])
>>> A*b #not matrix multiplication!
array([[ 5, 12],
      [15, 24]])
>>> A.dot(b.T) #matrix multiplication
array([[17],
      [39]])
>>> b = np.array([5,6]) #1D array
>>> b
array([5, 6])
>>> b.T  #not matrix transpose!
array([5, 6])
>>> A.dot(b)  #does not matter for multiplication
array([17, 39])

scipy.linalg操作は、numpy.matrixまたは2Dnumpy.ndarrayオブジェクト。

8
Yong Yang

このトリック はあなたが探しているものかもしれません。一種の単純な演算子のオーバーロードです。

その後、次のような推奨されるInfixクラスのようなものを使用できます。

a = np.random.Rand(3,4)
b = np.random.Rand(4,3)
x = Infix(lambda x,y: np.dot(x,y))
c = a |x| b
7
Bitwise

PEP 465-行列乗算のための専用の挿入演算子 からの適切な引用は、@ petr-viktorinによって言及されているように、OPが得ていた問題を明確にします:

[...] numpyは、異なる__mul__メソッドを持つ2つの異なるタイプを提供します。 numpy.ndarrayオブジェクトの場合、*は要素ごとの乗算を実行し、行列の乗算では関数呼び出し(numpy.dot)を使用する必要があります。 numpy.matrixオブジェクトの場合、*は行列乗算を実行し、要素ごとの乗算には関数構文が必要です。 numpy.ndarrayを使用したコードの記述は正常に機能します。 numpy.matrixを使用したコードの記述も正常に機能します。 しかし、これらの2つのコードを統合しようとするとすぐにトラブルが始まりますndarrayを期待し、matrixを取得するコード、またはその逆は、クラッシュするか、誤った結果を返す可能性があります

@挿入演算子の導入は、pythonマトリックスコードの統合と簡素化に役立ちます。

4
cod3monk3y

関数 matmul (numpy 1.10.1以降)は両方のタイプで正常に動作し、numpyマトリックスクラスとして結果を返します。

import numpy as np

A = np.mat('1 2 3; 4 5 6; 7 8 9; 10 11 12')
B = np.array(np.mat('1 1 1 1; 1 1 1 1; 1 1 1 1'))
print (A, type(A))
print (B, type(B))

C = np.matmul(A, B)
print (C, type(C))

出力:

(matrix([[ 1,  2,  3],
        [ 4,  5,  6],
        [ 7,  8,  9],
        [10, 11, 12]]), <class 'numpy.matrixlib.defmatrix.matrix'>)
(array([[1, 1, 1, 1],
       [1, 1, 1, 1],
       [1, 1, 1, 1]]), <type 'numpy.ndarray'>)
(matrix([[ 6,  6,  6,  6],
        [15, 15, 15, 15],
        [24, 24, 24, 24],
        [33, 33, 33, 33]]), <class 'numpy.matrixlib.defmatrix.matrix'>)

python 3.5が 前に述べた なので、新しい行列乗算演算子 @ のように使用することもできます

C = A @ B

上記と同じ結果が得られます。

1
Serenity