【发布时间】:2013-12-27 04:44:33
【问题描述】:
编辑:我正在处理一个性能敏感案例,它需要使用用户定义的检查点计算数据的总和或最大值。请参考演示代码:
from itertools import izip
timestamp=[1,2,3,4,...]#len(timestamp)=N
checkpoints=[1,3,5,7,..]#user defined
data=([1,1,1,1,...],
[2,2,2,2,...],
...)#len(data)=M,len(data[any])=N
processtype=('sum','max','min','snapshot',...)#len(processtype)=M
def processdata(timestamp, checkpoints, data, processtype):
checkiter=iter(checkpoints)
checher=checkiter.next()
tmp=[0 if t=='sum' else None for t in processtype]
for x, d in izip(timestamp,izip(*data)):
tmp =[tmp[i]+d[i] if t=='sum' else
d[i] if (t=='snapshot'
or (tmp[i] is None)
or (t=='max' and tmp[i]<d[i])
or (t=='min' and tmp[i]>d[i])) else
tmp[i] for (i,t) in enumerate(processtype)]
if x>checher:
yield (checher,tmp)
checher=checkiter.next()
tmp=[0 if t=='sum' else None for t in processtype]
基准测试的原始演示:
def speratedsum(iter, condition):
tmp=0
for x in iter:
if condition(x):
yield tmp
tmp=0
else:
tmp+=x
编辑:感谢@M4rtini 和@Chronial,我在以下测试代码上运行了banchmark:
from timeit import timeit
it=xrange(100001)
condition=lambda x: x % 100 == 0
def speratedsum(it, condition):
tmp=0
for x in it:
if condition(x):
yield tmp+x
tmp=0
else:
tmp+=x
def test1():
return list(speratedsum(it,condition))
def red_func2(acc, x):
if condition(x):
acc[0].append(acc[1]+x)
return (acc[0], 0)
else:
return (acc[0], acc[1] + x)
def test2():
return reduce(red_func2, it,([], 0))[0]
def red_func3(l, x):
if condition(x):
l[-1] += x
l.append(0)
else:
l[-1] += x
return l
def test3():
return reduce(red_func3, it, [0])[:-1]
import itertools
def test4():
groups = itertools.groupby(it, lambda x: (x-1) / 100)
return map(lambda g: sum(g[1]), groups)
import numpy as np
import numba
@numba.jit(numba.int_[:](numba.int_[:],numba.int_[:]),
locals=dict(si=numba.int_,length=numba.int_))
def jitfun(arr,con):
length=arr.shape[0]
out=np.zeros(con.shape[0],int)
si=0
for i in range(length):
out[si]+=arr[i]
if(arr[i]>=con[si]):
si+=1
return out
conditionlist=[x for x in it if condition(x)]
a=np.array(it, int)
c=np.array(conditionlist,int)
def test5():
return list(jitfun(a,c))
test5() #warm up for JIT
time1=timeit(test1,number=100)
time2=timeit(test2,number=100)
time3=timeit(test3,number=100)
time4=timeit(test4,number=100)
time5=timeit(test5,number=100)
print "test1:",test1()==test1(),time1/time1
print "test2:",test1()==test2(),time1/time2
print "test3:",test1()==test3(),time1/time3
print "test4:",test1()==test4(),time1/time4
print "test5:",test1()==test5(),time1/time5
输出:
test1: True 1.0
test2: True 0.369117307201
test3: True 0.496470798051
test4: True 0.833137283359
test5: True 34.1052257366
你对我应该去哪里寻找有什么建议吗?谢谢!
编辑:我设法使用带有回调的 numba 解决方案来替换 yield,它是在这里真正有效的最省力的解决方案。所以接受了@M4rtini 的回答。但是要小心 numba 的限制。通过我 2 天的尝试,numba 可以提高 numpy 数组索引迭代性能,但仅此而已。
【问题讨论】:
-
如果你更看重性能而不是可读性,那么 Python 不是最好的语言选择。
-
每当 x % 100 == 0 时,您重置 tmp = 0,这是您正在寻找的条件吗?
-
您需要显示更多代码,这部分不是您的瓶颈所在,如果这实际上需要 0.7 秒才能运行。这段代码对我来说运行时间不到 1 毫秒。
-
转换为numpy数组,用你的条件做布尔索引,对结果求和。
-
您正在计时的代码不会简单地提供生成器对象吗?
标签: python performance loops iterator