Trong số những điều tôi đã cố gắng cho đến nay, giải pháp PyTables hiện là tốt nhất, tiếp theo là giải pháp sử dụng hỗ trợ của numpy
cho mảng được ghi nhớ. Các giải pháp PyTables là không đơn giản mặc dù.Nếu bạn sử dụng một mảng xáo trộn của các số nguyên để trực tiếp chỉ mục một mảng PyTables, nó rất chậm. Nhanh hơn nhiều là quy trình gồm hai bước sau:
- Chọn một tập hợp con ngẫu nhiên của mảng sử dụng mảng chỉ mục boolean. Điều này phải được thực hiện theo cách chunkwise. Nếu bạn truyền mảng chỉ mục trực tiếp vào mảng PyTables, nó sẽ chậm.
- Preallocate một mảng numpy và tạo danh sách các lát tách mảng PyTables thành các khối.
- Đọc từng đoạn hoàn toàn vào bộ nhớ, sau đó sử dụng đoạn tương ứng của mảng chỉ mục để chọn giá trị chính xác cho đoạn đó.
- Lưu trữ các giá trị đã chọn trong mảng được phân bổ trước.
- Sau đó, xáo trộn mảng được phân bổ trước.
Quy trình này tạo ra hoán vị ngẫu nhiên như quy trình xáo trộn bình thường. Nếu điều đó không rõ ràng, hãy xem xét điều này: (n choose x) * x! = x! * n!/(x! * (n - x)!) = n!/(n - x)!
. Phương pháp này đủ nhanh để thực hiện tải ngẫu nhiên cho mỗi chu kỳ đào tạo. Nó cũng có thể nén dữ liệu xuống ~ 650M - gần như giảm 90%.
Đây là triển khai hiện tại của tôi; điều này được gọi một lần cho mỗi đoạn đào tạo trong kho văn bản. (Các mảng trở lại được xáo trộn ở những nơi khác.)
def _h5_fast_bool_ix(self, h5_array, ix, read_chunksize=100000):
'''Iterate over an h5 array chunkwise to select a random subset
of the array. `h5_array` should be the array itself; `ix` should
be a boolean index array with as many values as `h5_array` has
rows; and you can optionally set the number of rows to read per
chunk with `read_chunksize` (default is 100000). For some reason
this is much faster than using `ix` to index the array directly.'''
n_chunks = h5_array.shape[0]/read_chunksize
slices = [slice(i * read_chunksize, (i + 1) * read_chunksize)
for i in range(n_chunks)]
a = numpy.empty((ix.sum(), h5_array.shape[1]), dtype=float)
a_start = 0
for sl in slices:
chunk = h5_array[sl][ix[sl]]
a_end = a_start + chunk.shape[0]
a[a_start:a_end] = chunk
a_start = a_end
return a
Đó là hơi điên với tôi rằng một O (n^2) (phương pháp lặp qua mảng toàn bộ PyTables cho mỗi đoạn) là nhanh hơn trong trường hợp này hơn một O (n) cách tiếp cận (chọn ngẫu nhiên mỗi hàng trong một lần). Nhưng này, nó hoạt động. Với một chút gián tiếp hơn, điều này có thể được điều chỉnh để tải các hoán vị không ngẫu nhiên, nhưng điều đó làm tăng thêm độ phức tạp hơn giá trị của nó ở đây.
Giải pháp mmap
có tại đây để tham khảo, đối với những người cần giải pháp nguyên chất vất vả vì bất kỳ lý do gì. Nó xáo trộn tất cả các dữ liệu trong khoảng 25 phút, trong khi các giải pháp trên quản lý giống nhau trong ít hơn một nửa thời gian đó. Điều này cũng nên được quy mô tuyến tính, bởi vì mmap
cho phép (tương đối) truy cập ngẫu nhiên hiệu quả.
import numpy
import os
import random
X = []
Y = []
for filename in os.listdir('input'):
X.append(numpy.load(os.path.join('input', filename), mmap_mode='r'))
for filename in os.listdir('output'):
Y.append(numpy.load(os.path.join('output', filename), mmap_mode='r'))
indices = [(chunk, row) for chunk, rows in enumerate(X)
for row in range(rows.shape[0])]
random.shuffle(indices)
newchunks = 50
newchunksize = len(indices)/newchunks
for i in range(0, len(indices), newchunksize):
print i
rows = [X[chunk][row] for chunk, row in indices[i:i + newchunksize]]
numpy.save('X_shuffled_' + str(i), numpy.array(rows))
rows = [Y[chunk][row] for chunk, row in indices[i:i + newchunksize]]
numpy.save('Y_shuffled_' + str(i), numpy.array(rows))
Bạn có thể yates yates các hàng và sau đó fisher yates các cột? Vì bạn chỉ trao đổi các hàng/cột riêng lẻ nên nó không nên lạm dụng trí nhớ của bạn. Bạn có thể làm nó như là một phần mở rộng C nếu tốc độ là vấn đề (bạn cần một tấn hoán đổi để làm cho nó thực sự ngẫu nhiên). –
Xin lỗi, tôi không rõ ràng - Tôi không cần phải trộn các cột, chỉ là các hàng. Nó chỉ là không có cách nào tốt để tải tất cả vào bộ nhớ, cũng không phải là một số phương pháp dựa trên đĩa rõ ràng hơn thực tế. – senderle