Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:循环优化_Python_Loops - Fatal编程技术网

Python:循环优化

Python:循环优化,python,loops,Python,Loops,我对Python非常陌生,但我已经开始使用它进行一些数据分析,现在我喜欢它。以前,我使用C,我发现C对于文件I/O来说非常糟糕 我正在编写一个脚本,用周期性边界条件(PBC)计算3D长方体中一组N=10000(一万)个点之间的距离。基本上,我有一个10000行的文件,如下所示: 0.037827 0.127853 -0.481895 12.056849 -12.100216 1.607448 10.594823 1.937731 -9.527205 -5.333775 -2.345856 -9.

我对Python非常陌生,但我已经开始使用它进行一些数据分析,现在我喜欢它。以前,我使用C,我发现C对于文件I/O来说非常糟糕

我正在编写一个脚本,用周期性边界条件(PBC)计算3D长方体中一组N=10000(一万)个点之间的距离。基本上,我有一个10000行的文件,如下所示:

0.037827 0.127853 -0.481895
12.056849 -12.100216 1.607448
10.594823 1.937731 -9.527205
-5.333775 -2.345856 -9.217283
-5.772468 -10.625633 13.097802
-5.290887 12.135528 -0.143371
0.250986 7.155687 2.813220
    g=[0 for i in range(Nbins)]

for i in range(Nparticles):
    for j in range(i+1,Nparticles):

        #compute distance and apply PBC
        dx=coors[i][0]-coors[j][0]
        if(dx>halfSide):
            dx-=boxSide
        elif(dx<-halfSide):
            dx+=boxSide

        dy=coors[i][1]-coors[j][1]
        if(dy>halfSide):
            dy-=boxSide
        elif(dy<-halfSide):
            dy+=boxSide

        dz=coors[i][2]-coors[j][2]
        if(dz>halfSide):
            dz-=boxSide
        elif(dz<-halfSide):
            dz+=boxSide

        d2=dx**2+dy**2+dz**2

        if(d2<(cutoff*boxSide)**2):
            g[int(sqrt(d2)/dr)]+=2
表示N个点的坐标。我要做的是计算每一对点之间的距离(因此,我必须考虑所有2个元素的49995000个组合),然后对它做一些操作。< /P> 当然,程序中最累人的部分是49995000组合上的循环

我当前的函数如下所示:

0.037827 0.127853 -0.481895
12.056849 -12.100216 1.607448
10.594823 1.937731 -9.527205
-5.333775 -2.345856 -9.217283
-5.772468 -10.625633 13.097802
-5.290887 12.135528 -0.143371
0.250986 7.155687 2.813220
    g=[0 for i in range(Nbins)]

for i in range(Nparticles):
    for j in range(i+1,Nparticles):

        #compute distance and apply PBC
        dx=coors[i][0]-coors[j][0]
        if(dx>halfSide):
            dx-=boxSide
        elif(dx<-halfSide):
            dx+=boxSide

        dy=coors[i][1]-coors[j][1]
        if(dy>halfSide):
            dy-=boxSide
        elif(dy<-halfSide):
            dy+=boxSide

        dz=coors[i][2]-coors[j][2]
        if(dz>halfSide):
            dz-=boxSide
        elif(dz<-halfSide):
            dz+=boxSide

        d2=dx**2+dy**2+dz**2

        if(d2<(cutoff*boxSide)**2):
            g[int(sqrt(d2)/dr)]+=2
