【问题标题】:How to speedup this for loop in python如何在python中加速这个for循环
【发布时间】:2017-07-21 13:57:25
【问题描述】:

我正在处理两组大小相同的三个大型列表,其中包含 UTM 格式的经度、纬度和高度坐标(请参见下面的列表)。数组包含重叠坐标(即经度和纬度值相等)。如果 Lon 中的值等于 Lon2 并且 Lat 中的值等于 Lat2 那么我想计算这些索引处的平均高度。但是,如果它们不相等,则经度、纬度和高度值将保持不变。我只想将重叠数据替换为一组经度和纬度坐标并计算这些坐标的平均值。

这是我目前的尝试

 import numpy as np

 Lon = [450000.50,459000.50,460000,470000]
 Lat = [5800000.50,459000.50,500000,470000]
 Alt = [-1,-9,-2,1]
 Lon2 = [450000.50,459000.50,460000,470000]
 Lat2 = [5800000.50,459000.50,800000,470000]
 Alt2= [-3,-1,-20,2]

 MeanAlt = []
 appendAlt = MeanAlt.append
 LonOverlap = []
 appendLon = LonOverlap.append
 LatOverlap = []
 appendLat = LatOverlap.append

 for i, a in enumerate(Lon and Lat and Alt):
     for j, b in enumerate(Lon2 and Lat2 and Alt2):
         if Lon[i]==Lon2[j] and Lat[i]==Lat2[j]:
             MeanAltData = (Alt[i]+Alt2[j])/2
             appendAlt(MeanAltData)
             LonOverlapData = Lon[i]
             appendLat(LonOverlapData)
             LatOverlapData = Lat[i]
             appendLon(LatOverlapData)

 print(MeanAlt) # correct ans should be MeanAlt = [-2.0,-5,1.5]
 print(LonOverlap)
 print(LatOverlap)

我正在使用 jupyter 笔记本电脑,我的笔记本电脑速度很慢,所以我需要让这段代码更有效率。我将不胜感激这方面的任何帮助。谢谢你:)

【问题讨论】:

  • 为什么第三个MeanAlt 是-5? Lat[2]!=Lat2[2] 等等,根据您的问题表述"...如果它们不相等,则经度、纬度和高度值将保持"“高度值将保留” 是什么意思?这对MeanAlt[2] 有何影响?
  • 啊,看来你是丢弃值对应于不相等的经度或纬度。请确认。
  • 为什么你在开头有import numpy as np,而你从不在代码的任何地方使用np

标签: python loops for-loop


【解决方案1】:

我相信您的代码可以通过两种方式改进:

  • 首先,使用tuples 而不是lists,因为迭代元组generally faster,而不是迭代列表
  • 其次,您的for 循环可以简化为只有一个 循环,该循环遍历您要读取的元组的索引。当然,这个假设成立当且仅当你所有的元组都包含相同数量的项目(即:len(Lat) == len(Lon) == len(Alt) == len(Lat2) == len(Lon2) == len(Alt2))。

这是改进后的代码(我冒昧地删除了 import numpy 语句,因为它没有在您提供的代码中使用):

# use of tuples
Lon = (450000.50, 459000.50, 460000, 470000)
Lat = (5800000.50, 459000.50, 500000, 470000)
Alt = (-1, -9, -2, 1)
Lon2 = (40000.50, 459000.50, 460000, 470000)
Lat2 = (5800000.50, 459000.50, 800000, 470000)
Alt2 = (-3, -1, -20, 2)

MeanAlt = []
appendAlt = MeanAlt.append
LonOverlap = []
appendLon = LonOverlap.append
LatOverlap = []
appendLat = LatOverlap.append

# only one loop
for i in range(len(Lon)):
    if (Lon[i] == Lon2[i]) and (Lat[i] == Lat2[i]):
        MeanAltData = (Alt[i] + Alt2[i]) / 2
        appendAlt(MeanAltData)
        LonOverlapData = Lon[i]
        appendLat(LonOverlapData)
        LatOverlapData = Lat[i]
        appendLon(LatOverlapData)

print(MeanAlt)  # correct ans should be MeanAlt = [-2.0,-5,1.5]
print(LonOverlap)
print(LatOverlap)

我在笔记本电脑上执行了这个程序 100 万次。按照我的代码,所有执行所需的时间为:1.41 秒。另一方面,使用您的方法所需的时间是:4.01 秒

