在上一篇《手把手陪您学Python》52——数组的变形中,我们学习了数组变形的方法,并重点理解了如何进行按行以及按列的取值,这些都会在我们今天以及后面要学习的内容中加以体现。
今天我们将要学习的是数组的展开方法。
所谓数组的展开,就是将数组从二维、三维甚至更高维度,转变成一维的过程,就如同《三体》中质子的“低维展开”一般。在展开的过程中,就会涉及到我们上一篇学习的按行展开以及按列展开的顺序问题。
下面我们就来学习三种数组展开的方法。
1、flat
在入门阶段,我们学习过多种迭代器,比如常见的字符串、列表、元组、字典等等。还有迭代器的应用,最典型的就是在for循环中的使用。比如列表中的每一个元素,字典中的每一个键值,都可以在for循环中进行遍历。
如果我们将数组作为一个迭代器,会遍历出怎样的结果呢?
In [1]: import numpy as np
In [2]: arr1 = np.arange(24).reshape(4, 6)
arr1
Out[2]: array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23]])
In [3]: for a in arr1:
print(a)
Out[3]: [0 1 2 3 4 5]
[ 6 7 8 9 10 11]
[12 13 14 15 16 17]
[18 19 20 21 22 23]
In [4]: arr2 = np.arange(24).reshape(4, 3, 2)
arr2
Out[4]: array([[[ 0, 1],
[ 2, 3],
[ 4, 5]],
[[ 6, 7],
[ 8, 9],
[10, 11]],
[[12, 13],
[14, 15],
[16, 17]],
[[18, 19],
[20, 21],
[22, 23]]])
In [5]: for b in arr2:
print(b)
Out[5]: [[0 1]
[2 3]
[4 5]]
[[ 6 7]
[ 8 9]
[10 11]]
[[12 13]
[14 15]
[16 17]]
[[18 19]
[20 21]
[22 23]]
可以看到,当我们遍历二维数组的时候,每一次遍历的结果都是“一行”元素,而不是“一个数”。
当我们遍历三维数组的时候,每一次遍历的结果是一个嵌套列表,也不是“一个数”。
如果用我们上节课所学的知识来看,当我们遍历数组的时候,每一次遍历的结果都是最外层的一个元素。
如果是二维数组,那么最外层就是行,一个列表。
如果是三维数组,那么最外层就是嵌套列表,但不是数组。
以此类推,当我们对数组进行遍历的,实际上被遍历的是数组最外层结构,遍历的结果是数组最外层结构中的每一个元素,并且以列表或者嵌套列表的形式进行输出。
如果我们想遍历数组中的每一个数,就像在进行reshape时逐个取数一样,就需要使用flat函数,将数组从一个“最外层结构”迭代器,变成一个真正的“元素”迭代器。
In [6]: for c in arr1.flat:
print(c)
Out[6]: 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
In [7]: for d in arr2.flat:
print(d)
Out[7]: 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
可以看到,当使用flat对数组进行展开后,数组就变成了真正的“元素”迭代器。无论是二维数组,还是三维数组,甚至更高维的数组,全部都变成了元素迭代器,并可以在遍历的过程中,按顺序输出数组中的每一个“元素”,也就是每一个数。
flat并没有order参数,其默认的顺序是按行取值并展开,从上面的实例中我们也可以看到。
2、flatten
flatten与flat有些类似,只不过,flat是将数组变成元素迭代器后,按顺序逐个取值,并不能看到“展开”后的结果。
而flatten则可以真正地将数组进行展开,并将其转化为一维数组进行结果的输出,与《三体》中质子低维展开的描述完全相同。
此外,flatten具有order参数,能够按行或者按列进行展开并输出结果。如果不指定order的参数值,则默认按行展开。
In [8]: arr1.flatten(order = 'C')
Out[8]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])
In [9]: arr1.flatten(order = 'F')
Out[9]: array([ 0, 6, 12, 18, 1, 7, 13, 19, 2, 8, 14, 20, 3, 9, 15, 21, 4,
10, 16, 22, 5, 11, 17, 23])
In [10]: arr2.flatten(order = 'C')
Out[10]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])
In [11]: arr2.flatten(order = 'F')
Out[11]: array([ 0, 6, 12, 18, 2, 8, 14, 20, 4, 10, 16, 22, 1, 7, 13, 19, 3,
9, 15, 21, 5, 11, 17, 23])
由于我们已经在上一篇中学习了按行以及按列取值的规则,所以再理解上面的输出结果就非常容易了。
3、ravel
ravel和flatten的功能类似,都是将数组进行“展开”。
但从其语法格式上来看,flatten是方法,有一个参数,而ravel既可以有方法的格式,与flatten一样具有一个参数,也可以使用函数的格式,具有两个参数。
In [12]: arr1.ravel(order = 'C')
Out[12]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])
In [13]: arr1.ravel(order = 'F')
Out[13]: array([ 0, 6, 12, 18, 1, 7, 13, 19, 2, 8, 14, 20, 3, 9, 15, 21, 4,
10, 16, 22, 5, 11, 17, 23])
In [14]: np.ravel(arr2, order = 'C')
Out[14]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])
In [15]: np.ravel(arr2, order = 'F')
Out[15]: array([ 0, 6, 12, 18, 2, 8, 14, 20, 4, 10, 16, 22, 1, 7, 13, 19, 3,
9, 15, 21, 5, 11, 17, 23])
4、flatten与ravel的区别
除了上面说的flatten与ravel语法格式上的区别,其实他们还有一个重要的区别就是返回值的区别。
所谓返回值的区别是指返回的是拷贝(copy)还是视图(view)。
flatten返回的是数组的拷贝,对返回结果的修改不会影响原数组。而ravel返回的是视图,对返回结果的修改会影响原数组,也就相当于直接修改了原数组。
In [16]: arr1.flatten(order = 'C')[0] = 100
arr1
Out[16]: array([[ 0, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23]])
In [17]: arr1.ravel(order = 'C')[0] = 100
arr1
Out[17]: array([[100, 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10, 11],
[ 12, 13, 14, 15, 16, 17],
[ 18, 19, 20, 21, 22, 23]])
可以看到,同样都是将输出结果的第1个元素值修改为100,使用flatten时,原数组arr1并没有改变,只是对其展开的拷贝进行了修改。
而使用ravel进行展开时,原数组arr1的值也发生了改变。也就是说在使用ravel展开时,我们看到的是原数组的一种视图,类似于“哈哈镜”,虽然形状改变了,但看到的还是原来的数组。当对这个视图进行修改时,也就是对原数组进行了修改。
5、reshape(-1)
reshape(-1)是reshape的一种特殊用法,也可以将数组进行展开,具有order参数,返回的也是原数组的视图。
In [18]: arr2.reshape(-1,order = 'C')
Out[18]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23])
In [19]: arr2.reshape(-1,order = 'F')
Out[19]: array([ 0, 6, 12, 18, 2, 8, 14, 20, 4, 10, 16, 22, 1, 7, 13, 19, 3,
9, 15, 21, 5, 11, 17, 23])
In [20]: arr2.reshape(-1)[0] = 100
arr2
Out[20]: array([[[100, 1],
[ 2, 3],
[ 4, 5]],
[[ 6, 7],
[ 8, 9],
[ 10, 11]],
[[ 12, 13],
[ 14, 15],
[ 16, 17]],
[[ 18, 19],
[ 20, 21],
[ 22, 23]]])
以上就是对数组展开的几种方法的介绍,下一篇我们将会继续学习数组的操作——翻转,敬请关注。
感谢阅读本文!如有任何问题,欢迎留言,一起交流讨论^_^
要阅读《手把手陪您学Python》——NumPy系列文章的其他篇目,请关注公众号点击菜单选择,或点击下方链接直达。
《手把手陪您学Python》系列文章入门阶段的篇目已经全部完成。
为更加清晰地展示Python入门阶段的知识体系,整理了如下的鱼骨图,以方便大家查阅。
如要阅读相应篇目的内容,请关注公众号点击菜单选择,或点击下方链接直达。
《手把手陪您学Python》3——PyCharm的安装和配置
《手把手陪您学Python》5——Jupyter Notebook
For Fans:关注“亦说Python”公众号,回复“手53”,即可免费下载本篇文章所用示例语句。
