2012-03-14 74 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