2012-03-14 75 views
8

是否可以從函數構造一個numpy矩陣?在這種情況下,具體而言,函數是兩個向量的絕對差值:S[i,j] = abs(A[i] - B[j])。使用常規的Python的最小工作示例:從兩個向量的差異填充numpy矩陣

import numpy as np 

A = np.array([1,3,6]) 
B = np.array([2,4,6]) 
S = np.zeros((3,3)) 

for i,x in enumerate(A): 
    for j,y in enumerate(B): 
     S[i,j] = abs(x-y) 

,並提供:

[[ 1. 3. 5.] 
[ 1. 1. 3.] 
[ 4. 2. 0.]] 

這將是很好有一個建築,看起來像:

def build_matrix(shape, input_function, *args) 

,我可以通過一個輸入函數,並保留numpy的速度優勢。

+0

這是可能的。你有什麼嘗試? – Marcin 2012-03-14 15:13:29

+0

@Marcin - 如問題中所述,我現在使用普通的舊python方法來填充矩陣。查看numpy的文檔表明函數'vectorize'可能是有用的,但我仍然沒有看到如何從函數中首先構造矩陣。如果你能指出我正確的方向(文檔化),我會很感激! – Hooked 2012-03-14 15:17:30

+0

這應該是在普通的Python中可能的。你有沒有嘗試過創建你的build_matrix函數?當然你有一些東西,並且卡在某個地方,而不是希望有人會爲你寫這一切。 – Marcin 2012-03-14 15:23:12

回答

10

我建議考慮看看到numpy的廣播功能:

In [6]: np.abs(A[:,np.newaxis] - B) 
Out[6]: 
array([[1, 3, 5], 
     [1, 1, 3], 
     [4, 2, 0]]) 

http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html

然後,你可以簡單地寫你的函數爲:

In [7]: def build_matrix(func,args): 
    ...:  return func(*args) 
    ...: 

In [8]: def f1(A,B): 
    ...:  return np.abs(A[:,np.newaxis] - B) 
    ...: 

In [9]: build_matrix(f1,(A,B)) 
Out[9]: 
array([[1, 3, 5], 
     [1, 1, 3], 
     [4, 2, 0]]) 

這也應該是相當快於你更大陣列的解決方案。

+0

這是完美的,並且對於大N有一個可觀的收益。我會更多地關注廣播,謝謝。 – Hooked 2012-03-14 15:46:39

+2

爲了避免創建一箇中間數組來保存差異,可以使用''numpexpr'](https://code.google.com/p/numexpr/):'c = a [:,None]; result = numexpr.evaluate(「abs(c - b)」)' – jfs 2012-03-14 20:18:08

+0

@ J.F.Sebastian - 無論它值什麼,如果你沒有安裝'numexpr',你也可以通過就地取絕對值來避免它。儘管如此,它稍微更冗長:'c = a [:,None];結果= c - b; np.abs(結果,結果)' – 2012-03-14 20:35:44

13

除了@JoshAdel建議的內容外,還可以使用任何numpy ufuncouter method在兩個數組的情況下進行廣播。

在這種情況下,您只需要np.subtract.outer(A, B)(或者說,它的絕對值)。

雖然這個例子中的任何一個都是可讀的,但在某些情況下,廣播更有用,而另一些情況下使用ufunc方法則更清晰。

無論哪種方式,瞭解這兩種技巧都很有用。

E.g.

import numpy as np 

A = np.array([1,3,6]) 
B = np.array([2,4,6]) 

diff = np.subtract.outer(A, B) 
result = np.abs(diff) 

基本上,可以使用outeraccumulatereduce,和reduceat與任何numpy的ufuncsubtractmultiplydivide,或者甚至之類的東西logical_and

例如,np.cumsum相當於到np.add.accumulate。這意味着如果你需要的話,你可以通過np.divide.accumulate實現類似於cumdiv的東西。

+0

謝謝@JoeKington,如果廣播方法和外部方法之間存在內部差異,你是否知道副手?爲了實用性,我沒有注意到我的機器上的小測試有任何速度差異,所以我想我可以使用任何一種。 – Hooked 2012-03-14 15:50:57

+0

@JoeKington +1絕對是另一套非常棒的技巧來保持身材。在某些情況下,我更喜歡這種方法,因爲我發現語法更具描述性。 – JoshAdel 2012-03-14 16:02:45

+1

@talonmies在我的機器上使用10,100,1000和10000個元素的陣列,廣播和外部方法幾乎具有相同的定時,廣播方法只有少量獲勝。 – JoshAdel 2012-03-14 16:19:43