Чем отличается умножение для классов NumPy Matrix и Array? - PullRequest
130 голосов
/ 08 октября 2010

Для работы с матрицами в больших документах рекомендуется использовать массив вместо матрицы.Однако, в отличие от октавы (которую я использовал до недавнего времени), * не выполняет умножение матриц, вам нужно использовать функцию matrixmultipy ().Я чувствую, что это делает код очень нечитаемым.

Кто-нибудь разделяет мои взгляды и нашел решение?

Ответы [ 8 ]

126 голосов
/ 08 октября 2010

Основная причина, по которой следует избегать использования класса matrix, заключается в том, что а) он по своей сути 2-мерен, и б) есть дополнительные издержки по сравнению с "обычным" массивом-пустышкой. Если все, что вы делаете, это линейная алгебра, то, конечно, не стесняйтесь использовать матричный класс ... Лично я нахожу, что это больше проблем, чем оно того стоит.

Для массивов (до Python 3.5) используйте dot вместо matrixmultiply.

1010 * Е.Г. *

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.

81 голосов
/ 19 августа 2013

ключевые моменты, которые нужно знать для операций с NumPy массивами против операций с матрицами NumPy :

  • Матрица NumPy представляет собой подкласс массива NumPy

  • NumPy массив операции поэлементно (после учета широковещанияfor)

  • 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 выбрасывает.

единственное исключение, с которым я столкнулся (есть, вероятно, другие), это вычисление обратной матрицы .

ниже приведены фрагменты, в которых я назвал операцию чистой линейной алгебры (на самом деле, из модуля линейной алгебры Numpy) и передал в массив 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'

, но псевдообратный Мура-Пенроуза , кажется, работает просто отлично

>>> 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]])
20 голосов
/ 25 августа 2014

В 3.5 Python окончательно получил оператор умножения матриц . Синтаксис a @ b.

15 голосов
/ 03 октября 2013

Существует ситуация, когда оператор точки даст разные ответы при работе с массивами, как при работе с матрицами.Например, предположим следующее:

>>> 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.]]
8 голосов
/ 07 января 2014

Ссылка от http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html

..., использование numpy.matrix класса не рекомендуется , так как он не добавляет ничего, чего нельзя достичь с объектами 2D 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 голосов
/ 19 августа 2013

Этот трюк может быть тем, что вы ищете. Это своего рода простая перегрузка оператора.

Затем вы можете использовать что-то вроде предложенного класса 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 голосов
/ 11 января 2015

Соответствующая цитата из PEP 465. - Специальный инфиксный оператор для умножения матриц , как упомянуто @ petr-viktorin, разъясняет проблему, с которой столкнулся ОП:

[...] numpy предоставляет два разных типа с разными __mul__ методами.Для numpy.ndarray объектов * выполняет поэлементное умножение, а умножение матриц должно использовать вызов функции (numpy.dot).Для numpy.matrix объектов * выполняет умножение матриц, а поэлементное умножение требует синтаксиса функции.Написание кода с использованием numpy.ndarray работает нормально.Написание кода с использованием numpy.matrix также работает нормально. Но неприятности начинаются , как только мы пытаемся объединить эти две части кода вместе.Код, который ожидает ndarray и получает matrix или наоборот, может вылетать или возвращать неверные результаты

Введение инфиксного оператора @ должно помочь унифицировать и упростить pythonматричный код.

1 голос
/ 11 апреля 2019

Функция 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

и получите тот же результат, что и выше.

...