2015-09-24 22 views
6

Sono nuovo su python (e persino sulla programmazione!), Quindi cercherò di essere il più chiaro possibile per spiegare la mia domanda. Per voi ragazzi potrebbe essere facile, ma non ho ancora trovato un risultato soddisfacente su questo.Sommazione di soli valori consecutivi in ​​un array python

Qui è il problema:

Ho un array con entrambi i valori negativi e positivi, dire:

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

desidero sommare solo le negativi valori che sono continuo, cioè solo somma (-1, -6, -6), somma (-5, -2, -1, -4) e così via. Ho provato a utilizzare numpy.where, nonché a numpy.split in base alle condizioni.

Ad esempio:

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

Tuttavia, come ci si può aspettare, ho appena ricevuto la somma di tutti i valori negativi nella matrice, invece. In questo caso somma (-1, -6, -6, -5, -5, -2, -1, -4) Potrebbero ragazzi condividere con me un modo estetico ed efficiente per risolvere questo problema? Apprezzerò qualsiasi risposta su questo.

La ringrazio molto

+4

Qual è l'output previsto? –

+0

Sei alla ricerca di una soluzione 'numpy' solo o pura soluzione python? – Akavall

+0

Per me va bene con una soluzione pitonica. Sto cercando di seguire il consiglio di Kasramvd. Comunque, se mi consigli un'altra opzione oltre a usare itertools, andrebbe bene anche così. – hurrdrought

risposta

1

Ecco una soluzione NumPythonic vettorializzare -

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

È inoltre possibile utilizzare np.convolve per ottenere mask1, in questo modo -

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

È anche possibile ottenere il conteggio dei numeri negativi in ​​ogni "isola" con un piccolo ritocco al codice esistente -

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

Grazie mille! Sto anche provando questa opzione con buoni risultati. È buono perché posso vedere quanti numeri ho aggiunto (cioè conta). – hurrdrought

+0

Volevo farti sapere che, grazie al tuo post, ho (quasi) finito il mio programma. Mi piace molto questo modo semplice ma efficace per farlo. Grazie mille. – hurrdrought

+2

@hurrdrought Fantastico! Penserei che questa soluzione sia efficiente in termini di prestazioni in quanto ciò evita i loop ed è qui che brillano le soluzioni basate su NumPy. Eri anche in grado di cronometrare questi approcci per il tuo set di dati? – Divakar

7

È possibile utilizzare itertools modulo, qui con l'utilizzo di groupby è possibile raggruppare i vostri articoli basati su quelli segno quindi verificare se soddisfa la condizione in key funzione ed è quindi contiene i numeri negativi poi cedere la somma altro cederlo e alla fine è possibile utilizzare la funzione chain.from_iterable alla catena il risultato:

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

O come un modo più divinatorio utilizzare un elenco di comprensione:

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

Non sono necessari due iteratori, è sufficiente controllare se il valore di '_' (la chiave i.e) è' True' o 'False'. Se è 'True', allora è un gruppo di numeri positivi. –

+0

@AshwiniChaudhary Ooo si, certo, dato che uso sempre '_' invece di' k' ho appena dimenticato che è un uso ;-) grazie per averlo ricordato! – Kasramvd

+0

@ Kasramvd, grazie mille per questa opzione. Funziona come previsto. Inoltre, conosci un modo per conoscere la somma di quei valori negativi, ma sapendo quanti numeri (ad esempio la forma di quei pezzi) sono stati aggiunti? So che potrebbe essere complesso. Grazie in anticipo. – hurrdrought

1

è possibile contrassegnare valori negativi ....e farlo con python pianura

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) 

uscita

di stampa (temp)

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

con intertools vorrei fare proprio questo

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

somma di negativi -25 numero di sommato 7

Problemi correlati