Nếu bạn muốn tránh chi phí bộ nhớ khi chuyển đổi thành một loạt các bộ dữ liệu hoặc cấu trúc dữ liệu tương tự khác, bạn có thể khai thác các mảng có cấu trúc của numpy.
Mẹo nhỏ là xem mảng ban đầu của bạn dưới dạng một mảng có cấu trúc, trong đó mỗi mục tương ứng với một hàng của mảng ban đầu. Điều này không tạo ra một bản sao, và khá hiệu quả.
Ví dụ nhanh:
import numpy as np
data = np.array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
ncols = data.shape[1]
dtype = data.dtype.descr * ncols
struct = data.view(dtype)
uniq = np.unique(struct)
uniq = uniq.view(data.dtype).reshape(-1, ncols)
print uniq
Để hiểu những gì đang xảy ra, hãy xem kết quả trung gian.
Khi chúng ta xem mọi thứ như một mảng có cấu trúc, mỗi phần tử trong mảng là một hàng trong mảng ban đầu của bạn. (Về cơ bản, đây là cấu trúc dữ liệu tương tự như danh sách các bộ dữ liệu.)
In [71]: struct
Out[71]:
array([[(1, 1, 1, 0, 0, 0)],
[(0, 1, 1, 1, 0, 0)],
[(0, 1, 1, 1, 0, 0)],
[(1, 1, 1, 0, 0, 0)],
[(1, 1, 1, 1, 1, 0)]],
dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])
In [72]: struct[0]
Out[72]:
array([(1, 1, 1, 0, 0, 0)],
dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])
Khi chúng tôi chạy numpy.unique
, chúng tôi sẽ lấy lại một mảng có cấu trúc:
In [73]: np.unique(struct)
Out[73]:
array([(0, 1, 1, 1, 0, 0), (1, 1, 1, 0, 0, 0), (1, 1, 1, 1, 1, 0)],
dtype=[('f0', '<i8'), ('f1', '<i8'), ('f2', '<i8'), ('f3', '<i8'), ('f4', '<i8'), ('f5', '<i8')])
Sau đó chúng ta cần xem như một mảng "bình thường" ( _
lưu trữ kết quả của phép tính cuối cùng ipython
, đó là lý do tại sao bạn nhìn thấy _.view...
):
In [74]: _.view(data.dtype)
Out[74]: array([0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0])
Và sau đó định hình lại thành một mảng 2D ( -1
là một trình giữ chỗ cho numpy để tính toán số lượng hàng chính xác, đưa ra số lượng cột):
In [75]: _.reshape(-1, ncols)
Out[75]:
array([[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
Rõ ràng, nếu bạn muốn ngắn gọn hơn, bạn có thể viết nó dưới dạng:
import numpy as np
def unique_rows(data):
uniq = np.unique(data.view(data.dtype.descr * data.shape[1]))
return uniq.view(data.dtype).reshape(-1, data.shape[1])
data = np.array([[1, 1, 1, 0, 0, 0],
[0, 1, 1, 1, 0, 0],
[0, 1, 1, 1, 0, 0],
[1, 1, 1, 0, 0, 0],
[1, 1, 1, 1, 1, 0]])
print unique_rows(data)
Kết quả nào trong:
[[0 1 1 1 0 0]
[1 1 1 0 0 0]
[1 1 1 1 1 0]]