【问题标题】:Speeding up a for loop加速 for 循环
【发布时间】:2021-09-03 01:06:13
【问题描述】:

我的代码存在执行速度问题。以下代码尝试计算矩阵每一行的最近邻行。距离计算的度量是基于近邻排除约束的欧几里得距离。最后,我需要矩阵每一行的 8 个最近邻的行号。

输入矩阵 (EmbedMat) 是时间序列数据的分段版本。喜欢:

这是以下工作示例。 Buffer是创建EmbedMat的自定义函数。

import numpy as np
def buffer(data,num_perseg,overlap):
    numberOfSegments = int(math.ceil((len(data)-overlap)/(num_perseg-overlap)))
    tempBuf = [data[i:i+num_perseg] for i in range(0,len(data),(num_perseg-int(overlap)))]
    tempBuf[numberOfSegments-1] = np.pad(tempBuf[numberOfSegments-1],(0,num_perseg-tempBuf[numberOfSegments-1].shape[0]),'constant')
    tempBuf2 = np.vstack(tempBuf[0:numberOfSegments])
    return tempBuf2

EmbedMat=buffer(np.arange(0,50),5,4)

def distance_calculator(EmbedMat,E=5,nn=8):
# Calculates the Euclidian distance of the rows of embedded matrix
# subjecting it to a near-in-time neighbour exclusion constraint
# abs(jp-i)>E/2
    bins=np.arange(0,EmbedMat.shape[0])
    
    # calculate all possible combinations of rows
    bin_comb=[(x,y) for x in bins for y in bins]
    
    count=0
    dist=np.zeros((EmbedMat.shape[0]*EmbedMat.shape[0],))
    for i in bin_comb:
        if abs(i[0]-i[1])>E/2:
            # without numpy.linalg.norm library, execution time is less.
            dist[count]=math.sqrt(((EmbedMat[i[0],:]-EmbedMat[i[1],:])**2).sum())
        else:
            dist[count]=np.NAN
        count=count+1
    
    dist_buf=buffer(dist,EmbedMat.shape[0],0)
    dist_buf=dist_buf[:,0:EmbedMat.shape[0]-1]
    # distance from x/row to y/col
    # i.e [4,5] represents the distance(row4,row5) of EmbedMat
        
    sortIndex=np.argsort(dist_buf,axis=1)
    
    sort_red=sortIndex[:,0:nn]

    return sort_red

sort_red=distance_calculator(EmbedMat)

在 50 个样本时效果很好,但如果样本长度为 1000 或更多,则执行时间会变差(最多 5-7 秒)。

我对 Python 比较陌生,并且不是来自开发人员背景,因此您可能在上面的代码中看不到良好的编码实践。抱歉,您看到的一团糟。

任何帮助将不胜感激。

【问题讨论】:

  • 您可以profile 一个 Python 脚本来了解究竟什么是慢的。另外,您期望 N=1000 的性能如何?以上 ?我很快测量了(对time.time() 的调用之间存在差异),正是你的 for 循环减慢了你的脚本。我不是 NumPy 专家,所以我无法帮助您,但请专注于它(寻找另一种算法,优化您编写的内容,...)。
  • 你想使用来自sklearn的Balltree,它非常快。如果您需要一个工作示例,请告诉我
  • 快速 2 倍加速:bin_comb=[(x,y) for x in bins for y in bins if x>y];由于距离是对称的,每对只计算一次,也跳过自身距离。

标签: python performance numpy for-loop


【解决方案1】:

非常感谢您的建议。根据您的 cmets,我想出了这个解决方案,它将执行时间减少到原来的一半,正如 sabik 建议的那样:

EmbedMat=buffer(np.arange(0,50),5,4)

def distance_calculator(EmbedMat,E=5,nn=8):
# Calculates the Euclidian distance of the rows of embedded matrix
# subjecting it to a near-in-time neighbour exclusion constraint
# abs(jp-i)>E/2
    bins=np.arange(0,EmbedMat.shape[0])
    
    # calculate all possible combinations of rows
    bin_comb=[(x,y) for x in bins for y in bins]
    
    count=0
    dist=np.zeros((EmbedMat.shape[0]*EmbedMat.shape[0],))
    for i in bin_comb:
        if abs(i[0]-i[1])>E/2 and i[1]>i[0]:
            # without numpy.linalg.norm library, execution time is less.
            dist[count]=math.sqrt(((EmbedMat[i[0],:]-EmbedMat[i[1],:])**2).sum())
        else:
            dist[count]=np.NAN
        count=count+1
    
    dist_buf=buffer(dist,EmbedMat.shape[0],0)
    dist_buf=dist_buf+dist_buf.T
    dist_buf=dist_buf[:,0:EmbedMat.shape[0]-1]
    # distance from x/row to y/col
    # i.e [4,5] represents the distance(row4,row5) of EmbedMat
        
    sortIndex=np.argsort(dist_buf,axis=1)
    
    sort_red=sortIndex[:,0:nn]

    return sort_red

sort_red=distance_calculator(EmbedMat)

简而言之,我为处理 y>x (i[1]>i[0]) 的 for 循环引入了另一个约束。然后,为了得到相同的结果,我用它的转置来总结它。现在效果很好。谢谢!

【讨论】:

    猜你喜欢
    • 2021-01-30
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 2016-01-31
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多