numpy中array数组对象的储存方式(n,1)和(n,)的区别
资料:https://stackoverflow.com/questions/22053050/difference-between-numpy-array-shape-r-1-and-r
这篇文章是我偶然点开的stackoverflow上的一个问题,是关于numpy中的array对象的。numpy在python、机器学习界的重要地位不用多说了吧。在此把这个回答翻译领悟一下,以供学习。
注:仅为学习目的翻译,作者是Gareth Rees,可能会有我自己的修改。
For learning purposes only !!!
看待NumPy arrays的最好方式是把它分为两个部分,一个数据缓冲区包含了一块raw elements(原始元素),以及一个view(我叫它视窗)来描述解释数据缓冲区。
例如如果我们创建一个包含12个整型数的数组 a :
>>> a = numpy.arange(12) >>> a array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
则 a 包含了一个数据缓冲区,储存成如下的样子:
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
以及一个视窗,定义了怎样解释数据:
>>> a.flags C_CONTIGUOUS : True F_CONTIGUOUS : True OWNDATA : True WRITEABLE : True ALIGNED : True UPDATEIFCOPY : False >>> a.dtype dtype('int64') >>> a.itemsize 8 >>> a.strides (8,) >>> a.shape (12,)
在这里,shape=(12,)意味着这个数组仅仅被一个索引支配:从0到11。从概念上讲,假如我们使用这个单独的索引给 a 打上标签,那么 a 将看起来像这样:
i= 0 1 2 3 4 5 6 7 8 9 10 11 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
reshape一个数组的操作不会改变数据缓冲区,而是创建一个新的解释数据的视窗。
>>> b = a.reshape((3, 4))
上面的操作创建了一个和 a 拥有同一个数据缓冲区的 b ,但是现在它被两个索引所支配(two-dimensions indexed)。一个从0到2,一个从0到3,假如我们给数据打上标签,b 看起来会像这样:
i= 0 0 0 0 1 1 1 1 2 2 2 2 j= 0 1 2 3 0 1 2 3 0 1 2 3 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
这也意味着:
>>> b[2,1] 9
第二个索引比第一个索引变化的快,假如想反过来,可以使用下面的参数创造一个数组 c
>>> c = a.reshape((3, 4), order='F')
补充:order='F'或者order='C'表示数组的索引方式分别像C语言或者Fortran,'C'是缺省值
这样会产生一个有如下索引的数组:
i= 0 1 2 0 1 2 0 1 2 0 1 2 j= 0 0 0 1 1 1 2 2 2 3 3 3 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
意味着
>>> c[2,1] 5
有了前面的铺垫,就很容易理解下面一个例子了:
>>> d = a.reshape((12, 1))
数组 d 被两个索引支配,第一个索引从0到11,第二个索引始终为0:
i= 0 1 2 3 4 5 6 7 8 9 10 11 j= 0 0 0 0 0 0 0 0 0 0 0 0 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
所以:
>>> d[10,0] 10
一个展平的一维数组从某种意义上来说是自由的,所以我们完全可以自己定义每一维的大小:
>>> e = a.reshape((1, 2, 1, 6, 1))
上面的操作创建了一个这样的数组:
i= 0 0 0 0 0 0 0 0 0 0 0 0 j= 0 0 0 0 0 0 1 1 1 1 1 1 k= 0 0 0 0 0 0 0 0 0 0 0 0 l= 0 1 2 3 4 5 0 1 2 3 4 5 m= 0 0 0 0 0 0 0 0 0 0 0 0 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
所以:
>>> e[0,1,0,0,0] 6