[python] NumPy Matrix와 Array 클래스의 곱셈은 어떻게 다릅니 까?

numpy 문서는 행렬 작업을 위해 행렬 대신 배열을 사용하는 것이 좋습니다. 그러나 (최근까지 사용했던) 옥타브와 달리 *는 행렬 곱셈을 수행하지 않으므로 matrixmultipy () 함수를 사용해야합니다. 이것이 코드를 읽을 수 없게 만든다고 생각합니다.

아무도 내 의견을 공유하고 해결책을 찾았습니까?



답변

사용하지 않는 주요 이유 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.


답변

NumPy 배열 작업과 NumPy 행렬 작업에 대해 알아야 할 주요 사항 은 다음과 같습니다.

  • NumPy 행렬은 NumPy 배열 의 하위 클래스 입니다

  • NumPy 어레이 작업은 요소별로 이루어집니다 (방송이 처리되면 한 번)

  • NumPy 행렬 연산은 선형 대수의 일반적인 규칙을 따릅니다.

몇 가지 코드 스 니펫은 다음과 같습니다.

>>> 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]])

그러나이 두 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 구문을 사용하면 배열에서 작동 합니다 . 이 연산은 행렬 곱셈처럼 작동합니다.

>> 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의 올바른 구문을 알고 있다면)?

규칙 (배열)이 주어진 선형 대수 연산과 호환되는 모양 (mxn)을 가지고 있다면 괜찮습니다. 그렇지 않으면 NumPy가 발생합니다.

내가 겪은 유일한 예외 (다른 것들이있을 수 있음)는 행렬 inverse를 계산 하는 것 입니다.

아래는 내가 순수 선형 대수 연산 (실제로 Numpy의 Linear Algebra 모듈에서)을 호출하고 NumPy 배열로 전달 된 스 니펫입니다.

배열의 결정자 :

>>> 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   ]]))

매트릭스 규범 :

>>>> 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.]]))

매트릭스 순위 :

>>> 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

매트릭스 조건 :

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

반전 에는 NumPy 행렬이 필요합니다.

>>> 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]])


답변

3.5에서 파이썬은 마침내 행렬 곱셈 연산자를 얻었습니다 . 구문은 a @ b입니다.


답변

도트 연산자가 배열을 다룰 때 행렬을 다룰 때와는 다른 대답을하는 상황이 있습니다. 예를 들어, 다음을 가정하십시오.

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

그것들을 행렬로 변환하자 :

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

이제 두 경우에 대해 다른 출력을 볼 수 있습니다.

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


답변

http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html 에서 참조

…의 사용 numpy.matrix의 클래스입니다 낙담 은 2 차원으로 수행 할 수없는 아무것도 추가하지 않기 때문에, numpy.ndarray의 객체, 그리고 발생할 수 있습니다 혼란 클래스를 사용하고있는합니다. 예를 들어

>>> 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 또는 2D numpy.ndarray 객체 에 동일하게 적용될 수 있습니다 .


답변

이 트릭 은 당신이 찾고있는 것일 수 있습니다. 일종의 간단한 연산자 과부하입니다.

그런 다음 제안 된 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


답변

PEP 465 의 적절한 인용문 @ petr-viktorin이 언급했듯이 행렬 곱셈을위한 전용 인 픽스 연산자는 OP가 겪고있는 문제를 분명히합니다.

[…] numpy는 다른 __mul__방법으로 두 가지 유형을 제공 합니다. 들어 numpy.ndarray개체 *가 수행하는 곱셈 elementwise, 매트릭스 곱셈은 함수 호출을 사용한다 ( numpy.dot). 들면 numpy.matrix목적, *수행은 매트릭스 승산과 승산 elementwise 함수 구문을 필요로한다. 를 사용하여 코드를 작성하면 numpy.ndarray정상적으로 작동합니다. 를 사용하여 코드를 작성하는 numpy.matrix것도 좋습니다. 그러나이 두 가지 코드를 통합하려고하면 문제가 시작 됩니다. 기대 ndarray하고 얻는 코드matrix 그 반대를 는 충돌하거나 잘못된 결과를 반환 할 수 있습니다

@infix 연산자를 도입하면 파이썬 매트릭스 코드를 통합하고 단순화하는 데 도움이됩니다.