Python的NumPy库对于使用者来说是十分有用的,但是python的NumPy库使用有一些注意事项是初学者需要注意的,尤其是在定义数组的时候,需要注意和python列表区别。NumPy数组不同于python列表,python的一个list当中可以存储不同的数据类型,但是NumPy数组只可以存储一种类型的数据。
为了方便理解NumPy,我们不妨先介绍一点python的背景知识,python本质上是根植于C语言的程序语言,其之所以能够使用动态的数据类型,是因为python语言中数据对象其实是一个C语言的结构体,这也就意味着当定义一个python变量时,它会保存除了该变量的值以外的其他很多信息,也需要占用更多的内存。因此,python的列表也并不像C语言的数组一样调用连续的内存,而是像链表一样调用离散的内存,再用指针指向该变量。现在就不难理解,为什么python当中的list占用的内存和访问的速度可能不如C语言这么小这么快。但是NumPy库很好的解决了这个问题,定义固定类型的数组,很显然能够大幅度提高运算的速度和占用的空间。这也是NumPy的优越性,更是其成为现在很多热门领域(尤其在深度学习)必备的工具之一。
下面从代码角度展示NumPy数组的定义
一般为了方便,我们会import numpy as np
import numpy as np
a=np.array([1,2,3,4])
print(a)
print(a.T)
NumPy当中array函数的作用是把一个python的list转换成一个NumPy类型的数组,其运行结果如下
这便是NumPy当中的最简单的数组定义方式。
但是在很多应用场景下,我们更希望他是一个向量而不是一个数组,结合线性代数的知识可以得知,一个行向量可以转置得到一个列向量,但是很显然,上述代码print(a.T)的结构和print(a)完全相同,也就是没有成功转置,说明我们禁止是定义了数组,而不是向量,这是很多初学者最容易犯的错误。
import numpy as np
a=np.random.rand(3,4)
print(a)
print(a.T)
且看这段代码,我们利用NumPy当中的random函数创建一个3行4列的矩阵,其输出结果如下
可以看出,其确实发生了转置,如果用a.shape来输出矩阵维度,得到(3,4),而如果用同样的函数输出上面一段代码,会得到(4,),因此, 如果你想定义一个4行1列的数组,请一定用(4,1)。
请注意观察上图的“[”和“]”情况,不难发现,其实NumPy当中的数组是行向量用一个list来表示的,行向量元素个数,就是整个矩阵列的维度。
(初始的时候就用a=np.array([[1,2,3,4]])定义矩阵,也是可以得到一个向量的,本质就是括号的匹配。)
当然,你也可以自己不利用random相关的函数初始化矩阵,而是自己给矩阵赋值,自己进行初始化的时候遵寻一个行向量用[ ]括起来的原则即可,示例如下:
import numpy as np
a=np.array([[1],[2],[3],[4]])
print(a)
print(a.T)
print(a.shape)
运行结果如下:
不难看出,[ ]确实就是一个行向量,尽管我定义的时候确确实实写在了一行,但是python仍然识别出我定义的是一个4行1列的矩阵,并且成功进行了转置。
在很多应用场景中,我们面对的并不单纯是一个矩阵,或者说并不一定是层数为1的矩阵。最为典型的就是RGB通道的图片,比如,一张64*64的RGB图片,可以看作是由3层64*64的矩阵表示出来的。因此我们在处理过程中,有时候会遇到多层的矩阵,但事实上这样的操作也并不复杂,利用shape和array函数,下面也用一段代码就可以说明。
import numpy as np
a=np.array([[[1,2,3],[4,5,6],[7,8,9]],
[[10,11,12],[13,14,15],[16,17,18]]])
print(a)
print(a.shape)
运行结果如下:
定义的时候依然遵循括号的[ ]原则,最内侧的括号表示的一定是一个行向量,行向量并列就形成了列向量,与此同时,第二层括号就是一个矩阵,最外层括号,则是把多层矩阵统一在一起。shape函数的输出第0位是层数,第1位是每个矩阵的行数,第2位是每个矩阵的列数。
很多时候我们不希望python处理三层的矩阵,此时我们一般让矩阵重新排列,得到一个行向量或者一个列向量,要用到reshape函数(此时要注意,reshape的结果需要是一个合理的情况,比如把一个shape是(2,3,3,)的矩阵转换成(100,1)很显然是不合理的)。代码如下:
import numpy as np
a=np.array([[[1,2,3],[4,5,6],[7,8,9]],
[[10,11,12],[13,14,15],[16,17,18]]])
a_reshape=a.reshape(1,a.shape[0]*a.shape[1]*a.shape[2])
print(a_reshape)
运行结果如下:
从括号可以看出,重塑之后的矩阵仍然是一个行向量,而不是一个简单的python的list。