Чим відрізняються нумеровані масиви від матриць? Який я повинен використовувати?


346

Які переваги та недоліки кожного?

З того, що я бачив, будь-який може працювати заміною іншого, якщо потрібно, тож чи варто заважати використовувати обидва, чи слід дотримуватися лише одного з них?

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


3
У мене не вистачає інформації, щоб обґрунтувати відповідь, але головне відмінність полягає у здійсненні множення. Матриця виконує множення матриці / тензора, тоді як масив виконуватиме множення елементів.
Майк Аксіак

5
Python 3.5 додав оператор infix @ для матричного множення (PEP 465), а NumPy 1.10 додав підтримку. Тож якщо ви використовуєте Python 3.5+ та NumPy 1.10+, тоді ви можете просто писати A @ Bзамість A.dot(B), де Aта Bє 2D ndarrays. Це усуває головну перевагу використання matrixзамість звичайного ndarrays, IMHO.
MiniQuark

Відповіді:


4

Згідно з офіційними документами, використовувати матричний клас більше не доцільно, оскільки він буде видалений у майбутньому.

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

В інших відповідях вже зазначено, що ви можете досягти всіх операцій з NumPy-масивами.


396

Матричні матриці суворо двовимірні, а нумерові масиви (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 масиви послідовно дотримуються правила, що операції застосовуються по елементу (за винятком нового @оператора). Таким чином, якщо 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вибором елемента та поведінкою послідовностей).

Основна перевага нумерованих масивів полягає в тому, що вони більш загальні, ніж двовимірні матриці . Що відбувається, коли потрібно тривимірний масив? Тоді вам доведеться використовувати ndarray, а не матричний об'єкт. Таким чином, навчитися використовувати матричні об'єкти - це більше роботи - ви повинні вивчити матричні операції з об’єктами та операції ndarray.

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

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

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

PS. Звичайно, вам дійсно не потрібно вибирати одне за рахунок іншого, оскільки np.asmatrixі np.asarrayви дозволяєте перетворювати одне в інше (поки масив є двовимірним).


Існує короткий огляд відмінностей між NumPy arraysпроти NumPy matrixх років тут .


7
Для тих, хто цікавиться, mat**nбо матрицю можна неелегантно застосувати до масиву зreduce(np.dot, [arr]*n)
askewchan

6
Або простоnp.linalg.matrix_power(mat, n)
Ерік

Мені цікаво, чи будуть матриці швидшими ... ви б подумали, що вони повинні виконати менше перевірок, ніж ndarray.
PascalVKooten

1
Насправді випробування timeit показують, що операції ndarray такі 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 рекомендує використовувати масиви:

* 'масив' або 'матриця'? Який я повинен використовувати? - Коротка відповідь

Використовуйте масиви.

  • Вони є типовим типом вектора / матриці / тензора. Багато нумерованих функцій повертають масиви, а не матриці.

  • Існує чітке розмежування між операційними елементами та операціями лінійної алгебри.

  • Ви можете мати стандартні вектори або вектори рядків / стовпців, якщо хочете.

Єдиним недоліком використання типу масиву є те, що вам доведеться використовувати dotзамість *множення (зменшення) двох тензорів (скалярний добуток, множення матричного вектора тощо).


11
Незважаючи на те, що прийнята відповідь надає більше інформації, справжня відповідь справді повинна дотримуватися ndarray. Основним аргументом для використання matrixбуло б, якщо ваш код важкий в лінійній алгебрі і виглядає менш чітким при всіх викликах dotфункції. Але цей аргумент зникне в майбутньому, тепер, коли @ -operator прийнято використовувати для матричного множення, див. PEP 465 . Для цього знадобиться Python 3.5 та остання версія Numpy. Клас матриць може бути застарілим у далекому майбутньому, тому краще використовувати ndarray для нового коду ...
Bas Swinckels

6
Ця сторінка мило забуває про scipy.sparseматриці. Якщо ви використовуєте в коді обидві щільні та розріджені матриці, це дотримуватися набагато простіше matrix.
Девід Немескі

3
На мою думку, головним недоліком масивів є те, що нарізка стовпців повертає плоскі масиви, які можуть бути заплутаними і математично не дуже хорошими. Це також призводить до важливого недоліку в тому, що нумерові масиви не можуть оброблятися так само, як матриці scipy.sparse, тоді як нумерові матриці в основному можуть вільно обмінюватися з розрідженими матрицями. У цьому контексті абсурдно, що scipy рекомендує використовувати масиви, а потім не забезпечує сумісні рідкісні масиви.
Радіокерований

29

Просто додати один випадок до списку unutbu.

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

Наприклад, змішані рядки матриці або масиву:

з матрицею

>>> 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 завжди є матрицями в таких операторах, як множення.


20

Як зазначали інші, мабуть, головна перевага matrixполягала в тому, що вона забезпечувала зручне позначення для матричного множення.

Однак, в Python 3.5 є, нарешті, спеціальний оператор ІНФІКС для матричного множення : @.

З останніми версіями NumPy його можна використовувати з ndarrays:

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

Тож сьогодні, навіть більше, коли сумніваєтесь, слід дотримуватися ndarray.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.