2014-10-29 65 views
2

我有一個函數,它必須用f(x)來替換numpy數組X的每個元素x。如何修改一個numpy數組而不隱藏額外的內存分配?

def modify_inplace(X): 
    X = 2./(8. + numpy.exp(-X)) 

但是,這並不工作:

>>> X = numpy.random.random(size=(2,3)) 
>>> X 
array([[ 0.97476386, 0.76411101, 0.37690288], 
     [ 0.05462798, 0.44722799, 0.23570353]]) 
>>>> modify_inplace(X) 
>>> X 
array([[ 0.97476386, 0.76411101, 0.37690288], 
     [ 0.05462798, 0.44722799, 0.23570353]]) 

我知道,我可以簡單地返回新的數組,但我不知道是否有可能修改numpy的陣列就地所以沒有額外的內存將被分配?

Ashwini Chaudhary在下面提供了一個解決方案,但這不是我正在尋找的,因爲我需要在沒有任何其他malloc的情況下修改數組。

回答

6

A []真正的就地方法對於這種情況可能是:在@Ashwini喬杜裏的做法

def modify_inplace(X): 
    np.exp(X, out=X) 
    X += 8. 
    np.power(X, -1, out=X) 
    X *= 2 

兩個主要優點(這也是不錯的):

  • 一個新的陣列並不需要分配
  • 沒有數據要在操作後,複製

編輯:

需要注意的是更加複雜的表達式,其中X出現不止一次拷貝難以避免,例如:

(X + 2.)/(8. + np.exp(X)) 

這裏當你改變X原地計算np.exp(X)它將不再有效計算其餘的表達式...

+0

謝謝。在你使用兩個X的第二個例子中,有什麼可以成爲避免內存分配的另一種解決方案? – psihodelia 2014-11-01 11:49:03

+0

@psihodelia在這種情況下,我只看到循環數組,計算表達式在一個臨時變量中的答案,並替換舊的值...例如,可以在Cython中完成的例子 – 2014-11-01 23:54:52

3

目前你只需創建一個新的局部變量X,並給它分配一個新的值,來更新X指出函數使用切片分配內部對象:

>>> def modify_inplace(X): 
     X[:] = 2./(8. + numpy.exp(-X)) 
...  
>>> X = numpy.random.random(size=(2,3)) 
>>> X 
array([[ 0.21210661, 0.03573271, 0.07002263], 
     [ 0.77282535, 0.13973994, 0.82784145]]) 
>>> modify_inplace(X) 
>>> X 
array([[ 0.22704366, 0.22309233, 0.22390467], 
     [ 0.23635894, 0.22548971, 0.23705132]]) 
+0

謝謝。那麼,在這種情況下,Numpy將不會分配任何額外的存儲空間? – psihodelia 2014-10-29 14:08:18

+0

@psihodelia對於您的情況,首先將在內存中創建一個新數組,然後將原始數組的內容替換爲該數組。之後,新的數組被垃圾收集,因爲沒有更多的引用。 – 2014-10-29 14:21:09

+1

但是這意味着這個數組不是就地修改的。雖然我的問題是如何避免內存分配和修改陣列 - 就像你會用C做的一樣。 – psihodelia 2014-10-29 14:35:32