g=[0表示范围内的i(Nbins)]
对于范围内的i(nParticle):
对于范围内的j(i+1,nParticle):
#计算距离并应用PBC
dx=coors[i][0]-coors[j][0]
如果(dx>半侧):
dx-=箱侧
elif(半侧):
dy-=箱侧
elif(动态半侧):
dz-=箱侧
elif(dz如果内存不是问题(并且可能没有给出实际数据量不会与您现在所做的有所不同),您可以使用
numpy
为您计算,并将所有内容放入
NxN
数组中(大约800MB,8字节/code>float

考虑到您的代码试图执行的操作,我认为您不需要在
numpy
之外进行任何循环:

g = numpy.zeros((Nbins,))
coors = numpy.array(coors)

#compute distance and apply PBC
dx = numpy.subtract.outer(coors[:, 0], coors[:, 0])
dx[dx < -halfSide] += boxSide
dx[dx > halfSide)] -= boxSide
dy = numpy.subtract.outer(coors[:, 1], coors[:, 1])
dy[dy < -halfSide] += boxSide
dy[dy > halfSide] -= boxSide
dz = numpy.subtract.outer(coors[:, 2], coors[:, 2])
dz[dz < -halfSide] += boxSide
dz[dz > halfSide] -= boxSide

d2=dx**2 + dy**2 + dz**2
# Avoid counting diagonal elements: inf would do as well as nan
numpy.fill_diagonal(d2, numpy.nan)

# This is the same length as the number of times the
# if-statement in the loops would have triggered
cond = numpy.sqrt(d2[d2 < (cutoff*boxSide)**2]) / dr
# See http://stackoverflow.com/a/24100418/2988730
np.add.at(g, cond.astype(numpy.int_), 2)
g=numpy.zero((Nbins,)
coors=numpy.array(coors)
#计算距离并应用PBC
dx=numpy.subtract.outer(coors[:,0],coors[:,0])
dx[dx<-半侧]+=箱侧
dx[dx>半侧]-=箱侧
dy=numpy.subtract.outer(coors[:,1],coors[:,1])
dy[dy<-半边]+=箱边
dy[dy>半侧]-=箱侧
dz=numpy.subtract.outer(coors[:,2],coors[:,2])
dz[dz<-半侧]+=箱侧
dz[dz>半侧]-=箱侧
d2=dx**2+dy**2+dz**2
#避免计算对角线元素:inf和nan一样好
numpy.fill_对角线(d2,numpy.nan)
#此长度与所需时间的次数相同
#循环中的if语句会被触发
cond=numpy.sqrt(d2[d2<(截止*箱侧)**2])/dr
#看http://stackoverflow.com/a/24100418/2988730
np.add.at(g,cond.astype(numpy.int_2;),2)
关键是在处理大量数据时,始终避免在Python中循环。Python循环效率低下。他们执行大量的簿记操作,这会减慢数学代码的速度

诸如
numpy
dynd
之类的库提供了运行您希望“隐藏”的循环的操作,通常使用C实现绕过簿记。优点是,您可以为每个庞大的数组执行一次Python级别的簿记,然后继续处理原始数字,而不是处理Python包装器对象(数字在Python中是完整的对象,没有基本类型)


在这个特定的示例中,我重新编写了您的代码,以使用一系列数组级操作,这些操作与原始代码所做的操作相同。这需要重新构造您对这些步骤的思考方式,但在运行时会节省很多时间。

您遇到了一个有趣的问题。有一些关于高性能Python的通用指南;这些是用于Python2的,但大部分应携带到Python3

  • 配置您的代码。在jupyter/ipython上使用%timeit和%%timeit对于交互式会话来说既快又快,但是cProfile和line_profiler对于查找瓶颈非常有用
  • 这是一篇短文的链接,该短文涵盖了Python文档中的基础知识,我发现这些内容很有用:
  • Numpy是一个非常适合矢量化操作的软件包。请注意,numpy向量通常比中小型列表的处理速度慢,但节省的内存非常大。在进行多维阵列时,速度增益远远超过列表。此外,如果您开始使用纯Python观察缓存未命中和页面错误,那么numpy的好处将更大
  • 我最近一直在使用Cython,并取得了相当大的成功,numpy/scipy在使用内置函数时并没有完全做到这一点
  • 看看scipy,它有一个巨大的科学计算函数库。有很多东西需要探索;例如,scipy.spatial.pdist函数计算快速的nC2成对距离。在下面的测试中,10k项成对距离在375ms内完成。10万个项目可能会破坏我的机器,虽然没有重构

    import numpy as np
    from scipy.spatial.distance import pdist
    xyz_list = np.random.rand(10000, 3)
    xyz_list
    Out[2]: 
    array([[ 0.95763306,  0.47458207,  0.24051024],
           [ 0.48429121,  0.12201472,  0.80701931],
           [ 0.26035835,  0.76394588,  0.7832222 ],
           ..., 
           [ 0.07835084,  0.8775841 ,  0.20906537],
           [ 0.73248369,  0.60908474,  0.57163023],
           [ 0.68945879,  0.19393467,  0.23771904]])
    In [10]: %timeit xyz_pairwise = pdist(xyz_list)
    1 loop, best of 3: 375 ms per loop
    
    In [12]: xyz_pairwise = pdist(xyz_list)
    In [13]: len(xyz_pairwise)
    Out[13]: 49995000
    

探索快乐

如果您使用的是python2.x,那么您将希望使用
xrange
而不是
range
。如果这还不够快,您可能需要开始使用类似于
numpy
的东西,并找出如何使用numpy的矢量化函数进行操作。您是否绝对必须使用嵌套for循环?这通常是一种代码味道,应该避免。如果numpy或pandas的速度不够快,Python还允许您执行C代码——您可能也想检查一下。我会尝试一些基本数学来避免附加条件。例如:
if(dx>halfSide):dx-=boxSide-elif(dx尝试完全避免循环。
numpy
非常适合这种情况。谢谢你的回答,你给了我很多思考的东西!这个函数pdist真的很酷,但是我如何在其中实现周期性边界条件呢?很荣幸向Scipy介绍OP谢谢,回答非常清楚。不过有一个问题:我尝试了d来运行代码,我得到了以下错误:at
dx=numpy.subtract.outer(coors[:,0],coors[:,0])
I get
列表索引必须是整数,而不是元组
@valerio92。这是因为我假设您的
coors
数组是一个数组,而不是嵌套的Python列表。您可以做几件事。最简单的可能是转换
coors