制作一个可以采用各种形状的参数的函数

时间:2016-09-27 02:45:47

标签: python numpy

Q1) Numpy函数可以采用不同形状的参数。例如,np.sum(V)可以取下面两个中的任何一个并返回不同形状的输出。

x1= np.array( [1,3] ) #(1)
x2= np.array([[[1,2],[3,4]], [[5,6],[7,8]]]) #(2)

我正在创建类似下面的函数,它在1D向量中添加两个值,长度为2,并返回实数。

def foo(V):
    return V[0]+V[1];

但是,这个foo函数只能采用一个1D向量而不能采用任何其他形状。它只能将x1作为参数,而不是x2。如果我想让我的函数使用上面两个变量(x1和x2)中的任何一个,或者在最后一个维度中使用长度为2的数组的任何其他形状,我应该如何修改我的foo函数?

---------------------------更新------------------- -----------

我原来的功能是硬编码的负高斯pdf函数。

def nGauss(X, mu, cov):
    # multivariate negative gaussian.    
    # mu is a vector and cov is a covariance matrix.

    k = X.shape[0];
    dev = X-mu
    p1 = np.power( np.power(np.pi * 2, k) , -0.5);
    p2 = np.power( np.linalg.det(cov)  , -0.5)
    p3 = np.exp( -0.5 * np.dot( np.dot(dev.transpose(), np.linalg.inv(cov)), dev));

    return -1.0 * p1 * p2 * p3;

现在他的函数只能返回一个pdf值。例如,它只能接受像np.array([1,2])这样的参数,但不能像np.array那样接受参数X([[[1,2],[5,6]],[[7,8] ],[9,0]]])。这里我的问题是如何使我的高斯函数接受任意形状的参数并返回每个点的pdf值,保持除最后一个维度之外的相同结构,例如 nGauss(np.array( [1,2] ), mu, cov)返回[0.000023],然后 nGauss(np.array([[[1,2], [5,6]], [[7,8],[9,0]]]), mu, cov)返回[[0.000023,0000014],[0.000012,0.000042]]。

我注意到scipy功能' multivariate_normal.pdf'可以做到这一点。

Q2) 我也很难理解np的基本数组。

t1=np.array([[1,2,3], [4,5,6]])
t2=np.array([1,2,3])
t3=np.array([[1,2,3], [4,5,6],5])

t1的形状是(2,3),就矩阵透视而言似乎是合理的; 2行3列。然而,t2的形状是(3,),我认为必须是(3)。 " 3,"之后空白空间的含义是什么?而且,t3的形状是(3,)。在这种情况下,尺寸变化的空白空间的含义是什么?

提前,谢谢你的帮助。

3 个答案:

答案 0 :(得分:2)

您的函数适用于两个数组:

In [1]: def foo(V):
   ...:     return V[0]+V[1]
   ...: 
In [2]: foo(np.array([1,3]))
Out[2]: 4
In [3]: foo(np.array([[[1,2],[3,4]], [[5,6],[7,8]]]))
Out[3]: 
array([[ 6,  8],
       [10, 12]])

这个答案只是这两个数组的总和:

In [4]: np.array([[[1,2],[3,4]], [[5,6],[7,8]]])[0]
Out[4]: 
array([[1, 2],
       [3, 4]])
In [5]: np.array([[[1,2],[3,4]], [[5,6],[7,8]]])[1]
Out[5]: 
array([[5, 6],
       [7, 8]])

如果您对其他内容有所期待,那么您必须向我们展示。

至于你的第二个问题:

In [6]: t1=np.array([[1,2,3], [4,5,6]])
   ...: t2=np.array([1,2,3])
   ...: t3=np.array([[1,2,3], [4,5,6],5])
   ...: 
In [7]: t1.shape
Out[7]: (2, 3)
In [8]: t2.shape
Out[8]: (3,)
In [9]: t3.shape
Out[9]: (3,)

(3,)是1元素元组。比较这些表达方式。

In [11]: (3)
Out[11]: 3
In [12]: (3,)
Out[12]: (3,)

最近有几个关于(3,)v(3,1)形状数组和np.array([[1,2,3]]) v。np.array([1,2,3])的问题。

t3是一个对象dtype数组,有3个元素。 3个输入长度不同,因此无法创建2d数组。暂时远离这种类型的阵列。专注于更简单的数组。

In [10]: t3
Out[10]: array([[1, 2, 3], [4, 5, 6], 5], dtype=object)
In [13]: t3[0]
Out[13]: [1, 2, 3]
In [14]: t3[2]
Out[14]: 5

Numpy: Why is difference of a (2,1) array and a vertical matrix slice not a (2,1) array

