2

HDF5用来存储非常大的数据集uint8s(400 x 121000000)。列中存在大量冗余(97% 的列不是唯一的)。我需要有效地合并重复的列。这意味着我需要删除重复的列,同时存储元数据以记住合并了哪些列。

我目前正在使用 Python h5py,但如果有人有一个高效的 C++ 解决方案,我可以简单地使用boost::python它来实现它。

我当前的解决方案包括将数据集的块加载到NumPy数组中并使用 adictionary来存储唯一列和元数据。

注意: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删除冗余的新数据集的 a。

我需要帮助; 这不可能是最佳的!

谢谢!

4

1 回答 1

3

我用kernprof做了一些分析并优化了我的代码。

  • 最大的瓶颈是 HashableNDArray 对象的实例化。我发现通过将 numpy 数组设为只读,我可以散列它们的数据缓冲区,而无需使用包装类。此外,将缓冲区数据提取为字符串似乎可以实现更快的散列。为了恢复列数据,我使用np.frombuffer(dict_key, dtype=np.uint8).

  • 通过用defaultdict替换字典并消除 try/except 块,我还获得了一个小的加速。

  • 由于我的数据只包含二进制值,我发现在列上使用np.packbits可以在存储键时将内存节省 8 倍,并且仍然允许匹配相同的列。使用np.unpackbits唯一需要记住的是列的实际长度,因为 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
于 2014-07-17T14:44:05.893 回答