¿Cómo encontrar la sum acumulada de números en una lista?

time_interval = [4, 6, 12] 

Quiero resumir los números como [4, 4+6, 4+6+12] para obtener la lista t = [4, 10, 22] .

Intenté lo siguiente:

 for i in time_interval: t1 = time_interval[0] t2 = time_interval[1] + t1 t3 = time_interval[2] + t2 print(t1, t2, t3) 4 10 22 4 10 22 4 10 22 

Si está haciendo mucho trabajo numérico con matrices como esta, sugeriría numpy , que viene con una función de sum acumulativa cumsum :

 import numpy as np a = [4,6,12] np.cumsum(a) #array([4, 10, 22]) 

Numpy es a menudo más rápido que python puro para este tipo de cosas, consulte en comparación con el cúmulo de @ Ashwini :

 In [136]: timeit list(accumu(range(1000))) 10000 loops, best of 3: 161 us per loop In [137]: timeit list(accumu(xrange(1000))) 10000 loops, best of 3: 147 us per loop In [138]: timeit np.cumsum(np.arange(1000)) 100000 loops, best of 3: 10.1 us per loop 

Pero, por supuesto, si es el único lugar donde utilizará el numpy, puede que no valga la pena depender de él.

En Python 2 puedes definir tu propia función de generador de esta manera:

 def accumu(lis): total = 0 for x in lis: total += x yield total In [4]: list(accumu([4,6,12])) Out[4]: [4, 10, 22] 

Y en Python 3.2+ puedes usar itertools.accumulate() :

 In [1]: lis = [4,6,12] In [2]: from itertools import accumulate In [3]: list(accumulate(lis)) Out[3]: [4, 10, 22] 

Mirad:

 a = [4, 6, 12] reduce(lambda c, x: c + [c[-1] + x], a, [0])[1:] 

Saldrá (como se espera):

 [4, 10, 22] 

Hice una itertools.accumulate de las dos mejores respuestas con Python 3.4 y descubrí que itertools.accumulate es más rápido que numpy.cumsum en muchas circunstancias, a menudo mucho más rápido. Sin embargo, como puede ver en los comentarios, esto puede no ser siempre el caso, y es difícil explorar exhaustivamente todas las opciones. (No dude en agregar un comentario o editar esta publicación si tiene otros resultados de referencia de interés).

Algunos tiempos …

Para listas cortas, accumulate es aproximadamente 4 veces más rápido:

 from timeit import timeit def sum1(l): from itertools import accumulate return list(accumulate(l)) def sum2(l): from numpy import cumsum return list(cumsum(l)) l = [1, 2, 3, 4, 5] timeit(lambda: sum1(l), number=100000) # 0.4243644131347537 timeit(lambda: sum2(l), number=100000) # 1.7077815784141421 

Para listas más largas, accumulate es aproximadamente 3 veces más rápido:

 l = [1, 2, 3, 4, 5]*1000 timeit(lambda: sum1(l), number=100000) # 19.174508565105498 timeit(lambda: sum2(l), number=100000) # 61.871223849244416 

Si la array numpy no se numpy a la list , la accumulate es todavía 2 veces más rápida:

 from timeit import timeit def sum1(l): from itertools import accumulate return list(accumulate(l)) def sum2(l): from numpy import cumsum return cumsum(l) l = [1, 2, 3, 4, 5]*1000 print(timeit(lambda: sum1(l), number=100000)) # 19.18597290944308 print(timeit(lambda: sum2(l), number=100000)) # 37.759664884768426 

Si coloca las importaciones fuera de las dos funciones y aún devuelve una array numpy , accumulate es todavía casi 2 veces más rápido:

 from timeit import timeit from itertools import accumulate from numpy import cumsum def sum1(l): return list(accumulate(l)) def sum2(l): return cumsum(l) l = [1, 2, 3, 4, 5]*1000 timeit(lambda: sum1(l), number=100000) # 19.042188624851406 timeit(lambda: sum2(l), number=100000) # 35.17324400227517 

Primero, quieres una lista de subsecuencias:

 subseqs = (seq[:i] for i in range(1, len(seq)+1)) 

Entonces solo tienes que llamar sum en cada subsecuencia:

 sums = [sum(subseq) for subseq in subseqs] 

(Esta no es la forma más eficiente de hacerlo, porque está agregando todos los prefijos repetidamente. Pero eso probablemente no importe para la mayoría de los casos de uso, y es más fácil de entender si no tiene que pensar en los totales streams)

Si está usando Python 3.2 o más reciente, puede usar itertools.accumulate para hacerlo por usted:

 sums = itertools.accumulate(seq) 

Y si está utilizando 3.1 o anterior, simplemente puede copiar la fuente “equivalente a” directamente de los documentos (excepto para cambiar el next(it) a it.next() para 2.5 y it.next() anteriores).

 values = [4, 6, 12] total = 0 sums = [] for v in values: total = total + v sums.append(total) print 'Values: ', values print 'Sums: ', sums 

Ejecutando este código da

 Values: [4, 6, 12] Sums: [4, 10, 22] 

Si quieres una forma pythonica sin trabajar con numpy en 2.7, esta sería mi forma de hacerlo.

 l = [1,2,3,4] _d={-1:0} cumsum=[_d.setdefault(idx, _d[idx-1]+item) for idx,item in enumerate(l)] 

