Python: 如何提高脚本性能以获取一组点的边界框

3
我有一组点(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

我想请你提供一个建议,以避免这一步骤(将所有点存储在内存中)。 谢谢 Gianni

2个回答

5
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)

这样做只需要一次循环文件,并避免一次在内存中存在多个点。 编辑 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打开文件格式为LAS的文件并且仅需要一次遍历,那么Python不会创建一个列表(list),而是创建一个生成器/迭代器(generator/iterator)——它会每次返回一个点,直到文件被读取完毕。这种方法可以避免在同一时间将所有点存储在内存中,但只能进行一次迭代。
为了简化起见,我放弃了创建额外迭代器的方式,而是直接使用lasfile.File()创建的迭代器。

2
它是一个生成器,因此在内存中一次只应该有一个点。请注意第一行周围的括号而不是方括号。 - Steve Mayne
你应该注意到,它是File类提供了生成器(假设OP使用libLAS,我认为他确实使用了)。 - sloth
@SteveMayne:感谢您的帮助。对于这些大数据集(> 200万个点),我在Python中总是遇到问题。最近我在stackoverflow上写了这些帖子: http://stackoverflow.com/questions/12923935/python-improve-memory-efficiency-of-a-script 和 http://stackoverflow.com/questions/12883237/python-improve-the-efficency-of-my-script-using-multiprocessing-module-tips-an 来解释这些问题。 - Gianni Spear
@SteveMayne 我今晚一定会测试,并在SO上给你反馈。今天是/已经是一个会议(全)天,现在我正在电脑上准备今晚的数据。无论如何,请问您能否使用points = ((p.x,p.y) for p in lasfile.File(inFile,None,'r'))编写您的解决方案?谢谢Gianni提前。 - Gianni Spear
1
@Gianni 我已经填补了生成器版本答案中的空缺。在上面的示例中,列表推导式不会比使用生成器节省任何东西 - 而且它会消耗大量的 RAM。澄清一下 - 列表推导式是您代码第一行方括号中的部分 - 而不是传入完整列表的 max() 调用。 - Steve Mayne
显示剩余9条评论

3

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

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的调用以复制原始生成器。

正如评论中所指出的那样,这种解决方案的缺点是你必须(不必要地)迭代你的文件4次。像@SteveMayne所做的那样,在每次迭代中计算最大值和最小值可以避免这一点。


2
点不应该存储在内存中,因为使用(...)而不是[...]生成器表达式。这些点一次只能获取一个。 - halex
2
你确定这会起作用吗?在第一次max调用后,生成器points将被耗尽,所以下一次对min的调用将导致异常。 - sloth
2
@Mr.Steak,这也是我在想的。即使它可以工作,你还需要迭代4次文件才能完成单个循环所能做的事情。 - Steve Mayne
1
@Gianni 抱歉,我已经修复了。问题在于 maxmin 返回了 x 和 y 值的整个点作为一个由 2 个元素组成的元组。因此,我添加了另一个访问方式,第一个元素用于 x 值,第二个元素用于 y 值。感谢您的关注和耐心 :). - halex
@halex:测试一下看看是否有一些漏洞是一件愉快的事情。你和史蒂夫·梅恩做得很好。 - Gianni Spear
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接