Суммирование только последовательных значений в массиве python

Я новичок в Python (и даже Программирование!), поэтому я постараюсь как можно яснее объяснить мой вопрос. Для вас, ребята, это может быть легко, но я пока не нашел удовлетворительного результата.

вот в чем проблема:

у меня есть массив с отрицательными и положительными значениями, скажем:

x = numpy.array([1, 4, 2, 3, -1, -6, -6, 5, 6, 7, 3, 1, -5, 4, 9, -5, -2, -1, -4])

Я хотел бы суммировать только отрицательный значения постоянной, т. е. sum(-1, -6, -6), sum(-5, -2, -1, -4) и так далее. Я пробовал использовать и NumPy.где, а также и NumPy.сплит в зависимости от состояния.

например:

 for i in range(len(x)):
     if x[i] < 0.:
         y[i] = sum(x[i])

однако, как вы можете ожидать, я просто получил суммирование всех отрицательных значений в массиве. В этом случае sum(-1, -6, -6, -5, -5, -2, -1, -4) Могли бы ребята поделиться со мной эстетическим и эффективным способом решения этой проблемы? Буду признателен за любой ответ на этом.

большое спасибо

3 ответов


вот векторизованное Нумпитоническое решение -

# Mask of negative numbers
mask = x<0

# Differentiation between Consecutive mask elements. We would look for 
# 1s and -1s to detect rising and falling edges in the mask corresponding 
# to the islands of negative numbers.
diffs = np.diff(mask.astype(int))

# Mask with 1s at start of negative islands
start_mask = np.append(True,diffs==1) 

# Mask of negative numbers with islands of one isolated negative numbers removed
mask1 = mask & ~(start_mask & np.append(diffs==-1,True))

# ID array for IDing islands of negative numbers
id = (start_mask & mask1).cumsum()

# Finally use bincount to sum elements within their own IDs
out = np.bincount(id[mask1]-1,x[mask1])

вы также можете использовать np.convolve и mask1, вот так -

mask1 = np.convolve(mask.astype(int),np.ones(3),'same')>1

вы также можете получить количество отрицательных чисел в каждом "острове" с небольшой настройкой существующего кода -

counts = np.bincount(id[mask1]-1)

образец выполнения -

In [395]: x
Out[395]: 
array([ 1,  4,  2,  3, -1, -6, -6,  5,  6,  7,  3,  1, -5,  4,  9, -5, -2,
       -1, -4])

In [396]: out
Out[396]: array([-13., -12.])

In [397]: counts
Out[397]: array([3, 4])

можно использовать itertools модуль, здесь с использованием groupby вы можете группировать свои элементы на основе этих знаков, а затем проверить, соответствует ли он условию в key функция, поэтому она содержит отрицательные числа, а затем дает сумму, другую, и, наконец, вы можете использовать chain.from_iterable функция для цепочки результата:

>>> from itertools import groupby,tee,chain
>>> def summ_neg(li):
...     for k,g in groupby(li,key=lambda i:i<0) :
...           if k:
...              yield [sum(g)]
...           yield g
... 
>>> list(chain.from_iterable(summ_neg(x)))
[1, 4, 2, 3, -13, 5, 6, 7, 3, 1, -5, 4, 9, -12]

или как более питонический способ использовать понимание списка:

 list(chain.from_iterable([[sum(g)] if k else list(g) for k,g in groupby(x,key=lambda i:i<0)]))
[1, 4, 2, 3, -13, 5, 6, 7, 3, 1, -5, 4, 9, -12]

вы можете отметить отрицательные значения .... и сделайте это с помощью простого python

prev = False

    for i,v in enumerate(a):
            j = i + 1     
            if j < len(a):
                if a[i] < 0 and  a[j] < 0:
                    temp.append(v)
                    prev = True
                elif a[i] < 0 and prev:
                    temp.append(v)
                    prev = True
                elif a[i] > 0:
                    prev = False
            else:
                if prev and v < 0:
                    temp.append(v)

выход

печать (temp)

[-1, -6, -6, -5, -2, -1, -4]

С intertools я бы это сделал

def sum_conseq_negative(li):
    neglistAll = []
    for k, g in groupby(li, key=lambda i:i<0):
        negList = list(g)
        if k and len(negList) > 1:
            neglistAll.extend(negList)
    return sum(negList), len(negList)

 sumOf, numOf = sum_conseq_negative(li)

print("sum of negatives {} number of summed {}".format(sumOf,numOf))

сумма негативов -25 количество суммированных 7