web-dev-qa-db-fra.com

Comment trouver la somme cumulée de nombres dans une liste?

time_interval = [4, 6, 12]

Je veux résumer les nombres tels que [4, 4+6, 4+6+12] afin d'obtenir la liste t = [4, 10, 22].

J'ai essayé ce qui suit:

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
56
user2259323

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 cumulée cumsum :

import numpy as np

a = [4,6,12]

np.cumsum(a)
#array([4, 10, 22])

Numpy est souvent plus rapide que le python pur pour ce genre de chose, à comparer avec @ Ashwini's 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 ne vaut peut-être pas la peine d’en dépendre.

80
askewchan

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 dans 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]
66

Voir:

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

Sortie (comme prévu):

[4, 10, 22]
15
wonder.mice

J'ai comparé les deux premières réponses avec Python 3.4 et j'ai constaté que itertools.accumulate est plus rapide que numpy.cumsum dans de nombreuses circonstances, souvent beaucoup plus rapidement. Cependant, comme vous pouvez le constater dans les commentaires, il se peut que cela ne soit pas toujours le cas et qu'il soit difficile d'explorer toutes les options de manière exhaustive. (N'hésitez pas à ajouter un commentaire ou à modifier ce message si vous avez d'autres résultats de référence intéressants.)

Quelques timings ...

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

accumulate est environ 3 fois plus rapide pour les listes plus longues:

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

Si numpyarray n'est pas converti en list, accumulate reste environ deux 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 placez les importations en dehors des deux fonctions et que vous retournez quand même une numpyarray, accumulate reste 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
9
Chris_Rands

Tout d'abord, vous voulez une liste courante de sous-séquences:

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

Ensuite, vous appelez simplement sum sur chaque sous-séquence:

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

(Ce n’est pas le moyen le plus efficace de le faire, car vous ajoutez tous les préfixes à plusieurs reprises. Mais cela n’aura probablement pas d’importance pour la plupart des cas d’utilisation, et il est plus facile de comprendre si vous n’aurez pas à penser à les totaux cumulés.)

Si vous utilisez Python 3.2 ou une version plus récente, vous pouvez utiliser itertools.accumulate pour le faire à votre place:

sums = itertools.accumulate(seq)

Et si vous utilisez la version 3.1 ou une version antérieure, vous pouvez simplement copier la source "équivalente à" directement dans la documentation (à l'exception de la modification de next(it) en it.next() pour les versions 2.5 et antérieures).

3
abarnert

Si vous voulez une méthode Pythonic sans Numpy dans la version 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 et testons-le contre 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
2
Cobry
values = [4, 6, 12]
total  = 0
sums   = []

for v in values:
  total = total + v
  sums.append(total)

print 'Values: ', values
print 'Sums:   ', sums

Exécuter ce code donne

Values: [4, 6, 12]
Sums:   [4, 10, 22]
2
Chris Taylor

Les expressions d'affectation de PEP 572 (attendues pour Python 3.8) offrent un autre moyen 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]
1
Steven Rumbalski

Essaye ça:

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

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]

Je pensais que la fonction interne serait capable de modifier la variable y déclarée dans la portée lexicale externe, mais cela n'a pas fonctionné, nous avons donc joué à de vilains stratagèmes avec modification de structure. Il est probablement plus élégant d'utiliser un générateur.

0
Vatine
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
0
Ronnie Joshua

En Python3, pour trouver la somme cumulative d'une liste où l'élément ith est la somme des premiers éléments i + 1 de la liste d'origine, vous pouvez effectuer les opérations suivantes:

a = [4 , 6 , 12]
b = []
for i in range(0,len(a)):
    b.append(sum(a[:i+1]))
print(b)

OU vous pouvez utiliser la compréhension de liste:

b = [sum(a[:x+1]) for x in range(0,len(a))]

sortie

[4,10,22]
0
manish apte
lst = [4,6,12]

[sum(lst[:i+1]) for i in xrange(len(lst))]

Si vous recherchez une solution plus efficace (de plus grandes listes?), Un générateur peut être un bon appel (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]))
0
gonz

Essaye ça: fonction accumuler, avec opérateur add effectue l’ajout en cours.

import itertools  
import operator  
result = itertools.accumulate([1,2,3,4,5], operator.add)  
list(result)
0
Vani S
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 légèrement plus rapide que la méthode du générateur ci-dessus de @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 les plus grandes listes, le générateur est la voie à suivre à coup sûr. . . 

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
0
reptilicus

Un oneliner en python pur pour une somme cumulée: 

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

Ceci est une version récursive inspirée par sommes cumulatives récursives . Quelques explications:

  1. Le premier terme X[:1] est une liste contenant l’élément précédent et est presque identique à [X[0]] (qui se plaindrait des listes vides).
  2. L'appel récursif cumsum du second terme traite l'élément actuel [1] et la liste restante dont la longueur sera réduite de un.
  3. if X[1:] est plus court pour if len(X)>1.

Tester:

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

cumsum([])
#[]

Et simular pour le produit cumulatif:

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

Tester:

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

Vous pouvez calculer la liste des sommes cumulées en temps linéaire avec une simple boucle 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 bibliothèque standard itertools.accumulate peut être une alternative plus rapide (puisqu'elle est implémentée en C):

from itertools import accumulate
time_interval = [4, 6, 12]
print(list(accumulate(time_interval)))  # [4, 10, 22]
0
Eugene Yarmash

Sans avoir à utiliser Numpy, vous pouvez effectuer une boucle directe sur le tableau et accumuler la somme en cours de route. 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ésulte en: 

[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
0
user3062149
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))
0
Sugandha