【问题标题】:NumPy: 2D array from a list of arrays and scalarsNumPy:来自数组和标量列表的二维数组
【发布时间】:2016-05-16 14:54:05
【问题描述】:

我需要从一维数组和标量列表中创建一个二维 numpy 数组,以便复制标量以匹配一维数组的长度。

期望行为示例

>>> x = np.ones(5)
>>> something([x, 0, x])
array([[ 1.,  1.,  1.,  1.,  1.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  1.]])

我知道列表的矢量元素总是具有相同的长度(形状),因此我可以通过执行以下操作“手动”完成:

def something(lst):
    for e in lst:
        if isinstance(e, np.ndarray):
            l = len(e)
            break
    tmp = []
    for e in lst:
        if isinstance(e, np.ndarray):
            tmp.append(e)
            l = len(e)
        else:
            tmp.append(np.empty(l))
            tmp[-1][:] = e
    return np.array(tmp)

我要问的是是否有一些现成的解决方案隐藏在 numpy 的某个地方,或者,如果没有,是否有比上述解决方案更好(例如更通用、更可靠、更快)的解决方案。

【问题讨论】:

    标签: python arrays numpy scalar


    【解决方案1】:
    In [179]: np.column_stack(np.broadcast(x, 0, x))
    Out[179]: 
    array([[ 1.,  1.,  1.,  1.,  1.],
           [ 0.,  0.,  0.,  0.,  0.],
           [ 1.,  1.,  1.,  1.,  1.]])
    

    In [187]: np.row_stack(np.broadcast_arrays(x, 0, x))
    Out[187]: 
    array([[ 1.,  1.,  1.,  1.,  1.],
           [ 0.,  0.,  0.,  0.,  0.],
           [ 1.,  1.,  1.,  1.,  1.]])
    

    使用np.broadcastnp.broadcast_arrays 快​​:

    In [195]: %timeit np.column_stack(np.broadcast(*[x, 0, x]*10))
    10000 loops, best of 3: 46.4 µs per loop
    
    In [196]: %timeit np.row_stack(np.broadcast_arrays(*[x, 0, x]*10))
    1000 loops, best of 3: 380 µs per loop
    

    但比你的 something 函数慢:

    In [201]: %timeit something([x, 0, x]*10)
    10000 loops, best of 3: 37.3 µs per loop
    

    注意np.broadcast最多可以传递32个数组:

    In [199]: np.column_stack(np.broadcast(*[x, 0, x]*100))
    ValueError: Need at least two and fewer than (32) array objects.
    

    np.broadcast_arrays 是无限的:

    In [198]: np.row_stack(np.broadcast_arrays(*[x, 0, x]*100))
    Out[198]: 
    array([[ 1.,  1.,  1.,  1.,  1.],
           [ 0.,  0.,  0.,  0.,  0.],
           [ 1.,  1.,  1.,  1.,  1.],
           ..., 
           [ 1.,  1.,  1.,  1.,  1.],
           [ 0.,  0.,  0.,  0.,  0.],
           [ 1.,  1.,  1.,  1.,  1.]])
    

    使用np.broadcastnp.broadcast_arrays 比使用更通用一点 something。它将适用于不同(但可广播)形状的数组,例如 实例:

    In [209]: np.column_stack(np.broadcast(*[np.atleast_2d(x), 0, x]))
    Out[209]: 
    array([[ 1.,  1.,  1.,  1.,  1.],
           [ 0.,  0.,  0.,  0.,  0.],
           [ 1.,  1.,  1.,  1.,  1.]])
    

    something([np.atleast_2d(x), 0, x]) 返回:

    In [211]: something([np.atleast_2d(x), 0, x])
    Out[211]: 
    array([array([[ 1.,  1.,  1.,  1.,  1.]]), array([ 0.]),
           array([ 1.,  1.,  1.,  1.,  1.])], dtype=object)
    

    【讨论】:

      【解决方案2】:

      更短的方式,但我怀疑是否更快:

      l = len(max(lst, key=lambda e: len(e) if isinstance(e, np.ndarray) else 0))
      new_lst = np.array([(x if isinstance(x, np.ndarray) else np.ones(l) * x) for x in lst])
      

      编辑:使用np.fromiter 更快:

      l = len(max(lst, key=lambda e: len(e) if isinstance(e, np.ndarray) else 0))
      new_lst = np.fromiter(((x if isinstance(x, np.ndarray) else np.ones(l) * x) for x in lst))
      

      使用while循环可以更快,但代码有点长:

      i = 0
      while not isinstance(lst[i], np.ndarray):
        i += 1
      l = len(lst[i])
      new_lst = np.fromiter(((x if isinstance(x, np.ndarray) else np.ones(l) * x) for x in lst))
      

      【讨论】:

        【解决方案3】:

        对于 25 行,something 的列表理解版本的速度介于 broadcasebroadcast_arrays 之间:

        In [48]: ll=[x,0,x,x,0]*5
        
        In [49]: np.vstack([y if isinstance(y,np.ndarray) else np.zeros(5) for y in ll]).shape
        Out[49]: (25, 5)
        
        In [50]: timeit np.vstack([y if isinstance(y,np.ndarray) else np.zeros(5) for y in ll]).shape
        1000 loops, best of 3: 219 us per loop
        
        In [51]: timeit np.vstack(np.broadcast_arrays(*ll))
        1000 loops, best of 3: 790 us per loop
        
        In [52]: timeit np.column_stack(np.broadcast(*ll)).shape
        10000 loops, best of 3: 126 us per loop
        

        使用np.array 而不是vstack 会更好:

        In [54]: timeit np.array([y if isinstance(y,np.ndarray) else np.zeros(5) for y in ll]).shape
        10000 loops, best of 3: 54.2 us per loop
        

        对于 2d xvstack 上的 if 理解可能是唯一正确的一个:

        In [66]: x=np.arange(10).reshape(2,5)
        
        In [67]: ll=[x,0,x,x,0]
        
        In [68]: np.vstack([y if isinstance(y,np.ndarray) else np.zeros(5) for y in ll]) 
        Out[68]: 
        array([[ 0.,  1.,  2.,  3.,  4.],
               [ 5.,  6.,  7.,  8.,  9.],
               [ 0.,  0.,  0.,  0.,  0.],
               [ 0.,  1.,  2.,  3.,  4.],
               [ 5.,  6.,  7.,  8.,  9.],
               [ 0.,  1.,  2.,  3.,  4.],
               [ 5.,  6.,  7.,  8.,  9.],
               [ 0.,  0.,  0.,  0.,  0.]])
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-12-31
          • 2016-02-06
          • 1970-01-01
          • 1970-01-01
          • 2015-07-30
          相关资源
          最近更新 更多