Tạo mảng có cấu trúc¶
Có nhiều cách để chỉ định kiểu dữ liệu mảng có cấu trúc.Trước đó, chúng ta đã thấy phương pháp từ điển:
np.dtype({'names':('name', 'age', 'weight'), 'formats':('U10', 'i4', 'f8')})
dtype([('name', '<U10'), ('age', '<i4'), ('weight', '<f8')])
Để rõ ràng, các loại số có thể được chỉ định bằng cách sử dụng các kiểu dữ liệu Python hoặc các dtype
của NumPy:
np.dtype({'names':('name', 'age', 'weight'), 'formats':((np.str_, 10), int, np.float32)})
dtype([('name', '<U10'), ('age', '<i8'), ('weight', '<f4')])
Một kiểu hợp chất cũng có thể được chỉ định dưới dạng một danh sách các bộ:
np.dtype([('name', 'S10'), ('age', 'i4'), ('weight', 'f8')])
dtype([('name', 'S10'), ('age', '<i4'), ('weight', '<f8')])
Nếu các tên loại không quan trọng đối với bạn, bạn có thể chỉ định các loại riêng lẻ trong một chuỗi được phân cách bằng dấu phẩy:
np.dtype('S10,i4,f8')
dtype([('f0', 'S10'), ('f1', '<i4'), ('f2', '<f8')])
Các mã định dạng chuỗi rút gọn có thể có vẻ khó hiểu, nhưng chúng được xây dựng trên những nguyên tắc đơn giản.Kí tự đầu tiên (tùy chọn) là <
hoặc >
, nghĩa là “little endian” hoặc “big endian”, tương ứng, và chỉ định quy ước sắp xếp cho các bit có ý nghĩa.Kí tự tiếp theo chỉ định kiểu dữ liệu: kí tự, byte, int, floating point và vân vân (xem bảng dưới đây).Kí tự cuối cùng hoặc các kí tự còn lại đại diện cho kích thước của đối tượng tính bằng byte.
Các Loại Tổ Hợp Nâng Cao Hơn
Có thể định nghĩa các loại hợp chất phức tạp hơn.Ví dụ, bạn có thể tạo ra một loại dữ liệu mà mỗi phần tử chứa một mảng hoặc ma trận giá trị.Ở đây, chúng ta sẽ tạo ra một loại dữ liệu với một thành phần mat
bao gồm một ma trận số thực kích thước $3\times 3$:
tp = np.dtype([('id', 'i8'), ('mat', 'f8', (3, 3))])X = np.zeros(1, dtype=tp)print(X[0])print(X['mat'][0])
(0, [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]])[[ 0. 0. 0.] [ 0. 0. 0.] [ 0. 0. 0.]]
Bây giờ mỗi phần tử trong mảng X
bao gồm một id
và một ma trận $3\times 3$.Tại sao lại sử dụng điều này thay vì một mảng đa chiều đơn giản, hoặc có lẽ là một từ điển Python?Lý do là loại dữ liệu dtype
này của NumPy trực tiếp ánh xạ vào một định nghĩa cấu trúc C, vì vậy bộ đệm chứa nội dung mảng có thể được truy cập trực tiếp trong một chương trình C được viết phù hợp.Nếu bạn thấy mình đang viết một giao diện Python cho một thư viện C hay Fortran cũ xử lý dữ liệu có cấu trúc, bạn có thể thấy rằng các mảng có cấu trúc rất hữu ích!
RecordArrays: Mảng Cấu trúc với Một Chút Thay Đổi¶
NumPy cũng cung cấp lớp np.recarray
, tương tự như mảng có cấu trúc vừa được miêu tả, nhưng có một tính năng bổ sung: các trường có thể được truy cập như là các thuộc tính thay vì là các khóa từ điển.Nhớ rằng chúng ta trước đó đã truy cập vào tuổi bằng cách viết:
data['age']
array([25, 45, 37, 19], dtype=int32)
Nếu chúng ta xem dữ liệu của chúng ta như một mảng ghi chú thay vì thế, chúng ta có thể truy cập nó với số lượt đánh máy ít hơn một chút:
data_rec = data.view(np.recarray)data_rec.age
array([25, 45, 37, 19], dtype=int32)
Bất lợi là, đối với các mảng ghi, có một số công đoạn phức tạp hơn để truy cập các trường, ngay cả khi sử dụng cú pháp giống nhau. Chúng ta có thể thấy điều này ở đây:
%timeit data['age']%timeit data_rec['age']%timeit data_rec.age
1000000 loops, best of 3: 241 ns per loop100000 loops, best of 3: 4.61 µs per loop100000 loops, best of 3: 7.27 µs per loop
Dù viết ngắn gọn hơn có đáng đổi lại việc tốn thêm công suất xử lí hay không phụ thuộc vào ứng dụng của bạn.
Tiến tới Pandas¶
Phần này về mảng có cấu trúc và mảng ghi chú ý được đặt ở cuối chương này, vì nó rất tốt để tiếp nối với gói tiếp theo chúng tôi sẽ bàn về: Pandas.Mảng có cấu trúc như những cái đã được thảo luận ở đây là tốt để biết với các tình huống cụ thể, đặc biệt là trong trường hợp bạn đang sử dụng mảng NumPy để ánh xạ vào định dạng dữ liệu nhị phân trong C, Fortran hoặc một ngôn ngữ khác.Đối với việc sử dụng dữ liệu có cấu trúc hàng ngày, gói Pandas là sự lựa chọn tốt hơn nhiều và chúng ta sẽ đào sâu vào cuộc thảo luận chi tiết về nó trong chương tiếp theo.