Ahora vamos a probarlo y probarlo contra todas las otras implementaciones

 import timeit L=range(10000) def sum1(l): cumsum=[] total = 0 for v in l: total += v cumsum.append(total) return cumsum def sum2(l): import numpy as np return list(np.cumsum(l)) def sum3(l): return [sum(l[:i+1]) for i in xrange(len(l))] def sum4(l): return reduce(lambda c, x: c + [c[-1] + x], l, [0])[1:] def this_implementation(l): _d={-1:0} return [_d.setdefault(idx, _d[idx-1]+item) for idx,item in enumerate(l)] # sanity check sum1(L)==sum2(L)==sum3(L)==sum4(L)==this_implementation(L) >>> True # PERFORMANCE TEST timeit.timeit('sum1(L)','from __main__ import sum1,sum2,sum3,sum4,this_implementation,L', number=100)/100. >>> 0.001018061637878418 timeit.timeit('sum2(L)','from __main__ import sum1,sum2,sum3,sum4,this_implementation,L', number=100)/100. >>> 0.000829620361328125 timeit.timeit('sum3(L)','from __main__ import sum1,sum2,sum3,sum4,this_implementation,L', number=100)/100. >>> 0.4606760001182556 timeit.timeit('sum4(L)','from __main__ import sum1,sum2,sum3,sum4,this_implementation,L', number=100)/100. >>> 0.18932826995849608 timeit.timeit('this_implementation(L)','from __main__ import sum1,sum2,sum3,sum4,this_implementation,L', number=100)/100. >>> 0.002348129749298096 

Prueba esto:

 result = [] acc = 0 for i in time_interval: acc += i result.append(acc) 

Las expresiones de asignación de PEP 572 (esperadas para Python 3.8) ofrecen otra forma de resolver esto:

 time_interval = [4, 6, 12] total_time = 0 cum_time = [total_time := total_time + t for t in time_interval] 

Algo hacky, pero parece funcionar:

 def cumulative_sum(l): y = [0] def inc(n): y[0] += n return y[0] return [inc(x) for x in l] 

Pensé que la función interna sería capaz de modificar la y declarada en el ámbito léxico externo, pero eso no funcionó, así que jugamos algunos hacks desagradables con modificación de estructura. Probablemente sea más elegante usar un generador.

Sin tener que usar Numpy, puede pasar directamente sobre la matriz y acumular la sum a lo largo del camino. Por ejemplo:

 a=range(10) i=1 while((i>0) & (i<10)): a[i]=a[i-1]+a[i] i=i+1 print a 

Resultados en:

 [0, 1, 3, 6, 10, 15, 21, 28, 36, 45] 
 def cummul_sum(list_arguement): cumm_sum_lst = [] cumm_val = 0 for eachitem in list_arguement: cumm_val += eachitem cumm_sum_lst.append(cumm_val) return cumm_sum_lst 

Un oneliner de python puro para la sum acumulada:

 cumsum = lambda X: X[:1] + cumsum([X[0]+X[1]] + X[2:]) if X[1:] else X 

Esta es una versión recursiva inspirada en sums acumulativas recursivas . Algunas explicaciones:

  1. El primer término X[:1] es una lista que contiene el elemento anterior y es casi igual que [X[0]] (que se quejaría de listas vacías).
  2. La llamada cumsum recursiva en el segundo término procesa el elemento actual [1] y la lista restante cuya longitud se reducirá en uno.
  3. if X[1:] es más corto para if len(X)>1 .

Prueba:

 cumsum([4,6,12]) #[4, 10, 22] cumsum([]) #[] 

Y simular para producto acumulativo:

 cumprod = lambda X: X[:1] + cumprod([X[0]*X[1]] + X[2:]) if X[1:] else X 

Prueba:

 cumprod([4,6,12]) #[4, 24, 288] 

Intente esto: la función de acumulación, junto con el operador add realiza la adición en ejecución.

 import itertools import operator result = itertools.accumulate([1,2,3,4,5], operator.add) list(result) 

Puede calcular la lista de sums acumuladas en tiempo lineal con un simple bucle for :

 def csum(lst): s = lst.copy() for i in range(1, len(s)): s[i] += s[i-1] return s time_interval = [4, 6, 12] print(csum(time_interval)) # [4, 10, 22] 

La biblioteca estándar itertools.accumulate puede ser una alternativa más rápida (ya que se implementa en C):

 from itertools import accumulate time_interval = [4, 6, 12] print(list(accumulate(time_interval))) # [4, 10, 22] 
 lst = [4,6,12] [sum(lst[:i+1]) for i in xrange(len(lst))] 

Si está buscando una solución más eficiente (¿listas más grandes?), Un generador podría ser una buena numpy (o simplemente use numpy si realmente le interesa el rendimiento).

 def gen(lst): acu = 0 for num in lst: yield num + acu acu += num print list(gen([4, 6, 12])) 
 In [42]: a = [4, 6, 12] In [43]: [sum(a[:i+1]) for i in xrange(len(a))] Out[43]: [4, 10, 22] 

Esto es un poco más rápido que el método del generador anterior por @Ashwini para listas pequeñas

 In [48]: %timeit list(accumu([4,6,12])) 100000 loops, best of 3: 2.63 us per loop In [49]: %timeit [sum(a[:i+1]) for i in xrange(len(a))] 100000 loops, best of 3: 2.46 us per loop 

Para listas más grandes, el generador es el camino a seguir. . .

 In [50]: a = range(1000) In [51]: %timeit [sum(a[:i+1]) for i in xrange(len(a))] 100 loops, best of 3: 6.04 ms per loop In [52]: %timeit list(accumu(a)) 10000 loops, best of 3: 162 us per loop 

Esto sería estilo Haskell:

 def wrand(vtlg): def helpf(lalt,lneu): if not lalt==[]: return helpf(lalt[1::],[lalt[0]+lneu[0]]+lneu) else: lneu.reverse() return lneu[1:] return helpf(vtlg,[0])