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

在numpy数组中同时访问块

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

    提供了一个numpy数组:

    arr = np.array([0,1,2,3,4,5,6,7,8,9,10,11,12])
    

    我想知道access是如何选择大小的 大块 在选定的分隔中,连接和切片:

    E、 g.:获取大小为3的块,由两个值分隔:

    arr_chunk_3_sep_2 = np.array([0,1,2,5,6,7,10,11,12])
    arr_chunk_3_sep_2_in_slices = np.array([[0,1,2],[5,6,7],[10,11,12])
    

    最有效的方法是什么?如果可能,我希望尽可能避免复制或创建新对象。也许 吧 记忆视图 能帮上忙吗?

    2 回复  |  直到 8 年前
        1
  •  3
  •   Divakar    8 年前

    进近1

    这是一个 masking -

    def slice_grps(a, chunk, sep):
        N = chunk + sep
        return a[np.arange(len(a))%N < chunk]
    

    样本运行-

    In [223]: arr
    Out[223]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12])
    
    In [224]: slice_grps(arr, chunk=3, sep=2)
    Out[224]: array([ 0,  1,  2,  5,  6,  7, 10, 11, 12])
    

    方法2

    如果输入数组使得最后一块有足够的跑道,我们可以,我们可以利用 np.lib.stride_tricks.as_strided ,灵感来自 this post 选择 m 每一块的元素 n 元素-

    # https://stackoverflow.com/a/51640641/ @Divakar
    def skipped_view(a, m, n):
        s = a.strides[0]
        strided = np.lib.stride_tricks.as_strided
        shp = ((a.size+n-1)//n,n)
        return strided(a,shape=shp,strides=(n*s,s), writeable=False)[:,:m]
    
    out = skipped_view(arr,chunk,chunk+sep)
    

    注意,输出将是输入数组的视图,因此没有额外的内存开销,而且实际上是空闲的!

    试运行以澄清问题-

    In [255]: arr
    Out[255]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12])
    
    In [256]: chunk = 3
    
    In [257]: sep = 2
    
    In [258]: skipped_view(arr,chunk,chunk+sep)
    Out[258]: 
    array([[ 0,  1,  2],
           [ 5,  6,  7],
           [10, 11, 12]])
    
    # Let's prove that the output is a view indeed
    In [259]: np.shares_memory(arr, skipped_view(arr,chunk,chunk+sep))
    Out[259]: True
    
        2
  •  1
  •   hpaulj    8 年前

    整形和切片怎么样?

    In [444]: arr = np.array([0,1,2,3,4,5,6,7,8,9,10,11,12])
    In [445]: arr.reshape(-1,5)
    ...
    ValueError: cannot reshape array of size 13 into shape (5)
    

    啊,一个问题-你的阵列不够大,无法进行此重塑-因此我们必须填补它:

    In [446]: np.concatenate((arr,np.zeros(2,int))).reshape(-1,5)
    Out[446]: 
    array([[ 0,  1,  2,  3,  4],
           [ 5,  6,  7,  8,  9],
           [10, 11, 12,  0,  0]])
    In [447]: np.concatenate((arr,np.zeros(2,int))).reshape(-1,5)[:,:-2]
    Out[447]: 
    array([[ 0,  1,  2],
           [ 5,  6,  7],
           [10, 11, 12]])
    

    as_strided 可以通过在databuffer外部包含字节来解决这个问题。通常这被视为一个bug,尽管在这里它可能是一个资产——只要你真的扔掉了垃圾。

    或者扔掉最后一条不完整的线:

    In [452]: arr[:-3].reshape(-1,5)[:,:3]
    Out[452]: 
    array([[0, 1, 2],
           [5, 6, 7]])