代码之家  ›  专栏  ›  技术社区  ›  Him

numpy矢量化增维函数

  •  1
  • Him  · 技术社区  · 8 年前

    我想创建一个具有输入的函数: x.shape==(2,2) ,和输出 y.shape==(2,2,3) .

    例如:

    @np.vectorize
    def foo(x):
      #This function doesn't work like I want
      return x,x,x
    
    a = np.array([[1,2],[3,4]])
    print(foo(a))
    #desired output
    [[[1 1 1]
      [2 2 2]]
    
     [[3 3 3]
      [4 4 4]]]
    
    #actual output
    (array([[1, 2],
       [3, 4]]), array([[1, 2],
       [3, 4]]), array([[1, 2],
       [3, 4]]))
    

    或者可能:

    @np.vectorize
    def bar(x):
      #This function doesn't work like I want
      return np.array([x,2*x,5])
    
    a = np.array([[1,2],[3,4]])
    print(bar(a))
    #desired output
    [[[1 2 5]
      [2 4 5]]
    
     [[3 6 5]
      [4 8 5]]]
    

    请注意 foo 这只是一个例子。我想要一种方法 map 在numpy数组上(这是向量化应该做的),但是 地图 取一个0d对象,将一个1d对象推到位。在我看来,这里的维度也是任意的,因为人们可能希望使用一个函数,该函数接受一个1d对象并返回一个3d对象,将其矢量化,在5d对象上调用它,然后返回一个7d对象。。。。然而,我的特定用例只需要将0d矢量化为1d函数,并将其适当映射到2d数组上。

    3 回复  |  直到 8 年前
        1
  •  3
  •   hpaulj    8 年前

    在你的问题中,这将有助于显示实际结果和你想要的结果。正如所写的那样,这还不是很清楚。

    In [79]: foo(np.array([[1,2],[3,4]]))
    Out[79]: 
    (array([[1, 2],
            [3, 4]]), array([[1, 2],
            [3, 4]]), array([[1, 2],
            [3, 4]]))
    

    如中所示 vectorize docs,这返回了一个数组元组,对应于函数返回的值元组。

    你的 bar 返回一个数组,其中 矢量化 应返回标量(或单个值):

    In [82]: bar(np.array([[1,2],[3,4]]))
    ValueError: setting an array element with a sequence.
    

    矢量化 需要 otypes 有时有用的参数。例如,如果我这么说 酒吧 (没有包装器)返回一个对象,我得到:

    In [84]: f=np.vectorize(bar, otypes=[object])
    
    In [85]: f(np.array([[1,2],[3,4]]))
    Out[85]: 
    array([[array([1, 2, 5]), array([2, 4, 5])],
           [array([3, 6, 5]), array([4, 8, 5])]], dtype=object)
    

    由(3,)个数组组成的(2,2)个数组。这个 (2,2) 形状与输入的形状匹配。

    矢量化 有一个相对较新的参数, signature

    In [90]: f=np.vectorize(bar, signature='()->(n)')
    
    In [91]: f(np.array([[1,2],[3,4]]))
    Out[91]: 
    array([[[1, 2, 5],
            [2, 4, 5]],
    
           [[3, 6, 5],
            [4, 8, 5]]])
    In [92]: _.shape
    Out[92]: (2, 2, 3)
    

    我没怎么用过这个,所以我还是对它的工作原理有所了解。当我测试它时,它比的原始标量版本慢 矢量化 . 两者都没有显式循环的速度优势。然而 矢量化 在“广播”时有帮助,允许您使用各种输入形状。如果函数需要多个输入,而不是像本例中那样只需要一个输入,那么这将更加有用。

    In [94]: f(np.array([1,2]))
    Out[94]: 
    array([[1, 2, 5],
           [2, 4, 5]])
    
    In [95]: f(np.array(3))
    Out[95]: array([3, 6, 5])
    

    为了获得最佳速度,您希望尽可能使用现有的numpy全数组函数。例如,您的 foo 案例可通过以下方式完成:

    In [97]: np.repeat(a[:,:,None],3, axis=2)
    Out[97]: 
    array([[[1, 1, 1],
            [2, 2, 2]],
    
           [[3, 3, 3],
            [4, 4, 4]]])
    

    np.stack([a]*3, axis=2) 同样有效。

    还有你的 酒吧 预期结果:

    In [100]: np.stack([a, 2*a, np.full(a.shape, 5)], axis=2)
    Out[100]: 
    array([[[1, 2, 5],
            [2, 4, 5]],
    
           [[3, 6, 5],
            [4, 8, 5]]])
    

    2*a 利用整个数组乘法。这是真正的“numpy-onic”思想。

        2
  •  2
  •   ascripter    8 年前

    将值重复到另一个维度非常简单:

    import numpy as np
    
    x = a = np.array([[1,2],[3,4]])
    y = np.repeat(x[:,:,np.newaxis], 3, axis=2)
    print y.shape
    print y
    
    
    (2L, 2L, 3L)
    [[[1 1 1]
      [2 2 2]]
    
     [[3 3 3]
      [4 4 4]]]
    
        3
  •  0
  •   Him    8 年前

    这似乎适用于“f R0->R1映射到一个nd数组,给出一个(n+1)d数组”

    def foo(x):
      return np.concatenate((x,x))
    np.apply_along_axis(foo,2,x.reshape(list(x.shape)+[1]))
    

    但不能很好地概括