2013-09-29 3 views
4

Je travaille avec de très grands réseaux. Un problème que je suis en train de traiter est de manquer de RAM pour travailler avec, mais même avant que mon code ne tourne lentement, de sorte que, même si j'avais une RAM infinie, cela prendrait encore trop de temps. Je vais vous donner un peu de mon code pour montrer ce que je suis en train de faire:Efficacité avec de très grands tableaux numpy

#samplez is a 3 million element 1-D array 
#zfit is a 10,000 x 500 2-D array 

b = np.arange((len(zfit)) 

for x in samplez: 
    a = x-zfit 
    mask = np.ma.masked_array(a) 
    mask[a <= 0] = np.ma.masked 
    index = mask.argmin(axis=1) 
    # These past 4 lines give me an index array of the smallest positive number 
    # in x - zift  

    d = zfit[b,index] 
    e = zfit[b,index+1] 
    f = (x-d)/(e-d) 
    # f is the calculation I am after 

    if x == samplez[0]: 
     g = f 
     index_stack = index 
    else: 
     g = np.vstack((g,f)) 
     index_stack = np.vstack((index_stack,index)) 

je dois utiliser g et index_stack, dont chacun sont 3millions x 10.000 tableaux 2-D, dans un autre calcul . Chaque itération de cette boucle prend presque 1 seconde, soit 3 millions de secondes au total, ce qui est beaucoup trop long.

Y at-il quelque chose que je peux faire pour que ce calcul s'exécute beaucoup plus rapidement? J'ai essayé de penser comment je pourrais faire sans boucle, mais la seule façon que je puisse imaginer est de faire 3 millions de copies de zfit, ce qui est irréalisable.

Et puis-je travailler avec ces baies en ne gardant pas tout en RAM? Je suis un débutant et tout ce que j'ai cherché à ce sujet est soit hors de propos ou quelque chose que je ne peux pas comprendre. Merci d'avance.

+1

Existe-t-il une valeur dupliquée dans samplez? Ou il ne contient que des valeurs uniques? –

+0

Ils sont tous uniques et en ordre croissant – cracka31

+0

Il existe un problème potentiel dans 'e = zfit [b, index + 1]'. Si la plus petite valeur positive de est le dernier élément, dans n'importe quelle rangée du tableau, '[b, index + 1]' provoquera un 'IndexError' (hors limites). Et la première ligne devrait être 'b = np.arange (len (zfit))' –

Répondre

1

Il est bon de savoir que le plus petit nombre positif n'apparaîtra jamais à la fin des lignes.

En samplez il y a 1 million de valeurs uniques mais en zfit, chaque ligne ne peut avoir que 500 valeurs uniques au maximum. L'ensemble zfit peut avoir jusqu'à 50 millions de valeurs uniques. L'algorithme peut être grandement accéléré, si le nombre de calculs 'trouver le plus petit nombre positif> each_element_in_samplez' peut être considérablement réduit. Faire toutes les comparaisons 5e13 est probablement une exagération et planing prudent sera en mesure de se débarrasser d'une grande partie de celui-ci. Cela dépendra de vos mathématiques sous-jacentes réelles.

Sans le savoir, il reste encore quelques petites choses à faire. 1, il n'y a pas autant de (e-d) possible de sorte que cela peut être retiré de la boucle. 2, la boucle peut être éliminée par map. Ces deux petites réparations, sur ma machine, entraînent une accélération d'environ 22%.

def function_map(samplez, zfit): 
    diff=zfit[:,:-1]-zfit[:,1:] 
    def _fuc1(x): 
     a = x-zfit 
     mask = np.ma.masked_array(a) 
     mask[a <= 0] = np.ma.masked 
     index = mask.argmin(axis=1) 
     d = zfit[:,index] 
     f = (x-d)/diff[:,index] #constrain: smallest value never at the very end. 
     return (index, f) 
    result=map(_fuc1, samplez) 
    return (np.array([item[1] for item in result]), 
      np.array([item[0] for item in result])) 

suivant: masked_array peut être évité complètement (ce qui devrait apporter une amélioration significative). samplez doit également être trié.

>>> x1=arange(50) 
>>> x2=random.random(size=(20, 10))*120 
>>> x2=sort(x2, axis=1) #just to make sure the last elements of each col > largest val in x1 
>>> x3=x2*1 
>>> f1=lambda: function_map2(x1,x3) 
>>> f0=lambda: function_map(x1, x2) 
>>> def function_map2(samplez, zfit): 
    _diff=diff(zfit, axis=1) 
    _zfit=zfit*1 
    def _fuc1(x): 
     _zfit[_zfit<x]=(+inf) 
     index = nanargmin(zfit, axis=1) 
     d = zfit[:,index] 
     f = (x-d)/_diff[:,index] #constrain: smallest value never at the very end. 
     return (index, f) 
    result=map(_fuc1, samplez) 
    return (np.array([item[1] for item in result]), 
      np.array([item[0] for item in result])) 

>>> import timeit 
>>> t1=timeit.Timer('f1()', 'from __main__ import f1') 
>>> t0=timeit.Timer('f0()', 'from __main__ import f0') 
>>> t0.timeit(5) 
0.09083795547485352 
>>> t1.timeit(5) 
0.05301499366760254 
>>> t0.timeit(50) 
0.8838210105895996 
>>> t1.timeit(50) 
0.5063929557800293 
>>> t0.timeit(500) 
8.900799036026001 
>>> t1.timeit(500) 
4.614129018783569 

Donc, c'est une autre accélération de 50%.

masked_array est évitée et cela économise de la RAM. Impossible de penser à autre chose pour réduire l'utilisation de la RAM. Il peut être nécessaire de traiter samplez en pièces. Et aussi, dépendants sur les données et la précision requise, si vous pouvez utiliser float16 ou float32 au lieu de la float64 par défaut qui peut vous faire économiser beaucoup de RAM.

+0

Notez que dans python3 'map' renvoie un itérateur, donc l'instruction' return' échouera puisque le second tableau sera toujours vide. De même, évitez d'utiliser '\' comme continuation. Enveloppez simplement la valeur de retour entre parenthèses. – Bakuriu

+0

Merci, bons points et bien pris. –

+0

Bonjour CT. Lorsque vous l'exécutez sur votre machine, utilisez-vous les mêmes baies de taille que moi? Votre machine peut gérer cela? – cracka31

Questions connexes