я использую HDF5
хранить очень большие наборы данных uint8s
(400 х 121000000). В столбцах огромное количество избыточности (97% столбцов не являются уникальными). Мне нужно эффективно объединять дублирующиеся столбцы. Это означает, что мне нужно удалить повторяющиеся столбцы, сохраняя при этом метаданные, чтобы запомнить, какие столбцы были объединены.
Я в настоящее время использую Python с h5py
, но если у кого-то есть эффективное решение C ++, я мог бы просто использовать boost::python
реализовать это.
Мое текущее решение состоит в загрузке блоков набора данных в NumPy
массив и используя dictionary
хранить уникальные столбцы и метаданные.
Обратите внимание HashableNDArray
класс можно найти Вот. Я просто переименовал его.
def find_column_redundancy(dataset):
n_columns = dataset.shape[1]
block_size = 500000
n_blocks = int(ceil(float(n_columns) / float(block_size)))
d = {}
analysed_column_count = 0
for block in xrange(n_blocks):
block_offset = block*block_size
block_data = dataset[:, block_offset : block_offset+block_size]
for i in xrange(block_data.shape[1]):
hashable_array = HashableNDArray(np.ascontiguousarray(block_data[:, i]))
d[hashable_array] = np.append(d.get(hashable_array, np.array([], dtype=np.int32)), block_offset + i)
analysed_column_count += 1
return d
Как только я перебрал все столбцы, я возвращаю dictionary
что я использую, чтобы написать новый HDF5
набор данных с удаленной избыточностью.
Мне нужна помощь; это не может быть оптимальным!
Спасибо!
Я сделал некоторые профилирование с kernprof и оптимизировал мой код.
Самым большим узким местом было создание объектов HashableNDArray. Я обнаружил, что, делая эти массивы только для чтения, я мог хэшировать их буфер данных, не используя класс-оболочку. Кроме того, извлечение данных буфера в виде строки позволяет значительно ускорить хеширование. Чтобы восстановить данные столбца, я использую np.frombuffer(dict_key, dtype=np.uint8)
,
Я также получил небольшое ускорение, заменив словарь defaultdict и устранение блока try / кроме.
Поскольку мои данные содержат только двоичные значения, я обнаружил, что с помощью np.packbits на столбцах позволяет экономить память в 8 раз при хранении ключей и позволяет сопоставлять идентичные столбцы. Единственное, что вам нужно помнить, чтобы использовать np.unpackbits это фактическая длина ваших столбцов, поскольку пустые байты заполнены неполными байтами с конечным 0.
Наконец, я точно настроил block_size, чтобы использовать максимальный объем доступной памяти. Это позволяет немного увеличить время чтения с диска и значительно повысить загрузку процессора.
Эта функция использовалась для моих данных за ~ 18 часов, а теперь она работает за ~ 0.5 часа!
def find_column_redundancy(dataset):
n_columns = dataset.shape[1]
block_size = 10000000
n_blocks = int(ceil(float(n_columns) / float(block_size)))
d = defaultdict(list)
analysed_column_count = 0
for block in xrange(n_blocks):
block_offset = block*block_size
block_data = dataset[:, block_offset : block_offset+block_size]
block_data = np.asfortranarray(block_data)
block_data = np.packbits(block_data, axis=0)
block_data.flags.writeable = False
for i in xrange(block_data.shape[1]):
d[block_data[:, i].data[:]].append(block_offset + i)
analysed_column_count += 1
print float(analysed_column_count)/n_columns*100, "% completed. Dictionnary has", len(d), "items."
return d