我有一个numPy数组,例如arr = [1, 2, 3, 4]
,我想对每个元素后的元素求和,得出s = [10, 9, 7, 4]
。
在循环中,可以这样做:
for i in range(arr.size):
if i == 0:
s[i] = np.sum(arr)
else:
s[i] = np.sum(arr[:-i])
答案 0 :(得分:3)
您可以为此使用numpy的cumulative sum函数。您需要先反转原始数组,然后反转结果以按想要的顺序获取它:
a = np.array([1,2,3,4])
np.flip(np.cumsum(np.flip(a))) # array([10, 9, 7, 4], dtype=int32)
或者使用[::-1]
进行反转:
np.cumsum(a[::-1])[::-1]
对this question的回答包括对在python中计算累积总和的不同选项的完整讨论。 itertools.accumulate在Python 3.2或更高版本中似乎是一个不错的选择。
答案 1 :(得分:2)
您可以使用numpy的ufuncs及其accumulate函数来获取所需的输出。
np.add.accumulate(arr[::-1])[::-1]
答案 2 :(得分:2)
这是一种简洁(尽管成本很高)的方式:
arr = [1, 2, 3, 4]
s = np.sum(np.triu(arr),1)
尽管这是仅使用矩阵运算符的非过程(概念性)方法,但它是迄今为止最慢的解决方案。
我尝试了这里提出的各种解决方案,并亲自研究了哪种方法最快。结果如下:
subFromSum 0.06761518699999997 @Sarcoma
procedural 0.07242122200000001 @Alain T.
generator 0.08231979099999998 @Sarcoma
recursive 0.10890062199999995 @Alain T.
arraySum 0.1370264969999999 @JosepJoestar
listComp 0.13318894400000003 @student
iterAccumulate 0.14017220000000008 @Stuart (linked in comment)
funcReduce 0.1828948370000001 @Alain T.
npAccumulate 0.23582439700000002 @user2699
npCumSum 0.60332129 @Suart
npSumTriu 1.951785406 @Alain T.
所有numpy函数最后死在一个小列表上。
同一测试在更大的数组上执行:[1,2,3,4] * 100(重复10000次,而不是100000次)得出不同的结果,反映了这些解决方案的可伸缩性:
iterAccumulate 0.12888180999999932 @Stuart (linked in comment)
generator 0.24920542199999995 @Sarcoma
procedural 0.2719608119999999 @Alain T.
npCumSum 0.27731459299999983 @Suart
npAccumulate 0.30234721600000114 @user2699
subFromSum 0.339745362 @Sarcoma
funcReduce 1.845360363000001 @Alain T.
recursive 2.2268321760000003 @Alain T.
npSumTriu 3.234387397999999 @Alain T.
listComp 6.1435246800000005 @student
arraySum 6.342716752 @JosepJoestar
numpy开始在大型阵列上显示其功能,但对于这种类型的问题仍然不是最好的选择。 itertools模块(累积)似乎是最可扩展的方法。
这里是功能...
from timeit import timeit
array = [1, 2, 3, 4]
# Subtracting from sum :: @Sarcoma
# timeit: 0.6
def subFromSum(arr):
total = sum(arr)
result = []
for value in arr:
result.append(total)
total -= value
return result
print("subFromSum ", timeit(lambda :subFromSum(array), number=100000))
# Procedure for-loop assigning list items
# timeit: 0.07
def procedural(arr):
result = arr.copy()
total = 0
index = len(arr)-1
for value in reversed(arr):
total += value
result[index] = total
index -= 1
return result
print("procedural ", timeit(lambda :procedural(array), number=100000))
# generator :: @Sarcoma
# timeit: 0.08
def gen(a):
r = 0
for x in a:
r += x
yield r
def generator(arr):
return [*gen(arr[::-1])][::-1]
print("generator ", timeit(lambda : generator(array), number=100000))
# recursive concatenation
# timeit: 0.11
def recursive(arr,size=None):
size = (size or len(arr))
value = arr[size-1]
if size == 1 : return [value]
previous = recursive(arr,size-1)
return previous + [value+previous[-1]]
print("recursive ", timeit(lambda :recursive(array), number=100000))
# iterative array sum() :: @JosepJoestar
# timeit: 0.14
def arraySum(arr):
s = []
for i in range(len(arr)):
s.append(sum(arr[i:]))
return s
print("arraySum ", timeit(lambda : arraySum(array), number=100000))
# list comprehension :: @student
# timeit: 0.13
def listComp(arr):
return [sum(arr[i:]) for i in range(len(arr))]
print("listComp ", timeit(lambda : listComp(array), number=100000))
# accumulate() function form itertools
# timeit: 0.14
def iterAccumulate(arr):
from itertools import accumulate
return list(accumulate(arr[::-1]))[::-1]
print("iterAccumulate", timeit(lambda : iterAccumulate(array), number=100000))
# assigning list items using functools' reduce() function
# timeit: 0.18
def funcReduce(arr):
from functools import reduce
return reduce(lambda a,v: a + [a[-1]-v], arr[1:], [sum(arr)])
print("funcReduce ", timeit(lambda : funcReduce(array), number=100000))
# npAccumulate() function form numpy :: @ user2699
# timeit: 0.24
def mpAccumulate(arr):
import numpy as np
return np.add.accumulate(arr[::-1])[::-1]
print("npAccumulate ", timeit(lambda : mpAccumulate(array), number=100000))
# numpy's cumsum() function
# timeit: 0.55
def npCumSum(arr):
from numpy import cumsum
return cumsum(arr[::-1])[::-1]
print("npCumSum ", timeit(lambda : npCumSum(array), number=100000))
# conceptual matrix operations (using numpy)
# timeit: 2.05
def npSumTriu(arr):
import numpy as np
return np.sum(np.triu(arr),1)
print("npSumTriu ", timeit(lambda : npSumTriu(array), number=100000))
答案 3 :(得分:1)
求和一次,将当前总数t
附加到结果数组r
上,并减去当前值a
。
arr = [1, 2, 3, 4]
t = sum(arr)
r = []
for a in arr:
r.append(t)
t -= a
print r
虽然它不是一个Numpy数组,这很重要吗?
一些其他答案似乎将每次迭代的其余部分相加。在我看来这效率低下。
@ User2699指出,反转数组并将其简单地相加是实现此目的的最有效方法。
我能找到的最快方法是使用发电机:
def gen(a):
r = 0
for x in a:
r += x
yield r
def reverse_sum_with_generator(arr):
return [*gen(arr[::-1])][::-1]
更新
我发现有趣的是,基于Numpy的脚本似乎使Numpy Array快了多少。因此,我进行了进一步的测试,以了解其原因。
我意识到,我并没有考虑到生成列表的方式。每种创建列表的方法都有不同的开销,这在大多数情况下都说明了速度的差异。杰出的例外是np.arange()
,这对于基于Numpy的脚本来说要快得多。
基准:https://repl.it/repls/SumEachItemAfter
基准要点:https://gist.github.com/sarcoma/8fc4b87c3cf649d6ef9af92bffe5a771
答案 4 :(得分:0)
我认为您的意思是之后,而不是之前。要对每个元素之后的元素求和,请执行以下操作:
s = []
for i in range(len(arr)):
s.append(sum(arr[i:]))
或者您也可以使用列表理解符号来使其更短,更优雅:
s = [sum(arr[i:]) for i in range(len(arr))]
但是,当列表足够大时,这可能会导致性能下降。就效率而言,最好的解决方案是对列表进行迭代,以仅计算所见的最后一个元素与当前元素之和,因为最后一个元素是先前所有元素的总和:
s = list(arr) # Avoid copying reference if modify arr is not desired
# Iterate from last position - 1, until first position, descending
for i in range(len(arr) - 2, -1, -1):
s[i] += s[i + 1]