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
python
list
sum
accumulate
user2259323
источник
источник
Ответы:
Если вы много работаете с числами с подобными массивами, я бы посоветовал
numpy
воспользоваться функцией накопительной суммыcumsum
:import numpy as np a = [4,6,12] np.cumsum(a) #array([4, 10, 22])
Numpy часто быстрее, чем чистый питон для такого рода вещей, см. По сравнению с @ 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.cumsun
дело, которое начинается со списка, чтобы учесть время преобразования.list
я бы не рекомендовалnumpy
.timeit
, «если-n
не задано, подходящее количество циклов рассчитывается путем попытки последовательных степеней 10 до тех пор, пока общее время не составит не менее 0,2 секунды». Если вы ожидаете, что это изменит ситуацию, вы можете-n 1000
сделать их все равноценными.В 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]
источник
total = 0; partial_sums = [total := total + v for v in values]
. Я все равно ожидалaccumulate
бы быть быстрее.Вот:
a = [4, 6, 12] reduce(lambda c, x: c + [c[-1] + x], a, [0])[1:]
Выведет (как и ожидалось):
[4, 10, 22]
источник
c + [c[-1] + x]
снова и снова составляют общее время выполнения, квадратичное по длине ввода.Я провел тест двух лучших ответов с 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
не приведено к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
Если вы поместите импорт за пределы двух функций и все равно вернете a
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
источник
list
пяти элементов, особенно если вы не хотите приниматьarray
взамен. Если рассматриваемый список действительно такой короткий, то время их выполнения будет несущественным - зависимости и удобочитаемость, безусловно, будут преобладать. Но широкое использованиеlist
единого числового типа данных значительной длины было бы глупо; для этогоarray
будет подходящим numpy , и обычно быстрее.numpy
быть быстрее, если я что-то не упустил?sum2
функции, вероятно, заключается в преобразованииl
в массив. Попробуй таймингa = np.array(l)
иnp.cumsum(a)
отдельно. Тогда попробуйтеa = np.tile(np.arange(1, 6), 1000)
противl = [1,2,3,4,5]*1000
. В программе, выполняющей другие числовые процессы (например, создание или загрузкаl
в первую очередь), ваши рабочие данные, вероятно, уже будут в массиве, и создание будет стоить постоянную стоимость.Попробуйте следующее: функция накопления вместе с оператором add выполняет текущее сложение.
import itertools import operator result = itertools.accumulate([1,2,3,4,5], operator.add) list(result)
источник
operator.add
поскольку операция по умолчанию в любом случае является добавлением.Выражения присваивания из 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]
источник
Вы можете рассчитать совокупный список сумм за линейное время с помощью простого
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]
источник
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]
источник
В 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]
источник
Если вам нужен питонический способ без работы numpy в 2.7, это был бы мой способ сделать это
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
источник
На это может быть много ответов, в зависимости от длины списка и производительности. Один очень простой способ, который я могу думать, не думая о производительности, заключается в следующем:
a = [1, 2, 3, 4] a = [sum(a[0:x:1]) for x in range(len(a)+1)][1:] print(a)
[1, 3, 6, 10]
Это происходит с использованием понимания списка, и это может работать довольно хорошо, просто здесь я добавляю много раз над подмассивом, вы могли бы импровизировать с этим и упростить!
Приветствую вас!
источник
Во-первых, вам нужен текущий список подпоследовательностей:
subseqs = (seq[:i] for i in range(1, len(seq)+1))
Затем вы просто вызываете
sum
каждую подпоследовательность:sums = [sum(subseq) for subseq in subseqs]
(Это не самый эффективный способ сделать это, потому что вы постоянно добавляете все префиксы. Но это, вероятно, не имеет значения для большинства случаев использования, и его легче понять, если вам не нужно думать о промежуточные итоги.)
Если вы используете Python 3.2 или новее, вы можете использовать
itertools.accumulate
для этого:А если вы используете 3.1 или более раннюю версию, вы можете просто скопировать "эквивалентный" исходный код прямо из документации (за исключением перехода на 2.5 и более ранние
next(it)
версииit.next()
).источник
range
чем обойти это, делая[1:]
в конце, или игнорировать это.)[4,6,12]
поскольку, как он написал в вопросе, он уже знает, что это такое!Попробуй это:
result = [] acc = 0 for i in time_interval: acc += i result.append(acc)
источник
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
источник
Немного хакерский, но, похоже, работает:
def cumulative_sum(l): y = [0] def inc(n): y[0] += n return y[0] return [inc(x) for x in l]
Я действительно думал, что внутренняя функция сможет изменить
y
объявленное во внешней лексической области видимости, но это не сработало, поэтому вместо этого мы используем несколько неприятных хаков с модификацией структуры. Возможно, более элегантно использовать генератор.источник
Без использования 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]
источник
Чистый питон oneliner для накопительной суммы:
cumsum = lambda X: X[:1] + cumsum([X[0]+X[1]] + X[2:]) if X[1:] else X
Это рекурсивная версия, вдохновленная рекурсивными совокупными суммами . Некоторые пояснения:
X[:1]
- это список, содержащий предыдущий элемент, и он почти такой же, как[X[0]]
(который будет жаловаться на пустые списки).cumsum
вызов во втором члене обрабатывает текущий элемент[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]
источник
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))
источник
Вот еще одно забавное решение. Это использует преимущество
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)
Несмотря на то, что этот метод уродлив и непрактичен, он определенно забавен.
источник
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]))
источник
Это будет в стиле 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])
источник