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:
t1 = time_interval[0]
t2 = time_interval[1] + t1
t3 = time_interval[2] + t2
print(t1, t2, t3) # -> 4 10 22
python
list
sum
accumulate
usuario2259323
fuente
fuente

Respuestas:
Si está haciendo mucho trabajo numérico con matrices como esta, sugeriría
numpy, que viene con una función de suma acumulativacumsum: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, vea en comparación con @ Ashwini
accumu: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 loopPero, por supuesto, si es el único lugar en el que usará numpy, es posible que no valga la pena depender de él.
fuente
np.cumsuncaso que comience con una lista, para tener en cuenta el tiempo de conversión.list, no lo recomendaríanumpy.timeit, "si-nno se da, se calcula un número adecuado de bucles probando potencias sucesivas de 10 hasta que el tiempo total sea de al menos 0,2 segundos". Si espera que marque la diferencia, puede suministrar-n 1000para que todos sean equivalentes.En Python 2 puede definir su 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]fuente
total = 0; partial_sums = [total := total + v for v in values]. Todavía esperaríaaccumulateser más rápido.Mirad:
a = [4, 6, 12] reduce(lambda c, x: c + [c[-1] + x], a, [0])[1:]Saldrá (como se esperaba):
[4, 10, 22]fuente
c + [c[-1] + x]una y otra vez se suma a un tiempo de ejecución cuadrático total en la longitud de entrada.Hice una evaluación comparativa de las dos respuestas principales con Python 3.4 y descubrí que
itertools.accumulatees más rápido quenumpy.cumsumen muchas circunstancias, a menudo mucho más rápido. Sin embargo, como puede ver en los comentarios, es posible que este no sea 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 más resultados de referencia de interés).Algunos horarios ...
Para listas cortas
accumulatees 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.7077815784141421Para listas más largas
accumulatees 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.871223849244416Si
numpyarrayno se lanza alist,accumulatesigue siendo aproximadamente 2 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 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.759664884768426Si coloca las importaciones fuera de las dos funciones y aún devuelve a
numpyarray,accumulatesigue siendo 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.17324400227517fuente
listde cinco elementos, especialmente si no está dispuesto a aceptar unarraya cambio. Si la lista en cuestión es realmente tan corta, entonces su tiempo de ejecución sería intrascendente: las dependencias y la legibilidad seguramente dominarían. Pero el uso generalizado de unlisttipo de datos numéricos uniformes de longitud significativa sería una tontería; para eso, un numpyarraysería apropiado, y generalmente más rápido.numpyser más rápido, a menos que haya pasado por alto algo.sum2función es probablemente convertirlen una matriz. Intente cronometrara = np.array(l)y pornp.cumsum(a)separado. A continuación, intentea = np.tile(np.arange(1, 6), 1000)vsl = [1,2,3,4,5]*1000. En un programa que lleva a cabo otros procesos numéricos (como la creación o carga delen primer lugar), sus datos de trabajo probablemente ya estén en una matriz, y la creación tendría un costo constante.Intente esto: función de acumulación, junto con el operador agregar realiza la suma en ejecución.
import itertools import operator result = itertools.accumulate([1,2,3,4,5], operator.add) list(result)fuente
operator.addya que la operación predeterminada es la adición de todos modos.Las expresiones de asignación de PEP 572 (nuevo en 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]fuente
Puede calcular la lista de suma acumulada en tiempo lineal con un
forciclo simple :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.accumulatepuede ser una alternativa más rápida (ya que está implementada en C):from itertools import accumulate time_interval = [4, 6, 12] print(list(accumulate(time_interval))) # [4, 10, 22]fuente
values = [4, 6, 12] total = 0 sums = [] for v in values: total = total + v sums.append(total) print 'Values: ', values print 'Sums: ', sumsEjecutar este código da
Values: [4, 6, 12] Sums: [4, 10, 22]fuente
En Python3, para encontrar la suma acumulativa de una lista donde el
ielemento th es la suma de los primeros elementos i + 1 de la lista original, puede hacer:a = [4 , 6 , 12] b = [] for i in range(0,len(a)): b.append(sum(a[:i+1])) print(b)O puede utilizar la comprensión de listas:
b = [sum(a[:x+1]) for x in range(0,len(a))]Salida
[4,10,22]fuente
Si quieres una forma pitónica sin trabajar 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 probémoslo y probémoslo con todas las demás implementaciones
import timeit, sys L=list(range(10000)) if sys.version_info >= (3, 0): reduce = functools.reduce xrange = range 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.002348129749298096fuente
Puede haber muchas respuestas para esto dependiendo de la longitud de la lista y el rendimiento. Una forma muy simple en la que puedo pensar sin pensar en la actuación es esta:
a = [1, 2, 3, 4] a = [sum(a[0:x:1]) for x in range(len(a)+1)][1:] print(a)[1, 3, 6, 10]Esto es mediante el uso de la comprensión de listas y esto puede funcionar bastante bien, es solo que aquí estoy agregando sobre el subarreglo muchas veces, ¡posiblemente podría improvisar sobre esto y hacerlo simple!
¡Salud por tu esfuerzo!
fuente
Primero, desea una lista en ejecución de subsecuencias:
subseqs = (seq[:i] for i in range(1, len(seq)+1))Luego, simplemente llame
suma 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 importará 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 acumulados.)
Si está utilizando Python 3.2 o una versión más reciente, puede usar
itertools.accumulatepara hacerlo por usted:Y si está utilizando 3.1 o una versión anterior, puede copiar la fuente "equivalente a" directamente de los documentos (excepto para cambiar
next(it)ait.next()2.5 y versiones anteriores).fuente
rangeque hackearlo haciendo[1:]al final, o ignorarlo.)[4,6,12]ya que, como escribió en la pregunta, ¡ya sabe qué es eso!Prueba esto:
result = [] acc = 0 for i in time_interval: acc += i result.append(acc)fuente
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 generador anterior de @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 loopPara 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 loopfuente
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 lo
ydeclarado en el ámbito léxico externo, pero eso no funcionó, así que jugamos algunos trucos desagradables con la modificación de la estructura. Probablemente sea más elegante usar un generador.fuente
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 aResultados en:
[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]fuente
Un delineador de pitón puro para suma acumulativa:
cumsum = lambda X: X[:1] + cumsum([X[0]+X[1]] + X[2:]) if X[1:] else XEsta es una versión recursiva inspirada en sumas acumulativas recursivas . Algunas explicaciones:
X[:1]es una lista que contiene el elemento anterior y es casi igual a[X[0]](que se quejaría de listas vacías).cumsumllamada recursiva en el segundo término procesa el elemento actual[1]y la lista restante cuya longitud se reducirá en uno.if X[1:]es más corto paraif len(X)>1.Prueba:
cumsum([4,6,12]) #[4, 10, 22] cumsum([]) #[]Y similar para producto acumulativo:
cumprod = lambda X: X[:1] + cumprod([X[0]*X[1]] + X[2:]) if X[1:] else XPrueba:
cumprod([4,6,12]) #[4, 24, 288]fuente
l = [1,-1,3] cum_list = l def sum_list(input_list): index = 1 for i in input_list[1:]: cum_list[index] = i + input_list[index-1] index = index + 1 return cum_list print(sum_list(l))fuente
Aquí tienes otra solución divertida. Esto aprovecha el
locals()dictado de una comprensión, es decir, las variables locales generadas dentro del ámbito de comprensión de la lista:>>> [locals().setdefault(i, (elem + locals().get(i-1, 0))) for i, elem in enumerate(time_interval)] [4, 10, 22]Esto es lo que se
locals()ve para cada iteración:>>> [[locals().setdefault(i, (elem + locals().get(i-1, 0))), locals().copy()][1] for i, elem in enumerate(time_interval)] [{'.0': <enumerate at 0x21f21f7fc80>, 'i': 0, 'elem': 4, 0: 4}, {'.0': <enumerate at 0x21f21f7fc80>, 'i': 1, 'elem': 6, 0: 4, 1: 10}, {'.0': <enumerate at 0x21f21f7fc80>, 'i': 2, 'elem': 12, 0: 4, 1: 10, 2: 22}]El rendimiento no es terrible para listas pequeñas:
>>> %timeit list(accumulate([4, 6, 12])) 387 ns ± 7.53 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) >>> %timeit np.cumsum([4, 6, 12]) 5.31 µs ± 67.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each) >>> %timeit [locals().setdefault(i, (e + locals().get(i-1,0))) for i,e in enumerate(time_interval)] 1.57 µs ± 12 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)Y, obviamente, cae plano para listas más grandes.
>>> l = list(range(1_000_000)) >>> %timeit list(accumulate(l)) 95.1 ms ± 5.22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) >>> %timeit np.cumsum(l) 79.3 ms ± 1.07 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) >>> %timeit np.cumsum(l).tolist() 120 ms ± 1.23 ms per loop (mean ± std. dev. of 7 runs, 10 loops each) >>> %timeit [locals().setdefault(i, (e + locals().get(i-1, 0))) for i, e in enumerate(l)] 660 ms ± 5.14 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)Aunque el método es feo y no práctico, seguro que es divertido.
fuente
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 opción (o simplemente usarlo
numpysi realmente le importa el rendimiento).def gen(lst): acu = 0 for num in lst: yield num + acu acu += num print list(gen([4, 6, 12]))fuente
Este sería al 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])fuente