例如,假设我正在模拟一堆粒子随时间做某些事情,我有一个名为
particles
的多维数组,其中包含这些索引:
- 粒子的x/y/z坐标(长度为
a
,对于3d空间来说是3
) - 单个粒子的索引(长度为
b
) - 它所在的时间步骤的索引(长度为
c
)
构建数组时,particles.shape == (a, b, c)
或particles.shape == (c, b, a)
哪种更好?
我更关心惯例而不是效率:Numpy数组可以按C风格(最后一个索引变化最快)或Fortran风格(第一个索引)设置,因此它可以高效地支持任何一种设置。我也意识到我可以使用transpose
将索引以任何顺序排列,但我想将其最小化。
我开始自己研究并找到了支持两种方式的论据:
赞成(c,b,a):
- 默认情况下,Numpy使用C风格的数组,其中最后一个索引是变化最快的。
- 大多数向量代数函数(
inner
、cross
等)作用于最后一个索引。(dot
在一个数组的最后一个索引和另一个数组的倒数第二个索引之间进行计算。) matplotlib
集合对象(LineCollection
、PolyCollection
)期望在最后一个轴中具有空间坐标的数组。
Pro-(a,b,c):
- 如果我想使用
meshgrid
和mgrid
来生成一组点,它会将空间轴放在第一位。例如,np.mgrid[0:5,0:5,0:5].shape == (3,5,5,5)
。我知道这些函数主要是用于整数数组索引,但通常也可以用它们来生成点的网格。 matplotlib
的scatter
和plot
函数将其参数分离,因此它对数组的形状不感知,但是ax.plot3d(particles[0], particles[1], particles[2])
比带有particles[..., 0]
的版本更短。
总的来说,似乎存在两种不同的约定(可能是由于C和Fortran之间的历史差异造成的),并且不清楚哪种约定在Numpy社区中更常见,或者更适合我的工作。
x = np.ones((3,4,5));y = np.linalg.norm(x,axis=0)
与x = np.ones((5,4,3));y = np.linalg.norm(x,axis=-1)
进行比较。当空间索引在第一位时,x/y
可以在没有任何索引调整的情况下对x
进行标准化。 当空间索引在最后时,您必须执行类似于x/y[..., np.newaxis]
的操作。 - Apocheirsum
,mean
)都有一个keepdims
参数,以消除需要将此“newaxis”添加回去的需要。 - hpaulj