【问题标题】:NumPy: Selecting n points every m pointsNumPy:每 m 个点选择 n 个点
【发布时间】:2018-08-01 18:13:29
【问题描述】:

如果我有一个numpy.ndarray,即大小为 300 点(目前为 1 x 300),并且我想每 30 点选择 10 个点,我该怎么做?

换句话说:我想要前 10 个点,然后跳过 20 个,然后再抓取 10 个,然后再跳过 10 个......直到数组结束。

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    要从30 元素的每个块中选择10 元素,我们可以简单地重塑为2D 并从每行中切出第一列10 -

    a.reshape(-1,30)[:,:10]
    

    好处是输出将是输入的视图,因此几乎是免费的,没有任何额外的内存开销。让我们运行一个示例来展示和证明这些 -

    In [43]: np.random.seed(0)
    
    In [44]: a = np.random.randint(0,9,(1,300))
        
    In [48]: np.shares_memory(a,a.reshape(10,30)[0,:,:10])
    Out[48]: True
    

    如果您需要扁平化版本,请使用.ravel() -

    a.reshape(-1,30)[:,:10].ravel()
    

    时间安排 -

    In [38]: a = np.random.randint(0,9,(300))
    
    # @sacul's soln
    In [39]: %%timeit
        ...: msk = [True] * 10 + [False] * 20
        ...: out = a[np.tile(msk, len(a)//len(msk))]
    100000 loops, best of 3: 7.6 µs per loop
    
    # From this post
    In [40]: %timeit a.reshape(-1,30)[:,:10].ravel()
    1000000 loops, best of 3: 1.07 µs per loop
    
    In [41]: a = np.random.randint(0,9,(3000000))
    
    # @sacul's soln
    In [42]: %%timeit
        ...: msk = [True] * 10 + [False] * 20
        ...: out = a[np.tile(msk, len(a)//len(msk))]
    100 loops, best of 3: 3.66 ms per loop
    
    # From this post
    In [43]: %timeit a.reshape(-1,30)[:,:10].ravel()
    100 loops, best of 3: 2.32 ms per loop
    
    # If you are okay with `2D` output, it is virtually free
    In [44]: %timeit a.reshape(-1,30)[:,:10]
    1000000 loops, best of 3: 519 ns per loop
    

    1D 数组的一般情况

    A.元素数是块长度的倍数

    对于 1D 数组 a 的元素数量是 n 的倍数,从 n 元素的每个块中选择 m 元素并获得 1D 数组输出,我们将有:

    a.reshape(-1,n)[:,:m].ravel()
    

    请注意,ravel() 展平部分会在此处复制。因此,如果可能,请保留未扁平化的 2D 版本以提高内存效率。

    示例运行 -

    In [59]: m,n = 2,5
    
    In [60]: N = 25
    
    In [61]: a = np.random.randint(0,9,(N))
    
    In [62]: a
    Out[62]: 
    array([5, 0, 3, 3, 7, 3, 5, 2, 4, 7, 6, 8, 8, 1, 6, 7, 7, 8, 1, 5, 8, 4,
           3, 0, 3])
    
    # Select 2 elements off each block of 5 elements
    In [63]: a.reshape(-1,n)[:,:m].ravel()
    Out[63]: array([5, 0, 3, 5, 6, 8, 7, 7, 8, 4])
    

    B.通用编号元素数

    我们将利用np.lib.stride_tricks.as_strided,受this post 的启发,从n 元素的每个块中选择m 元素-

    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]
    
    def slice_m_everyn(a, m, n):
        a_slice2D = skipped_view(a,m,n)
        extra = min(m,len(a)-n*(len(a)//n))
        L = m*(len(a)//n) + extra
        return a_slice2D.ravel()[:L]
    

    请注意,skipped_view 可以让我们查看输入数组,并可能查看未分配给输入数组的内存区域,但之后我们会进行展平和切片以将其限制为所需的输出,这就是副本。

    示例运行 -

    In [170]: np.random.seed(0)
         ...: a = np.random.randint(0,9,(16))
    
    In [171]: a
    Out[171]: array([5, 0, 3, 3, 7, 3, 5, 2, 4, 7, 6, 8, 8, 1, 6, 7])
    
    # Select 2 elements off each block of 5 elements
    In [172]: slice_m_everyn(a, m=2, n=5)
    Out[172]: array([5, 0, 3, 5, 6, 8, 7])
    
    In [173]: np.random.seed(0)
         ...: a = np.random.randint(0,9,(19))
    
    In [174]: a
    Out[174]: array([5, 0, 3, 3, 7, 3, 5, 2, 4, 7, 6, 8, 8, 1, 6, 7, 7, 8, 1])
    
    # Select 2 elements off each block of 5 elements
    In [175]: slice_m_everyn(a, m=2, n=5)
    Out[175]: array([5, 0, 3, 5, 6, 8, 7, 7])
    

    【讨论】:

      【解决方案2】:

      您可以创建一个掩码并通过掩码创建索引,重复直到达到数组的长度:

      msk = [True] * 10 + [False] * 20
      
      arr[np.tile(msk, len(arr)//len(msk))]
      

      小例子:

      在一个包含 30 个值的数组中,选择 1 个元素,然后跳过 2 个元素:

      >>> arr
      array([6, 7, 2, 7, 1, 9, 1, 4, 4, 8, 6, 5, 2, 6, 3, 6, 8, 5, 6, 7, 2, 1, 9,
             6, 7, 2, 1, 8, 2, 2])
      
      msk = [True] * 1 + [False] * 2
      
      >>> arr[np.tile(msk, len(arr)//len(msk))]
      array([6, 7, 1, 8, 2, 6, 6, 1, 7, 8])
      

      解释

      msk 是一个布尔掩码

      >>> msk
      [True, False, False]
      

      然后您可以使用 np.tile 重复该掩码,直到它与原始数组的长度相同(数组的长度除以掩码的长度):

      >>> np.tile(msk, len(arr)//len(msk))
      array([ True, False, False,  True, False, False,  True, False, False,
              True, False, False,  True, False, False,  True, False, False,
              True, False, False,  True, False, False,  True, False, False,
              True, False, False], dtype=bool)
      

      然后,通过布尔值进行索引是一件简单的事情,numpy 擅长

      【讨论】:

        【解决方案3】:

        IIUC

        get = 10
        skip = 20
        k = [item for z in [np.arange(get) + idx for idx in np.arange(0, x.size, skip+get)] for item in z]
        

        然后切片

        x[k]
        

        例子:

        x = np.arange(100)
        x[k]
        
        array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 30, 31, 32, 33, 34, 35, 36,
               37, 38, 39, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 90, 91, 92, 93,
               94, 95, 96, 97, 98, 99])
        

        【讨论】:

          猜你喜欢
          • 2017-01-13
          • 1970-01-01
          • 1970-01-01
          • 2013-02-22
          • 1970-01-01
          • 1970-01-01
          • 2021-10-20
          • 1970-01-01
          • 2013-10-07
          相关资源
          最近更新 更多