Những lợi thế của NumPy so với danh sách Python thông thường là gì?


466

Những lợi thế của NumPy so với danh sách Python thông thường là gì?

Tôi có khoảng 100 chuỗi thị trường tài chính và tôi sẽ tạo ra một khối lập phương 100x100x100 = 1 triệu tế bào. Tôi sẽ hồi quy (3 biến) cho mỗi x với mỗi y và z, để lấp đầy mảng với các lỗi tiêu chuẩn.

Tôi đã nghe nói rằng đối với "ma trận lớn" tôi nên sử dụng NumPy thay vì danh sách Python, vì lý do hiệu suất và khả năng mở rộng. Điều đó là, tôi biết danh sách Python và chúng dường như hoạt động với tôi.

Những lợi ích sẽ là gì nếu tôi chuyển sang NumPy?

Điều gì xảy ra nếu tôi có 1000 chuỗi (nghĩa là, 1 tỷ ô dấu phẩy động trong khối)?

Câu trả lời:


727

Mảng NumPy nhỏ gọn hơn danh sách Python - một danh sách các danh sách như bạn mô tả, trong Python, sẽ mất ít nhất 20 MB hoặc hơn, trong khi đó mảng NumPy 3D có độ chính xác đơn trong các ô sẽ phù hợp với 4 MB. Truy cập vào các mục đọc và viết cũng nhanh hơn với NumPy.

Có thể bạn không quan tâm đến điều đó chỉ với một triệu ô, nhưng bạn chắc chắn sẽ có một tỷ ô - không cách tiếp cận nào phù hợp với kiến ​​trúc 32 bit, nhưng với các bản dựng 64 bit, NumPy sẽ có được 4 GB hoặc hơn , Chỉ riêng Python sẽ cần ít nhất khoảng 12 GB (rất nhiều con trỏ có kích thước gấp đôi) - một phần cứng đắt hơn nhiều!

Sự khác biệt chủ yếu là do "tính gián tiếp" - danh sách Python là một mảng các con trỏ tới các đối tượng Python, ít nhất 4 byte cho mỗi con trỏ cộng với 16 byte cho đối tượng Python nhỏ nhất (4 cho con trỏ kiểu, 4 cho số tham chiếu, 4 cho giá trị - và bộ cấp phát bộ nhớ làm tròn lên đến 16). Mảng NumPy là một mảng gồm các giá trị đồng nhất - các số có độ chính xác đơn lấy 4 byte mỗi, độ chính xác kép, 8 byte. Ít linh hoạt hơn, nhưng bạn phải trả đáng kể cho tính linh hoạt của danh sách Python tiêu chuẩn!


Tôi đã cố gắng sử dụng "sys.getsizeof ()" để so sánh kích thước của danh sách Python và mảng NumPy với cùng một số phần tử và dường như không chỉ ra rằng mảng NumPy nhỏ hơn nhiều. Đây có phải là trường hợp hay là sys.getsizeof () có vấn đề để tìm ra một mảng NumPy lớn như thế nào?
Jack Simpson

3
@JackSimpson getsizeofkhông đáng tin cậy. Tài liệu nêu rõ rằng: Chỉ có mức tiêu thụ bộ nhớ được gán trực tiếp cho đối tượng, chứ không phải mức tiêu thụ bộ nhớ của các đối tượng mà nó đề cập đến. Điều này có nghĩa là nếu bạn đã liệt kê python lồng kích thước của các phần tử không được tính đến.
Bakuriu

4
getsizeoftrong danh sách chỉ cho bạn biết chính đối tượng danh sách đó tiêu thụ bao nhiêu RAM và RAM được tiêu thụ bởi các con trỏ trong mảng dữ liệu của nó, nó không cho bạn biết mức độ tiêu thụ RAM của các đối tượng mà các con trỏ đó đề cập đến.
PM 2Ring

@AlexMartelli, bạn có thể vui lòng cho tôi biết bạn lấy những con số này ở đâu không?
lmiguelvargasf

Chỉ cần ngẩng cao lên, ước tính của bạn về kích thước của danh sách danh sách Python tương đương sẽ bị tắt. Mảng gọn gàng 4 GB của C floats (4 byte) sẽ dịch sang thứ gì đó gần với giá trị 32 GB của lists và Python float(thực tế là C doubles), không phải 12 GB; mỗi floatPython 64 bit chiếm ~ 24 byte (giả sử không có mất liên kết trong bộ cấp phát), cộng thêm 8 byte khác listđể giữ tham chiếu (và bỏ qua các tiêu đề tổng thể và tiêu đề cho listchính chúng, có thể thêm GB khác tùy thuộc vào chính xác bao nhiêu tổng thể xảy ra).
ShadowRanger

232

