Sự khác biệt giữa mảng numpy và ma trận là gì? Tôi nên sử dụng cái nào?


345

Những lợi thế và bất lợi của mỗi là gì?

Từ những gì tôi đã thấy, một trong hai người có thể làm việc thay thế cho người khác nếu cần, vậy tôi có nên sử dụng cả hai hay tôi chỉ nên sử dụng một trong số họ?

Phong cách của chương trình sẽ ảnh hưởng đến sự lựa chọn của tôi? Tôi đang thực hiện một số máy học bằng cách sử dụng numpy, vì vậy thực sự có rất nhiều ma trận, nhưng cũng có rất nhiều vectơ (mảng).


3
Tôi không có đủ thông tin để biện minh cho câu trả lời nhưng từ những gì tôi có thể nói sự khác biệt chính là việc thực hiện phép nhân. Một ma trận thực hiện phép nhân ma trận / tenxơ, trong khi đó một mảng sẽ thực hiện phép nhân phần tử.
Mike Axiak

5
Python 3.5 đã thêm toán tử infix @ để nhân ma trận (PEP 465) và NumPy 1.10 đã thêm hỗ trợ cho nó. Vì vậy, nếu bạn đang sử dụng Python 3.5+ và NumPy 1.10+, thì bạn chỉ có thể viết A @ Bthay vì A.dot(B), ở đâu ABlà 2D ndarrays. Điều này loại bỏ lợi thế chính của việc sử dụng matrixthay vì đơn giản ndarray, IMHO.
MiniQuark

Câu trả lời:



396

Ma trận Numpy hoàn toàn là 2 chiều, trong khi các mảng numpy (ndarrays) là N chiều. Các đối tượng ma trận là một lớp con của ndarray, vì vậy chúng kế thừa tất cả các thuộc tính và phương thức của ndarrays.

Ưu điểm chính của ma trận numpy là chúng cung cấp một ký hiệu thuận tiện cho phép nhân ma trận: nếu a và b là ma trận, thì đó a*blà sản phẩm ma trận của chúng.

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

Mặt khác, kể từ Python 3.5, NumPy hỗ trợ nhân ma trận infix bằng cách sử dụng @toán tử, do đó bạn có thể đạt được sự thuận tiện tương tự của phép nhân ma trận với các câu lệnh trong 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]]

Cả hai đối tượng ma trận và ndarrays đều .Tphải trả về chuyển vị, nhưng các đối tượng ma trận cũng có .Hcho chuyển vị liên hợp và .Icho nghịch đảo.

Ngược lại, mảng numpy luôn tuân thủ quy tắc rằng các hoạt động được áp dụng phần tử khôn ngoan (ngoại trừ @toán tử mới ). Do đó, nếu ablà mảng numpy, thì a*bmảng được hình thành bằng cách nhân các thành phần thành phần khôn ngoan:

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

Để có được kết quả của phép nhân ma trận, bạn sử dụng np.dot(hoặc @trong Python> = 3.5, như được hiển thị ở trên):

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

Các **nhà điều hành cũng cư xử khác nhau:

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

alà một ma trận, a**2trả về sản phẩm ma trận a*a. Vì clà một ndarray, c**2trả về một ndarray với mỗi thành phần bình phương thành phần tử.

Có sự khác biệt kỹ thuật khác giữa các đối tượng ma trận và ndarrays (phải làm với np.ravel, lựa chọn vật phẩm và hành vi trình tự).

Ưu điểm chính của mảng numpy là chúng tổng quát hơn ma trận 2 chiều . Điều gì xảy ra khi bạn muốn một mảng 3 chiều? Sau đó, bạn phải sử dụng một ndarray, không phải là một đối tượng ma trận. Do đó, học cách sử dụng các đối tượng ma trận là công việc nhiều hơn - bạn phải học các hoạt động của đối tượng ma trận và các hoạt động ndarray.

Viết một chương trình pha trộn cả ma trận và mảng khiến cuộc sống của bạn trở nên khó khăn vì bạn phải theo dõi loại đối tượng của mình là gì, nhân lên sẽ trả về thứ bạn không mong đợi.

Ngược lại, nếu bạn chỉ gắn bó với ndarrays, thì bạn có thể làm mọi thứ mà các đối tượng ma trận có thể làm, và hơn thế nữa, ngoại trừ với các hàm / ký hiệu hơi khác nhau.

Nếu bạn sẵn sàng từ bỏ sự hấp dẫn trực quan của ký hiệu sản phẩm ma trận NumPy (có thể đạt được gần như thanh lịch với các câu lệnh trong Python> = 3.5), thì tôi nghĩ rằng mảng NumPy chắc chắn là hướng đi.

Tái bút Tất nhiên, bạn thực sự không phải chọn cái này với chi phí khác, vì np.asmatrixnp.asarraycho phép bạn chuyển đổi cái này sang cái khác (miễn là mảng là 2 chiều).


Có một bản tóm tắt về sự khác biệt giữa NumPy arraysvà NumPy matrixes ở đây .


