최근에 numpy 배열을 반복하는 여러 기법에 대해 많이 읽었으며 합의가 반복되지 않는 것으로 보입니다 (예 : a comment here 참조). 너무 비슷한 질문이 몇 가지 있지만, "반복"(또는 반복하지 않음)과 이전 값에 액세스해야하므로 내 경우가 약간 다릅니다.여러 개의 numpy 배열을 반복하고 현재 및 이전 요소를 처리하는 효율적인 방법은 무엇입니까?
목록에 X
인 N (N은 작음, 보통 4, 최대 7 일 수 있음) float128
의 1-D numpy 배열이 있다고 가정 해 봅시다. 모든 배열의 크기는 같습니다. 당신에게 약간의 통찰력을주기 위해 PDE 통합에서 나온 데이터입니다. 각 배열은 하나의 함수를 나타내며 Poincare 섹션을 적용하고 싶습니다. 불행히도이 알고리즘은 각각 ~ 1Gb의 메모리와 시간에 효율적이기 때문에 메모리에 4Gb의 RAM 만 있습니다. (저는 memmap'ing에 대해 배웠습니다.).
이러한 배열 중 하나는 다른 필터를 필터링하는 데 사용되므로 secaxis = X.pop(idx)
으로 시작합니다. 이제 인덱스 쌍을 찾고 (secaxis[i-1] > 0 and secaxis[i] < 0) or (secaxis[i-1] < 0 and secaxis[i] > 0)
을 입력 한 다음 나머지 배열에 간단한 대수 변환을 적용한 후 X
(및 결과 저장)을 수행해야합니다. 언급하면,이 작업 중에 데이터를 낭비해서는 안됩니다.
이렇게하는 방법은 여러 가지가 있지만 그 중 어느 것도 나에게 효율적이지는 않습니다. 하나는 당신이 단지에서 반복은 C와 같은 접근 방식 인을위한 루프 :
import array # better than lists
res = [ array.array('d') for _ in X ]
for i in xrange(1,secaxis.size):
if condition: # see above
co = -secaxis[i-1]/secaxis[i]
for j in xrange(N):
res[j].append((X[j][i-1] + co*X[j][i])/(1+co))
이것은 분명히 매우 비효율적 아닌 파이썬 방법 외에입니다.
또 다른 방법은 numpy.nditer을 사용하는 것입니다,하지만 하나는 이전 값에 액세스하는 방법은 한 번에 여러 배열을 통해 반복하는 수 있지만 나는 아직 파악되지 않은 :
# without secaxis = X.pop(idx)
it = numpy.nditer(X)
for vec in it:
# vec[idx] is current value, how do you get the previous (or next) one?
세 번째 가능성은 처음이다 효율적인 numpy 조각으로 찾은 색인을 찾은 다음 대량 증분/추가에 사용합니다. 지금이 하나의 선호 :
res = []
inds, = numpy.where((secaxis[:-1] < 0) * (secaxis[1:] > 0) +
(secaxis[:-1] > 0) * (secaxis[1:] < 0))
coefs = -secaxis[inds]/secaxis[inds+1] # array of coefficients
for f in X: # loop is done only N-1 times, that is, 3 to 6
res.append((f[inds] + coefs*f[inds+1])/(1+coefs))
을 그러나 이것은 겉으로 7 + 2 *에서 이루어집니다 (N - 1), 또한, 내가 (주소는 슬라이스 일반적으로하지 않습니다의 secaxis[inds]
유형에 대한 확실하지 않다 패스 첫 번째 방법과 마찬가지로 모든 요소를 인덱스로 찾아야합니다.
마지막으로, 나는 또한 itertools를 사용하여 시도하고 그것이 내가 함수형 프로그래밍에 익숙하지 않다는 사실에서 줄기 수있는 괴물과 모호한 구조, 결과 :
def filt(x):
return (x[0] < 0 and x[1] > 0) or (x[0] > 0 and x[1] < 0)
import array
from itertools import izip, tee, ifilter
res = [ array.array('d') for _ in X ]
iters = [iter(x) for x in X] # N-1 iterators in a list
prev, curr = tee(izip(*iters)) # 2 similar iterators, each of which
# consists of N-1 iterators
next(curr, None) # one of them is now for current value
seciter = tee(iter(secaxis))
next(seciter[1], None)
for x in ifilter(filt, izip(seciter[0], seciter[1], prev, curr)):
co = - x[0]/x[1]
for r, p, c in zip(res, x[2], x[3]):
r.append((p+co*c)/(1+co))
뿐만 아니라이 모습 매우 못생긴, 그것은 또한 완료하는 데 엄청난 시간이 걸립니다.
그래서, 다음 한 질문 : 이러한 모든 방법의
- 는 세번째는 참으로 최고? 그렇다면, 마지막 것을 impove하기 위해 무엇을 할 수 있습니까?
- 아직 더 좋은 것들이 있습니까?
- 단순한 호기심에서 nditer를 사용하여 문제를 해결할 수있는 방법이 있습니까?
- 마지막으로 numpy 배열의 memmap 버전을 사용하는 것이 더 낫지 않습니까? 아니면 많은 것을 느리게할까요?어쩌면 내가 RAM에
secaxis
배열을로드해야합니다 디스크에 다른 사람을 유지하고 세 번째 방법을 사용합니까? - (보너스 질문) 길이가 같은 1-D numpy 배열 목록은 크기가 미리 알 수없는 파일 (N은 있음)을로드하는 데서 발생합니다 (N
.npy
). 하나의 배열을 읽고, 그 다음에 2-D numpy 배열 (여기에 약간의 메모리 오버 헤드)을 할당하고 그 2-D 배열에 나머지를 읽는 것이 더 효율적입니까?