2017-09-07 6 views
1

Ich habe eine riesige (30GB) ndarray Memory-Mapped:numpy.std auf memmapped ndarray nicht mit Memory

arr = numpy.memmap(afile, dtype=numpy.float32, mode="w+", shape=(n, n,))

Nachdem es mit einigen Werten füllen (was sehr fein geht - max Speichernutzung ist unter 1 GB) ich möchte die Standardabweichung berechnen:

print('stdev: {0:4.4f}\n'.format(numpy.std(arr)))

Diese Linie mit MemoryError kläglich versagt.

Ich bin nicht sicher, warum das fehlschlägt. Ich wäre dankbar für Tipps, wie man diese auf speichereffiziente Weise berechnet?

Umwelt: Venv + Python3.6.2 + NumPy 1.13.1

Antwort

0
import math 
BLOCKSIZE = 1024**2 
# For numerical stability. The closer this is to mean(arr), the better. 
PIVOT = arr[0] 


n = len(arr) 
sum_ = 0. 
sum_sq = 0. 
for block_start in xrange(0, n, BLOCKSIZE): 
    block_data = arr[block_start:block_start + BLOCKSIZE] 
    block_data -= PIVOT 
    sum_ += math.fsum(block_data) 
    sum_sq += math.fsum(block_data**2) 

stdev = np.sqrt(sum_sq/n - (sum_/n)**2) 
1

Tat numpy Implementierung von std und mean machen vollständige Kopien des Arrays und sind schrecklich Speicher ineffizient. Hier ist eine bessere Umsetzung:

# Memory overhead is BLOCKSIZE * itemsize. Should be at least ~1MB 
# for efficient HDD access. 
BLOCKSIZE = 1024**2 
# For numerical stability. The closer this is to mean(arr), the better. 
PIVOT = arr[0] 

n = len(arr) 
sum_ = 0. 
sum_sq = 0. 
for block_start in xrange(0, n, BLOCKSIZE): 
    block_data = arr[block_start:block_start + BLOCKSIZE] 
    block_data -= PIVOT 
    sum_ += np.sum(block_data) 
    sum_sq += np.sum(block_data**2) 
stdev = np.sqrt(sum_sq/n - (sum_/n)**2) 
+0

Vielen Dank für die Umsetzung jedoch mit NumPy 'sum' ist numerisch instabil und gerade bei großen Matrizen es nicht wirklich kläglich ([siehe Frage SO] (https: //stackoverflow.com/questions/33004029/is-numpy-sum-implemented-in-such-a-way-that-numerical-errors-are-avoided)). Die korrigierte (wenn auch langsamere) Version unten. – sophros