(一)Numpy数组对象
Numpy中的nadrray是一个多维数组对象,该对象由两部分组成:
- 实际的数据
- 描述这些数据的元数据
大部分的数组操作仅仅修改元数据部分,而不改变底层的实际数据。
数组的数据类型:
In: a = arange(5)
In: a.dtype
Out: dtype('int64')
数组的维度:
In [4]: a
Out[4]: array([0, 1, 2, 3, 4])
In: a.shape
Out: (5,)
数组的shape属性返回一个元组(tuple),元组中的元素即为NumPy数组每一个维度上的大小。上面例子中的数组是一维的,
因此元组中只有一个元素。
(二)动手实践:创建多维数组
创建一个多维数组
显示该数组的维度
In: m = array([arange(2), arange(2)])
In: m
Out:
array([[0, 1],
[0, 1]])
In: m.shape
Out: (2, 2)
我们将arange函数创建的数组作为列表元素,把这个列表作为参数传给array函数。
array函数可以依据给定的对象生成数组。给定的对象应该是类数组,如Python中的列表。
(1)选取数组元素
In: a = array([[1,2],[3,4]])
In: a
Out:
array([[1, 2],
[3, 4]])
在创建这个多维数组时,我们给array函数传递的对象是一个嵌套的列表。
数组的下标是从0开始的。
In: a[0,0]
Out: 1
In: a[1,1]
Out: 4
(2)Numpy数据类型
a.每一种数据类型均有对应的类型转换函数
In: float64(42)
Out: 42.0
In: int8(42.0)
Out: 42
In: bool(42)
Out: True
In: bool(0)
Out: False
In: bool(42.0)
Out: True
In: float(True)
Out: 1.0
In: float(False)
Out: 0.0
b.许多函数的参数中可以指定数据类型,通常这个参数是可选的:
In: arange(7, dtype=uint16)
Out: array([0, 1, 2, 3, 4, 5, 6], dtype=uint16)
注意:
a.复数是不能转换为整数的
b.复数也不能转换为浮点数
c.浮点数可以转换为复数
(3)数据类型对象
数据类型对象是numpy.dtype类的实例。
数据类型对象可以给出单个数组元素在内存中占用的字节数,即dtype的itemsize属性:
In: a.dtype.itemsize
Out: 8
(4)字符编码
Numpy可以使用字符编码来表示数据类型,这是为了兼容NumPy的前身Numeric。
不推荐使用字符编码,应该优先使用dtype对象来表示数据类型。
但有时会用到,因此下面列出了字符编码的对应表。
下面的编码创建了一个单精度浮点数组:
In: arange(7, dtype='f')
Out: array([ 0., 1., 2., 3., 4., 5., 6.], dtype=float32)
(5)自定义数据类型
我们有很多可以自定义数据类型的方法,以浮点型为例:
- 可以使用python中的浮点数类型
In: dtype(float)
Out: dtype('float64')
- 可以使用字符编码来指定单精度浮点数类型
In: dtype('f')
Out: dtype('float32')
- 可以将两个字符作为参数传给数据类型的构造函数,此时:
第一个字符表示数据类型,第二个字符表示该类型在内存中占用的字节数(2,4,8分别代表精度为16,32,64位)
In: dtype('f8')
Out: dtype('float64')
完整的的Numpy数据类型列表可以在sctypeDict.keys()中找到:
In: sctypeDict.keys()
Out: [0, ...
'i2',
'int0']
(6)dtype类的属性
- 获取数据类型的字符编码:char属性
In: t = dtype('Float64')
In: t.char
Out: 'd'
- 数组元素的数据类型:type属性
In: t.type
Out: <type 'numpy.float64'>
- 给出数据类型的字符串表示:str属性
该字符串的首个字符表示字节序(endianness),后面如果还有字符的话,将是一个字符编码,接着一个数字表示每个数组元素存储所需的字节数。
字节序是指长为32或64的字(word)存储的顺序:
大端序(big-endian):是将最高位字节存储在最低的内存地址处,用>表示;
小端序(little-endian):是将最低位字节存储在最低的内存地址处,用<表示.
In: t.str
Out: '<f8'
(三)动手实践:创建自定义数据类型
自定义数据类型是一种异构数据类型,可以当做用来记录电子表格或数据库中一行数据的结构。
(1)创建数据类型
In: t = dtype([(,name', str_, 40), ('numitems', int32), ('price',float32)])
In: t
Out: dtype([('name', '|S40'), ('numitems', '<i4'), ('price', '<f4')])
(2)查看数据类型(也可以查看某一字段数据类型)
In: t['name']
Out: dtype('|S40')
(3)创建自定义数据类型的数组
In: itemz = array([('Meaning of life DVD', 42, 3.14), ('Butter', 13, 2.72)], dtype=t)
In: itemz[1]
Out: ('Butter', 13, 2.7200000286102295)
必须在参数中指定数据类型,否则将触发TypeError错误
(四)一维数组的索引和切片
- 用下标3~7来选取元素3~6:
In: a = arange(9)
In: a[3:7]
Out: array([3, 4, 5, 6])
- 以2为步长选取元素:
In: a[:7:2]
Out: array([0, 2, 4, 6])
- 利用负数下标翻转数组:
In: a[::-1]
Out: array([8, 7, 6, 5, 4, 3, 2, 1, 0])
(五)动手实践:多维数组的切片和索引
(1)创建一个三维数组:
先用arange函数创建一个数组,用reshape函数改变其维度,使之变为一个三维数组
In: b = arange(24).reshape(2,3,4)
In: b.shape
Out: (2, 3, 4)
In: b
Out:
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]]])
多维数组b中有0~23的整数,共24个元素,是一个2×3×4的三维数组。我们可以形象地把它
看做一个两层楼建筑,每层楼有12个房间,并排列成3行4列。
(2) 我们可以用三维坐标来选定任意一个房间,即楼层、行号和列号。
In: b[0,0,0]
Out: 0
(3) 如果我们不关心楼层,也就是说要选取所有楼层的第1行、第1列的房间,那么可以将第1
个下标用英文标点的冒号:来代替:
In: b[:,0,0]
Out: array([ 0, 12])
This selects the first floor
In: b[0]
Out:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9,10,11]])
我们还可以这样写,选取第1层楼的所有房间:
In: b[0, :, :]
Out:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9,10,11]])
多个冒号可以用一个省略号(...)来代替,因此上面的代码等价于:
In: b[0, ...]
Out:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
进而可以选取第1层楼、第2排的所有房间:
In: b[0,1]
Out: array([4, 5, 6, 7])
(4) 再进一步,我们可以在上面的数组切片中间隔地选定元素:
In: b[0,1,::2]
Out: array([4, 6])
(5) 如果要选取所有楼层的位于第2列的房间,即不指定楼层和行号,用如下代码即可:
In: b[...,1]
Out:
array([[ 1, 5, 9],
[13,17,21]])
类似地,我们可以选取所有位于第2行的房间,而不指定楼层和列号:
In: b[:,1]
Out:
array([[ 4, 5, 6, 7],
[16,17,18,19]])
如果要选取第1层楼的所有位于第2列的房间,在对应的两个维度上指定即可:
In: b[0,:,1]
Out: array([1, 5, 9])
(6) 如果要选取第1层楼的最后一列的所有房间,使用如下代码:
In: b[0,:,-1]
Out: array([ 3, 7, 11])
如果要反向选取第1层楼的最后一列的所有房间,使用如下代码:
In: b[0,::-1, -1]
Out: array([11, 7, 3])
在该数组切片中间隔地选定元素:
In: b[0,::2,-1]
Out: array([ 3, 11])
如果在多维数组中执行翻转一维数组的命令,将在最前面的维度上翻转元素的顺序,在我们
的例子中将把第1层楼和第2层楼的房间交换:
In: b[::-1]
Out:
array([[[12,13,14,15],
[16,17,18,19],
[20,21,22,23],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9,10,11]]])
(六)动手实践:改变数组的维度
(1)ravel 用ravel函数完成展平的操作:
In: b
Out:
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: b.ravel()
Out:
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])
(2) flatten 与ravel函数的功能相同,不过,
flatten函数会请求内存来保存结果,
而ravel函数只是返回数组的一个视图(view)
In: b.flatten()
Out:
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])
(3)用元组设置维度(也可以使用reshape函数:b.reshape(6,4))
In: b.shape = (6,4)
In: b
Out:
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]],
(4)transpose 多维数组转置
In: b.transpose()
Out:
array([[ 0, 4, 8, 12, 16, 20],
[ 1, 5, 9, 13, 17, 21],
[ 2, 6,10, 14, 18, 22],
[ 3, 7,11, 15, 19, 23]])
(5)resize resize函数和reshape函数功能一样,但是resize函数会直接修改所操作的数组
In: b.resize((2,12))---书上这样写,其实写为b.resize(2,12)就可以
In: b
Out:
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]])
(七)数组的组合
Numpy数组有水平组合、垂直组合和深度组合等多种方式
首先创建一些数组:
In: a = arange(9).reshape(3,3)
In: a
Out:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In: b = 2 * a
In: b
Out:
array([[ 0, 2, 4],
[ 6, 8, 10],
[12, 14,16]])
(1)水平组合 hstack函数、concatenate函数
In: hstack((a, b))
Out:
array([[ 0, 1, 2, 0, 2, 4],
[ 3, 4, 5, 6, 8,10],
[ 6, 7, 8,12,14,16]])
也可以用concatenate函数实现同样的效果。
In: concatenate((a, b), axis=1)
Out:
array([[ 0, 1, 2, 0, 2, 4],
[ 3, 4, 5, 6, 8,10],
[ 6, 7, 8,12,14,16]])
(2)垂直组合 vstack函数和concatenate函数
In: vstack((a, b))
Out:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 0, 2, 4],
[ 6, 8,10],
[12,14,16]])
In: concatenatel((a, b), axis = 0)
Out:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 0, 2, 4],
[ 6, 8,10],
[12,14,16]])
(3)深度组合 dstack
所谓深度组合,就是将一系列数组沿着纵轴(深度)方向进行层叠组合。
In: dstack((a, b))
Out:
array([[[0, 0],
[1, 2],
[2, 4]],
[[3, 6],
[4, 8],
[5,10]],
[[6,12],
[7,14],
[8,16]]])
(4)列组合
column_stack函数对于一维数组将按列方向进行组合。效果等同于dstack
In: oned = arange(2)
In: oned
Out: array([0, 1])
In: twice_oned = 2 * oned
In: twice_oned
Out: array([0, 2])
In: column_stack((oned, twice_oned))
Out:
array([[0, 0],
[1, 2]])
对于二维数组,column_stack与hstack的效果是相同的。
In: column_stack((a, b))
Out:
array([[ 0, 1, 2, 0, 2, 4],
[ 3, 4, 5, 6, 8,10],
[ 6, 7, 8,12,14,16]])
In: column_stack((a, b)) == hstack((a, b))
Out:
array([[ True, True, True, True, True, True],
[ True, True, True, True, True, True],
[ True, True, True, True, True, True]], dtype=bool)
可以用==运算符来比较两个NumPy数组
(八)数组的分割
Numpy数组可以进行水平,垂直或深度分割。相关的函数有hsplit、vsplit、dsplit和split。
我们可以将数组分割成相同大小的子数组,也可以指定原数组中需要分割的位置。
(1)水平分割
In: a
Out:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In: hsplit(a, 3)
Out:
[array([[0],
[3],
[6]]),
array ([[1],
[4],
[7]]),
array ([[2],
[5],
[8]])]
对同样的数组,调用split函数并在参数中指定参数axis=1,对比一下结果:
In: split(a, 3, axis=1)
Out:
[array([[0],
[3],
[6]]),
array ([[1],
[4],
[7]]),
array ([[2],
[5],
[8]])]
(2) 垂直分割 vsplit函数将把数组沿着垂直方向分割:
In: vsplit(a, 3)
Out: [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
同样,调用split函数并在参数中指定参数axis=0,也可以得到同样的结果:
In: split(a, 3, axis=0)
Out: [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
(3)深度分割 dsplit函数将按深度方向分割数组
In: c = arange(27).reshape(3, 3, 3)
In: c
Out:
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],
[24,25,26]]])
In: dsplit(c, 3)
Out:
[array([[[ 0],
[ 3],
[ 6]],
[[ 9],
[12],
[15]],
[[18],
[21],
[24]]]),
array([[[ 1],
[ 4],
[ 7]],
[[10],
[13],
[16]],
[[19],
[22],
[25]]]),
array([[[ 2],
[ 5],
[ 8]],
[[11],
[14],
[17]],
[[20],
[23],
[26]]])]
只能用于三维或三维以上的数组。
(九)数组的属性
除了shape属性和dtype属性以外,ndarray对象还有很多其他的属性。
- ndim属性,给出数组的维数,或数组轴的个数:
In: b
Out:
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: b.ndim
Out: 2
- size属性,给出数组元素的总个数,如下所示:
In: b.size
Out: 24
- itemsize属性,给出数组中的元素在内存中所占的字节数:
In: b.itemsize
Out: 8
- 如果你想知道整个数组所占的存储空间,可以用nbytes属性来查看。这个属性的值其实
就是itemsize和size属性值的乘积:
In: b.nbytes
Out: 192
In: b.size * b.itemsize
Out: 192
- T属性的效果和transpose函数一样,如下所示:
In: b.resize(6,4)
In: b
Out:
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: b.T
Out:
array([[ 0, 4, 8, 12,16, 20],
[ 1, 5, 9, 13,17, 21],
[ 2, 6,10, 14,18, 22],
[ 3, 7,11, 15,19, 23]])
- 对于一维数组,其T属性就是原数组:
In: b.ndim
Out: 1
In: b.T
Out: array([0, 1, 2, 3, 4])
- 在NumPy中,复数的虚部是用j表示的。例如,我们可以创建一个由复数构成的数组:
In: b = array([1.j + 1, 2.j + 3])
In: b
Out: array([ 1.+1.j, 3.+2.j])
- real属性,给出复数数组的实部。如果数组中只包含实数元素,则其real属性将输出原
数组:
In: b.real
Out: array([ 1., 3.])
- imag属性,给出复数数组的虚部:
In: b.imag
Out: array([ 1., 2.])
- 如果数组中包含复数元素,则其数据类型自动变为复数型:
In: b.dtype
Out: dtype('complex128')
In: b.dtype.str
Out: '<c16'
- flat属性将返回一个numpy.flatiter对象, 这是获得flatiter对象的唯一方式——我
们无法访问flatiter的构造函数。这个所谓的“扁平迭代器”可以让我们像遍历一维数
组一样去遍历任意的多维数组,如下所示:
In: b = arange(4).reshape(2,2)
In: b
Out:
array([[0, 1],
[2, 3]])
In: f = b.flat
In: f
Out: <numpy.flatiter object at 0x103013e00>
In: for item in f: print item
.....:
0
1
2
3
我们还可以用flatiter对象直接获取一个数组元素:
In: b.flat[2]
Out: 2
或者获取多个元素:
In: b.flat[[1,3]]
Out: array([1, 3])
flat属性是一个可赋值的属性。对flat属性赋值将导致整个数组的元素都被覆盖:
In: b.flat = 7
In: b
Out:
array([[7, 7],
[7, 7]])
or selected elements
In: b.flat[[1,3]] = 1
In: b
Out:
array([[7, 1],
[7, 1]])
(十)数组的转换
(1)tolist函数将Numpy数组转换成python列表
In: b
Out: array([ 1.+1.j, 3.+2.j])
In: b.tolist()
Out: [(1+1j), (3+2j)]
(2)astype函数可以在转换数组时指定数据类型
In: b
Out: array([ 1.+1.j, 3.+2.j])
In: b.astype(int)
/usr/local/bin/ipython:1: ComplexWarning: Casting complex values to real discards the
imaginary part
#!/usr/bin/python
Out: array([1, 3])