113
time_interval = [4, 6, 12]

我想总结这些数字[4, 4+6, 4+6+12]以获得列表t = [4, 10, 22]

我尝试了以下方法:

t1 = time_interval[0]
t2 = time_interval[1] + t1
t3 = time_interval[2] + t2
print(t1, t2, t3)  # -> 4 10 22
4

23 回答 23

152

如果您正在使用这样的数组进行大量数值工作,我建议您numpy使用累积和函数cumsum

import numpy as np

a = [4,6,12]

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

对于这种事情,Numpy 通常比纯 python 更快,与@Ashwini'saccumu相比,请参见:

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

但当然,如果它是您唯一使用 numpy 的地方,那么依赖它可能不值得。

于 2013-04-08T21:31:07.867 回答
111

在 Python 2 中,您可以像这样定义自己的生成器函数:

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]

在 Python 3.2+ 中,您可以使用itertools.accumulate()

In [1]: lis = [4,6,12]

In [2]: from itertools import accumulate

In [3]: list(accumulate(lis))
Out[3]: [4, 10, 22]
于 2013-04-08T21:19:42.960 回答
26

我用 Python 3.4 对前两个答案进行了基准测试,我发现itertools.accumulate它比numpy.cumsum许多情况下都快,通常要快得多。但是,正如您从评论中看到的那样,情况可能并非总是如此,并且很难详尽地探索所有选项。(如果您有更多感兴趣的基准测试结果,请随时添加评论或编辑此帖子。)

一些时间...

对于短列表accumulate,速度大约快 4 倍:

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,速度大约快 3 倍:

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

如果numpy array不强制转换为listaccumulate仍然快 2 倍:

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

如果您将导入放在两个函数之外并且仍然返回 a numpy arrayaccumulate则仍然快近 2 倍:

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
于 2016-09-16T15:12:20.087 回答
21

试试这个 itertools.accumulate()功能。

import itertools  

list(itertools.accumulate([1,2,3,4,5]))
# [1, 3, 6, 10, 15]
于 2018-12-13T03:51:43.827 回答
20

看哪:

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

将输出(如预期):

[4, 10, 22]
于 2015-10-09T09:43:50.107 回答
12

PEP 572 (Python 3.8 中的新功能)中的赋值表达式提供了另一种解决此问题的方法:

time_interval = [4, 6, 12]

total_time = 0
cum_time = [total_time := total_time + t for t in time_interval]
于 2018-07-15T16:54:36.383 回答
11

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]

标准库itertools.accumulate可能是更快的选择(因为它是用 C 实现的):

from itertools import accumulate
time_interval = [4, 6, 12]
print(list(accumulate(time_interval)))  # [4, 10, 22]
于 2019-03-23T16:59:46.360 回答
5

python 3.8开始可以使用赋值表达式,所以这样的事情变得更容易实现

nums = list(range(1, 10))
print(f'array: {nums}')

v = 0
cumsum = [v := v + n for n in nums]
print(f'cumsum: {cumsum}')

生产

array: [1, 2, 3, 4, 5, 6, 7, 8, 9]
cumsum: [1, 3, 6, 10, 15, 21, 28, 36, 45]

可以应用相同的技术来查找兼积、均值等。

p = 1
cumprod = [p := p * n for n in nums]
print(f'cumprod: {cumprod}')

s = 0
c = 0
cumavg = [(s := s + n) / (c := c + 1) for n in nums]
print(f'cumavg: {cumavg}')

结果是