7
Đối với những người thắc mắc, mat**nđối với một ma trận có thể được áp dụng liên tục vào một mảng vớireduce(np.dot, [arr]*n)
askewchan

6
Hoặc chỉnp.linalg.matrix_power(mat, n)
Eric

Tôi đang tự hỏi liệu ma trận sẽ nhanh hơn ... bạn nghĩ rằng họ phải thực hiện kiểm tra ít hơn ndarray.
PascalVKooten

1
Trên thực tế, các bài kiểm tra thời gian cho thấy các hoạt động ndarray như np.dot(array2, array2)nhanh hơn matrix1*matrix2. Điều này có ý nghĩa bởi vì matrixlà một lớp con của ndarray ghi đè các phương thức đặc biệt như thế nào __mul__. matrix.__mul__các cuộc gọinp.dot . Vì vậy, có mã reusage ở đây. Thay vì thực hiện ít kiểm tra hơn, sử dụng matrix*matrixyêu cầu thêm chức năng gọi. Vì vậy, lợi thế của việc sử dụng matrixlà hoàn toàn cú pháp, hiệu suất không tốt hơn.
unutbu

4 * 1 + 3 * 3 mang lại cho bạn 13 khi bạn đã làm np.dot (c, d) không thực sự được gọi là sản phẩm chéo trong toán học
PirateApp

92

Scipy.org khuyên bạn nên sử dụng mảng:

* 'mảng' hoặc 'ma trận'? Tôi nên sử dụng cái nào? - Câu trả lời ngắn

Sử dụng mảng.

  • Chúng là loại vectơ / ma trận / tenor chuẩn của numpy. Nhiều hàm numpy trả về mảng, không phải ma trận.

  • Có một sự phân biệt rõ ràng giữa các phép toán phần tử và các phép toán đại số tuyến tính.

  • Bạn có thể có các vectơ tiêu chuẩn hoặc vectơ hàng / cột nếu bạn muốn.

Nhược điểm duy nhất của việc sử dụng kiểu mảng là bạn sẽ phải sử dụng dotthay vì *nhân (giảm) hai thang đo (sản phẩm vô hướng, nhân vectơ ma trận, v.v.).


11
Mặc dù câu trả lời được chấp nhận cung cấp thêm thông tin, nhưng câu trả lời thực sự thực sự gắn bó ndarray. Đối số chính để sử dụng matrixsẽ là nếu mã của bạn nặng về đại số tuyến tính và sẽ trông không rõ ràng hơn với tất cả các lệnh gọi đến dothàm. Nhưng đối số này sẽ biến mất trong tương lai, bây giờ khi @ -operator được chấp nhận để sử dụng với phép nhân ma trận, xem PEP 465 . Điều này sẽ cần Python 3.5 và phiên bản mới nhất của Numpy. Lớp ma trận có thể không được dùng nữa trong tương lai xa, vì vậy tốt hơn là sử dụng ndarray cho mã mới ...
Bas Swinckels

6
Trang đó ân cần quên đi về scipy.sparsema trận. Nếu bạn sử dụng cả ma trận dày đặc & thưa thớt trong mã của mình, việc dính vào sẽ dễ dàng hơn nhiều matrix.
David Nemekey

3
Theo tôi, nhược điểm chính của mảng là việc cắt cột trả về mảng phẳng có thể gây nhầm lẫn và về mặt toán học không thực sự đúng. Điều này cũng dẫn đến nhược điểm quan trọng là các mảng numpy không thể được xử lý theo cách tương tự như ma trận scipy.spude trong khi ma trận numpy về cơ bản có thể được trao đổi tự do với ma trận thưa thớt. Loại vô lý trong bối cảnh này mà scipy khuyên bạn nên sử dụng mảng và sau đó không cung cấp mảng thưa thớt tương thích.
Đài phát thanh được điều khiển

29

Chỉ cần thêm một trường hợp vào danh sách của unutbu.

Một trong những khác biệt thực tế lớn nhất đối với tôi về các câu lệnh numpy so với ma trận numpy hoặc ngôn ngữ ma trận như matlab, là kích thước không được bảo toàn trong các hoạt động giảm. Ma trận luôn là 2d, trong khi giá trị trung bình của một mảng chẳng hạn, có ít hơn một chiều.

Ví dụ: hàng demean của ma trận hoặc mảng:

với ma trận

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

với mảng

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

Tôi cũng nghĩ rằng việc trộn các mảng và ma trận sẽ tạo ra nhiều giờ gỡ lỗi "hạnh phúc". Tuy nhiên, ma trận scipy.spude luôn là ma trận về các toán tử như phép nhân.


20

Như những người khác đã đề cập, có lẽ ưu điểm chính matrixlà nó cung cấp một ký hiệu thuận tiện cho phép nhân ma trận.

Tuy nhiên, trong Python 3.5 cuối cùng cũng có một toán tử infix chuyên dụng để nhân ma trận : @.

Với các phiên bản NumPy gần đây, nó có thể được sử dụng với ndarrays:

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

Vì vậy, ngày nay, thậm chí nhiều hơn, khi nghi ngờ, bạn nên bám vào ndarray.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.