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 loop
Pero, por supuesto, si es el único lugar en el que usará numpy, es posible que no valga la pena depender de él.
fuente
np.cumsun
caso que comience con una lista, para tener en cuenta el tiempo de conversión.list
, no lo recomendaríanumpy
.timeit
, "si-n
no 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 1000
para 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íaaccumulate
ser 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.accumulate
es más rápido quenumpy.cumsum
en 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
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
numpy
array
no se lanza alist
,accumulate
sigue 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.759664884768426
Si coloca las importaciones fuera de las dos funciones y aún devuelve a
numpy
array
,accumulate
sigue 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.17324400227517
fuente
list
de cinco elementos, especialmente si no está dispuesto a aceptar unarray
a 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 unlist
tipo de datos numéricos uniformes de longitud significativa sería una tontería; para eso, un numpyarray
sería apropiado, y generalmente más rápido.numpy
ser más rápido, a menos que haya pasado por alto algo.sum2
función es probablemente convertirl
en 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 del
en 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.add
ya 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
for
ciclo 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.accumulate
puede 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: ', sums
Ejecutar 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
i
elemento 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.002348129749298096
fuente
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
sum
a 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.accumulate
para 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
range
que 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 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
fuente
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
y
declarado 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 a
Resultados 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 X
Esta 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).cumsum
llamada 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 X
Prueba:
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
numpy
si 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