Comment trouver la somme cumulative des numéros dans une liste?
time_interval = [4, 6, 12]
je veux faire la somme des nombres comme [4, 4+6, 4+6+12]
pour obtenir la liste t = [4, 10, 22]
.
j'ai essayé la suivante:
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
17 réponses
si vous faites beaucoup de travail numérique avec des tableaux comme celui-ci, je suggérerais numpy
, qui vient avec une fonction de somme cumulative cumsum
:
import numpy as np
a = [4,6,12]
np.cumsum(a)
#array([4, 10, 22])
num Python est souvent plus rapide que python pur pour ce genre de chose, voir en comparaison à de @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
mais bien sûr si c'est le seul endroit où vous utiliserez numpy, il pourrait pas la peine d'avoir une dépendance sur lui.
en Python 2 Vous pouvez définir votre propre fonction de générateur comme ceci:
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]
et en Python 3.2 + vous pouvez utiliser itertools.accumulate()
:
In [1]: lis = [4,6,12]
In [2]: from itertools import accumulate
In [3]: list(accumulate(lis))
Out[3]: [4, 10, 22]
Voici:
a = [4, 6, 12]
reduce(lambda c, x: c + [c[-1] + x], a, [0])[1:]
produira (comme prévu):
[4, 10, 22]
j'ai fait un bench-mark des deux premières réponses avec Python 3.4 et j'ai trouvé que itertools.accumulate
est plus rapide que numpy.cumsum
dans de nombreuses circonstances, souvent beaucoup plus rapide. Cependant, comme vous pouvez le voir dans les commentaires, ce n'est pas toujours le cas, et il est difficile d'explorer de manière exhaustive toutes les options. (N'hésitez pas à ajouter un commentaire ou modifier ce post si vous avez d'autres résultats d'un benchmark d'intérêt.)
quelques chronométrages...
Pour listes courtes accumulate
est environ 4 fois plus rapide:
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
Pour les longues listes de accumulate
est environ 3 fois plus vite:
l = [1, 2, 3, 4, 5]*1000
timeit(lambda: sum1(l), number=100000)
# 19.174508565105498
timeit(lambda: sum2(l), number=100000)
# 61.871223849244416
si le numpy
array
n'est pas moulé à list
, accumulate
est encore environ 2 fois plus rapide:
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 vous mettez les importations en dehors des deux fonctions et encore retourner un numpy
array
, accumulate
est encore presque 2 fois plus rapide:
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
values = [4, 6, 12]
total = 0
sums = []
for v in values:
total = total + v
sums.append(total)
print 'Values: ', values
print 'Sums: ', sums
exécute ce code donne
Values: [4, 6, 12]
Sums: [4, 10, 22]
si vous voulez une façon pythonique sans numpy travailler en 2.7 ce serait ma façon de le faire
l = [1,2,3,4]
_d={-1:0}
cumsum=[_d.setdefault(idx, _d[idx-1]+item) for idx,item in enumerate(l)]
maintenant, essayons-le et testons-le par rapport à toutes les autres implémentations
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
tout d'abord, vous voulez une liste en cours d'exécution des suites:
subseqs = (seq[:i] for i in range(1, len(seq)+1))
ensuite vous appelez juste sum
sur chaque suite:
sums = [sum(subseq) for subseq in subseqs]
(ce n'est pas la façon la plus efficace de le faire, parce que vous ajoutez tous les préfixes à plusieurs reprises. Mais ce ne sera probablement pas important pour la plupart des cas d'utilisation, et il est plus facile de comprendre si vous n'avez pas à penser aux totaux en cours d'exécution.)
si vous utilisez Python 3.2 ou plus récent, vous pouvez utiliser itertools.accumulate
pour le faire pour vous:
sums = itertools.accumulate(seq)
et si vous utilisez 3.1 ou plus tôt, vous pouvez simplement copier l'équivalent de la source directement à partir du docs (sauf pour changer next(it)
en it.next()
pour 2.5 et plus tôt).
essayez ceci:
result = []
acc = 0
for i in time_interval:
acc += i
result.append(acc)
lst = [4,6,12]
[sum(lst[:i+1]) for i in xrange(len(lst))]
si vous cherchez une solution plus efficace (listes plus grandes?) un générateur peut être un bon choix (ou utilisez simplement numpy
si vous vous souciez vraiment de perf).
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]
c'est slighlty plus rapide que la méthode génératrice ci-dessus par @Ashwini pour les petites listes
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
pour des listes plus larges, le générateur est la voie à suivre. . .
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
Affectation des expressions de PEP 572 (prévu pour Python 3.8) offrent encore une autre façon de résoudre ce problème:
time_interval = [4, 6, 12]
total_time = 0
cum_time = [total_time := total_time + t for t in time_interval]
Un pur python oneliner pour la somme cumulative:
cumsum = lambda X: X[:1] + cumsum([X[0]+X[1]] + X[2:]) if X[1:] else X
C'est une version récursive inspiré par récursive sommes cumulées . Quelques explications:
- le premier terme
X[:1]
est une liste contenant l'élément précédent et est presque identique à[X[0]]
(qui se plaindrait pour les listes vides). - récursifs
cumsum
appel dans le deuxième terme traite l'élément courant[1]
et la liste restante dont la longueur sera réduite d'un. -
if X[1:]
est plus court pourif len(X)>1
.
Test:
cumsum([4,6,12])
#[4, 10, 22]
cumsum([])
#[]
et similaire pour produit cumulatif:
cumprod = lambda X: X[:1] + cumprod([X[0]*X[1]] + X[2:]) if X[1:] else X
Test:
cumprod([4,6,12])
#[4, 24, 288]
un peu hacky, mais semble fonctionner:
def cumulative_sum(l):
y = [0]
def inc(n):
y[0] += n
return y[0]
return [inc(x) for x in l]
j'ai pensé que la fonction interne serait capable de modifier le y
déclaré dans la portée lexicale externe, mais cela n'a pas fonctionné, donc nous jouons quelques coups méchants avec la modification de la structure à la place. Il est probablement plus élégant d'utiliser un générateur.
sans avoir à utiliser num Py, vous pouvez boucler directement sur le tableau et accumuler la somme le long du chemin. Par exemple:
a=range(10)
i=1
while((i>0) & (i<10)):
a[i]=a[i-1]+a[i]
i=i+1
print a
résultats dans:
[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
ce serait du style 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])
en réponse à la question initiale demandant comment "faire la somme des nombres dans une liste": Vérifiez la fonction de la somme intégrée (), elle fait probablement ce que vous voulez.