2013-09-29 79 views
4

我正在處理一些非常大的陣列。當然,我正在處理的一個問題是RAM耗盡,但即使在我的代碼運行緩慢之前,即使我有無限的RAM,它仍然會花費太長時間。我給一點我的代碼,以顯示我想要做的事:非常大的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)) 

我需要使用G和index_stack,其中的每一個300萬×10,000 2-d陣列,在進一步的計算。這個循環的每次迭代需要將近1秒,總共300萬秒,這太長了。

有什麼我可以做的,這樣的計算將運行得更快?我試着想,如果沒有這個循環,我可以做什麼,但我能想象的唯一方法是製作300萬份zfit,這是不可行的。

有沒有辦法通過不將所有內容保存在RAM中來處理這些數組?我是一名初學者,我所搜尋過的所有內容都是無關緊要的,或者我無法理解的。提前致謝。

+1

samplez中有沒有重複的值?或者它只包含獨特的價值? –

+0

它們都是獨一無二的,並且依次遞增 – cracka31

+0

'e = zfit [b,index + 1]'有一個潛在的問題。如果數組的最小正值是最後一個元素,那麼在數組的任何行中,'[b,index + 1]'將導致一個'IndexError'(超出範圍)。第一行應該是'b = np.arange(len(zfit))' –

回答

1

很高興知道最小的正數永遠不會顯示在行的末尾。

samplez有100萬個唯一值,但在zfit中,每行最多隻能有500個唯一值。整個zfit可以有多達5000萬個唯一值。如果找到最小正數> each_element_in_samplez計算的次數可以大大減少,算法可以大大加快。做所有的5e13比較可能是一種矯枉過正,仔細的計劃將能夠擺脫它的很大一部分。這將很大程度上取決於你的實際潛在數學。

不知道,還有一些小事情可以做。 1,沒有太多可能的(e-d),所以可以從循環中取出。 2,循環可以通過map消除。這兩個小的修復程序在我的機器上導致了大約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])) 

下一個:masked_array可以完全避免(這應該帶來顯着的改進)。還需要對samplez進行排序。

>>> 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 

因此,這是另一個50%的加速。

masked_array被避免,並節省了一些RAM。想不到其他任何東西來減少RAM使用。可能需要部分處理samplez。此外,依賴於數據和所需的精度,如果您可以使用float16float32而不是默認的float64,可以爲您節省大量的RAM。

+0

請注意,在python3'map'中返回一個迭代器,因此'return'語句將失敗,因爲第二個數組將始終爲空。另外,請避免使用'\'作爲延續。只需在括號中包裝返回值。 – Bakuriu

+0

謝謝,好點,很好。 –

+0

嗨CT。當你在你的機器上運行它時,你是否使用與我一樣大小的數組?你的機器可以處理這個? – cracka31