【问题标题】:Speeding up array iteration time in python加快python中的数组迭代时间
【发布时间】:2015-05-26 18:54:12
【问题描述】:

目前我正在迭代一个数组,对于这个数组中的每个值,我正在寻找另一个数组中对应点的最接近值,该数组位于对应点周围的区域内。

综上所述:对于一个数组中的任意一点,距离另一个数组中的对应点需要走多远才能得到相同的值。

代码似乎适用于小型数组,但我现在使用 1024x768 数组,导致我每次运行都要等待很长时间......

任何帮助或建议将不胜感激,因为我已经有一段时间了!

我使用的格式示例矩阵:np.array[[1,2],[3,4]]

#Distance to agreement

#Used later to define a region of pixels around a corresponding point
#to iterate over:
DTA = 26

#To account for noise in pixels - doesnt have to find the exact value,   
#just one within +/-130 of it.
limit = 130

#Containers for all pixel value matches and also the smallest distance
#to pixel match
Dist = []
Dist_min = []   

#Continer matrix for gamma pass/fail values
Dist_to_agree = np.zeros((i_size,j_size))

#i,j indexes the reference matrix (x), ii,jj indexes the measured     
#matrix(y). Finds a match within the limits, 
#appends the distance to the match into Dist.
#Then find the minimum distance to a match for that pixel and append it 
#to dist_min


for i, k in enumerate(x):
    for j, l in enumerate(k):
#added 10 packing to y matrix, so need to shift it by 10 in i&j
        for ii in range((i+10)-DTA,(i+10)+DTA):  
            for jj in range((j+10)-DTA,(j+10)+DTA):


#If the pixel value is within a range to account for noise, 
#let it be "found"
                if (y[ii,jj]-limit) <= x[i,j] <= (y[ii,jj]+limit):
                    #Calculating distance
                    dist_eu = sqrt(((i)-(ii))**2 + ((j) - (jj))**2)
                    Dist.append(dist_eu)

#If a value cannot be found within the noise range, 
#append 10 = instant fail. 
                else:
                    Dist.append(10)
        try:
            Dist_min.append(min(Dist))
            Dist_to_agree[i,j] = min(Dist)
        except ValueError:
            pass

        #Need to reset container or previous values will also be
        #accounted for when finding minimum
        Dist = []

print Dist_to_agree

【问题讨论】:

  • 您似乎在for jj in range(...) 循环中有缩进错误。在 Stackoverflow 上复制/粘贴代码时通常会发生这种情况,有时,复制/粘贴会以这种方式呈现,因为您在源代码中混合了空格和制表符 - 您可能需要检查 :-)
  • 首先,尝试使用 numpy 数组操作而不是逐点评估整个 ii,jj 窗口。将ii 视为值向量。

标签: python arrays numpy


【解决方案1】:

首先,您在kl 中获取x 的元素,然后将其丢弃并再次索引x。所以代替x[i,j],你可以使用l,这样会更快(虽然l不是一个很有意义的名字,像xixij可能会更好)。

