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

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ặp

Cà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 NumPy

Ufuncs 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ảng

Cá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 loop
0Phủ định đơn nguyên (e. g. ,
100 loops, best of 3: 4.6 ms per loop
1)
100 loops, best of 3: 4.6 ms per loop
2
100 loops, best of 3: 4.6 ms per loop
3Phép nhân (e. g. ,
100 loops, best of 3: 4.6 ms per loop
4)
100 loops, best of 3: 4.6 ms per loop
5
100 loops, best of 3: 4.6 ms per loop
6Phân chia (e. g. ,
100 loops, best of 3: 4.6 ms per loop
7)_______8_______8
100 loops, best of 3: 4.6 ms per loop
9Phâ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 đối

Giố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ác

NumPy 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 loop
0

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 loop
1

1 loop, best of 3: 2.91 s per loop
2

Số mũ và logarit

Mộ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 loop
3

1 loop, best of 3: 2.91 s per loop
4

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 loop
5

1 loop, best of 3: 2.91 s per loop
6

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

1 loop, best of 3: 2.91 s per loop
8

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ành

NumPy 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 loop
9

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 cao

Nhiề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ài

Cuố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ữa

Bạ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