我有一个时间列表(在我的代码中称为时间,由我在线程astropy.io fits efficient element access of a large table中建议的代码生成)并且我想对周期性进行一些统计测试,使用Zn ^ 2和epoch折叠试验。代码中的一些步骤需要花费一段时间才能运行,我想知道是否有更快的方法来执行它。我已经尝试了等效的map和lambda函数,但这需要更长的时间。我的时间列表有几百或几千个元素,具体取决于数据集。这是我的代码:
phase=[(x-mintime)*testfreq[m]-int((x-mintime)*testfreq[m]) for x in times]
# the above step takes 3 seconds for the dataset I am using for testing
# testfreq[m] is just one of several hundred frequencies I am testing
# times is of type numpy.ndarray
phasebin=[int(ph*numbins)for ph in phase]
# 1 second (numbins is 20)
powerarray=[phasebin.count(n) for n in range(0,numbins-1)]
# 0.3 seconds
poweravg=np.mean(powerarray)
chisq[m]=sum([(pow-poweravg)**2/poweravg for pow in powerarray])
# the above 2 steps are very quick
for n in range(0,maxn): # maxn is 3
cosparam=sum([(np.cos(2*np.pi*(n+1)*ph)) for ph in phase])
sinparam=sum([(np.sin(2*np.pi*(n+1)*ph)) for ph in phase])
# these steps each take 4 seconds
z2[m,n]=sum(z2[m,])+(cosparam**2+sinparam**2)/count
# this is quick (count is the number of times)
当通过FFT搜索识别出频率两侧的数百个频率时,运行需要很长时间。低级语言中的相同功能运行得更快,但我需要一些Python模块用于绘图等。我希望Python可以被说服去做一些操作,特别是阶段,phasebin,powerarray,cosparam和sinparam计算,明显更快,但我不知道如何实现这一点。任何人都可以告诉我如何做到这一点,还是我必须用C或fortran编写和调用函数?我知道这可以在几分钟内完成,例如在fortran中,但是这个Python代码需要几个小时。
非常感谢。
答案 0 :(得分:5)
您可以使用numpy
库而不是Python列表,它对于线性代数类型操作来说要快得多。例如,以元素方式添加两个数组
>>> import numpy as np
>>> a = np.array([1,2,3,4,5])
>>> b = np.array([2,3,4,5,6])
>>> a + b
array([ 3, 5, 7, 9, 11])
同样,您可以通过标量乘以数组,这些标量会将每个元素与您期望的相乘
>>> 2 * a
array([ 2, 4, 6, 8, 10])
就速度而言,这里是Python列表相当于添加两个列表
>>> c = [1,2,3,4,5]
>>> d = [2,3,4,5,6]
>>> [i+j for i,j in zip(c,d)]
[3, 5, 7, 9, 11]
然后计时两个
>>> from timeit import timeit
>>> setup = '''
import numpy as np
a = np.array([1,2,3,4,5])
b = np.array([2,3,4,5,6])'''
>>> timeit('a+b', setup)
0.521275608325351
>>> setup = '''
c = [1,2,3,4,5]
d = [2,3,4,5,6]'''
>>> timeit('[i+j for i,j in zip(c,d)]', setup)
1.2781205834379108
在这个小例子中,numpy
的速度提高了两倍多。
答案 1 :(得分:1)
for
循环替换 - 在完整数组上运行
首先使用broadcasting
将phase
乘以2 * pi * n
phase = np.arange(10)
maxn = 3
ens = np.arange(1, maxn+1) # array([1, 2, 3])
two_pi_ens = 2*np.pi*ens
b = phase * two_pi_ens[:, np.newaxis]
每个b.shape
值的 range(1, maxn)
是(3,10)一个行
取余弦然后求和得到三个余弦参数
c = np.cos(b)
c_param = c.sum(axis = 1) # c_param.shape is 3
取正弦然后求和得到三个正弦参数
s = np.sin(b)
s_param = s.sum(axis = 1) # s_param.shape is 3
平方和除以计数
d = (np.square(c_param) + np.square(s_param)) / count
# d.shape is (3,)
分配到z2
for n in range(maxn):
z2[m,n] = z2[m,:].sum() + d[n]
该循环正在进行累计求和。 numpy ndarrays有一个cumsum
方法。
如果maxn
很小(在您的情况下为3),则可能不会明显加快。
z2[m,:] += d
z2[m,:].cumsum(out = z2[m,:])
举例说明:
>>> a = np.ones((3,3))
>>> a
array([[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]])
>>> m = 1
>>> d = (1,2,3)
>>> a[m,:] += d
>>> a
array([[ 1., 1., 1.],
[ 2., 3., 4.],
[ 1., 1., 1.]])
>>> a[m,:].cumsum(out = a[m,:])
array([ 2., 5., 9.])
>>> a
array([[ 1., 1., 1.],
[ 2., 5., 9.],
[ 1., 1., 1.]])
>>>