【问题标题】:Python: How to improve performance of a script to obtain the Bounding Box of a set of pointsPython:如何提高脚本的性能以获取一组点的边界框
【发布时间】:2012-10-08 19:42:25
【问题描述】:

我有一组点(x 和 y),我想知道 X 和 Y(边界框)的最大值和最小值。我对这些行进行了编码,在这些行中我使用列表理解读取了所有点,然后在 X 和 Y 上使用了 max 和 min。最后我删除了这些点。

这个解决方案不是内存效率,因为我需要读取所有点

points = [(p.x,p.y) for p in lasfile.File(inFile,None,'r')] # read in list comprehension
X_Max = max(zip(*points)[0])
X_Min = min(zip(*points)[0])
Y_Max = max(zip(*points)[1])
Y_Min = min(zip(*points)[1])
del points

我要求建议避免此步骤(将所有点存储在内存中)。 提前致谢 詹尼

【问题讨论】:

    标签: python performance memory-management coding-style


    【解决方案1】:

    您可以为points 使用生成器表达式,并为maxmin 使用key 参数:

    from itertools import tee
    points = ((p.x,p.y) for p in lasfile.File(inFile,None,'r'))
    points = tee(points, 4)
    
    X_Max = max(points[0], key=lambda x:x[0])[0]
    X_Min = min(points[1], key=lambda x:x[0])[0]
    Y_Max = max(points[2], key=lambda x:x[1])[1]
    Y_Min = min(points[3], key=lambda x:x[1])[1]
    

    更新:

    我添加了对 itertools.tee 的调用以复制原始生成器。

    如 cmets 中所述,此解决方案的缺点是您必须(不必要地)对文件进行 4 次迭代。正如@SteveMayne 所做的那样,计算每次迭代的最大值和最小值,可以避免这种情况。

    【讨论】:

    • 感谢halex,但我的想法是尽量不在内存中存储点(超过200万)。 PS:我没有投票(我从来没有)
    • 点不应该存储在内存中,因为生成器表达式使用(...) 而不是[...]。一次获取一个点。
    • 你确定这会起作用吗?在第一次max 调用之后,生成器points 将被耗尽,所以下面对min 的调用将导致异常。
    • @Mr.Steak 我也是这么想的。即使它有效,您也必须对文件进行 4 次迭代才能完成可以通过单个循环执行的操作。
    • @Gianni 对不起。我现在修好了。问题是 maxmin 将 x 和 y 值的整个点作为 2 个元素的元组返回。因此,我为 x 值的第一个元素和 y 值的第二个元素添加了另一个访问权限。谢谢你这么用心:)。
    【解决方案2】:
    X_Max = float('-inf')
    X_Min = float('+inf')
    Y_Max = float('-inf')
    Y_Min = float('+inf')
    
    for p in lasfile.File(inFile,None,'r'):
        X_Max = max(X_Max, p.x)
        X_Min = min(X_Min, p.x)
        Y_Max = max(Y_Max, p.y)
        Y_Min = min(Y_Min, p.y)
    

    这样您只需在文件上循环一次,同时避免一次在内存中拥有多个点。

    EDIT File() 提供了一个迭代器,它一次只从文件中读取一行,并在需要时将其提供给循环变量 p

    在您的问题中,您在初始分数分配周围使用了方括号。这是一个列表推导,顾名思义,它创建了一个列表——所以从那时起所有的点都保存在内存中。如果你像这样使用括号:

    points = ((p.x,p.y) for p in lasfile.File(inFile,None,'r'))
    
    X_Max = float('-inf')
    X_Min = float('+inf')
    Y_Max = float('-inf')
    Y_Min = float('+inf')
    
    for p in points:
        X_Max = max(X_Max, p.x)
        X_Min = min(X_Min, p.x)
        Y_Max = max(Y_Max, p.y)
        Y_Min = min(Y_Min, p.y)
    

    ...那么 Python 不会创建一个列表,而是一个生成器/迭代器——它将一次返回一个点,直到文件用完为止。这将避免同时在内存中拥有所有点 - 但只能迭代一次。

    不过,为了简单起见,我放弃了创建一个额外的迭代器,而是直接使用 lasfile.File() 一个。

    【讨论】:

    • 积分在这里仍然存储在内存中。
    • 谢谢史蒂夫,但我的想法是尽量不在内存中存储积分(超过 200 万)
    • 它是一个生成器,所以它应该在内存中一次只有一个点。注意第一行的括号而不是方括号。
    • 为什么是points 生成器而不仅仅是for p in lasfile.File(inFile,None,'r'): X_Max = max(X_Max, p.x) ...
    • @Gianni 我已经填补了我的答案生成器版本中的空白。列表推导不会比在上面的示例中使用生成器为您节省任何东西 - 它会花费您大量的 RAM。澄清一下 - 列表理解是代码第一行方括号中的位 - 而不是 max() 调用,传递完整列表。
    猜你喜欢
    • 1970-01-01
    • 2020-06-05
    • 2011-07-10
    • 2022-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多