我正在使用HDF5
来存储uint8s
(400 x 121000000)的非常大的数据集。列中有大量冗余(97%的列不是唯一的)。我需要有效地合并重复的列。这意味着我需要删除重复的列,同时存储元数据以记住合并的列。
我目前正在使用h5py
的Python,但如果某人有一个高效的C ++解决方案,我可以简单地使用boost::python
来实现它。
我当前的解决方案包括将数据集的块加载到NumPy
数组中,并使用dictionary
来存储唯一列和元数据。
注意:可以找到HashableNDArray
课程here。我刚刚重命名了。
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
数据集并删除冗余。
我需要帮助;这不可能是最佳的!
谢谢!
答案 0 :(得分:3)
我使用kernprof进行了一些分析并优化了我的代码。
最大的瓶颈是HashableNDArray对象的实例化。我发现通过使numpy数组成为只读,我可以散列它们的数据缓冲区而不必使用包装类。此外,将缓冲区数据提取为字符串似乎允许更快的散列。要恢复列数据,我使用np.frombuffer(dict_key, dtype=np.uint8)
。
通过用defaultdict替换字典并取消try / except块,我也获得了一个小的加速。
由于我的数据只包含二进制值,因此我发现在列上使用np.packbits可以在存储密钥时将内存节省8倍,并且仍允许匹配相同的列。使用np.unpackbits时唯一需要记住的是列的实际len,因为numpy填充不完整的字节,尾随为0。
最后,我对block_size进行了微调,以使用最大可用内存量。这允许稍长的磁盘读取和更好的CPU使用。
此功能过去在我的数据上运行约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