其次,您正在重新计算y[ii,jj]-limit 和 y[ii,jj]+limitevery time. If you have enough memory, you can-precomputer these:ym = y-limitandyp = y+limit`。

第三,追加到列表比创建数组和设置长列表的值与长数组相比要慢。您也可以通过预设默认值跳过整个else 子句。

第四,您计算min(dist) 两次,并且可能使用python 版本而不是numpy 版本,后者对于数组更快(这是制作dist 和数组的另一个原因) .

但是,最大的加速是对内部两个循环进行矢量化。这是我的测试,x=np.random.random((10,10))y=np.random.random((100,100))

您的版本需要 623 毫秒。

这是我的版本,耗时 7.6 毫秒:

dta = 26
limit = 130

dist_to_agree = np.zeros_like(x)
dist_min = []

ym = y-limit
yp = y+limit
for i, xi in enumerate(x):
    irange = (i-np.arange(i+10-dta, i+10+dta))**2
    if not irange.size:
        continue

    ymi = ym[i+10-dta:i+10+dta, :]
    ypi = yp[i+10-dta:i+10+dta, :]

    for j, xij in enumerate(xi):
        jrange = (j-np.arange(j+10-dta, j+10+dta))**2
        if not jrange.size:
            continue

        ymij = ymi[:, j+10-dta:j+10+dta]
        ypij = ypi[:, j+10-dta:j+10+dta]

        imesh, jmesh = np.meshgrid(irange, jrange, indexing='ij')
        dist = np.sqrt(imesh+jmesh)
        dist[ymij > xij  or xij < ypij]  = 10

        mindist = dist.min()
        dist_min.append(mindist)
        dist_to_agree[i,j] = mindist

print(dist_to_agree)

【讨论】:

  • 另外,我一直在努力解决这个错误:“ValueError:具有多个元素的数组的真值不明确。使用 a.any() 或 a.all( )" ...对于这一行:dist[ymij > xij or xij
  • 感谢您的帮助,我学到了很多东西,现在运行速度确实快了很多。但是,它给出的答案并不完全正确,我是否正确理解这两行采用 (i+/-dta),但沿 (j) 的其余部分?:ymi = ym[i+10-dta:i +10+dta, :] ypi = yp[i+10-dta:i+10+dta,:] 简而言之,我试图获取 x 中的每个 [i,j] 值,并寻找2D 中 y[i,j] 附近的最接近值出现相同的值。在距 y[i,j] 的可调节 2D 距离内。任何关于代码的建议都会很棒!给您添麻烦了!
  • 是的,这些行按照你说的做,但是这些行在 j 上做同样的事情:ymij = ymi[:, j+10-dta:j+10+dta]ypij = ypi[:, j+10-dta:j+10+dta]。合并后的结果和做ymij = ymi[i+10-dta:i+10+dta, j+10-dta:j+10+dta]ypij = ypi[i+10-dta:i+10+dta, j+10-dta:j+10+dta]一样
  • 我想我找到了问题,现在试试吧。
  • 终于完成了所有工作,让我的版本按照我想要的方式工作。感谢您的支持,我确实学到了很多东西!
【解决方案2】:

@Ciaran Meshgrid 有点像两个嵌套循环的矢量化等价物。以下是计算 dist 的两种等效方法。一种带有循环,一种带有 meshgrid+numpy 向量操作。第二个快六倍。

DTA=5
i=100
j=200

 def func1():
        dist1=np.zeros((DTA*2,DTA*2))
        for ii in range((i+10)-DTA,(i+10)+DTA):  
            for jj in range((j+10)-DTA,(j+10)+DTA):
                dist1[ii-((i+10)-DTA),jj-((j+10)-DTA)] =sqrt(((i)-(ii))**2 + ((j) - (jj))**2)
        return dist1

    def func2():
        dist2=np.zeros((DTA*2,DTA*2))
        ii, jj = meshgrid(np.arange((i+10)-DTA,(i+10)+DTA), 
                          np.arange((j+10)-DTA,(j+10)+DTA))
        dist2=np.sqrt((i-ii)**2+(j-jj)**2)
        return dist2

这就是 ii 和 jj 矩阵在网格网格操作后的样子

ii=
 [[105 106 107 108 109 110 111 112 113 114]
 [105 106 107 108 109 110 111 112 113 114]
 [105 106 107 108 109 110 111 112 113 114]
 [105 106 107 108 109 110 111 112 113 114]
 [105 106 107 108 109 110 111 112 113 114]
 [105 106 107 108 109 110 111 112 113 114]
 [105 106 107 108 109 110 111 112 113 114]
 [105 106 107 108 109 110 111 112 113 114]
 [105 106 107 108 109 110 111 112 113 114]
 [105 106 107 108 109 110 111 112 113 114]]
jj= 
 [[205 205 205 205 205 205 205 205 205 205]
 [206 206 206 206 206 206 206 206 206 206]
 [207 207 207 207 207 207 207 207 207 207]
 [208 208 208 208 208 208 208 208 208 208]
 [209 209 209 209 209 209 209 209 209 209]
 [210 210 210 210 210 210 210 210 210 210]
 [211 211 211 211 211 211 211 211 211 211]
 [212 212 212 212 212 212 212 212 212 212]
 [213 213 213 213 213 213 213 213 213 213]
 [214 214 214 214 214 214 214 214 214 214]]

【讨论】:

  • 这实际上对我正在做的事情非常有用,感谢您的解释!
【解决方案3】:

for 循环在纯 python 中非常慢,你有四个嵌套循环会非常慢。 Cython 对 for 循环速度确实有奇效。您也可以尝试矢量化。虽然我不确定我是否完全理解您要执行的操作,但您可能会尝试最后对一些操作进行矢量化。尤其是最后两个循环。

所以不是两个 ii,jj 循环结束

y[ii,jj]-limit) <= x[i,j] <= (y[ii,jj]+limit)

你可以做类似的事情

ii, jj = meshgrid(np.arange((i+10)-DTA,(i+10)+DTA), np.arange((j+10)-DTA,(j+10)+DTA))
t=(y[(i+10)-DTA,(i+10)+DTA]-limit>=x[i,j]) & (y[(i+10)-DTA,(i+10)+DTA]+limit<=x[i,j])
Dist=np.sqrt((i-ii)**2)+(j-jj)**2))

np.min(Dist[t]) 将具有元素 i,j 的最小距离

【讨论】:

  • 你能不能把长长的meshgrid 表达式拆开,让它更易读?
  • 感谢您的评论,我一直在尝试了解您对 meshgrid 的使用情况,如果进一步细分它会很棒!
【解决方案4】:

numbapro 编译器提供 gpu 加速。不幸的是,它不是免费的。

http://docs.continuum.io/numbapro/

【讨论】:

    猜你喜欢
    • 2021-10-21
    • 2019-05-19
    • 2018-06-08
    • 1970-01-01
    • 1970-01-01
    • 2020-07-15
    • 2015-12-12
    • 2015-01-14
    • 2020-03-29
    相关资源
    最近更新 更多