Python 在numpy中加速阵列分析

Python 在numpy中加速阵列分析,python,performance,numpy,multiprocessing,fft,Python,Performance,Numpy,Multiprocessing,Fft,我有一个python代码,它导入带有数字的4列txt文件 前三列是x、y、z坐标,第四列是该坐标处的密度 下面是读取、转换为ndarray、对该字段进行傅里叶变换、计算到原点的距离(k=(0,0,0))和转换后的坐标、取平均值并绘制它们的代码。 多亏了pandas(用于数据分析的python库)和python FFT,加载256^3行并对其进行傅里叶变换非常快速,只需几秒钟 但是,将加载的txt转换为numpy ndarray、计算平均密度(每个坐标的平均值)以及计算到原点的距离(k=(0,0,

我有一个python代码,它导入带有数字的4列txt文件 前三列是x、y、z坐标,第四列是该坐标处的密度

下面是读取、转换为ndarray、对该字段进行傅里叶变换、计算到原点的距离(k=(0,0,0))和转换后的坐标、取平均值并绘制它们的代码。 多亏了pandas(用于数据分析的python库)和python FFT,加载256^3行并对其进行傅里叶变换非常快速,只需几秒钟

但是,将加载的txt转换为numpy ndarray、计算平均密度(每个坐标的平均值)以及计算到原点的距离(k=(0,0,0))需要很长时间

我认为问题的最终部分是np,但我不知道如何优化它

我有一台32核的机器

有人能教我如何加快速度,使之成为一个多进程代码,或类似的东西,以便可以很快地完成这些工作吗?谢谢

(如果您是宇宙学家,需要此代码,您可以使用它,但如果可以,请与我联系。谢谢)

来自未来进口部的

将numpy作为np导入
ngridx=128
ngridy=128
ngridz=128
maxK=max(ngridx、ngridy、ngridz)
#制作输入文件
f=np.0((ngridx*ngridy*ngridz,4))
i=0
对于np.arange中的i(len(f)):
f[i][0]=int(i/(ngridy*ngridz))
f[i][1]=int((i/ngridz))%ngridy
f[i][2]=int(i%ngridz)
f[i][3]=np.rand.rand(1)
如果i%1000000==0:
打印i
#这需要永远
#结束制作输入文件
#多亏了迈克,
a=f[:,3]。重塑(ngridx,ngridy,ngridz)
平均值=np.和(f[:,3])/len(f)
a/=平均值
p=np.fft.fftn(a)
#这部分比以前快多了(原文)。
#跟踪p中每个元素的相应波数(k_x,k_y,k_z)
#这只是傅里叶变换的一个约定,所以你可以忽略这一部分
kValx=np.fft.fftfreq(ngridx,(1.0/ngridx))
kValy=np.fft.fftfreq(ngridy,(1.0/ngridy))
kValz=np.fft.fftfreq(ngridz,(1.0/ngridz))
kx=np.零((ngridx,ngridy,ngridz))
ky=np.零((ngridx,ngridy,ngridz))
kz=np.零((ngridx,ngridy,ngridz))
rangecolx=np.arange(ngridx)
rangecoly=np.arange(ngridy)
rangecolz=np.arange(ngridz)
对于np.arange(ngridx)中的行:
对于np.arange(ngridy)中的列:
高度单位为np.arange(ngridz):
kx[行][列][高度]=(kValx[行])
ky[行][列][高度]=(kValy[列])
kz[行][列][高度]=(kValz[高度])
如果行%10==0:
打印行
打印“波数生成完成!”
#根据固定K(从原点到傅里叶空间中一点的距离)计算平均功率谱
#取厚度为1的球壳,取其内部的平均值。
#我确信这个过程可以以某种方式得到优化,但我放弃了。
qlen=maxK/2#Nyquist频率
q=np.zero(((qlen),4),dtype=complex)
#q是长度为maxK/2的四列数组。
#q[:,0]是整数波数(K,是到原点的距离=sqrt(kx^2+ky^2+kz^2))
#q[:,1]是傅里叶变换值的平方和
#q[:,2]是傅里叶变换值的和,
#q[:,3]是K=q[:,0]的样本总数
对于np.arange中的i(len(q)):
q[i][0]=i
i=0
对于np.arange中的i(len(p)):
对于np.arange中的r(len(p[0]):
对于np.arange(len(p[0,0]))中的s:
K=np.around(np.sqrt(kx[i,r,s]**2+ky[i,r,s]**2+kz[i,r,s]**2))
如果K
Numpy通常比普通python快数百倍,只需很少的额外工作(有时甚至会自动使用多个核心,而无需您的任何工作)。您只需要知道编写代码的正确方法。我首先想到的是:

  • 考虑一下你的方法——简化它,并在编码之前确保它是正确的
  • 学习使用numpy的索引
  • 如果可能,不要复制数据
  • 不惜一切代价避免循环
  • 使用numpy的内置函数
  • 处理整个阵列(或大型阵列),而不是一次处理单个元素
  • 分析代码以找到慢点
  • 使用,尤其是对于无法避免或numpy无法帮助的循环
你的方法 我认为我们都会犯的一个错误是试图只用代码编写,即使我们仍在试图弄清楚代码应该做什么——基本上,说的是一种我们不太理解的语言,它不是真正的描述性语言,而且字数非常有限。我发现最好先用简单的英语将我的方法概括为一系列步骤。这让我清楚地看到,用我自己的话来说,我希望代码做什么。因此,很容易得到一个概述并思考正在发生的事情,但如果我意识到某些事情需要修改,也很容易重写

事实上,我将这些步骤作为注释写在代码文件的不同行上。一旦我对这种方法感到满意,我就开始在这些注释之间编写代码。这给我留下了一个结构良好、注释正确的代码

在OP中原始代码的特定示例中,整个
f
数组可能不需要存在。如果你只是用通俗易懂的英语写出程序,我想你会看到这一点,并且能够在编写代码之前用通俗易懂的英语轻松地改变你的方法。就目前而言,大部分代码都依赖于
f
,因此需要完全重写才能对其进行更改

索引 普通python在计算机应该擅长的事情上通常非常慢。一个例子是索引,所以像

a[f[i,0]][f[i,1]][f[i,2]]=f[i,3]
这让我很怀疑。这就是你要找的人吗
a[f[i,0]][f[i,1]][f[i,2]]=f[i,3]
a = f[:,3].reshape(ngridx,ngridy,ngridz)
a = np.random.rand(ngridx,ngridy,ngridz)
def Firstdel(a):
    return a[1:]
def Firstdel(a):
    return numpy.copy(a[1:])
while i < len(f):
    # do stuff
    i = i+1
for i in range(len(f)):
    # do stuff
for row in range(ngridx):
    kx[row,:,:] = kValx[row]
for column in range(ngridy):
    ky[:,column,:] = kValy[column]
for height in range(ngridz):
    kz[:,:,height] = kValz[height]
i = 0
while i < len(q):
    q[i][0] = i
    i = i + 1
q[:,0] = np.arange(len(q))
while i < len(f):
    masstot = masstot + f[i,3]
    i = i+1
masstot = np.sum(f[:,3])
for i in np.arange(len(p)):
    for r in np.arange(len(p[0])):
        for s in np.arange(len(p[0,0])):
            K = np.around(np.sqrt(kx[i,r,s]**2+ky[i,r,s]**2+kz[i,r,s]**2))
K = np.around(np.sqrt(kx**2+ky**2+kz**2))
# Again, we get rid of nested loops, to get a large improvement in speed and scaling
K = np.around(np.sqrt(kx**2+ky**2+kz**2)).astype(int)
for i in range(qlen):
    p_i = p[K==i]  # This will be just the elements of p where K==i
    q[i,0] = i
    q[i,1] = np.sum(np.abs(p_i)**2)
    q[i,2] = np.sum(p_i)
    q[i,3] = len(p_i)
print q
size = ngridx*ngridy*ngridz
f = np.zeros((size,4))
a = np.arange(size)
f[:, 0] = np.floor_divide(a, ngridy*ngridz)
f[:, 1] = np.fmod(np.floor_divide(a, ngridz), ngridy)
f[:, 2] = np.fmod(a, ngridz)
f[:, 3] = np.random.rand(size)
kx += kValx[:, np.newaxis, np.newaxis]
ky += kValy[np.newaxis, :, np.newaxis]
kz += kValz[np.newaxis, np.newaxis, :]