2014-07-16 2 views
1

HDF5를 사용하여 매우 큰 uint8s (400 x 121000000)의 데이터 세트를 저장하고 있습니다. 열에는 많은 양의 중복이 있습니다 (열의 97 %는 고유하지 않습니다). 효율적으로 중복 열을 병합해야합니다. 즉, 병합 된 열을 기억하는 메타 데이터를 저장하는 동안 중복 열을 제거해야합니다.HDF5 데이터 세트에서 고유 한 열 찾기

저는 현재 h5py와 함께 python을 사용하고 있지만 누군가가 효율적인 C++ 솔루션을 가지고 있다면 간단히 boost :: python을 사용하여 구현할 수 있습니다.

현재의 솔루션은 데이터 세트의 블록을 수십 개의 배열로로드하고 사전과 고유 한 열 및 메타 데이터를 저장하는 데 사용됩니다.

참고 : HashableNDArray 클래스는 http://machineawakening.blogspot.ca/2011/03/making-numpy-ndarrays-hashable.html에서 찾을 수 있습니다. 방금 이름을 변경했습니다.

나는 모든 컬럼을 통해 반복하면
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 

, 나는 내가 제거 중복으로 새 HDF5 데이터 세트를 작성하는 데 사용하는 딕셔너리를 반환합니다.

이것은 최적 일 수 없습니다! 도움이 필요해.

감사합니다.

+0

왜 이것이 최적이 아니라고 말합니까? 당신은 거기에 더 나은 방법이 될 것 같니? 아니면 당신은 메모리/속도 성능에 불만을 가지고 있습니까? 제가 제목을 읽을 때 가장 먼저 생각한 것은 당신이 한 일이었습니다. 이 질문은 아마도 [Code Review] (http://codereview.stackexchange.com/)에 대해 더 알기 쉽습니까? – Reti43

+0

안녕 Reti43, 답변 주셔서 감사합니다! 처음에는 속도 성능에 만족하지 않았습니다. 내 노트북에서 ~ 18 시간이 걸렸습니다. 내 추측에 따르면 수백만 개의 HashableNDArrays를 인스턴스화하는 것이 불가피하게 병목 현상 이었지만이를 우회하는 방법을 알지 못했습니다. 내 코드를 최적화하고 아래에 솔루션을 게시했습니다. 건배! Alex – aldro61

답변

3

kernprof으로 일부 프로파일 링을 수행하고 내 코드를 최적화했습니다.

  • 가장 큰 병목은 HashableNDArray 개체의 인스턴스 생성입니다. numpy 배열을 읽기 전용으로 만들면 래퍼 클래스를 사용하지 않고 데이터 버퍼를 해싱 할 수 있다는 것을 알게되었습니다. 또한 버퍼 데이터를 문자열로 추출하는 것이 훨씬 빠른 해싱을 허용하는 것으로 보입니다. 열 데이터를 복구하기 위해 np.frombuffer(dict_key, dtype=np.uint8)을 사용합니다.

  • 나는 또한 단축키를 defaultdict으로 대체하고 try/except 블록을 제거하여 작은 스피드 업을 얻었다.

  • 내 데이터에는 이진 값만 포함되어 있기 때문에 열을 np.packbits으로 사용하면 키를 저장할 때 계수를 8 배로 늘릴 수 있으며 여전히 동일한 열을 일치시킬 수 있습니다. 당신이 np.unpackbits를 사용하는 것을 기억해야 할 유일한 것은 0

마지막으로, 나는 잘 사용할 수있는 최대 메모리 양을 사용하는 블록 _ 크기를 조정 후행 NumPy와 패드 불완전 바이트 있기 때문에, 당신의 열의 실제 렌이다. 이것은 약간 더 긴 디스크 읽기와 훨씬 더 나은 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 
+0

와우, 36 개선 요인. 잊지 마십시오. 문제가 해결 된 경우 답변을 선택한 것으로 표시 할 수 있습니다. ;) – Reti43

관련 문제