Tự Học Data Science · 23/09/2023 0

Chương 2 – Bài 2 – Cơ bản về NumPy Arrays

Thuộc tính của mảng NumPy

Đầu tiên, chúng ta hãy thảo luận về một số thuộc tính mảng. Chúng ta sẽ bắt đầu bằng cách xác định ba mảng ngẫu nhiên, một chiều, hai chiều và ba chiều.Chúng ta sẽ sử dụng trình tạo số ngẫu nhiên của NumPy, mà chúng ta sẽ “seed” bằng một giá trị cố định để đảm bảo rằng cùng một mảng ngẫu nhiên được tạo ra mỗi khi chạy mã này:

import numpy as np
np.random.seed(0)  # seed for reproducibility
x1 = np.random.randint(10, size=6)  # One-dimensional array
x2 = np.random.randint(10, size=(3, 4))  # Two-dimensional array
x3 = np.random.randint(10, size=(3, 4, 5))  # Three-dimensional array

Mỗi mảng có các thuộc tính ndim (số chiều), shape (kích thước của mỗi chiều) và size (kích thước tổng của mảng):

print("x3 ndim: ", x3.ndim)
print("x3 shape:", x3.shape)
print("x3 size: ", x3.size)
x3 ndim:  3
x3 shape: (3, 4, 5)
x3 size:  60

Một thuộc tính hữu ích khác là dtype, loại dữ liệu của mảng (cùng được chúng ta đã thảo luận trước đây trong bài viết Hiểu rõ kiểu dữ liệu trong Python):

print("dtype:", x3.dtype)
dtype: int64

Các thuộc tính khác bao gồm itemsize, liệt kê kích thước (theo byte) của mỗi phần tử trong mảng, và nbytes, liệt kê tổng kích thước (theo byte) của mảng:

print("itemsize:", x3.itemsize, "bytes")
print("nbytes:", x3.nbytes, "bytes")
itemsize: 8 bytes
nbytes: 480 bytes

Đại khái, nbytes bằng itemsize nhân với size.

Cấu trúc Mảng: Truy cập phần tử đơn

Nếu bạn quen thuộc với việc index phần tử trong list của Python, chỉ mục trong NumPy sẽ cảm giác rất quen thuộc.Trong một mảng một chiều, giá trị thứ $i$ (đếm từ không) có thể được truy cập bằng cách chỉ định chỉ mục mong muốn trong dấu ngoặc vuông, giống như trong danh sách Python:

Để lập chỉ mục từ cuối của mảng, bạn có thể sử dụng chỉ mục âm:

Trong một mảng đa chiều, các phần tử có thể được truy cập bằng cách sử dụng một bộ chỉ số được phân tách bằng dấu phẩy:

Giá trị cũng có thể được sửa đổi bằng cách sử dụng bất kỳ cú pháp nào bên trên:

Nhớ rằng, khác với list trong Python, mảng NumPy có một loại dữ liệu cố định. Điều này có nghĩa, ví dụ, nếu bạn cố gắng chèn một giá trị thập phân vào một mảng số nguyên, giá trị sẽ bị cắt đi trong im lặng. Đừng bất ngờ!

Array Slicing: Truy cập vào các mảng con

Giống như chúng ta có thể sử dụng các dấu ngoặc vuông để truy cập từng phần tử của mảng, chúng ta cũng có thể sử dụng chúng để truy cập các mảng con với cú pháp slice, được đánh dấu bằng ký tự hai chấm (:).

x[start:stop:step]

Nếu bất kỳ giá trị nào không được chỉ định, chúng mặc định là các giá trị start=0, stop=kích thước của chiều, step=1. Dưới đây là các cách truy cập các mảng con trong một chiều và trong nhiều chiều.

Mảng con một chiều

Một trường hợp có thể gây khó hiểu là khi giá trị của step là số âm. Trong trường hợp này, giá trị mặc định cho startstop bị đảo ngược. Đây một cách tiện lợi để đảo ngược một mảng:

Mảng con nhiều chiều

