two lists python list sum numbers accumulate

python - lists - ¿Cómo encontrar la suma acumulada de números en una lista?



cumsum python pandas (16)

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 podría modificar el y declarado en el alcance 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.

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


En Python 2 puedes definir tu propia función de generador así:

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]


Este sería el 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])


Hice un itertools.accumulate de las dos respuestas principales con Python 3.4 y encontré 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, este no siempre es el caso, y es difícil explorar exhaustivamente todas las opciones. (Siéntase libre de agregar un comentario o editar esta publicación si tiene más resultados de referencia de interés).

Algunos tiempos ...

Para las 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 que las listas más largas se 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 aproximadamente 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 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


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]


Mirad:

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

Será la salida (como se esperaba):

[4, 10, 22]


Primero, quieres una lista de subsecuencias en ejecución:

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

Entonces solo debes llamar a la sum de 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 probablemente eso no importe en la mayoría de los casos de uso, y es más fácil de entender si no tiene que pensar en los totales acumulados).

Si está utilizando Python 3.2 o posterior, puede usar itertools.accumulate() para hacerlo por usted:

sums = itertools.accumulate(seq)

Y si está utilizando 3.1 o una versión anterior, puede simplemente 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).


Prueba esto:

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


Respondiendo a la pregunta original preguntando cómo "resumir los números en una lista": revise la función sum () incorporada, probablemente haga lo que quiera.


Si estás haciendo mucho trabajo numérico con matrices como esta, te sugiero numpy , que viene con una suma acumulativa de funciones 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 el pitón puro para este tipo de cosas, ver en comparación con accumu 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 que utilizará numpy, puede que no valga la pena tener una dependencia de él.


Si quieres una forma pythonic sin numpy trabajando 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 probemos y probémoslo contra todas las demás 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


Sin tener que usar Numpy, puede recorrer directamente la matriz y acumular la suma en el 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]


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 levemente 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 con seguridad. . .

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


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


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 usar numpy si realmente le interesa el perf).

def gen(lst): acu = 0 for num in lst: yield num + acu acu += num print list(gen([4, 6, 12]))


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]