Каковы различия между массивами numpy и матрицами? Какой я должен использовать?

347

Каковы преимущества и недостатки каждого?

Из того, что я видел, либо один может работать в качестве замены другого, если это необходимо, поэтому я должен беспокоиться об использовании обоих или я должен придерживаться только одного из них?

Повлияет ли стиль программы на мой выбор? Я занимаюсь машинным обучением, используя numpy, поэтому действительно много матриц, но также много векторов (массивов).

Левек
источник
3
У меня недостаточно информации, чтобы оправдать ответ, но из того, что я могу сказать, главное отличие - реализация умножения. Матрица выполняет матричное / тензорное умножение, тогда как массив выполняет поэлементное умножение.
Майк Аксиак
5
В Python 3.5 добавлен оператор infix @ для умножения матриц (PEP 465), а в NumPy 1.10 добавлена ​​его поддержка. Так что, если вы используете Python 3.5+ и NumPy 1.10+, вы можете просто написать A @ Bвместо A.dot(B), где Aи B2D ndarray. Это устраняет основное преимущество использования matrixвместо простых ndarrays, IMHO.
MiniQuark

Ответы:

4

Согласно официальным документам, больше не рекомендуется использовать матричный класс, так как он будет удален в будущем.

https://numpy.org/doc/stable/reference/generated/numpy.matrix.html

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

Акс
источник
396

Матрицы Numpy строго двумерны, а массивы NumPy (ndarrays) N-мерны. Матричные объекты являются подклассом ndarray, поэтому они наследуют все атрибуты и методы ndarrays.

Основное преимущество числовых матриц состоит в том, что они обеспечивают удобное обозначение для умножения матриц: если a и b являются матрицами, то a*bэто их матричное произведение.

import numpy as np

a = np.mat('4 3; 2 1')
b = np.mat('1 2; 3 4')
print(a)
# [[4 3]
#  [2 1]]
print(b)
# [[1 2]
#  [3 4]]
print(a*b)
# [[13 20]
#  [ 5  8]]

С другой стороны, @начиная с Python 3.5, NumPy поддерживает умножение инфиксных матриц с помощью оператора, поэтому вы можете добиться такого же удобства умножения матриц с помощью ndarrays в Python> = 3.5.

import numpy as np

a = np.array([[4, 3], [2, 1]])
b = np.array([[1, 2], [3, 4]])
print(a@b)
# [[13 20]
#  [ 5  8]]

И матричные объекты, и ndarrays должны .Tвозвращать транспозицию, но матричные объекты также имеют .Hдля сопряженной транспозиции, и.I для обратной.

Напротив, массивы numpy последовательно придерживаются правила, согласно которому операции применяются поэлементно (за исключением @оператора new ). Таким образом, если aи bявляются массивами, то a*bмассив формируется путем умножения компонентов поэлементно:

c = np.array([[4, 3], [2, 1]])
d = np.array([[1, 2], [3, 4]])
print(c*d)
# [[4 6]
#  [6 4]]

Чтобы получить результат умножения матриц, вы используете np.dot(или @в Python> = 3.5, как показано выше):

print(np.dot(c,d))
# [[13 20]
#  [ 5  8]]

**Оператор также ведет себя по- разному:

print(a**2)
# [[22 15]
#  [10  7]]
print(c**2)
# [[16  9]
#  [ 4  1]]

Так aкак является матрицей, a**2возвращает матричное произведение a*a. Так cкак ndarray, c**2возвращает ndarray с каждым компонентом в квадрате поэлементно.

Существуют и другие технические различия между матричными объектами и ndarrays (связанные с np.ravelвыбором элементов и поведением последовательности).

Основное преимущество числовых массивов состоит в том, что они являются более общими, чем двумерные матрицы. . Что происходит, когда вы хотите 3-мерный массив? Тогда вы должны использовать ndarray, а не матричный объект. Таким образом, научиться использовать матричные объекты - это больше работы - вы должны изучить операции с матричными объектами и операции ndarray.

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

Напротив, если вы придерживаетесь только ndarrays, то можете делать все, что могут делать матричные объекты, и даже больше, за исключением слегка отличающихся функций / обозначений.

Если вы готовы отказаться от визуальной привлекательности обозначения продуктов матрицы NumPy (что может быть достигнуто почти так же элегантно с помощью ndarrays в Python> = 3.5), то я думаю, что массивы NumPy - это определенно правильный путь.

PS. Конечно, вы действительно не должны выбрать один за счет другого, так np.asmatrixи np.asarrayпозволяют конвертировать один к другому ( до тех пор , пока массив является 2-мерным).


Существует краткий обзор различий между NumPy arraysпротив NumPy matrixх годов здесь .

