例如,假设我正在模拟一堆粒子随着时间的推移做某事,并且我有一个名为 particles
的多维数组,其中包含以下索引:
- 粒子的 x/y/z 坐标(长度为
a
,对于 3d 空间为3
) - 单个粒子的索引(长度
b
) - 时间步长的索引(长度
c
)
构建这样的数组是否更好 particles.shape == (a, b, c)
或 particles.shape == (c, b, a)
?
我对约定比效率更感兴趣:Numpy 数组可以设置为 C 风格(最后一个索引变化最快)或 Fortran 风格(第一个索引),因此它可以有效地支持任何一种设置。我还意识到我可以使用 transpose
将索引按我需要的任何顺序放置,但我想尽量减少它。
我开始自己研究这个并找到了对这两种方式的支持:
Pro-(c,b,a):
- 默认情况下,Numpy 使用 C 风格数组,其中最后一个索引变化最快。
- 大多数向量代数函数(
inner
、cross
等)作用于最后一个索引。 (点
作用于一个的最后一个和另一个的倒数第二个。) matplotlib
集合对象(LineCollection
、PolyCollection
)期望数组的最后一个轴具有空间坐标。
Pro-(a,b,c):
- 如果我要使用
meshgrid
和mgrid
生成一组点,它会将空间轴放在第一位。例如,np.mgrid[0:5,0:5,0:5].shape == (3,5,5,5)
。我意识到这些功能主要用于 integer array indexing ,但使用它们生成点网格的情况并不少见。 matplotlib
scatter
和plot
函数拆分了它们的参数,因此它与数组的形状无关,但是ax .plot3d(particles[0], particles[1], particles[2])
比带有particles[..., 0]
的版本更短
一般来说,似乎存在两种不同的约定(可能是由于 C 和 Fortran 之间的历史差异),目前尚不清楚哪一种在 Numpy 社区中更常见,或者更适合我正在做的事情。
最佳答案
根据我的经验,此类约定与特定文件格式的关系比其他任何事情都多。但是,有一种快速的方法可以回答哪一个可能最适合您正在做的事情:
如果您必须遍历一个轴,您最有可能遍历哪个轴?换句话说,最有可能的是:
# a first
for dimension in particles:
...
# b first
for particle in particles:
...
# c first
for timestep in particles:
...
就效率而言,这假定了 C 阶,但这实际上与此处无关。在 python 级别,无论内存布局如何,对 numpy 数组的访问都被视为 C 顺序。 (您总是迭代第一个轴,即使它不是内存中“最连续”的轴。)
当然,在很多情况下,你应该避免在这件事上直接遍历 numpy 数组。尽管如此,这是您应该考虑的方式,尤其是当涉及到磁盘文件结构时。使最常见的用例成为最快/最简单的。
如果不出意外,希望这能为您提供一种思考问题的有用方法。
关于python - Numpy 多维数组中的索引顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27606209/