NumPy không chỉ hiệu quả hơn; nó cũng thuận tiện hơn Bạn nhận được rất nhiều hoạt động véc tơ và ma trận miễn phí, đôi khi cho phép một người tránh được những công việc không cần thiết. Và chúng cũng được thực hiện một cách hiệu quả.

Ví dụ: bạn có thể đọc khối của bạn trực tiếp từ một tệp thành một mảng:

x = numpy.fromfile(file=open("data"), dtype=float).reshape((100, 100, 100))

Tổng theo chiều thứ hai:

s = x.sum(axis=1)

Tìm những ô nào ở trên ngưỡng:

(x > 0.5).nonzero()

Xóa mọi lát cắt được lập chỉ mục chẵn dọc theo chiều thứ ba:

x[:, :, ::2]

Ngoài ra, nhiều thư viện hữu ích hoạt động với mảng NumPy. Ví dụ, phân tích thống kê và thư viện trực quan.

Ngay cả khi bạn không gặp vấn đề về hiệu suất, việc học NumPy vẫn đáng để nỗ lực.


Cảm ơn - bạn đã cung cấp một lý do chính đáng khác trong ví dụ thứ ba của mình, thực sự, tôi sẽ tìm kiếm ma trận cho các ô trên ngưỡng. Hơn nữa, tôi đã tải lên từ sqlLite. Cách tiếp cận tập tin sẽ hiệu quả hơn nhiều.
Thomas Browne

112

Alex đã đề cập đến hiệu quả bộ nhớ và Roberto đề cập đến sự tiện lợi, và cả hai đều là những điểm tốt. Để biết thêm một vài ý tưởng, tôi sẽ đề cập đến tốc độchức năng .

Chức năng: Bạn nhận được rất nhiều tích hợp với NumPy, FFT, kết luận, tìm kiếm nhanh, thống kê cơ bản, đại số tuyến tính, biểu đồ, v.v. Và thực sự, ai có thể sống mà không có FFT?

Tốc độ: Đây là một thử nghiệm để thực hiện tổng số trên một danh sách và mảng NumPy, cho thấy rằng tổng trên mảng NumPy nhanh hơn 10 lần (trong thử nghiệm này - số dặm có thể thay đổi).

from numpy import arange
from timeit import Timer

Nelements = 10000
Ntimeits = 10000

x = arange(Nelements)
y = range(Nelements)

t_numpy = Timer("x.sum()", "from __main__ import x")
t_list = Timer("sum(y)", "from __main__ import y")
print("numpy: %.3e" % (t_numpy.timeit(Ntimeits)/Ntimeits,))
print("list:  %.3e" % (t_list.timeit(Ntimeits)/Ntimeits,))

mà trên các hệ thống của tôi (trong khi tôi đang chạy bản sao lưu) sẽ cung cấp:

numpy: 3.004e-05
list:  5.363e-04

44

Đây là một câu trả lời hay từ FAQ trên trang web scipy.org :

Những lợi thế nào mà mảng NumPy cung cấp cho các danh sách Python (lồng nhau)?

Danh sách của Python là các thùng chứa đa năng hiệu quả. Chúng hỗ trợ (khá) hiệu quả việc chèn, xóa, nối thêm và nối, và việc hiểu danh sách của Python giúp chúng dễ dàng xây dựng và thao tác. Tuy nhiên, chúng có một số hạn chế nhất định: chúng không hỗ trợ các hoạt động được vectơ hóa của Viking như cộng và nhân theo nguyên tố, và thực tế là chúng có thể chứa các đối tượng thuộc các loại khác nhau có nghĩa là Python phải lưu trữ thông tin loại cho mọi phần tử và phải thực thi mã gửi loại khi hoạt động trên từng yếu tố. Điều này cũng có nghĩa là rất ít thao tác danh sách có thể được thực hiện bằng các vòng C hiệu quả - mỗi lần lặp sẽ yêu cầu kiểm tra loại và ghi sổ API Python khác.


9

Tất cả đã nhấn mạnh gần như tất cả sự khác biệt lớn giữa danh sách numpy và danh sách python, tôi sẽ chỉ tóm tắt chúng ở đây:

  1. Mảng Numpy có kích thước cố định khi tạo, không giống như danh sách python (có thể phát triển linh hoạt). Thay đổi kích thước của ndarray sẽ tạo ra một mảng mới và xóa bản gốc.

  2. Các phần tử trong một mảng Numpy đều được yêu cầu phải có cùng kiểu dữ liệu (chúng ta cũng có thể có kiểu không đồng nhất nhưng điều đó sẽ không cho phép bạn hoạt động toán học) và do đó sẽ có cùng kích thước trong bộ nhớ

  3. Mảng Numpy được tạo điều kiện thúc đẩy toán học và các loại hoạt động khác trên số lượng lớn dữ liệu. Thông thường các hoạt động như vậy được thực hiện hiệu quả hơn và với ít mã hơn có thể sử dụng xây dựng pythons theo trình tự

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.