unutbu
источник
7
Для тех, кто интересуется, mat**nматрица может быть неэлегентно применена к массиву с помощьюreduce(np.dot, [arr]*n)
askewchan
6
Или простоnp.linalg.matrix_power(mat, n)
Эрик
Мне интересно, будут ли матрицы быстрее ... вы думаете, что они должны выполнять меньше проверок, чем ndarray.
PascalVKooten
1
На самом деле, тесты timeit показывают, что такие операции np.dot(array2, array2)выполняются быстрее, чем matrix1*matrix2. Это имеет смысл, потому что matrixэто подкласс ndarray, который переопределяет специальные методы, такие как __mul__. matrix.__mul__звонкиnp.dot . Так что здесь есть повторное использование кода. Вместо того, чтобы выполнять меньше проверок, использование matrix*matrixтребует дополнительного вызова функции. Таким образом, преимущество использования matrixчисто синтаксическое, а не лучшая производительность.
unutbu
4 * 1 + 3 * 3 дает вам 13, когда вы делали np.dot (c, d), разве это не называется на самом деле перекрестным произведением в математике
PirateApp
92

Scipy.org рекомендует использовать массивы:

* «массив» или «матрица»? Какой я должен использовать? - Короткий ответ

Используйте массивы.

  • Это стандартный вектор / матрица / тензорный тип numpy. Многие функции numpy возвращают массивы, а не матрицы.

  • Существует четкое различие между поэлементными операциями и операциями линейной алгебры.

  • Вы можете иметь стандартные векторы или векторы строк / столбцов, если хотите.

Единственный недостаток использования типа массива состоит в том, что вам придется использовать dotвместо *умножения (уменьшения) два тензора (скалярное произведение, умножение матрицы на вектор и т. Д.).

atomh33ls
источник
11
Несмотря на то, что принятый ответ дает больше информации, реальный ответ - действительно придерживаться ndarray. Основным аргументом для использования matrixбыло бы, если ваш код тяжел в линейной алгебре и выглядел бы менее ясно со всеми вызовами dotфункции. Но этот аргумент исчезнет в будущем, теперь, когда @ -оператор принят для использования с умножением матриц, см. PEP 465 . Для этого потребуется Python 3.5 и последняя версия Numpy. Класс матрицы может устареть в далеком будущем, поэтому лучше использовать ndarray для нового кода ...
Бас Свинкельс
6
Эта страница любезно забывает о scipy.sparseматрицах. Если вы используете в своем коде как плотные, так и разреженные матрицы, гораздо проще придерживаться этого matrix.
Дэвид Немески
3
На мой взгляд, основным недостатком массивов является то, что срезы столбцов возвращают плоские массивы, что может сбивать с толку и математически не совсем правильно. Это также приводит к важному недостатку, заключающемуся в том, что числовые массивы не могут обрабатываться так же, как матрицы scipy.sparse, в то время как пустые матрицы в основном могут свободно заменяться разреженными матрицами. Вид абсурда в этом контексте, что Сципи рекомендует использовать массивы, а затем не предоставляет совместимых разреженных массивов.
Радиоуправляемый
29

Просто чтобы добавить один случай в список unutbu.

Одно из самых больших практических отличий для меня от numpy ndarrays по сравнению с numpy матрицами или матричными языками, такими как matlab, заключается в том, что измерение не сохраняется в операциях приведения. Матрицы всегда 2d, в то время как среднее значение массива, например, имеет на одно измерение меньше.

Например, demean строки матрицы или массива:

с матрицей

>>> m = np.mat([[1,2],[2,3]])
>>> m
matrix([[1, 2],
        [2, 3]])
>>> mm = m.mean(1)
>>> mm
matrix([[ 1.5],
        [ 2.5]])
>>> mm.shape
(2, 1)
>>> m - mm
matrix([[-0.5,  0.5],
        [-0.5,  0.5]])

с массивом

>>> a = np.array([[1,2],[2,3]])
>>> a
array([[1, 2],
       [2, 3]])
>>> am = a.mean(1)
>>> am.shape
(2,)
>>> am
array([ 1.5,  2.5])
>>> a - am #wrong
array([[-0.5, -0.5],
       [ 0.5,  0.5]])
>>> a - am[:, np.newaxis]  #right
array([[-0.5,  0.5],
       [-0.5,  0.5]])

Я также думаю, что смешивание массивов и матриц порождает много «счастливых» часов отладки. Однако матрицы scipy.sparse всегда являются матрицами в терминах таких операторов, как умножение.

Josef
источник
21

Как уже упоминалось, возможно, главное преимущество matrix заключалось в том, что он предоставлял удобную запись для умножения матриц.

Однако в Python 3.5, наконец, есть специальный инфиксный оператор для умножения матриц :@ .

В последних версиях NumPy его можно использовать с ndarrays:

A = numpy.ones((1, 3))
B = numpy.ones((3, 3))
A @ B

Так что в настоящее время, даже больше, когда вы сомневаетесь, вы должны придерживаться ndarray.

Peque
источник