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


130

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

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


8
당신은 의견이 아니라 질문을 요구합니다. 좀 더 구체적으로 읽을 수 있도록 도와 주거나 안내해 줄 수있는 구체적인 내용이 있습니까?
wheaties

2
실제로 문서는 선형 대수를 수행하고 multiply ()를 사용하지 않으려는 경우 행렬을 사용하는 것이 좋습니다. 문제가 무엇입니까?
Matti Pastell

1
나는 문서를 자세히 보지 않았다. 궁금한 점은 배열이 매트릭스 클래스에 비해 어떤 이점을 제공합니까? 배열이 행과 열을 구분하지 않는다는 것을 알았습니다. 배열이 행렬이 아닌 텐서로 간주되기 때문입니까? Joe가 지적했듯이 매트릭스 클래스가 2 차원이라는 사실은 매우 제한적입니다. MATLAB / octave와 같은 단일 매트릭스 클래스를 사용하지 않는 이유는 무엇입니까?
elexhobby

주요 문제는 파이썬 .*에 요소 현명한 대 행렬 곱셈에 대한 vs '*'구문 이 없다는 것 입니다. 그것이 있었다면 *매트릭스 곱셈이 아닌 요소 단위를 의미하기로 선택 하는 것에 놀랐지 만 모두 더 간단 할 것 입니다.
Charlie Parker

답변:


127

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


10
곱셈의 스택이있을 때 읽을 수 없습니다 (예 : x ' A'* A x).
elexhobby

14
@elexhobby- x.T.dot(A.T).dot(A).dot(x)읽을 수없는 것은 아니지만, 각자 자신에게. 주로 행렬 곱셈을 수행하는 경우 반드시 numpy.matrix!
Joe Kington

7
그런데 왜 행렬 곱셈이 "도트"라고 불리는가? 어떤 의미에서 그것은 도트 제품입니까?
amcnabb

8
@amcnabb-행렬 곱셈은 때때로 교과서에서 "도트 제품"이라고합니다 (이러한 책에서는 생각하고있는 도트 제품을 "스칼라 제품"또는 "스칼라 도트 제품"이라고합니다). 스칼라 도트 곱은 결국 두 벡터의 행렬 곱셈이므로 결국 "점"을 사용하여 일반적으로 행렬 곱셈을 의미하는 것은 그리 많지 않습니다. 그 특별한 표기법은 적어도 나의 경험에서 수학보다 공학 및 과학 텍스트에서 더 일반적으로 보입니다. numpy의 유병률은 대부분 입력하기 numpy.matrixmultiply가 어렵 기 때문 입니다.
Joe Kington

7
@amcnabb 요점은 점이 모호하지 않고 임의의 차원으로 일반화 된다는 것 입니다. 이것이 numpy.dot행렬 곱셈과 동일합니다. 표기법이 마음에 들지 않으면 matrix수업을 사용하십시오 .
Henry Gomersall

80

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
mInv = NP.linalg.inv (m)는 배열의 역수를 계산합니다
db1234

여기서 주목해야 할 중요한 점은 *는 요소 별 곱셈이고, 점은 실제 행렬 곱셈입니다. 참조하시기 바랍니다 stackoverflow.com/a/18255635/1780570
호치민 Triet

IMP 참고 : 배열을 선호하는 numpy 행렬은 피해야합니다. 문서의 참고 사항-> "선형 대수에도이 클래스를 사용하지 않는 것이 좋습니다. 대신 일반 배열을 사용하십시오. 나중에 클래스가 제거 될 수 있습니다." 참조 stackoverflow.com/a/61156350/6043669
HopeKing


15

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

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

구체적으로, *는 요소 별 곱셈이고, 도트는 실제 행렬 곱셈입니다. 참조하시기 바랍니다 stackoverflow.com/a/18255635/1780570
호치민 Triet

그것은 숫자 배열 인 aT == a이기 때문에 조옮김은 아무것도하지 않기 때문입니다.
patapouf_ai

= np.array ([[1], [2], [3]])에 쓰면 numpy.dot (at, b)가 같아야합니다. matix와 array의 차이점은 점이 아니라 조옮김입니다.
patapouf_ai

또는 실제로 = numpy.array ([[1,2,3]])를 쓰면 aT는 실제로 전치되며 모든 것이 행렬처럼 작동합니다.
patapouf_ai

8

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


7

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

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

5

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

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

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


1

함수 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'>)

파이썬 3.5 이후 언급 일찍 당신은 또한 새로운 행렬 곱셈 연산자 사용 @등이

C = A @ B

위와 동일한 결과를 얻습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.