【讨论】:

  • 另外,我相信您对MeanAlt 的预期结果有误,因为它应该包含 only 2 元素作为坐标匹配的唯一项目是 第二第四
  • 您的代码仅在(不太可能)假设重叠的纬度/经度保证在两个列表中位于相同位置的情况下有效。
  • 嗨 P.Shark,感谢您的回答。你是对的,这是我为 Lon2 输入的第一个值的错误。假设所有纬度/经度都在同一位置,您也是正确的。谢谢!
  • @TimeExplorer 很高兴我能帮上忙。虽然我的解决方案确实只适用于 knipknap 描述的场景,但从编写代码的方式来看,我假设您只对比较相同位置的元素感兴趣。无论如何,为了获得更高的性能(如果您的硬件支持),您可以考虑利用 multiprocessing 包 (link)
【解决方案2】:

这不是 100% 的功能等效,但我猜它更接近你真正想要的:

Lon = [450000.50,459000.50,460000,470000]
Lat = [5800000.50,459000.50,500000,470000]
Alt = [-1,-9,-2,1]
Lon2 = [40000.50,459000.50,460000,470000]
Lat2 = [5800000.50,459000.50,800000,470000]
Alt2= [-3,-1,-20,2]

MeanAlt = []
appendAlt = MeanAlt.append
LonOverlap = []
appendLon = LonOverlap.append
LatOverlap = []
appendLat = LatOverlap.append

ll = dict((str(la)+'/'+str(lo), al) for (la, lo, al) in zip(Lat, Lon, Alt))

for la, lo, al in zip(Lon2, Lat2, Alt2):
    al2 = ll.get(str(la)+'/'+str(lo))
    if al2:
        MeanAltData = (al+al2)/2
        appendAlt(MeanAltData)
        LonOverlapData = lo
        appendLat(LonOverlapData)
        LatOverlapData = la
        appendLon(LatOverlapData)

print(MeanAlt) # correct ans should be MeanAlt = [-2.0,-5,1.5]
print(LonOverlap)
print(LatOverlap)

或者更简单:

Lon = [450000.50,459000.50,460000,470000]
Lat = [5800000.50,459000.50,500000,470000]
Alt = [-1,-9,-2,1]

Lon2 = [40000.50,459000.50,460000,470000]
Lat2 = [5800000.50,459000.50,800000,470000]
Alt2= [-3,-1,-20,2]

ll = dict((str(la)+'/'+str(lo), al) for (la, lo, al) in zip(Lat, Lon, Alt))

result = []
for la, lo, al in zip(Lon2, Lat2, Alt2):
    al2 = ll.get(str(la)+'/'+str(lo))
    if al2:
        result.append((la, lo, (al+al2)/2))

print(result)

在实践中,我会尝试从结构更好的输入数据开始,使转换为 dict,或者至少不需要“zip()”。

【讨论】:

  • 您好,感谢您的回答。我喜欢你最后排列数据的方式。但是,它仅在 Lon 和 Lat 相等时提取坐标。我需要在 Lon 和 Lon2 相等时计算平均值,但可以与 Lat 和 Lat2 不同的数字应该相等。例如:Lon = [450000.50] Lon2 = [450000.50] Lat= [5800000.50] Lat2=[5800000.50]。我不确定如何在您提供的代码中实现这一点,呵呵。另外,如果您对安排输入数据有更好的建议,请告诉我。我只在列表中设置它,因为我对它们最熟悉。
【解决方案3】:

使用numpy 向量化计算。对于 1,000,000 个长数组,如果输入已经是 numpy.ndarrays,则执行时间应该在 15-25ms 微秒左右,如果输入是 Python 列表,则大约需要 140ms。

import numpy as np
def mean_alt(lon, lon2, lat, lat2, alt, alt2):
    lon = np.asarray(lon)
    lon2 = np.asarray(lon2)
    lat = np.asarray(lat)
    lat2 = np.asarray(lat2)
    alt = np.asarray(alt)
    alt2 = np.asarray(alt2)
    ind = np.where((lon == lon2) & (lat == lat2))
    mean_alt = (0.5 * (alt[ind] + alt2[ind])).tolist()
    return (lon[ind].tolist(), lat[ind].tolist(), mean_alt)

【讨论】:

    猜你喜欢
    • 2021-12-08
    • 2022-01-21
    • 2011-09-22
    • 1970-01-01
    • 2011-05-14
    • 2021-01-30
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    相关资源
    最近更新 更多