2012-02-13 77 views
11

什麼是優雅的pythonic方式來實施cumsum?
或者 - 如果there'a已經內置的方式做到這一點,那將是更好的,當然...優雅的pythonic cumsum

+2

cumsum在http://docs.scipy.org/doc/numpy/reference/generated/numpy.cumsum.html? – 2012-02-13 10:06:37

+5

http://docs.python.org/dev/library/itertools.html#itertools.accumulate – ChessMaster 2012-02-13 10:20:24

回答

34

它的問世在Numpy

>>> import numpy as np 
>>> np.cumsum([1,2,3,4,5]) 
array([ 1, 3, 6, 10, 15]) 

或者使用itertools.accumulate因爲Python 3.2 :

>>> from itertools import accumulate 
>>> list(accumulate([1,2,3,4,5])) 
[ 1, 3, 6, 10, 15] 

如果numpy的是不是一種選擇,一臺發電機循環將是最完美的解決方案,我能想到的:

def cumsum(it): 
    total = 0 
    for x in it: 
     total += x 
     yield total 

Ex。

>>> list(cumsum([1,2,3,4,5])) 
>>> [1, 3, 6, 10, 15] 
+1

不錯,簡單,收益率總計:) – 2012-02-13 10:16:40

1

for循環Python的

def cumsum(vec): 
    r = [vec[0]] 
    for val in vec[1:]: 
     r.append(r[-1] + val) 
    return r 
+1

@larsmans:在這種情況下,會有'r [-1]'是什麼? – WolframH 2013-02-25 00:05:06

1
a=[1,2,3,4,5] 

def cumsum(a): 
    a=iter(a) 
    cc=[next(a)] 
    for i in a: 
     cc.append(cc[-1]+i) 
    return cc 

print cumsum(a) 
"[1, 3, 6, 10, 15]" 
2

到位:

a=[1,2,3,4,5] 
def cumsum(a): 
    for i in range(1,len(a)): 
     a[i]+=a[i-1] 

cumsum(a) 
print a 
"[1, 3, 6, 10, 15]" 
1
a=[1,2,3,4,5] 
def cumsum(a): 
    b=a[:] 
    for i in range(1,len(a)): 
     b[i]+=b[i-1] 
    return b 

print cumsum(a) 
"[1, 3, 6, 10, 15]" 
5
a = [1, 2, 3 ,4, 5] 

# Using list comprehention 
cumsum = [sum(a[:i+1]) for i in range(len(a))]   # [1, 3, 6, 10, 15] 

# Using map() 
cumsum = map(lambda i: sum(a[:i+1]), range(len(a)))  # [1, 3, 6, 10, 15] 
+3

雖然這很好,很容易,但要警惕的是,在一個大的列表中,這將非常緩慢! :) – 2012-02-14 07:32:14

6

我的想法是用減少功能方式:

from operator import iadd 
reduce(lambda acc, itm: iadd(acc, [acc[-1] + itm]), [1, 2, 3, 4, 5], [0])[1:] 
>>> [1, 3, 6, 10, 15] 

來自操作員模塊的iadd具有進行原地添加並返回目的地的獨特屬性。

如果[1:]副本讓你畏縮,你可以這樣做:

from operator import iadd 
reduce(lambda acc, itm: (iadd(acc[0], [acc[1] + itm]), acc[1] + itm), 
     [1, 2, 3, 4, 5], ([], 0))[0] 
>>> [1, 3, 6, 10, 15] 

但我發現,在當地的第一個例子是更快,IMO發電機比像函數式編程更Python化「減少「:

reduce(lambda acc, itm: (iadd(acc[0], [acc[1] + itm]), acc[1] + itm), values_ten, ([], 0))[0] 
Average: 6.4593828736e-06 
reduce(lambda acc, itm: (iadd(acc[0], [acc[1] + itm]), acc[1] + itm), values_mil, ([], 0))[0] 
Average: 0.727404361961 
reduce(lambda acc, itm: iadd(acc, [acc[-1] + itm]), values_ten, [0])[1:] 
Average: 5.16271911336e-06 
reduce(lambda acc, itm: iadd(acc, [acc[-1] + itm]), values_mil, [0])[1:] 
Average: 0.524223491301 
cumsum_rking(values_ten) 
Average: 1.9828751369e-06 
cumsum_rking(values_mil) 
Average: 0.234241141632 
list(cumsum_larsmans(values_ten)) 
Average: 2.02786211569e-06 
list(cumsum_larsmans(values_mil)) 
Average: 0.201473119335 

這裏的基準測試腳本,情況因人而異:

from timeit import timeit 

def bmark(prog, setup, number): 
    duration = timeit(prog, setup=setup, number=number) 
    print prog 
    print 'Average:', duration/number 

values_ten = list(xrange(10)) 
values_mil = list(xrange(1000000)) 

from operator import iadd 

bmark('reduce(lambda acc, itm: (iadd(acc[0], [acc[1] + itm]), acc[1] + itm), \ 
values_ten, ([], 0))[0]', 
     setup='from __main__ import iadd, values_ten', number=1000000) 
bmark('reduce(lambda acc, itm: (iadd(acc[0], [acc[1] + itm]), acc[1] + itm), \ 
values_mil, ([], 0))[0]', 
     setup='from __main__ import iadd, values_mil', number=10) 

bmark('reduce(lambda acc, itm: iadd(acc, [acc[-1] + itm]), \ 
values_ten, [0])[1:]', 
     setup='from __main__ import iadd, values_ten', number=1000000) 
bmark('reduce(lambda acc, itm: iadd(acc, [acc[-1] + itm]), \ 
values_mil, [0])[1:]', 
     setup='from __main__ import iadd, values_mil', number=10) 

def cumsum_rking(iterable): 
    values = list(iterable) 
    for pos in xrange(1, len(values)): 
     values[pos] += values[pos - 1] 
    return values 

bmark('cumsum_rking(values_ten)', 
     setup='from __main__ import cumsum_rking, values_ten', number=1000000) 
bmark('cumsum_rking(values_mil)', 
     setup='from __main__ import cumsum_rking, values_mil', number=10) 

def cumsum_larsmans(iterable): 
    total = 0 
    for value in iterable: 
     total += value 
     yield total 

bmark('list(cumsum_larsmans(values_ten))', 
     setup='from __main__ import cumsum_larsmans, values_ten', number=1000000) 
bmark('list(cumsum_larsmans(values_mil))', 
     setup='from __main__ import cumsum_larsmans, values_mil', number=10) 

這是我的Python版本字符串:

Python 2.7 (r27:82525, Jul 4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32 
+0

+1進行徹底的基準測試 – Jonathan 2013-02-25 14:16:27

2
def cumsum(a): 
    return map(lambda x: sum(a[0:x+1]), range(0, len(a))) 

cumsum([1,2,3]) 

> [1, 3, 6]