【问题标题】:Good ways to "expand" a numpy ndarray?“扩展” numpy ndarray 的好方法?
【发布时间】:2012-09-21 23:49:06
【问题描述】:

有没有“扩展” numpy ndarray 的好方法?假设我有一个这样的 ndarray:

[[1 2]
 [3 4]]

我希望每一行通过填充零来包含更多元素:

[[1 2 0 0 0]
 [3 4 0 0 0]]

我知道必须有一些蛮力的方法来做到这一点(比如用零构造一个更大的数组,然后从旧的更小的数组中复制元素),只是想知道有没有 Pythonic 方法可以做到这一点。试过numpy.reshape但没用:

import numpy as np
a = np.array([[1, 2], [3, 4]])
np.reshape(a, (2, 5))

Numpy 抱怨说:ValueError: total size of new array must be unchanged

【问题讨论】:

    标签: python numpy multidimensional-array


    【解决方案1】:

    您应该使用np.column_stackappend

    import numpy as np
    
    p = np.array([ [1,2] , [3,4] ])
    
    p = np.column_stack( [ p , [ 0 , 0 ],[0,0] ] )
    
    p
    Out[277]: 
    array([[1, 2, 0, 0],
           [3, 4, 0, 0]])
    

    Append 似乎更快:

    timeit np.column_stack( [ p , [ 0 , 0 ],[0,0] ] )
    10000 loops, best of 3: 61.8 us per loop
    
    timeit np.append(p, [[0,0],[0,0]],1)
    10000 loops, best of 3: 48 us per loop
    

    np.c_np.hstack 的比较[追加似乎仍然是最快的]:

    In [295]: z=np.zeros((2, 2), dtype=a.dtype)
    
    In [296]: timeit np.c_[a, z]
    10000 loops, best of 3: 47.2 us per loop
    
    In [297]: timeit np.append(p, z,1)
    100000 loops, best of 3: 13.1 us per loop
    
    In [305]: timeit np.hstack((p,z))
    10000 loops, best of 3: 20.8 us per loop
    

    np.concatenate [比append 还要快一点]:

    In [307]: timeit np.concatenate((p, z), axis=1)
    100000 loops, best of 3: 11.6 us per loop
    

    【讨论】:

    • 奇怪。你可能会发现 np.concatenate((a, z), axis=1) 比 append 更快
    • 是的,这是因为 append 在简单地调用 concatenate 之前做了一些额外的逻辑(这里实际上不需要)。
    【解决方案2】:

    有索引技巧r_c_

    >>> import numpy as np
    >>> a = np.array([[1, 2], [3, 4]])
    >>> z = np.zeros((2, 3), dtype=a.dtype)
    >>> np.c_[a, z]
    array([[1, 2, 0, 0, 0],
           [3, 4, 0, 0, 0]])
    

    如果这是性能关键代码,您可能更喜欢使用等效的np.concatenate 而不是索引技巧。

    >>> np.concatenate((a,z), axis=1)
    array([[1, 2, 0, 0, 0],
           [3, 4, 0, 0, 0]])
    

    还有 np.resizenp.ndarray.resize,但它们有一些限制(由于 numpy 在内存中布局数据的方式),因此请阅读这些文档字符串。您可能会发现简单地连接更好。

    顺便说一句,当我需要这样做时,我通常只是按照您已经提到的基本方式进行(创建一个零数组并在其中分配较小的数组),我看不出有什么问题接着就,随即!

    【讨论】:

      【解决方案3】:

      要明确一点:没有“好的”方法来扩展 NumPy 数组,因为 NumPy 数组是不可可扩展的。一旦定义了数组,它在内存中占据的空间,它的元素数量和每个元素的大小的组合,是固定的,不能改变。您唯一能做的就是创建一个新数组并将其中的一些元素替换为原始数组的元素。

      为了方便起见,提供了很多函数(np.concatenate 函数及其np.*stack 快捷方式、np.column_stack、索引例程np.r_np.c_...),但仅此而已:便利功能。其中一些在 C 级别进行了优化(我认为是 np.concatenate 和其他),有些则不是。

      请注意,您最初的建议是“手动”创建一个大数组(可能用零填充)并自己用初始数组填充它,这根本没有任何意义。它可能比更复杂的解决方案更具可读性。

      【讨论】:

      • +1 虽然有np.ndarray.resize,它会改变数组的大小。它确实为数据重新分配空间如有必要
      • ...如果数组 (i) 是连续的并且 (ii) 不是对另一个数组的引用。无论如何,结果总是要经过三次检查,所以我想知道这是否真的值得麻烦。
      • +1 到 Numpy 数组上的固定大小备注。如果你必须经常这样做,最好使用列表并在最后将它们转换为数组。
      【解决方案4】:

      你可以使用numpy.pad,如下:

      >>> import numpy as np
      >>> a=[[1,2],[3,4]]
      >>> np.pad(a, ((0,0),(0,3)), mode='constant', constant_values=0)
      array([[1, 2, 0, 0, 0],
             [3, 4, 0, 0, 0]])
      

      这里np.pad 说:“获取数组a 并在其上方添加 0 行,在其下方添加 0 行,在其左侧添加 0 列,在其右侧添加 3 列。用constantconstant_values 指定。

      【讨论】:

      • 作为个人经验,我在使用 np.pad 动态扩展数组的大小时发现时间性能很差。在我更改为 np.concatenate 后,运行时间减少了 ~x10 倍。
      【解决方案5】:

      还有类似的方法,如 np.vstack、np.hstack、np.dstack。我喜欢这些而不是 np.concatente,因为它清楚地表明了正在“扩展”的维度。

      temp = np.array([[1, 2], [3, 4]])
      np.hstack((temp, np.zeros((2,3))))
      

      很容易记住,因为 numpy 的第一个轴是垂直的,所以 vstack 扩展了第一个轴,第二个轴是水平的,所以 hstack.

      【讨论】:

        【解决方案6】:

        一个简单的方法:

        # what you want to expand
        x = np.ones((3, 3))
        
        # expand to what shape 
        target = np.zeros((6, 6))
        
        # do expand
        target[:x.shape[0], :x.shape[1]] = x
        
        # print target
        array([[ 1.,  1.,  1.,  0.,  0.,  0.],
               [ 1.,  1.,  1.,  0.,  0.,  0.],
               [ 1.,  1.,  1.,  0.,  0.,  0.],
               [ 0.,  0.,  0.,  0.,  0.,  0.],
               [ 0.,  0.,  0.,  0.,  0.,  0.],
               [ 0.,  0.,  0.,  0.,  0.,  0.]])
        

        功能方式:

        借鉴https://stackoverflow.com/a/35751427/1637673,稍作修改。

        def pad(array, reference_shape, offsets=None):
            """
            array: Array to be padded
            reference_shape: tuple of size of narray to create
            offsets: list of offsets (number of elements must be equal to the dimension of the array)
            will throw a ValueError if offsets is too big and the reference_shape cannot handle the offsets
            """
        
            if not offsets:
                offsets = np.zeros(array.ndim, dtype=np.int32)
        
            # Create an array of zeros with the reference shape
            result = np.zeros(reference_shape, dtype=np.float32)
            # Create a list of slices from offset to offset + shape in each dimension
            insertHere = [slice(offsets[dim], offsets[dim] + array.shape[dim]) for dim in range(array.ndim)]
            # Insert the array in the result at the specified offsets
            result[insertHere] = array
            return result
        

        【讨论】:

          猜你喜欢
          • 2018-06-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-10
          • 2021-08-10
          相关资源
          最近更新 更多