【问题标题】:Cutting numpy array based on index基于索引切割numpy数组
【发布时间】:2018-05-02 00:43:12
【问题描述】:

我有一个一维 numpy 数组。此数组中两个后续值之间的差值要么是 1,要么大于 1。我想为每次出现差异大于一的情况将数组切割成部分。因此:

arr = numpy.array([77, 78, 79, 80, 90, 91, 92, 100, 101, 102, 103, 104])

应该变成

[array([77, 78, 79, 80]), array([90, 91, 92]), array([100, 101, 102, 103, 104])]

我有以下代码可以解决问题,但我觉得我在这里很复杂。必须有更好/更蟒蛇的方式。谁有更优雅的方法?

import numpy

def split(arr, cut_idxs):

  empty_arr = []
  for idx in range(-1, cut_idxs.shape[0]):  
    if idx == -1:
      l, r = 0, cut_idxs[0]
    elif (idx != -1) and (idx != cut_idxs.shape[0] - 1):
      l, r = cut_idxs[idx] + 1, cut_idxs[idx + 1]
    elif idx == cut_idxs.shape[0] - 1:
      l, r = cut_idxs[-1] + 1, arr.shape[0]

    empty_arr.append(arr[l:r + 1]) 

  return empty_arr 


arr = numpy.array([77, 78, 79, 80, 90, 91, 92, 100, 101, 102, 103, 104])
cuts = numpy.where(numpy.ediff1d(arr) > 2)[0]

print split(arr, cuts)

【问题讨论】:

    标签: python arrays numpy optimization


    【解决方案1】:

    一种 Pythonic 方式是 -

    np.split(arr, np.flatnonzero(np.diff(arr)>1)+1)
    

    示例运行 -

    In [10]: arr
    Out[10]: array([ 77,  78,  79,  80,  90,  91,  92, 100, 101, 102, 103, 104])
    
    In [11]: np.split(arr, np.flatnonzero(np.diff(arr)>1)+1)
    Out[11]: 
    [array([77, 78, 79, 80]),
     array([90, 91, 92]),
     array([100, 101, 102, 103, 104])]
    

    另一个slicing -

    In [16]: cut_idx = np.r_[0,np.flatnonzero(np.diff(arr)>1)+1,len(arr)]
                 # Or np.flatnonzero(np.r_[True, np.diff(arr)>1, True])
    
    In [17]: [arr[i:j] for i,j in zip(cut_idx[:-1],cut_idx[1:])]
    Out[17]: 
    [array([77, 78, 79, 80]),
     array([90, 91, 92]),
     array([100, 101, 102, 103, 104])]
    

    【讨论】:

    • 使用 np.flatnonzero 代替 np.where 有什么好处吗?
    • @TheDude Nope,np.flatnonzero 更明确地表明我们正在使用一维数组。
    【解决方案2】:

    另一种切片方式,使用np.diff获取适当的索引:

    import numpy as np
    def split(arr):
        idx = np.pad(np.where(np.diff(arr) > 1)[0]+1, (1,1),
                 'constant', constant_values = (0, len(arr)))
        return [arr[idx[i]: idx[i+1]] for i in range(len(idx)-1)]
    

    结果:

    arr = np.array([77, 78, 79, 80, 90, 91, 92, 100, 101, 102, 103, 104])
    >>> split(arr)
    [array([77, 78, 79, 80]), array([90, 91, 92]), array([100, 101, 102, 103, 104])]
    

    在您的情况下,您的切片“映射”idx 最终为:array([ 0, 4, 7, 12]),这就是 diff 大于 1(索引 47)的位置,用零填充左边,右边数组的长度(12)使用np.pad

    但是np.split,正如@Divakar 所建议的,似乎是要走的路

    【讨论】:

      猜你喜欢
      • 2017-06-24
      • 1970-01-01
      • 2017-09-20
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多