使用元组还是numpy数组存储坐标更好

10 投票
2 回答
7756 浏览
提问于 2025-04-15 21:08

我正在把一个C++的科学应用程序移植到Python,因为我对Python还不太熟悉,所以有一些问题想请教:

1) 我定义了一个类,用来存储坐标(x,y)。这些值会被多次访问,但在类实例化后才会读取。用元组(tuple)还是用numpy数组在内存和访问速度上更好呢?

2) 在某些情况下,这些坐标会用来构建一个复数,并在一个复杂的函数上进行计算,最后只用到这个函数的实部。假设没有办法将这个函数的实部和虚部分开,而最终又必须使用实部,那么直接用复数来存储(x,y)是否更好?在Python中,从复数转换到实数的开销有多大?在C++的代码中,这种转换很多,导致了性能的大幅下降。

3) 另外,还需要进行一些坐标转换,对于坐标来说,x和y的值会分别被访问,进行转换后再返回结果。坐标转换是在复平面上定义的,那么直接使用x和y这两个分量会比依赖复数变量更快吗?

谢谢!

2 个回答

3

一个带有额外维度的 numpy 数组在内存使用上更紧凑,而且速度至少和一个元组的 numpy 数组一样快!对于复数来说,效果也一样好,甚至更好,这也包括你提的第三个问题。顺便说一下,你可能注意到了——虽然比你晚提问的问题得到了很多回答,但你的问题却没有人回应:部分原因无疑是因为在一个问题里问了 三个 问题,这让回答的人觉得有点烦。为什么不每次只问一个问题呢?反正提问也不会收费,对吧...!

7

从内存使用的角度来看,numpy数组比Python元组更节省空间。numpy数组使用的是一块连续的内存区域。所有的numpy数组元素都必须是声明好的类型(比如32位或64位的浮点数)。而Python元组不一定使用连续的内存,元组里的元素可以是任意的Python对象,这通常会占用比numpy数值类型更多的内存。

所以在这方面,numpy绝对是赢家(前提是数组里的元素可以作为numpy数值类型存储)。

在速度方面,我觉得关键在于“你能否将代码向量化?”

也就是说,你能否把计算表达为对整个数组的逐元素操作。

如果代码可以向量化,那么numpy通常会比Python元组快。(我能想到的唯一例外是,如果你有很多非常小的元组。在这种情况下,创建numpy数组的开销和导入numpy的一次性成本可能会抵消向量化带来的好处。)

一个无法向量化的代码示例是,如果你的计算需要查看数组z中的第一个复数,进行一个计算得到一个整数索引idx,然后取出z[idx],再对这个数字进行计算得到下一个索引idx2,然后再取出z[idx2],依此类推。这种计算可能无法向量化。在这种情况下,你可以选择使用Python元组,因为你无法利用numpy的优势。

我不太担心访问复数的实部或虚部的速度。我的猜测是,向量化的问题更可能决定哪种方法更快。(顺便说一下,numpy可以通过遍历复数数组,跳过每个浮点数,简单地将复数数组转换为实部,结果视为浮点数。而且语法非常简单:如果z是一个复数numpy数组,那么z.real就是实部的浮点数numpy数组。这应该比使用列表推导式进行属性查找的纯Python方法[z.real for z in zlist]快得多。)

顺便问一下,你为什么要把C++代码移植到Python呢?

撰写回答