Jakie są różnice między tablicami numpy a macierzami? Którego powinienem użyć?

346

Jakie są zalety i wady każdego z nich?

Z tego, co widziałem, jedno z nich może działać jako zamiennik drugiego, jeśli zajdzie taka potrzeba, więc powinienem zawracać sobie głowę używaniem obu, czy też powinienem trzymać się tylko jednego?

Czy styl programu wpłynie na mój wybór? Robię uczenie maszynowe za pomocą numpy, więc rzeczywiście jest wiele macierzy, ale także wiele wektorów (tablic).

levesque
źródło
3
Nie mam wystarczających informacji, aby uzasadnić odpowiedź, ale z tego, co mogę powiedzieć, główną różnicą jest implementacja mnożenia. Macierz wykonuje mnożenie macierzy / tensora, podczas gdy macierz wykonuje mnożenie elementów.
Mike Axiak,
5
Python 3.5 dodał operator infix @ do mnożenia macierzy (PEP 465), a NumPy 1.10 dodał do niego obsługę. Więc jeśli używasz Python 3.5+ i NumPy 1.10+, możesz po prostu pisać A @ Bzamiast A.dot(B), gdzie Ai Bsą 2D ndarray. Usuwa to główną zaletę używania matrixzamiast zwykłego ndarrays IMHO.
MiniQuark,

Odpowiedzi:

396

Macierze numpy są ściśle dwuwymiarowe, a tablice numpy (ndarrays) są N-wymiarowe. Obiekty macierzy są podklasą ndarray, więc dziedziczą wszystkie atrybuty i metody ndarrays.

Główną zaletą macierzy numpy jest to, że zapewniają one wygodny zapis mnożenia macierzy: jeśli aib są macierzami, a*bto ich iloczyn macierzy.

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

Z drugiej strony, począwszy od Pythona 3.5, NumPy obsługuje mnożenie macierzy infix za pomocą @operatora, dzięki czemu można osiągnąć tę samą wygodę mnożenia macierzy za pomocą ndarrays w Pythonie> = 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]]

Zarówno obiekty macierzowe, jak i ndarrays muszą .Tzwracać transpozycję, ale obiekty macierzowe mają także .Htranspozycję sprzężoną i .Iodwrotną.

Natomiast tablice numpy konsekwentnie przestrzegają zasady, że operacje są stosowane elementarnie (z wyjątkiem nowego @operatora). Tak więc, jeśli ai bsą tablicami liczbowymi, a*bto tablica tworzona jest przez pomnożenie składników pod względem elementów:

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

Aby uzyskać wynik mnożenia macierzy, użyj np.dot(lub @w Pythonie> = 3.5, jak pokazano powyżej):

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

**Operatora zachowuje także w inny sposób:

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

Ponieważ ajest to macierz, a**2zwraca iloczyn macierzy a*a. Ponieważ cjest to ndarray, c**2zwraca ndarray z każdym komponentem do kwadratu względem elementu.

Istnieją inne techniczne różnice między obiektami macierzowymi a ndarrays (związane z np.ravelwyborem elementów i zachowaniem sekwencji).

Główną zaletą tablic numpy jest to, że są one bardziej ogólne niż matryce dwuwymiarowe . Co dzieje się, gdy potrzebujesz trójwymiarowej tablicy? Następnie musisz użyć ndarray, a nie obiektu macierzy. Zatem nauka korzystania z obiektów macierzowych wymaga więcej pracy - musisz nauczyć się operacji na obiektach macierzowych i operacji ndarray.

Napisanie programu, który miesza zarówno macierze, jak i tablice, utrudnia życie, ponieważ musisz śledzić, jakiego rodzaju obiekt są twoje zmienne, aby mnożenie nie zwróciło czegoś, czego się nie spodziewasz.

W przeciwieństwie do tego, jeśli trzymasz się wyłącznie ndarrays, możesz robić wszystko, co mogą robić obiekty macierzowe, i więcej, z wyjątkiem nieco innych funkcji / notacji.

Jeśli chcesz zrezygnować z atrakcyjności wizualnej notacji macierzowej NumPy (którą można osiągnąć niemal równie elegancko za pomocą ndarrays w Pythonie> = 3,5), to myślę, że tablice NumPy są zdecydowanie najlepszym rozwiązaniem.

PS. Oczywiście, tak naprawdę nie mają do wyboru jeden kosztem drugiego, ponieważ np.asmatrixi np.asarraypozwala na konwersję jednego do drugiego (tak długo, jak tablica jest 2-wymiarowe).


Istnieje streszczenie różnic między NumPy arraysa NumPy matrixes tutaj .

