2015-09-24 1 views
6

Jestem nowy na python (a nawet programowaniu!), Więc postaram się być tak czysty, jak tylko mogę, aby wyjaśnić moje pytanie. Dla was to może być łatwe, ale nie znalazłem jeszcze satysfakcjonującego wyniku na ten temat.Podsumowanie tylko kolejnych wartości w pythonowej tablicy

Oto problem:

Mam tablicę z obu wartości ujemnych i dodatnich, powiedzieć:

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

chciałbym podsumować TYLKO negatywne wartości, które są ciągły, tj. tylko suma (-1, -6, -6), suma (-5, -2, -1, -4) i tak dalej. Próbowałem używać numpy.where, a także numpy.split w oparciu o warunek.

Na przykład:

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

Jednak, jak można się spodziewać, po prostu dostał sumowanie wszystkich wartości ujemnych w tablicy zamiast. W tym przypadku suma (-1, -6, -6, -5, -5, -2, -1, -4) Czy moglibyście podzielić się ze mną estetycznym i skutecznym sposobem rozwiązania tego problemu? Będę wdzięczny za każdą odpowiedź w tej sprawie.

Dziękuję bardzo

+4

Jakie są oczekiwane wyniki? –

+0

Szukasz rozwiązania "numpy" lub czystego Pythona? – Akavall

+0

Dla mnie jest w porządku z pythonic rozwiązaniem. Próbuję postępować zgodnie z radą Kasramvd. Jednakże, jeśli polecisz mi inną opcję oprócz używania itertools, to też byłoby w porządku. – hurrdrought

Odpowiedz

1

Oto wektorowy NumPythonic rozwiązanie -

# 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]) 

Można również użyć np.convolve dostać mask1, jak tak -

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

Można również uzyskać zliczania liczb ujemnych w każdej „wyspy” z niewielką zmianą istniejącego kodu -

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

Sa mple run -

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]) 
+0

Dziękuję bardzo! Próbuję również tej opcji z dobrymi wynikami. Jest to dobre, ponieważ widzę, ile dodałem liczb (to jest liczb). – hurrdrought

+0

Chciałem was poinformować, że dzięki waszemu stanowisku (prawie) skończyłem mój program. Bardzo podoba mi się ten prosty, ale skuteczny sposób na zrobienie tego. Dziękuję Ci bardzo. – hurrdrought

+2

@hurrdrought Awesome! Wydaje mi się, że to rozwiązanie jest wydajne pod względem wydajności, ponieważ pozwala uniknąć pętli i tam właśnie lśnią rozwiązania oparte na NumPy. Czy byłbyś w stanie odmienić te podejścia dla swojego zestawu danych? – Divakar

7

można użyć modułu itertools, tutaj z użyciem groupby można grupowania przedmiotów w oparciu o te znakiem następnie sprawdzić, czy spełniają warunek w key funkcji jest więc zawiera liczby ujemne następnie wytworzeniem Podsumowując inny otrzymując go i wreszcie można użyć chain.from_iterable funkcji łańcucha rezultat:

>>> 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] 

lub jako bardziej pythonic sposób skorzystać z listy ze zrozumieniem:

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] 
+0

Nie potrzebujesz dwóch iteratorów, po prostu sprawdź, czy wartość '_' (tj. Klucza) to' True' lub 'False'. Jeśli jest to "True", to jest to grupa liczb dodatnich. –

+0

@AshwiniChaudhary Ooo tak, ponieważ zawsze używam '_' zamiast' k' po prostu zapomniałem, że to jest użytek ;-) dziękuję za przypomnienie! – Kasramvd

+0

@Kasramvd, dziękuję bardzo za tę opcję. Działa zgodnie z oczekiwaniami. Czy znasz również sposób na poznanie sumy tych wartości ujemnych, ale wiedząc, ile liczb (tj. Kształt tych fragmentów) zostało dodanych? Wiem, że to może być skomplikowane. Z góry dziękuję. – hurrdrought

1

możesz oznaczać wartości ujemne ....i tym zwykły pytona

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) 

wyjście

druku (Temp)

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

z intertools chciałbym zrobić tylko to

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)) 

sumę negatywów -25 liczbę zsumowane 7