6.12. Lựa chọn và sắp xếp lại¶
Các phép rút gọn thu gọn mảng thành một giá trị vô hướng hoặc kết quả có bậc thấp hơn. Lựa chọn bao gồm các phép toán xác định phần tử nào được giữ lại và chúng kết thúc ở đâu: lựa chọn có điều kiện, cắt ngưỡng, sắp xếp, tra cứu chỉ số, sắp xếp lại theo trục.
6.12.1. Lựa chọn có điều kiện¶
where() trả về một mảng lấy phần tử từ x khi điều kiện đúng và từ y khi điều kiện sai. Ba toán hạng được phát (broadcast) cùng nhau:
a = np.array([1, 2, 3, 4, 5], dtype=np.float)
np.where(a < 3, a, 0.0)
# array([1.0, 2.0, 0.0, 0.0, 0.0])
Đây là công cụ phù hợp cho phép "if/else theo từng phần tử" mà không cần viết vòng lặp Python.
clip() là cách viết tắt của maximum(lo, minimum(a, hi)) -- bão hòa các giá trị vào một khoảng:
np.clip(a, 2.0, 4.0)
# array([2.0, 2.0, 3.0, 4.0, 4.0])
maximum() và minimum() nhận hai toán hạng và trả về phần tử lớn hơn / nhỏ hơn theo từng phần tử:
np.maximum(a, 3.0)
np.minimum(a, np.array([5, 4, 3, 2, 1]))
6.12.2. Tìm chỉ số¶
nonzero() trả về tọa độ của mọi phần tử khác không, tách thành một mảng chỉ số cho mỗi chiều. Với đầu vào 2-D, kết quả là một tuple gồm hai mảng: mảng đầu tiên chứa chỉ số hàng, mảng thứ hai chứa chỉ số cột. Ghép chúng theo từng cột cho ta (row, col) của từng vị trí khác không:
m = np.array([[0, 2, 0],
[3, 0, 0]], dtype=np.float)
np.nonzero(m)
# (array([0, 1], dtype=uint16), array([1, 0], dtype=uint16))
Các phần tử khác không trong m là m[0, 1] = 2 và m[1, 0] = 3. Mảng đầu tiên [0, 1] cho biết chỉ số hàng của chúng; mảng thứ hai [1, 0] cho biết chỉ số cột. Đọc song song hai mảng cho ta vị trí (0, 1) và (1, 0).
Hai phép rút gọn cũng trả về chỉ số:
argmin()/argmax()-- chỉ số của phần tử nhỏ nhất / lớn nhất.argsort()-- một mảng số nguyên mà nếu dùng để sắp xếp thì sẽ sắp xếp đầu vào theo trục được chỉ định (mặc định là trục cuối):a = np.array([40, 10, 30, 20], dtype=np.uint8) idx = np.argsort(a) # array([1, 3, 2, 0], dtype=uint16) a[idx] # array([10, 20, 30, 40])
argsortluôn trả vềuint16; do đó mảng được sắp xếp phải có không quá 65.535 phần tử trên trục sắp xếp.
bincount() đếm số lần xuất hiện của mỗi số nguyên không âm trong đầu vào uint8 / uint16 1-D:
histogram = np.bincount(np.array([0, 1, 1, 2, 2, 2], dtype=np.uint8))
# array([1, 2, 3], dtype=uint16)
Hữu ích để xây dựng biểu đồ tần suất của các giá trị điểm ảnh số nguyên nhỏ mà không cần viết vòng lặp Python.
6.12.3. Sắp xếp và sắp xếp lại¶
sort() trả về một bản sao đã được sắp xếp của mảng theo trục được chỉ định (mặc định là trục cuối). Dùng sort() trực tiếp trên mảng để sắp xếp tại chỗ:
np.sort(np.array([3, 1, 2], dtype=np.float))
# array([1.0, 2.0, 3.0])
flip() đảo ngược thứ tự theo trục được chỉ định (mọi trục khi không truyền axis):
np.flip(np.array([1, 2, 3, 4]))
# array([4, 3, 2, 1])
roll() dịch chuyển tuần hoàn các phần tử theo số lượng cho trước. Hữu ích để triển khai thanh ghi dịch theo kiểu ring-buffer:
np.roll(np.array([1, 2, 3, 4]), 1)
# array([4, 1, 2, 3])
take() là dạng tường minh của fancy indexing -- lấy các phần tử tại các chỉ số tùy ý:
a = np.array([10, 20, 30, 40, 50], dtype=np.uint8)
np.take(a, [0, 2, 4])
# array([10, 30, 50], dtype=uint8)
6.12.4. Lọc và chỉnh sửa cấu trúc¶
compress() là dạng tường minh của boolean indexing -- trả về các lát cắt của a được chọn bởi điều kiện boolean:
a = np.array([10, 20, 30, 40], dtype=np.uint8)
np.compress(a > 15, a)
# array([20, 30, 40], dtype=uint8)
delete() trả về một bản sao với các phần tử tại các chỉ số đã cho bị xóa:
a = np.array([10, 20, 30, 40, 50], dtype=np.uint8)
np.delete(a, [1, 3])
# array([10, 30, 50], dtype=uint8)
diff() trả về hiệu sai phân rời rạc tiến bậc n của mảng theo một trục. Dùng để tính các thay đổi bậc nhất giữa các mẫu liền kề:
samples = np.array([1, 3, 6, 10, 15], dtype=np.float)
np.diff(samples)
# array([2.0, 3.0, 4.0, 5.0])
6.12.5. Chi phí của từng phép toán¶
Hầu hết mọi hàm trên trang này đều trả về một mảng mới được cấp phát. Có hai ngoại lệ:
sort()sắp xếp tại chỗ; hàm độc lậpsort()trả về một bản sao đã được sắp xếp.take()chấp nhận từ khóaout=để ghi vào bộ đệm đã tồn tại sẵn.
Trong một vòng lặp chạy nhiều lần mỗi giây, hãy ưu tiên sort() tại chỗ và tái sử dụng các bộ đệm đã cấp phát trước ở mọi nơi khác. Các mặt nạ boolean được cấp phát mỗi lần phép so sánh chạy -- hãy xây dựng mặt nạ một lần và tái sử dụng nó qua các phép toán thay vì xây dựng lại bên trong mỗi lần lặp.