对于Numpy的循环速度

时间:2013-06-07 20:28:16

标签: python numpy

我试图让这段代码在python中快速运行但是我无法让它在MATLAB中运行的速度附近运行。问题似乎是这个for循环,当数字“SRpixels”大约等于25000时,运行大约需要2秒。

我似乎无法找到任何方法来进一步削减这一点,我正在寻找建议。

下面的numpy数组的数据类型是float32,除了** _ Location [],它们都是uint32。

for j in range (0,SRpixels):
    #Skip data if outside valid range
    if (abs(SR_pointCloud[j,0]) > SR_xMax or SR_pointCloud[j,2] > SR_zMax or SR_pointCloud[j,2] < 0):
        pass
    else:           
        RIGrid1_Location[j,0] = np.floor(((SR_pointCloud[j,0] + xPosition + 5) - xGrid1Center) / gridSize)
        RIGrid1_Location[j,1] = np.floor(((SR_pointCloud[j,2] + yPosition) - yGrid1LowerBound) / gridSize)

        RIGrid1_Count[RIGrid1_Location[j,0],RIGrid1_Location[j,1]] += 1
        RIGrid1_Sum[RIGrid1_Location[j,0],RIGrid1_Location[j,1]] += SR_pointCloud[j,1]
        RIGrid1_SumofSquares[RIGrid1_Location[j,0],RIGrid1_Location[j,1]] += SR_pointCloud[j,1] * SR_pointCloud[j,1]

        RIGrid2_Location[j,0] = np.floor(((SR_pointCloud[j,0] + xPosition + 5) - xGrid2Center) / gridSize)
        RIGrid2_Location[j,1] = np.floor(((SR_pointCloud[j,2] + yPosition) - yGrid2LowerBound) / gridSize)

        RIGrid2_Count[RIGrid2_Location[j,0],RIGrid2_Location[j,1]] += 1 
        RIGrid2_Sum[RIGrid2_Location[j,0],RIGrid2_Location[j,1]] += SR_pointCloud[j,1]
        RIGrid2_SumofSquares[RIGrid2_Location[j,0],RIGrid2_Location[j,1]] += SR_pointCloud[j,1] * SR_pointCloud[j,1]

我确实尝试过使用Cython,我用cdef int j替换了j并进行了编译。没有明显的性能提升。有人有建议吗?

2 个答案:

答案 0 :(得分:5)

矢量化几乎总是加速numpy代码的最好方法,其中大部分似乎都是可矢量化的。例如,要开始,位置数组似乎很简单:

# these are all of your j values
inds = np.arange(0,SRpixels)

# these are the j values you don't want to skip
sel = np.invert((abs(SR_pointCloud[inds,0]) > SR_xMax) | (SR_pointCloud[inds,2] > SR_zMax) | (SR_pointCloud[inds,2] < 0))

RIGrid1_Location[sel,0] = np.floor(((SR_pointCloud[sel,0] + xPosition + 5) - xGrid1Center) / gridSize)
RIGrid1_Location[sel,1] = np.floor(((SR_pointCloud[sel,2] + yPosition) - yGrid1LowerBound) / gridSize)
RIGrid2_Location[sel,0] = np.floor(((SR_pointCloud[sel,0] + xPosition + 5) - xGrid2Center) / gridSize)
RIGrid2_Location[sel,1] = np.floor(((SR_pointCloud[sel,2] + yPosition) - yGrid2LowerBound) / gridSize)

这没有python循环。

其余的比较复杂,取决于你在做什么,但如果以这种方式考虑它们,也应该是可矢量化的。

如果你确实有一些无法矢量化的东西而且必须用循环来完成 - 我只是发生了几次 - 我建议Weave over Cython。它更难使用,但应该提供与C相当的速度。

答案 1 :(得分:1)

首先尝试向量化计算,如果必须逐个元素进行计算,这里有一些加速提示:

  1. 使用NumPy标量计算比内置标量慢得多。 array [i,j]将得到一个numpy标量,array.item(i,j)将返回一个内置标量。

  2. 在进行标量计算时,数学模块中的函数比numpy快。

  3. 以下是一个例子:

    import numpy as np
    import math
    a = np.array([[1.1, 2.2, 3.3],[4.4, 5.5, 6.6]])
    %timeit np.floor(a[0,0]*2)
    %timeit math.floor(a[0,0]*2)
    %timeit np.floor(a.item(0,0)*2)
    %timeit math.floor(a.item(0,0)*2)
    

    输出:

    100000 loops, best of 3: 10.2 µs per loop
    100000 loops, best of 3: 3.49 µs per loop
    100000 loops, best of 3: 6.49 µs per loop
    1000000 loops, best of 3: 851 ns per loop
    

    所以将np.floor更改为math.floor,将SR_pointCloud[j,0]更改为SR_pointCloud.item(j,0)会加快循环速度。