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
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
numpy
,其中包含一个累计求和函数cumsum
:import numpy as np
a = [4,6,12]
np.cumsum(a)
#array([4, 10, 22])
Numpy在这种情况下通常比纯Python更快,相对于@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
但是如果你只在一个地方使用numpy,可能没有必要依赖它。
np.cumsum
情况,以考虑转换时间。 - hpauljnumpy
。 - askewchantimeit
,“如果未给出-n
,则通过尝试连续的10的幂次来计算适当数量的循环,直到总时间至少为0.2秒。”如果您希望有所不同,可以提供-n 1000
使它们都等效。 - askewchandef accumu(lis):
total = 0
for x in lis:
total += x
yield total
In [4]: list(accumu([4,6,12]))
Out[4]: [4, 10, 22]
itertools.accumulate()
函数:In [1]: lis = [4,6,12]
In [2]: from itertools import accumulate
In [3]: list(accumulate(lis))
Out[3]: [4, 10, 22]
total = 0; partial_sums = [total := total + v for v in values]
。然而,我仍然认为 accumulate
更快。 - Steven Rumbalskiif (value := some_dict.get(key)) is not None: ...
可以避免臭名昭著的双重查找。或者在带有 if
过滤器的列表推导中,像 [func_result for x in xs if satisfies_property(func_result := f(x))]
,这也避免了函数 f(x)
的臭名昭著的双重评估。 - bluenote10itertools.accumulate()
函数。import itertools
list(itertools.accumulate([1,2,3,4,5]))
# [1, 3, 6, 10, 15]
operator.add
,因为默认的操作是加法。 - Eugene Yarmash我使用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数组转换为列表,使用accumulate
函数仍然比使用其它方式快大约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
如果你把导入语句放在两个函数外面, 但仍然返回一个numpy
array
, accumulate
仍然快近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
array
数组的话,你也不应该使用 numpy 来处理只有五个项目的列表 list
。如果这个列表真的很短,那么它们的运行时间无关紧要——依赖性和可读性肯定更重要。但是,对于包含大量统一数字数据类型的列表,使用 numpy 的数组会更加合适,通常会更快。 - askewchannumpy
更快? - Chris_Randssum2
函数中大部分时间可能都用在将 l
转换为数组上了。尝试分别计时 a = np.array(l)
和 np.cumsum(a)
。然后尝试 a = np.tile(np.arange(1, 6), 1000)
和 l = [1,2,3,4,5]*1000
。在执行其他数值处理(例如首次创建或加载 l
)的程序中,你的工作数据可能已经在一个数组中,并且创建过程是一个恒定的成本。 - askewchan看哪:
a = [4, 6, 12]
reduce(lambda c, x: c + [c[-1] + x], a, [0])[1:]
将输出(与预期相同):
[4, 10, 22]
c + [c[-1] + x]
的总开销会随输入长度的平方级别增加。 - user2357112赋值表达式(在Python 3.8中新增)提供了另一种解决这个问题的方法:
time_interval = [4, 6, 12]
total_time = 0
cum_time = [total_time := total_time + t for t in time_interval]
你可以使用简单的 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]
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]
这个问题的答案取决于列表的长度和性能,可能会有许多不同的答案。我能想到一个非常简单的方法,即使没有考虑性能影响:
a = [1, 2, 3, 4]
a = [sum(a[0:x]) for x in range(1, len(a)+1)]
print(a)
[1, 3, 6, 10]
使用列表推导式可以做到这一点,这可能会相当有效,只是在这里我将多次添加子数组,您可能可以改进它并使其更简单!
祝你好运!
O(n²)
,因此仅在处理小型列表时才使用它有意义。 - Eugene Yarmashl = [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