Hoạt động mảng Python
Cho đến bây giờ, chúng ta đã thảo luận về một số vấn đề cơ bản của NumPy; . Cụ thể, nó cung cấp một giao diện dễ dàng và linh hoạt để tối ưu hóa tính toán với các mảng dữ liệu Show
Tính toán trên mảng NumPy có thể rất nhanh hoặc có thể rất chậm. Chìa khóa để làm cho nó nhanh là sử dụng các hoạt động được véc tơ hóa, thường được triển khai thông qua các hàm phổ quát của NumPy (ufuncs). Phần này thúc đẩy nhu cầu về ufunc của NumPy, có thể được sử dụng để thực hiện các phép tính lặp lại trên các phần tử mảng hiệu quả hơn nhiều. Sau đó, nó giới thiệu nhiều ufunc số học phổ biến và hữu ích nhất có sẵn trong gói NumPy Sự chậm chạp của các vòng lặpCài đặt mặc định của Python (được gọi là CPython) thực hiện một số thao tác rất chậm. Điều này một phần là do bản chất năng động, được diễn giải của ngôn ngữ. thực tế là các loại linh hoạt, do đó các chuỗi hoạt động không thể được biên dịch thành mã máy hiệu quả như trong các ngôn ngữ như C và Fortran. Gần đây đã có nhiều nỗ lực khác nhau để giải quyết điểm yếu này. các ví dụ nổi tiếng là dự án PyPy, một triển khai Python được biên dịch kịp thời; . Mỗi cách trong số này đều có điểm mạnh và điểm yếu, nhưng có thể nói rằng không có cách tiếp cận nào trong số ba cách tiếp cận vượt qua phạm vi tiếp cận và mức độ phổ biến của công cụ CPython tiêu chuẩn Sự chậm chạp tương đối của Python thường thể hiện trong các tình huống có nhiều thao tác nhỏ được lặp lại – ví dụ như lặp qua các mảng để thao tác trên từng phần tử. Ví dụ: hãy tưởng tượng chúng ta có một mảng các giá trị và chúng ta muốn tính nghịch đảo của từng giá trị. Một cách tiếp cận đơn giản có thể trông như thế này Trong 1] import numpy as np np.random.seed(0) def compute_reciprocals(values): output = np.empty(len(values)) for i in range(len(values)): output[i] = 1.0 / values[i] return output values = np.random.randint(1, 10, size=5) compute_reciprocals(values) Ra[1] array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ]) Việc triển khai này có thể cảm thấy khá tự nhiên đối với một người nào đó có nền tảng C hoặc Java. Nhưng nếu chúng ta đo thời gian thực hiện mã này cho một đầu vào lớn, chúng ta sẽ thấy rằng hoạt động này rất chậm, có lẽ đáng ngạc nhiên là như vậy. Chúng tôi sẽ so sánh điều này với phép thuật [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ]8 của IPython (được thảo luận trong Mã hồ sơ và thời gian) Trong 2] big_array = np.random.randint(1, 100, size=1000000) %timeit compute_reciprocals(big_array) 1 loop, best of 3: 2.91 s per loop Phải mất vài giây để tính toán hàng triệu thao tác này và lưu trữ kết quả. Khi ngay cả điện thoại di động cũng có tốc độ xử lý được đo bằng Giga-FLOPS (i. e. , hàng tỷ phép toán số mỗi giây), điều này có vẻ chậm một cách vô lý. Hóa ra nút cổ chai ở đây không phải là bản thân các hoạt động, mà là kiểm tra kiểu và gửi chức năng mà CPython phải thực hiện ở mỗi chu kỳ của vòng lặp. Mỗi khi đối ứng được tính toán, trước tiên Python sẽ kiểm tra loại đối tượng và thực hiện tra cứu động của hàm chính xác để sử dụng cho loại đó. Thay vào đó, nếu chúng ta đang làm việc trong mã được biên dịch, đặc tả loại này sẽ được biết trước khi mã thực thi và kết quả có thể được tính toán hiệu quả hơn nhiều Giới thiệu UFuncĐối với nhiều loại hoạt động, NumPy cung cấp một giao diện thuận tiện cho loại quy trình được biên dịch, nhập tĩnh này. Điều này được gọi là một hoạt động véc tơ. Điều này có thể được thực hiện bằng cách đơn giản là thực hiện một thao tác trên mảng, thao tác này sau đó sẽ được áp dụng cho từng phần tử. Cách tiếp cận vector hóa này được thiết kế để đẩy vòng lặp vào lớp đã biên dịch làm nền tảng cho NumPy, giúp thực thi nhanh hơn nhiều So sánh kết quả của hai bài toán sau Trong 3] print(compute_reciprocals(values)) print(1.0 / values) [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ] Nhìn vào thời gian thực hiện cho mảng lớn của chúng tôi, chúng tôi thấy rằng nó hoàn thành các đơn đặt hàng lớn nhanh hơn vòng lặp Python Trong [4] %timeit (1.0 / big_array) ________số 8_______ Các hoạt động được vector hóa trong NumPy được triển khai thông qua ufunc, với mục đích chính là thực hiện nhanh chóng các hoạt động lặp lại trên các giá trị trong mảng NumPy. Ufuncs cực kỳ linh hoạt – trước đây chúng ta đã thấy thao tác giữa một vô hướng và một mảng, nhưng chúng ta cũng có thể thao tác giữa hai mảng Trong [5] np.arange(5) / np.arange(1, 6) Ra[5] array([ 0. , 0.5 , 0.66666667, 0.75 , 0.8 ]) Và các hoạt động của ufunc không bị giới hạn đối với mảng một chiều – chúng cũng có thể hoạt động trên mảng nhiều chiều. Trong [6] array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])0 Ra[6] array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])1 Các tính toán sử dụng vector hóa thông qua ufunc hầu như luôn hiệu quả hơn so với đối tác của chúng được triển khai bằng các vòng lặp Python, đặc biệt là khi các mảng tăng kích thước. Bất cứ khi nào bạn nhìn thấy một vòng lặp như vậy trong tập lệnh Python, bạn nên cân nhắc xem có thể thay thế vòng lặp đó bằng một biểu thức được vector hóa hay không Khám phá UFuncs của NumPyUfuncs tồn tại trong hai hương vị. ufunc đơn nguyên, hoạt động trên một đầu vào duy nhất và ufunc nhị phân, hoạt động trên hai đầu vào. Chúng ta sẽ xem các ví dụ về cả hai loại chức năng này tại đây Số học mảngCác ufunc của NumPy cảm thấy rất tự nhiên khi sử dụng vì chúng sử dụng các toán tử số học gốc của Python. Tất cả các phép cộng, trừ, nhân và chia tiêu chuẩn đều có thể được sử dụng Trong [7] array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])2 array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])3 Ngoài ra còn có một ufunc đơn nguyên cho phép phủ định và toán tử [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ]9 cho phép lũy thừa và toán tử %timeit (1.0 / big_array)0 cho mô đun Trong [8] array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])4 array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])5 Ngoài ra, những thứ này có thể được xâu chuỗi lại với nhau theo cách bạn muốn và thứ tự hoạt động tiêu chuẩn được tôn trọng Trong [9] array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])6 Ra[9] array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])7 Mỗi phép toán số học này chỉ đơn giản là các trình bao bọc thuận tiện xung quanh các chức năng cụ thể được tích hợp trong NumPy; Trong [10] array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])8 Ra[10] array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])9 Bảng sau liệt kê các toán tử số học được triển khai trong NumPy OperatorEquivalent ufuncDescription%timeit (1.0 / big_array)1 %timeit (1.0 / big_array)4Addition (e. g. , %timeit (1.0 / big_array)5) %timeit (1.0 / big_array)6 %timeit (1.0 / big_array)7Phép trừ (e. g. , %timeit (1.0 / big_array)8) %timeit (1.0 / big_array)6 100 loops, best of 3: 4.6 ms per loop0Phủ định đơn nguyên (e. g. , 100 loops, best of 3: 4.6 ms per loop1) 100 loops, best of 3: 4.6 ms per loop2 100 loops, best of 3: 4.6 ms per loop3Phép nhân (e. g. , 100 loops, best of 3: 4.6 ms per loop4) 100 loops, best of 3: 4.6 ms per loop5 100 loops, best of 3: 4.6 ms per loop6Phân chia (e. g. , 100 loops, best of 3: 4.6 ms per loop7)_______8_______8 100 loops, best of 3: 4.6 ms per loop9Phân chia tầng (e. g. , np.arange(5) / np.arange(1, 6)0) [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ]9 np.arange(5) / np.arange(1, 6)2Lũy thừa (e. g. , np.arange(5) / np.arange(1, 6)3) %timeit (1.0 / big_array)0 np.arange(5) / np.arange(1, 6)5Mô đun/phần dư (e. g. , np.arange(5) / np.arange(1, 6)6) Ngoài ra còn có các toán tử Boolean/bitwise; Giá trị tuyệt đốiGiống như NumPy hiểu các toán tử số học tích hợp sẵn của Python, nó cũng hiểu hàm giá trị tuyệt đối tích hợp sẵn của Python Trong [11] big_array = np.random.randint(1, 100, size=1000000) %timeit compute_reciprocals(big_array)0 Ra[11] big_array = np.random.randint(1, 100, size=1000000) %timeit compute_reciprocals(big_array)1 NumPy ufunc tương ứng là np.arange(5) / np.arange(1, 6)7, cũng có sẵn dưới bí danh np.arange(5) / np.arange(1, 6)8 Trong [12] big_array = np.random.randint(1, 100, size=1000000) %timeit compute_reciprocals(big_array)2 Ra[12] big_array = np.random.randint(1, 100, size=1000000) %timeit compute_reciprocals(big_array)1 Trong [13] big_array = np.random.randint(1, 100, size=1000000) %timeit compute_reciprocals(big_array)4 Ra[13] big_array = np.random.randint(1, 100, size=1000000) %timeit compute_reciprocals(big_array)1 Ufunc này cũng có thể xử lý dữ liệu phức tạp, trong đó giá trị tuyệt đối trả về độ lớn Trong [14] big_array = np.random.randint(1, 100, size=1000000) %timeit compute_reciprocals(big_array)6 Ra[14] big_array = np.random.randint(1, 100, size=1000000) %timeit compute_reciprocals(big_array)7 Hàm lượng giácNumPy cung cấp một số lượng lớn các ufunc hữu ích và một số hữu ích nhất cho nhà khoa học dữ liệu là các hàm lượng giác. Chúng ta sẽ bắt đầu bằng cách xác định một loạt các góc Trong [15] big_array = np.random.randint(1, 100, size=1000000) %timeit compute_reciprocals(big_array)8 Bây giờ chúng ta có thể tính toán một số hàm lượng giác trên các giá trị này Trong [16] big_array = np.random.randint(1, 100, size=1000000) %timeit compute_reciprocals(big_array)9 1 loop, best of 3: 2.91 s per loop0 Các giá trị được tính theo độ chính xác của máy, đó là lý do tại sao các giá trị phải bằng 0 không phải lúc nào cũng chính xác bằng 0. Hàm lượng giác nghịch đảo cũng có sẵn Trong [17] 1 loop, best of 3: 2.91 s per loop1 1 loop, best of 3: 2.91 s per loop2 Số mũ và logaritMột loại hoạt động phổ biến khác có sẵn trong ufunc NumPy là hàm mũ Trong [18] 1 loop, best of 3: 2.91 s per loop3 1 loop, best of 3: 2.91 s per loop4 Nghịch đảo của cấp số nhân, logarit, cũng có sẵn. Cơ bản np.arange(5) / np.arange(1, 6)9 cho logarit tự nhiên; Trong 19] 1 loop, best of 3: 2.91 s per loop5 1 loop, best of 3: 2.91 s per loop6 Ngoài ra còn có một số phiên bản chuyên biệt hữu ích để duy trì độ chính xác với đầu vào rất nhỏ Trong 20] 1 loop, best of 3: 2.91 s per loop7 1 loop, best of 3: 2.91 s per loop8 Khi array([ 0. , 0.5 , 0.66666667, 0.75 , 0.8 ])0 rất nhỏ, các hàm này cho giá trị chính xác hơn so với khi sử dụng np.arange(5) / np.arange(1, 6)9 hoặc array([ 0. , 0.5 , 0.66666667, 0.75 , 0.8 ])2 thô ufunc chuyên ngànhNumPy có sẵn nhiều ufunc khác, bao gồm các hàm lượng giác hyperbolic, số học bitwise, toán tử so sánh, chuyển đổi từ radian sang độ, làm tròn và phần dư, v.v. Xem qua tài liệu NumPy cho thấy rất nhiều chức năng thú vị Một nguồn tuyệt vời khác cho các ufunc chuyên biệt và khó hiểu hơn là mô hình con array([ 0. , 0.5 , 0.66666667, 0.75 , 0.8 ])3. Nếu bạn muốn tính toán một hàm toán học mơ hồ nào đó trên dữ liệu của mình, rất có thể nó được triển khai trong array([ 0. , 0.5 , 0.66666667, 0.75 , 0.8 ])3. Có quá nhiều chức năng để liệt kê tất cả, nhưng đoạn mã sau đây cho thấy một số chức năng có thể xuất hiện trong ngữ cảnh thống kê Trong [21] 1 loop, best of 3: 2.91 s per loop9 Trong [22] print(compute_reciprocals(values)) print(1.0 / values)0 print(compute_reciprocals(values)) print(1.0 / values)1 Trong [23] print(compute_reciprocals(values)) print(1.0 / values)2 print(compute_reciprocals(values)) print(1.0 / values)3 Có rất nhiều, rất nhiều ufunc khác có sẵn trong cả NumPy và array([ 0. , 0.5 , 0.66666667, 0.75 , 0.8 ])3. Bởi vì tài liệu của các gói này có sẵn trực tuyến, tìm kiếm trên web dọc theo dòng "chức năng gamma python" thường sẽ tìm thấy thông tin liên quan Tính năng Ufunc nâng caoNhiều người dùng NumPy sử dụng ufunc mà không cần học đầy đủ các tính năng của chúng. Chúng tôi sẽ phác thảo một số tính năng chuyên biệt của ufunc tại đây Chỉ định đầu raĐối với các phép tính lớn, đôi khi rất hữu ích khi có thể chỉ định mảng nơi kết quả của phép tính sẽ được lưu trữ. Thay vì tạo một mảng tạm thời, điều này có thể được sử dụng để ghi kết quả tính toán trực tiếp vào vị trí bộ nhớ mà bạn muốn chúng ở đó. Đối với tất cả ufunc, điều này có thể được thực hiện bằng cách sử dụng đối số array([ 0. , 0.5 , 0.66666667, 0.75 , 0.8 ])6 của hàm Trong [24] print(compute_reciprocals(values)) print(1.0 / values)4 print(compute_reciprocals(values)) print(1.0 / values)5 Điều này thậm chí có thể được sử dụng với chế độ xem mảng. Ví dụ: chúng ta có thể viết kết quả tính toán cho mọi phần tử khác của một mảng được chỉ định Trong [25] print(compute_reciprocals(values)) print(1.0 / values)6 print(compute_reciprocals(values)) print(1.0 / values)7 Thay vào đó, nếu chúng ta viết array([ 0. , 0.5 , 0.66666667, 0.75 , 0.8 ])7, điều này sẽ dẫn đến việc tạo ra một mảng tạm thời để giữ kết quả của array([ 0. , 0.5 , 0.66666667, 0.75 , 0.8 ])8, tiếp theo là thao tác thứ hai sao chép các giá trị đó vào mảng array([ 0. , 0.5 , 0.66666667, 0.75 , 0.8 ])9. Điều này không tạo ra nhiều sự khác biệt đối với một phép tính nhỏ như vậy, nhưng đối với các mảng rất lớn, việc tiết kiệm bộ nhớ từ việc sử dụng cẩn thận đối số array([ 0. , 0.5 , 0.66666667, 0.75 , 0.8 ])6 có thể là đáng kể uẩnĐối với các ufunc nhị phân, có một số tập hợp thú vị có thể được tính trực tiếp từ đối tượng. Ví dụ: nếu chúng tôi muốn giảm một mảng bằng một thao tác cụ thể, chúng tôi có thể sử dụng phương thức array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])01 của bất kỳ ufunc nào. Giảm liên tục áp dụng một thao tác nhất định cho các phần tử của một mảng cho đến khi chỉ còn lại một kết quả duy nhất Ví dụ: gọi array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])01 trên ufunc %timeit (1.0 / big_array)2 trả về tổng của tất cả các phần tử trong mảng Trong [26] print(compute_reciprocals(values)) print(1.0 / values)8 Hết[26] print(compute_reciprocals(values)) print(1.0 / values)9 Tương tự, gọi array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])01 trên ufunc array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])05 dẫn đến tích của tất cả các phần tử mảng Trong [27] [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ]0 Hết[27] [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ]1 Nếu chúng ta muốn lưu trữ tất cả các kết quả trung gian của phép tính, thay vào đó, chúng ta có thể sử dụng array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])06 Trong [28] [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ]2 Hết[28] [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ]3 Trong [29] [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ]4 Hết[29] [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ]5 Lưu ý rằng đối với những trường hợp cụ thể này, có các hàm NumPy chuyên dụng để tính toán kết quả ( array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])07, array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])08, array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])09, array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])10), mà chúng ta sẽ khám phá trong Tổng hợp. Tối thiểu, Tối đa và Mọi thứ ở giữa sản phẩm bên ngoàiCuối cùng, bất kỳ ufunc nào cũng có thể tính toán đầu ra của tất cả các cặp có hai đầu vào khác nhau bằng cách sử dụng phương thức array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])11. Điều này cho phép bạn, trong một dòng, làm những việc như tạo bảng cửu chương Trong [30] [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ]6 Ra[30] [ 0.16666667 1. 0.25 0.25 0.125 ] [ 0.16666667 1. 0.25 0.25 0.125 ]7 Các phương pháp array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])12 và array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])13, mà chúng ta sẽ khám phá trong Lập chỉ mục ưa thích, cũng rất hữu ích Một tính năng cực kỳ hữu ích khác của ufunc là khả năng hoạt động giữa các mảng có kích thước và hình dạng khác nhau, một tập hợp các hoạt động được gọi là phát sóng. Chủ đề này quan trọng đến mức chúng ta sẽ dành cả một phần cho nó (xem Tính toán trên mảng. Phát thanh truyền hình) Ufunc. Học nhiều hơn nữaBạn có thể tìm thêm thông tin về các hàm phổ dụng (bao gồm danh sách đầy đủ các hàm khả dụng) trên các trang web tài liệu NumPy và SciPy Nhớ lại rằng bạn cũng có thể truy cập thông tin trực tiếp từ bên trong IPython bằng cách nhập các gói và sử dụng chức năng hoàn thành tab và trợ giúp ( array([ 0.16666667, 1. , 0.25 , 0.25 , 0.125 ])14) của IPython, như được mô tả trong Trợ giúp và Tài liệu trong IPython có nghĩa là gì [. ] có nghĩa là gì trong mảng Python?Các [. ] tạo một bản sao nông của mảng , do đó cho phép bạn sửa đổi bản sao của mình mà không làm hỏng bản gốc. Lý do điều này cũng hoạt động đối với các chuỗi là trong Python, Chuỗi là các mảng byte đại diện cho các ký tự Unicode.
Các hoạt động của mảng là gì?Thao tác cơ bản
. Traverse − print all the array elements one by one. Chèn − Thêm phần tử vào chỉ mục đã cho. Xóa - Xóa một phần tử tại chỉ mục đã cho. Tìm kiếm - Tìm kiếm một phần tử bằng cách sử dụng chỉ mục đã cho hoặc theo giá trị.
Làm cách nào để xây dựng mảng trong Python?Trong Python, bạn có thể tạo kiểu dữ liệu mới, được gọi là mảng bằng cách sử dụng gói NumPy. Mảng NumPy được tối ưu hóa cho các phân tích số và chỉ chứa một loại dữ liệu duy nhất. Trước tiên, bạn nhập NumPy rồi sử dụng hàm array() để tạo một mảng . Hàm array() lấy một danh sách làm đầu vào.
Các hoạt động khác nhau của NumPy trong Python là gì?Hoạt động. . sử dụng np. trục mới và np. định hình lại. . Chuyển đổi bất kỳ loại dữ liệu nào thành mảng NumPy. . Nhận một mảng n chiều của những cái. . np. đầy đủ và np. trống. . Lấy một mảng các giá trị cách đều nhau với np. sắp xếp và np. khoảng trống. . Cách tạo một bản sao của mảng NumPy. . Nhận chuyển vị của một mảng n-d |