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

如何计算数组中相邻的循环元素?

  •  3
  • PyRsquared  · 技术社区  · 7 年前

    我有一个0和1的数组

    [0,0,1,1,1,0,0,0,0,1,1,0,0]
    

    我想定义一个函数,它将把这个数组作为输入,并输出一个长度相同的数组,其中第一个1出现在索引中相邻1的计数(否则为0)。所以输出将是

    [0,0,3,0,0,0,0,0,0,2,0,0,0]
    

    因为1在第二个指数中连续出现3次,1在第九个指数中连续出现2次。

    有没有办法用numpy来做这个?如果没有,有没有一些(有效的)蟒蛇的方法来做呢?

    8 回复  |  直到 7 年前
        1
  •  3
  •   Nils Werner    7 年前

    下面是一个使用纯矢量化操作和无列表迭代的解决方案:

    import numpy as np
    
    data = np.array([0,0,1,1,1,0,0,0,0,1,1,0,0])
    output = np.zeros_like(data)
    
    where = np.where(np.diff(data))[0]
    vals = where[1::2] - where[::2]
    idx = where[::2] + 1
    
    output[idx] = vals
    output
    # array([0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0])
    
        2
  •  2
  •   jpp    7 年前

    使用 itertools 模块:

    from itertools import chain, groupby
    
    A = [0,0,1,1,1,0,0,0,0,1,1,0,0]
    
    def get_lst(x):
        values = list(x[1])
        return [len(values)] + [0]*(len(values) - 1) if x[0] else values
    
    res = list(chain.from_iterable(map(get_lst, groupby(A))))
    
    # [0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0]
    
        3
  •  1
  •   Dani Mesejo    7 年前

    你可以使用 groupby 将连续元素分组:

    from itertools import groupby
    
    a = [0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0]
    
    
    def groups(lst):
        result = []
        for key, group in groupby(lst):
            if not key:  # is a group of zeroes
                result.extend(list(group))
            else:  # is a group of ones
                count = sum(1 for _ in group)
                if count > 1:  # if more than one
                    result.append(count)
                    result.extend(0 for _ in range(count - 1))
                else:
                    result.append(0)
        return result
    
    
    print(groups(a))
    

    产量

    [0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0]
    

    更短(更多) 蟒蛇的 ?)如下所示:

    def groups(lst):
        for key, group in groupby(lst):
            count = sum(1 for _ in group)
            if key and count > 1:
                yield count
            yield from (0 for _ in range(count - key))
    
    
    print(list(groups(a)))
    
        4
  •  1
  •   Scott Boston    7 年前

    利用熊猫,利用熊猫 count 计算非NaN值。使用创建nan mask 然后按s值的变化分组。

    import pandas as pd
    l = [0,0,1,1,1,0,0,0,0,1,1,0,0]
    s = pd.Series(l)
    g = s.diff().ne(0).cumsum()
    s.mask(s==0).groupby(g).transform('count').mask(g.duplicated(), 0).tolist()
    

    输出:

    [0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0]
    
        5
  •  1
  •   Mazdak    7 年前

    以下是一种使用numpy和列表理解的方法:

    In [23]: a = np.array([0,0,1,1,1,0,0,0,0,1,1,0,0])
    In [24]: np.hstack([x.sum() if x[0] == 1 else x for x in np.split(a, np.where(np.diff(a) != 0)[0]+1)])
    Out[24]: array([0, 0, 3, 0, 0, 0, 0, 2, 0, 0])
    

    逻辑:

    1. 查找结果1所在位置的前导和尾随索引。
    2. 从这些索引中拆分数组
    3. 对有一个的子列表求和,将子列表保留为零。
    4. 使用扁平化结果 np.hstack .

    如果要用0替换剩余的,只需执行以下操作:

    In [28]: np.hstack([[x.sum(), *[0]*(len(x) -1)]  if x[0] == 1 else x for x in np.split(a, np.where(np.diff(a) != 0)[0]+1)])
    Out[28]: array([0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0])
    

    [0]*(len(x) -1) 将为您创建预期的0,并使用就地解包,您将能够将它们放在 sum(x) .

    如果您想要纯Python方法,这里有一种方法可以使用 itertools.groupby :

    In [63]: def summ_cons(li):
        ...:     for k,g in groupby(li) :
        ...:            if k:
        ...:               s = sum(g)
        ...:               yield s
        ...:               yield from (0 for _ in range(s-1))
        ...:            yield from g
        ...:            
    
    
    In [65]: list(summ_cons(a))
    Out[65]: [0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0]
    
        6
  •  0
  •   mad_    7 年前

    使用 groupby

    from itertools import groupby
    a=[0,0,1,1,1,0,0,0,0,1,1,0,0]
    lst_of_tuples=[]
    for k,v in groupby(a):
        lst_of_tuples.append((k,len(list(v))))
    ans=[]
    for k,v in lst_of_tuples:
        temp=[v if k==1 else k]
        for i in range(v-1):
            temp.append(0)
        ans=ans+temp
    

    输出

    [0,0,3,0,0,0,0,0,0,2,0,0,0]
    
        7
  •  0
  •   Jörg Beyer    7 年前

    tl;dr:这将为您提供所需的输出:

    import itertools
    
    input = [0,0,1,1,1,0,0,0,0,1,1,0,0]   
    result = []
    
    for k, g in itertools.groupby(input):
        if k == 1:
            ll = len(list(g))
            result.extend([ll,] + [0 for _ in range(ll-1)])
        else:
            result.extend(list(g)) 
    

    会给你:

    [0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0]
    

    说明:

    Itertools有 groupby 用于拆分“相同”运行的函数

    for k, g in itertools.groupby(input):
        print(g, list(k))
    

    会给你:

    0 [0, 0]
    1 [1, 1, 1]
    0 [0, 0, 0, 0]
    1 [1, 1]
    0 [0, 0]
    

    所以 k 是键、输入序列中的元素和 g 是小组。

    因此,if条件将输入的0的序列附加(在0的情况下),或者长度附加(如果1的行距加0以填充1的行距)。

        8
  •  0
  •   iGian    7 年前

    无依赖项的其他选项:

    老好人 while 按索引访问循环(有时比numpy快):

    def count_same_adjacent_non_zeros(iterable):
      i, x, size = 0, 0, len(iterable)
      while i < size-1:
        if iterable[i] != iterable[i+1]:
          tmp = iterable[x:i+1]
          if not iterable[i] == 0:
            tmp = [len(tmp)] + [0 for _ in range(i-x)]
          for e in tmp: yield e
          x = i + 1
        i += 1
      for e in iterable[x:size]: yield e
    
    
    print(list(count_same_adjacent_non_zeros(array)))
    
    #=> [0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0]
    

    它也适用于 array = [0,0,4,4,4,0,0,0,0,5,5,0,0]