2

(400 x 121000000)HDF5の非常に大きなデータセットを保存するために使用しています。uint8s列には大量の冗長性があります (列の 97% は一意ではありません)。重複した列を効率的にマージする必要があります。これは、マージされた列を記憶するためにメタデータを保存しながら、重複する列を削除する必要があることを意味します。

私は現在 Python をh5pyで使用していますが、誰かが効率的な C++ ソリューションを持っている場合は、boost::pythonそれを実装するために使用できます。

私の現在の解決策は、データ セットのブロックをNumPy配列に読み込み、 a を使用し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

私は助けが必要です; これは最適ではありません。

ありがとう!

4

1 に答える 1

3

kernprofでプロファイリングを行い、コードを最適化しました。

  • 最大のボトルネックは、HashableNDArray オブジェクトのインスタンス化でした。numpy 配列を読み取り専用にすることで、ラッパー クラスを使用せずにデータ バッファーをハッシュできることがわかりました。また、バッファデータを文字列として抽出すると、ハッシュがはるかに高速になるようです。列データを復元するには、 を使用しますnp.frombuffer(dict_key, dtype=np.uint8)

  • また、dictionnary を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
于 2014-07-17T14:44:05.893 に答える