【发布时间】:2011-04-05 23:40:18
【问题描述】:
请参阅此问题底部的重要说明。
我正在使用 numpy 来加快一些经度/纬度坐标的处理。不幸的是,我的 numpy“优化”使我的代码运行速度比不使用 numpy 时运行速度快 5 倍。
瓶颈似乎在于用我的数据填充 numpy 数组,然后在我完成数学转换后提取该数据。为了填充数组,我基本上有一个循环,例如:
point_list = GetMyPoints() # returns a long list of ( lon, lat ) coordinate pairs
n = len( point_list )
point_buffer = numpy.empty( ( n, 2 ), numpy.float32 )
for point_index in xrange( 0, n ):
point_buffer[ point_index ] = point_list[ point_index ]
那个循环,只是在操作之前填充 numpy 数组,非常慢,比没有 numpy 的整个计算要慢得多。 (也就是说,这不仅仅是 python 循环本身的缓慢,而且显然在将每个小数据块从 python 传输到 numpy 时会产生巨大的开销。)在另一端也有类似的缓慢;在处理完 numpy 数组后,我在循环中访问每个修改后的坐标对,再次作为
some_python_tuple = point_buffer[ index ]
再一次,提取数据的循环比没有 numpy 的整个原始计算慢得多。那么,我如何实际填充 numpy 数组并从 numpy 数组中提取数据,而不会破坏首先使用 numpy 的目的?
我正在使用 C 库从形状文件中读取数据,该库将数据作为常规 python 列表传递给我。我知道,如果图书馆将坐标交给我已经在 numpy 数组中,则不需要“填充”numpy 数组。但不幸的是,我使用数据的起点是常规的 python 列表。更重要的是,总的来说,我想了解如何使用 python 中的数据快速填充一个 numpy 数组。
澄清
上面显示的循环实际上过于简单化了。我在这个问题中这样写是因为我想专注于我看到的尝试在循环中缓慢填充 numpy 数组的问题。我现在明白这样做很慢。
在我的实际应用程序中,我拥有的是坐标点的形状文件,并且我有一个 API 来检索给定对象的点。大约有 200,000 个对象。所以我反复调用函数GetShapeCoords( i ) 来获取对象i 的坐标。这将返回一个列表列表,其中每个子列表是 lon/lat 对的列表,它是列表列表的原因是某些对象是多部分的(即多多边形)。然后,在我的原始代码中,当我读取每个对象的点时,我通过调用常规 python 函数对每个点进行转换,然后使用 PIL 绘制转换后的点。整个过程花了大约 20 秒来绘制所有 200,000 个多边形。不可怕,但还有很大的改进空间。我注意到这 20 秒中至少有一半用于转换逻辑,所以我想我会在 numpy.而我最初的实现只是一次读取一个对象,并不断将子列表中的所有点附加到一个大的 numpy 数组中,然后我可以在 numpy 中进行数学运算。
所以,我现在明白,简单地将整个 python 列表传递给 numpy 是设置大数组的正确方法。但就我而言,我一次只读取一个对象。所以我可以做的一件事是在一个列表列表的大 python 列表中继续附加点。然后当我以这种方式编译了大量对象的点(例如,10000 个对象)时,我可以简单地将怪物列表分配给 numpy。
所以我现在的问题是三个部分:
(a) numpy 是不是真的可以把这么大的、不规则形状的列表列表的列表,然后又快又好地吞下去?
(b) 然后我希望能够转换那棵怪物树的叶子中的所有点。例如,让 numpy 的表达式是“进入每个子列表,然后进入每个子子列表,然后对于在这些子子列表中找到的每个坐标对,将第一个(lon 坐标)乘以 0.5”?我可以这样做吗?
(c) 最后,我需要将这些转换后的坐标取回以便绘制它们。
Winston 在下面的回答似乎暗示了我如何使用 itertools 来完成这一切。我想做的很像温斯顿所做的,把列表弄平。但我不能完全把它弄平。当我去绘制数据时,我需要能够知道一个多边形何时停止,下一个多边形何时开始。因此,我认为如果有一种方法可以使用特殊的坐标对(如 (-1000, -1000) 或类似的东西)快速标记每个多边形(即每个子子列表)的结尾,我可以让它工作。然后我可以像 Winston 的回答那样用 itertools 展平,然后在 numpy 中进行转换。然后我需要使用 PIL 从点到点实际绘制,在这里我想我需要将修改后的 numpy 数组重新分配回 python 列表,然后在常规 python 循环中遍历该列表以进行绘图。这似乎是我最好的选择,而不是仅仅编写一个 C 模块来为我一步处理所有的阅读和绘图?
【问题讨论】:
-
point_buffer_index到底是什么? -
抱歉,point_buffer_index 是一个错字;它已更改为 point_index
-
你能举例说明
point_list的样子吗?因为现在看来您只是将point_list的每个元素放在point_buffer的对应点中。然后你可以使用point_buffer = np.array(point_list) -
请,当您提出性能问题时,不要简化性能问题部分。
-
温斯顿,谢谢,你是对的。请参阅下面我对您的回答的后续行动。
标签: python arrays performance numpy loading