2010-08-03 5 views
4

상당히 큰 NumPy 배열 (수백 메가 바이트)을 처리하는 Python 프로그램이 있습니다.이 배열은 pickle 파일 (파일 당 1 ~ 100MB 배열)에 디스크에 저장됩니다. 데이터에 대한 쿼리를 실행하려면 pickle을 통해 전체 배열을로드 한 다음 쿼리를 수행하십시오 (따라서 OS가 파이썬 프로그램의 관점에서 볼 때 전체 배열은 메모리에 저장됩니다) . 주로 NumPy 배열에서 벡터화 된 연산을 사용할 수 있다는 것은 각 항목을 통해 for 루프를 사용하는 것보다 훨씬 빠르다고 믿었 기 때문에 주로이 작업을 수행했습니다.NumPy 배열을 통한 반복적 인 지연 평가

저는 메모리 제한이있는 웹 서버에서이 프로그램을 실행하고 있습니다. 필자는 데이터에서 실행되는 여러 가지 종류의 쿼리를 사용하여 개별 피클 파일에서 데이터의 일부를로드하고 처리 한 후 다음 청크로 진행할 때 많은 복잡성이 추가되는 코드 "청킹"을 작성합니다. 이러한 큰 배열을 처리하는 모든 기능에 대해 "청킹"을 투명하게 만드는 것이 바람직합니다.

이상적인 솔루션은 디스크의 데이터 블록을 주기적으로로드 한 다음 하나씩 배열 값을 전달하는 것과 같은 것 같습니다. 이렇게하면 개별 쿼리 기능 부분에서 별도의 작업을 수행하지 않고도 프로그램에 필요한 메모리 양이 크게 줄어 듭니다. 이런 식으로 할 수 있습니까?

+0

유용한 참고 자료 : 이것을 "코어 밖"작업이라고합니다. – erich

답변

9

PyTables가 관리하는 패키지는 다음과 같습니다 대신 picklecPickle 및 프로토콜에 대한 -1, 등, ;-) 물론 원하는 것이다 2.any에 -

예제 코드 (파이썬 3.1 계층 적 데이터 세트. 이 문제를 해결할 수 있도록 설계되었습니다.

2

이상적인 솔루션 주기적 디스크에서 데이터 블록을로드하고 하나씩을 배열 값을 전달 발전기 같은 것처럼 보인다. 이 은 의 메모리 양을 실질적으로 줄이며 은 별도 쿼리없이 에 대한 추가 작업없이 의 기능을 수행합니다. 이렇게 할 수 있습니까?

예, 단일 피클의 디스크에 배열을 유지하지는 않습니다. 피클 프로토콜은 "증분 직렬화"용으로 설계되지 않았습니다.

당신은 같은 파일 열기, 하나씩 여러 절임 (dump를 사용 하지dumps) 쓸 수 있습니다 다음 "반복에 대한 게으른 평가자는"단지 pickle.load 때마다 사용해야합니다.

>>> import pickle 
>>> lol = [range(i) for i in range(5)] 
>>> fp = open('/tmp/bah.dat', 'wb') 
>>> for subl in lol: pickle.dump(subl, fp) 
... 
>>> fp.close() 
>>> fp = open('/tmp/bah.dat', 'rb') 
>>> def lazy(fp): 
... while True: 
...  try: yield pickle.load(fp) 
...  except EOFError: break 
... 
>>> list(lazy(fp)) 
[range(0, 0), range(0, 1), range(0, 2), range(0, 3), range(0, 4)] 
>>> fp.close() 
4

NumPy와의 메모리 매핑 데이터 구조 (memmap는) 여기 좋은 선택이 될 수 있습니다.

전체 파일을 한 번에 메모리에로드하지 않고 디스크의 이진 파일에서 NumPy 배열에 액세스합니다.

(주, Numpys memmap 객체가 파이로 하지 동일하다는 것을, 나는 생각하지만, 나는 확실하지 오전 - 특히, NumPys 배열과 같은 것입니다, 파이썬의 파일과 같은 것입니다.)

메소드 서명은 다음과 같습니다

A = NP.memmap(filename, dtype, mode, shape, order='C') 

모든 인수

은 간단합니다 (즉, 그들은 NumPy와 다른 곳에서 사용 된 것과 동일한 의미를 가지고)를 ndarray 메모리 레이아웃의 순서를 말한다 '순서'를 제외합니다. Fortran의 경우 기본값은 'C'이고 다른 옵션은 'F'입니다. 다른 곳에서는이 두 옵션이 각각 행 주요 및 열 주요 순서를 나타냅니다.

두 가지 방법은 다음과 같습니다

(디스크 어레이에 변경 사항을 기록합니다)

플러시; 및

예시적인 사용 (디스크에 저장되어있는 데이터에 어레이 형상의 메모리 맵을보다 정확하게 memmap 어레이에 데이터를 기록하거나)

근접 : 어쩌면

import numpy as NP 
from tempfile import mkdtemp 
import os.path as PH 

my_data = NP.random.randint(10, 100, 10000).reshape(1000, 10) 
my_data = NP.array(my_data, dtype="float") 

fname = PH.join(mkdtemp(), 'tempfile.dat') 

mm_obj = NP.memmap(fname, dtype="float32", mode="w+", shape=1000, 10) 

# now write the data to the memmap array: 
mm_obj[:] = data[:] 

# reload the memmap: 
mm_obj = NP.memmap(fname, dtype="float32", mode="r", shape=(1000, 10)) 

# verify that it's there!: 
print(mm_obj[:20,:]) 
+0

PyTables를 설치하는 과정을 거치지 않으려면이 기능을 사용하면 편리합니다. – erich