web-dev-qa-db-ja.com

リスト内の数字の累積和を見つける方法は?

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

このような配列で多くの数値処理を行う場合は、 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を使用する唯一の場所であれば、それに依存する価値はないかもしれません。

92
askewchan

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]
75

見よ:

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

出力(予想どおり):

[4, 10, 22]
15
wonder.mice

私はPython 3.4で上位2つの答えのベンチマークを行いましたが、多くの状況でitertools.accumulatenumpy.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

numpyarraylistにキャストされない場合、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つの関数の外側に配置し、numpyarrayを返す場合、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
11
Chris_Rands

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
3
Cobry

最初に、サブシーケンスの実行リストが必要です。

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()に変更する場合を除く)。

3
abarnert

割り当て式 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]
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]
2
Chris Taylor

これを試してください:累積関数は、演算子addと共に実行中の追加を実行します。

import itertools  
import operator  
result = itertools.accumulate([1,2,3,4,5], operator.add)  
list(result)
2
Vani S

これを試して:

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

単純な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]
1
Eugene Yarmash

ややハックですが、動作するようです:

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

内側の関数は外側の字句スコープで宣言されたyを変更できると思いましたが、それは機能しなかったので、代わりに構造の変更を伴う厄介なハックをします。ジェネレーターを使用する方がおそらくよりエレガントです。

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
jarvis

Python3では、ith要素が元のリストの最初の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]
0
manish apte
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]))
0
gonz
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
0
reptilicus

累積合計用の純粋な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. 2番目の項の再帰cumsum呼び出しは、現在の要素[1]および残りのリストを処理し、その長さは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]
0
Friedrich

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