2017-09-07 1 views
1

J'ai un énorme (30 Go) de mémoire mappée ndarray:numpy.std sur ndarray memmapped échoue avec MemoryError

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

Après le remplir avec des valeurs (qui va très bien - utilisation de la mémoire max est ci-dessous 1 Go) Je veux calculer l'écart-type:

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

Cette ligne échoue lamentablement avec MemoryError.

Je ne sais pas pourquoi cela échoue. Je serais reconnaissant pour les conseils sur la façon de calculer ceux-ci d'une manière efficace sur le plan de la mémoire?

Environnement: venv + Python3.6.2 + NumPy 1.13.1

Répondre

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

En effet la mise en œuvre de numpy de std et mean faire des copies complètes du tableau, et sont horriblement mémoire inefficace. Voici une meilleure mise en œuvre:

# 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

Nous vous remercions de la mise en œuvre mais en utilisant NumPy 'sum' est numériquement instable et précisément dans le cas des grandes matrices il échoue lamentablement vraiment ([voir SO question] (https: //stackoverflow.com/questions/33004029/is-numpy-sum-implemented-in-such-a-way-that-numerical-errors-are-avoided)). La version corrigée (quoique plus lente) ci-dessous. – sophros