time_interval = [4, 6, 12]
リスト[4, 4+6, 4+6+12]
を取得するために、t = [4, 10, 22]
のような数字を合計したいと思います。
私は次を試しました:
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
このような配列で多くの数値処理を行う場合は、 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を使用する唯一の場所であれば、それに依存する価値はないかもしれません。
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]
見よ:
a = [4, 6, 12]
reduce(lambda c, x: c + [c[-1] + x], a, [0])[1:]
出力(予想どおり):
[4, 10, 22]
私はPython 3.4で上位2つの答えのベンチマークを行いましたが、多くの状況で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
がlist
にキャストされない場合、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
インポートを2つの関数の外側に配置し、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
2.7でnumpyが動作しないPythonの方法が必要な場合は、これが私の方法です
l = [1,2,3,4]
_d={-1:0}
cumsum=[_d.setdefault(idx, _d[idx-1]+item) for idx,item in enumerate(l)]
今すぐ試して、他のすべての実装に対してテストしてみましょう
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
最初に、サブシーケンスの実行リストが必要です。
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以前を使用している場合は、ドキュメントから「同等の」ソースを直接コピーできます(2.5以前のnext(it)
をit.next()
に変更する場合を除く)。
割り当て式 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]
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]
これを試してください:累積関数は、演算子addと共に実行中の追加を実行します。
import itertools
import operator
result = itertools.accumulate([1,2,3,4,5], operator.add)
list(result)
これを試して:
result = []
acc = 0
for i in time_interval:
acc += i
result.append(acc)
単純な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]
ややハックですが、動作するようです:
def cumulative_sum(l):
y = [0]
def inc(n):
y[0] += n
return y[0]
return [inc(x) for x in l]
内側の関数は外側の字句スコープで宣言されたy
を変更できると思いましたが、それは機能しなかったので、代わりに構造の変更を伴う厄介なハックをします。ジェネレーターを使用する方がおそらくよりエレガントです。
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
Python3では、i
th要素が元のリストの最初の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]
lst = [4,6,12]
[sum(lst[:i+1]) for i in xrange(len(lst))]
より効率的なソリューション(より大きなリスト?)を探している場合は、ジェネレーターが適切な呼び出しになる可能性があります(または、perfが本当に必要な場合はnumpy
を使用します)。
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]
これは、小さなリストの@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
累積合計用の純粋なpython oneliner:
cumsum = lambda X: X[:1] + cumsum([X[0]+X[1]] + X[2:]) if X[1:] else X
これは 再帰累積和 に触発された再帰バージョンです。いくつかの説明:
X[:1]
は前の要素を含むリストであり、[X[0]]
(空のリストに対して文句を言う)とほぼ同じです。cumsum
呼び出しは、現在の要素[1]
および残りのリストを処理し、その長さは1つ削減されます。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]
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]
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))