Phương pháp bên trên cho mảng nhiều chiều hoạt động theo cách tương tự, với nhiều khoảng phân tách bằng dấu phẩy. Ví dụ:

Cuối cùng, mảng con có thể được đảo ngược luôn:

Truy cập hàng và cột trong mảng

Một cách thông thường để truy cập các hàng hoặc cột duy nhất của một mảng là kết hợp index và slice:

Trong trường hợp truy xuất một hàng, phần slice có thể được bỏ qua để cú pháp gọn hơn:

Các mảng con là view, không phải copy

Một điểm quan trọng và cực kỳ hữu ích về phần cắt mảng là nó trả về views thay vì copies của dữ liệu mảng. Đây là phần mà slicing trong NumPy khác biệt so với list Python: trong list, các thành phần con sẽ là các bản sao. Xem xét mảng hai chiều của chúng ta từ trước và trích xuất một phần mảng có kích thước 2x2:

Bây giờ nếu chúng ta thay đổi mảng con này, chúng ta sẽ thấy rằng mảng gốc bị thay đổi!

Cái này khá hữu ích khi chúng ta làm việc với các bộ dữ liệu lớn, chúng ta có thể truy cập và xử lý các phần của nó mà không cần tốn bộ nhớ để sao chép 1 phần của mảng gốc.

Tạo bản sao của mảng

Dù có những tính năng tuyệt vời của các bộ xem mảng, đôi khi việc sao chép dữ liệu trong một mảng hoặc mảng con lại là cần thiết. Điều này có thể được thực hiện một cách dễ dàng nhất bằng phương thức copy():

Nếu chúng ta chỉnh sửa phần con này, mảng gốc sẽ không bị tác động:

Cấu trúc lại các Mảng

Cách linh hoạt nhất để tái cấu trúc một mảng là sử dụng phương thức reshape. Ví dụ, nếu bạn muốn đặt các số từ 1 đến 9 vào một mảng 3x3, bạn có thể làm như sau:

Chú ý rằng để phương thức này hoạt động, kích thước của mảng ban đầu phải khớp với kích thước của mảng được reshape.

Một cách reshape phổ biến khác là chuyển đổi một mảng một chiều thành một ma trận hai chiều dạng hàng hoặc cột. Điều này có thể được thực hiện bằng phương thức reshape, hoặc dễ dàng hơn bằng cách sử dụng từ khóa newaxis với slice:

Chúng ta sẽ thường xuyên thấy loại reshape này trong phần còn lại của series.

Ghép và tách mảng – Concatenation và Splitting

Tất cả các quy trình trước đó đều hoạt động trên các mảng đơn. Ta cũng có thể kết hợp nhiều mảng thành một và ngược lại chia một mảng thành nhiều mảng. Chúng ta sẽ tìm hiểu những thao tác đó ở đây.

Ghép các mảng thành một mảng duy nhất – Concatenation

Kết hợp, hoặc ghép hai mảng trong NumPy, chủ yếu được thực hiện bằng cách sử dụng các hàm np.concatenate, np.vstack, và np.hstack.np.concatenate lấy một bộ nhiều hoặc danh sách các mảng làm đối số đầu tiên, như chúng ta có thể thấy ở đây:

Bạn cũng có thể nối hai hay nhiều mảng cùng lúc:

Nó cũng có thể được sử dụng cho các mảng hai chiều:

Để ghép các mảng có kích thước khác nhau, có thể sử dụng rõ ràng các hàm np.vstack (vertical stack) và np.hstack (horizontal stack) để ghép theo chiều tương ứng:

Tương tự, np.dstack sẽ xếp chồng các mảng theo trục thứ ba.

Phân chia mảng – Splitting

Ngược lại với ghép mảng, chia mảng được thực hiện bởi các hàm np.split, np.hsplitnp.vsplit. Đối với mỗi hàm này, chúng ta có thể truyền một danh sách các chỉ mục chỉ định điểm chia:

Lưu ý rằng N điểm chia sẽ tạo ra N + 1 mảng con. Các hàm liên quan np.hsplitnp.vsplit tương tự nhau:

Tương tự, np.dsplit sẽ chia các mảng theo trục thứ ba.