unutbu
źródło
7
Dla tych, którzy zastanawiają się, mat**nmacierz może być nieelegancko zastosowana do tablicy za pomocąreduce(np.dot, [arr]*n)
askewchan
6
Lub po prostunp.linalg.matrix_power(mat, n)
Eric
Zastanawiam się, czy matryce byłyby szybsze ... można by pomyśleć, że muszą wykonywać mniej kontroli niż ndarray.
PascalVKooten
1
W rzeczywistości testy timeit pokazują, że operacje ndarray np.dot(array2, array2)są szybsze niż matrix1*matrix2. Ma to sens, ponieważ matrixjest podklasą ndarray, która zastępuje specjalne metody, takie jak __mul__. matrix.__mul__połączenianp.dot . Więc tutaj jest ponowne użycie kodu. Zamiast wykonywania mniejszej liczby kontroli użycie matrix*matrixwymaga dodatkowego wywołania funkcji. Zaletą używania matrixjest czysto składniowa, a nie lepsza wydajność.
unutbu
4 * 1 + 3 * 3 daje ci 13, gdy zrobiłeś np ..dot (c, d), czy tak naprawdę nie nazywa się to iloczynem krzyżowym z matematyki
PirateApp 20.04.2018
92

Scipy.org zaleca używanie tablic:

* „tablica” czy „matryca”? Z którego powinienem korzystać? - Krótka odpowiedź

Użyj tablic.

  • Są standardowym typem numpy wektor / macierz / tensor. Wiele funkcji numpy zwraca tablice, a nie macierze.

  • Istnieje wyraźne rozróżnienie między operacjami elementarnymi a operacjami algebry liniowej.

  • Możesz mieć wektory standardowe lub wektory wierszy / kolumn, jeśli chcesz.

Jedyną wadą używania typu macierzy jest to, że będziesz musiał użyć dotzamiast *pomnożyć (zmniejszyć) dwa tensory (iloczyn skalarny, mnożenie wektora macierzy itp.).

atomh33ls
źródło
11
Mimo że zaakceptowana odpowiedź zawiera więcej informacji, prawdziwą odpowiedzią jest rzeczywiście trzymać się ndarray. Głównym argumentem przemawiającym za użyciem matrixbyłoby, jeśli kod jest ciężki w algebrze liniowej i wyglądałby mniej czytelnie przy wszystkich wywołaniach dotfunkcji. Ale ten argument zniknie w przyszłości, teraz, gdy operator @ jest akceptowany do użycia z mnożeniem macierzy, patrz PEP 465 . Będzie to wymagało Python 3.5 i najnowszej wersji Numpy. Klasa macierzy może być przestarzała w dalekiej przyszłości, więc lepiej użyć ndarray do nowego kodu ...
Bas Swinckels,
6
Ta strona łaskawie zapomina o scipy.sparsematrycach. Jeśli używasz zarówno gęstej, jak i rzadkiej macierzy w kodzie, o wiele łatwiej jest się jej trzymać matrix.
David Nemeskey,
3
Moim zdaniem, główną wadą tablic jest to, że wycinanie kolumn zwraca płaskie tablice, które mogą być mylące i matematycznie niezbyt poprawne. Prowadzi to również do istotnej wady, że tablice numpy nie mogą być traktowane w taki sam sposób jak macierze scipy.sparse, podczas gdy macierze numpy można w zasadzie swobodnie wymieniać na macierze rzadkie. W tym kontekście absurdalne, że scipy zaleca używanie tablic, a następnie nie zapewnia kompatybilnych rzadkich tablic.
Kontrolowany radiowo
29

Wystarczy dodać jedną skrzynkę do listy unutbu.

Jedną z największych praktycznych różnic dla mnie numpy ndarrays w porównaniu do macierzy numpy lub języków macierzy, takich jak matlab, jest to, że wymiar nie jest zachowany w operacjach zmniejszania. Macierze są zawsze 2d, podczas gdy na przykład średnia tablicy ma jeden wymiar mniej.

Na przykład poniższe wiersze macierzy lub tablicy:

z matrycą

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

z tablicą

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

Myślę też, że mieszanie tablic i macierzy powoduje wiele „szczęśliwych” godzin debugowania. Jednak macierze scipy.sparse są zawsze macierzami pod względem operatorów, takich jak mnożenie.

Josef
źródło
20

Jak wspomnieli inni, być może główną zaletą matrixbyło to, że zapewnia wygodny zapis mnożenia macierzy.

Jednak w Pythonie 3.5 jest w końcu przypisanego operatora infiks mnożenia macierzy : @.

W najnowszych wersjach NumPy można go używać z ndarrays:

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

Dlatego w dzisiejszych czasach, nawet w razie wątpliwości, powinieneś się trzymać ndarray.

Peque
źródło