cumprod: [1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
cumavg: [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0]
于 2021-08-16T10:18:44.197 回答
3

首先,您需要一个正在运行的子序列列表:

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

然后你只需调用sum每个子序列:

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

(这不是最有效的方法,因为您要重复添加所有前缀。但这对于大多数用例来说可能无关紧要,如果您不必考虑就更容易理解运行总数。)

如果您使用的是 Python 3.2 或更高版本,您可以使用itertools.accumulate它来为您执行此操作:

sums = itertools.accumulate(seq)

如果您使用的是 3.1 或更早版本,您可以直接从文档中复制“等效于”源代码(更改next(it)it.next()2.5 或更早版本除外)。

于 2013-04-08T21:19:58.600 回答
3

根据列表的长度和性能,可能会有很多答案。我可以在不考虑性能的情况下思考的一种非常简单的方法是:

a = [1, 2, 3, 4]
a = [sum(a[0:x]) for x in range(1, len(a)+1)]
print(a)

[1, 3, 6, 10]

这是通过使用列表理解,这可能工作得很好,只是在这里我在子数组上添加了很多次,你可能会即兴创作并让它变得简单!

为你的努力干杯!

于 2020-05-06T13:47:37.853 回答
3

如果您想要一种没有 numpy 在 2.7 中工作的 Pythonic 方式,这将是我的做法

l = [1,2,3,4]
_d={-1:0}
cumsum=[_d.setdefault(idx, _d[idx-1]+item) for idx,item in enumerate(l)]

现在让我们尝试一下并针对所有其他实现进行测试

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
于 2017-11-16T15:38:38.703 回答
2
values = [4, 6, 12]
total  = 0
sums   = []

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

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

运行此代码给出

Values: [4, 6, 12]
Sums:   [4, 10, 22]
于 2013-04-08T21:21:29.280 回答
1

尝试这个:

result = []
acc = 0
for i in time_interval:
    acc += i
    result.append(acc)
于 2013-04-08T21:21:00.723 回答
1

在 Python3 中,要查找第一个i元素是原始列表中前 i+1 个元素的总和的列表的累积和,您可以执行以下操作:

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

或者您可以使用列表理解:

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

输出

[4,10,22]
于 2019-08-30T10:10:32.663 回答
1
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))
于 2019-08-08T17:32:53.917 回答
0

有点hacky,但似乎有效:

def cumulative_sum(l):
  y = [0]
  def inc(n):
    y[0] += n
    return y[0]
  return [inc(x) for x in l]

我确实认为内部函数可以修改y外部词法范围中的声明,但这不起作用,所以我们用结构修改来玩一些讨厌的黑客攻击。使用生成器可能更优雅。

于 2013-12-30T09:52:58.720 回答
0

无需使用 Numpy,您可以直接在数组上循环并沿途累加总和。例如:

a=range(10)
i=1
while((i>0) & (i<10)):
    a[i]=a[i-1]+a[i]
    i=i+1
print a

结果是:

[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
于 2014-02-11T15:26:13.867 回答
0
lst = [4, 6, 12]

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

如果您正在寻找更有效的解决方案(更大的列表?),那么生成器可能是一个不错的选择(或者numpy如果您真的关心性能,就使用它)。

def gen(lst):
    acu = 0
    for num in lst:
        yield num + acu
        acu += num

print list(gen([4, 6, 12]))
于 2013-04-08T21:24:52.203 回答
0
In [42]: a = [4, 6, 12]

In [43]: [sum(a[:i+1]) for i in xrange(len(a))]
Out[43]: [4, 10, 22]

对于小列表,这比@Ashwini上面的生成器方法快一点

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

对于较大的列表,生成器肯定是要走的路。. .

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
于 2013-04-08T21:27:28.730 回答
0

我认为下面的代码是最简单的:

a=[1,1,2,1,2]
b=[a[0]]+[sum(a[0:i]) for i in range(2,len(a)+1)]
于 2022-02-11T13:44:47.280 回答
0

用于累积和的纯 python oneliner:

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

这是一个受递归累积和启发的递归版本。一些解释:

  1. 第一项X[:1]是包含前一个元素的列表,几乎与[X[0]](它会抱怨空列表)相同。
  2. 第二项中的递归cumsum调用处理当前元素[1]和长度将减一的剩余列表。
  3. if X[1:]对于 来说更短if len(X)>1

测试:

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

cumsum([])
#[]

与累积产品类似:

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

测试:

cumprod([4,6,12])
#[4, 24, 288]
于 2018-08-23T01:26:27.277 回答
0

这是另一个有趣的解决方案。这利用locals()了理解的字典,即在列表理解范围内生成的局部变量:

>>> [locals().setdefault(i, (elem + locals().get(i-1, 0))) for i, elem 
     in enumerate(time_interval)]
[4, 10, 22]

以下是locals()每次迭代的外观:

>>> [[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}]

小型列表的性能并不差:

>>> %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)

对于较大的列表,显然是持平的。

>>> 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)

尽管该方法丑陋且不实用,但它确实很有趣。

于 2020-08-09T18:17:22.520 回答
-3

这将是 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])
于 2016-05-14T04:34:35.117 回答