代码之家  ›  专栏  ›  技术社区  ›  yuri kilochek

numpy矢量化函数,用于重复连续元素块

  •  2
  • yuri kilochek  · 技术社区  · 8 年前

    numpy有° repeat 函数,它将数组的每个元素重复给定(每个)元素的次数。

    我想实现一个函数,它执行相似的操作,但不重复单个元素,而是重复大小可变的连续元素块。本质上我想要以下功能:

    import numpy as np
    
    def repeat_blocks(a, sizes, repeats):
        b = []    
        start = 0
        for i, size in enumerate(sizes):
            end = start + size
            b.extend([a[start:end]] * repeats[i])
            start = end
        return np.concatenate(b)
    

    例如,给定

    a = np.arange(20)
    sizes = np.array([3, 5, 2, 6, 4])
    repeats = np.array([2, 3, 2, 1, 3])
    

    然后

    repeat_blocks(a, sizes, repeats)
    

    退货

    array([ 0,  1,  2, 
            0,  1,  2,
    
            3,  4,  5,  6,  7, 
            3,  4,  5,  6,  7, 
            3,  4,  5,  6,  7, 
    
            8,  9, 
            8,  9,
    
            10, 11, 12, 13, 14, 15,
    
            16, 17, 18, 19,
            16, 17, 18, 19,
            16, 17, 18, 19 ])
    

    我想以性能的名义将这些循环推到numpy中。这有可能吗?如果是,如何?

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

    cumsum

    # Get repeats for each group using group lengths/sizes
    r1 = np.repeat(np.arange(len(sizes)), repeats)
    
    # Get total size of output array, as needed to initialize output indexing array
    N = (sizes*repeats).sum() # or np.dot(sizes, repeats)
    
    # Initialize indexing array with ones as we need to setup incremental indexing
    # within each group when cumulatively summed at the final stage. 
    # Two steps here:
    # 1. Within each group, we have multiple sequences, so setup the offsetting
    # at each sequence lengths by the seq. lengths preceeeding those.
    id_ar = np.ones(N, dtype=int)
    id_ar[0] = 0
    insert_index = sizes[r1[:-1]].cumsum()
    insert_val = (1-sizes)[r1[:-1]]
    
    # 2. For each group, make sure the indexing starts from the next group's
    # first element. So, simply assign 1s there.
    insert_val[r1[1:] != r1[:-1]] = 1
    
    # Assign index-offseting values
    id_ar[insert_index] = insert_val
    
    # Finally index into input array for the group repeated o/p
    out = a[id_ar.cumsum()]
    
        2
  •  2
  •   John Zwinck    8 年前

    @numba.njit
    def repeat_blocks_jit(a, sizes, repeats):
        out = np.empty((sizes * repeats).sum(), a.dtype)
        start = 0
        oi = 0
        for i, size in enumerate(sizes):
            end = start + size
            for rep in range(repeats[i]):
                oe = oi + size
                out[oi:oe] = a[start:end]
                oi = oe
            start = end
        return out
    

    np.dot() np.repeat()

    njit @numba.njit(nogil=True)