Difference between single and double bracket Numpy array?

=====================

使用nGauss

In [53]: mu=np.array([0,0])
In [54]: cov=np.eye(2)
In [55]: xx=np.array([[[1,2], [5,6]], [[7,8],[9,0]]])
In [56]: np.apply_along_axis(nGauss, -1, xx, mu, cov)
Out[56]: 
array([[ -1.30642333e-02,  -9.03313360e-15],
       [ -4.61510838e-26,  -4.10103631e-19]])

apply_along_axis在第1个2 dim上进行迭代,将每个xx[i,j,:]传递给nGauss。它并不快,但相对容易应用。

k = X.shape[0];  # I assume you want
k = X.shape[[1]   # the last dimension
dev = X-mu     # works as long as mu has k terms

这是一个标量:

p1 = np.power( np.power(np.pi * 2, k) , -0.5);

所以

p2 = np.power( np.linalg.det(cov)  , -0.5)

所以归结为概括这个表达式:

p3 = np.exp( -0.5 * np.dot( np.dot(dev.transpose(), np.linalg.inv(cov)), dev));

在简单(2,)x的情况下,dev为1d,dev.transpose()什么都不做。

einsum更容易概括dot;我认为相当于:

p3 = np.einsum('j,j', np.einsum('i,ij', dev, np.linalg.inv(cov)), dev)
p3 = np.exp( -0.5 * p3)

简化为

p3 = np.einsum('i,ij,j', dev, np.linalg.inv(cov), dev)

概括为更高的暗淡:

p3 = np.einsum('...i,ij,...j', dev, np.linalg.inv(cov), dev)

所以:

def nGaussA(X, mu, cov):
    # multivariate negative gaussian.    
    # mu is a vector and cov is a covariance matrix.

    k = X.shape[-1];
    dev = X-mu
    p1 = np.power( np.power(np.pi * 2, k) , -0.5);
    p2 = np.power( np.linalg.det(cov)  , -0.5)
    p3 = np.einsum('...i,ij,...j', dev, np.linalg.inv(cov), dev)
    p3 = np.exp( -0.5 * p3)
    return -1.0 * p1 * p2 * p3;

匹配之前的值:

In [85]: nGaussA(x,mu,cov)
Out[85]: -0.013064233284684921
In [86]: nGaussA(xx,mu,cov)
Out[86]: 
array([[ -1.30642333e-02,  -9.03313360e-15],
       [ -4.61510838e-26,  -4.10103631e-19]])

因此,推广该功能的方法是检查每一步。如果它产生标量,请保留它。如果使用x进行操作,请保留它。但是如果它需要与其他数组协调维度,请使用执行该操作的numpy操作。通常涉及广播。有时,研究其他numpy函数有助于了解它们的推广方式(例如apply_along_axisapply_over_axescross等。

互动的numpy会议至关重要;允许我尝试使用小样本数组的想法。

答案 1 :(得分:1)

对于Q1,您可以打包和解压缩参数:

def foo(*args):

    result = []
    for v in args:
        result.append(v[0] + v[1])

    return result

这将允许您传入任意数量的矢量参数,然后迭代它们,返回每个结果的列表。你也可以用**打包和解包kwargs。更多信息:

https://docs.python.org/2/tutorial/controlflow.html#unpacking-argument-lists

答案 2 :(得分:1)

对于Q1,我猜你想要添加数组的最内层维度,无论数组有多少维度。最简单的方法是使用ellipsis indexing。这是一个详细的例子:

example.com

这对于一维数组同样有效:

>>> a = np.arange(24).reshape((3, 4, 2))
>>> a
array([[[ 0,  1],
        [ 2,  3],
        [ 4,  5],
        [ 6,  7]],

       [[ 8,  9],
        [10, 11],
        [12, 13],
        [14, 15]],

       [[16, 17],
        [18, 19],
        [20, 21],
        [22, 23]]])
>>> a[..., 0]
array([[ 0,  2,  4,  6],
       [ 8, 10, 12, 14],
       [16, 18, 20, 22]])
>>> a[..., 1]
array([[ 1,  3,  5,  7],
       [ 9, 11, 13, 15],
       [17, 19, 21, 23]])
>>> a[..., 0] + a[..., 1]
array([[ 1,  5,  9, 13],
       [17, 21, 25, 29],
       [33, 37, 41, 45]])

所以只需将>>> a = np.array([1, 2]) >>> a[..., 0] + a[..., 1] 3 定义为:

foo

对于def foo(V): return V[..., 0] + V[..., 1] 功能,最简单的解决方案是使用np.apply_along_axis。例如,您可以这样称呼它:

nGauss