1.1 NumPy 数组对象
NumPy中的ndarray是一个多维数组对象,该对象由两部分组成: 实际的数据; 描述这些数据的元数据。 大部分的数组操作仅仅修改元数据部分,而不改变底层的实际数据。 NumPy数组的下标也是从0开始的。数组元素的数据类型用专门的对象表示。 我们再次用arange函数创建数组,并获取其数据类型: In: a = arange(5) In: a.dtype Out: dtype('int64') 数组a的数据类型为int64(在我的机器上是这样),当然如果你使用32位的Python,得到的 结果可能是int32。不论是哪种情形,该数组的数据类型都是整数(64位或32位)。除了数据类 型,数组的维度也是重要的属性。
>>> import array
>>> import numpy
>>> m= array([arange(2),arange(2)])
Traceback (most recent call last): File "", line 1, in
NameError: name 'arange' is not defined
>>> import array
>>> from numpy import *
>>> m= array([arange(2),arange(2)])
>>> m array([[0, 1], [0, 1]])
>>> m.shape (2, 2)
我们将arange函数创建的数组作为列表元素,把这个列表作为参数传给array函数,从而 创建了一个2×2的数组 数组的shape属性 返回一个元组(tuple),元组中的元素即为NumPy数组每一个维度上的大小。上面例子中的数组 是一维的,因此元组中只有一个元素。 选取数组元素
>>> import array
>>> from numpy import *
>>> a =array([[1,2],[3,4]])
>>> a array([[1, 2], [3, 4]])
>>> a[1,2]
Traceback (most recent call last): File "", line 1, in
IndexError: index 2 is out of bounds for axis 1 with size 2
>>> a[1,1]
4
对于数组a,只需要用a[m,n]选取各数组元素,其 中m和n为元素下标
NumPy 数据类型
bool 用一位存储的布尔类型(值为TRUE或FALSE)
inti 由所在平台决定其精度的整数(一般为int32或int64)
int8 整数,范围为128至127
int16 整数,范围为32 768至32 767
int32 整数,范围为-2exp31~2exp31-1
int64 整数,范围为-2exp63~2exp63-1
uint8 无符号整数,范围为0至255
uint16 无符号整数,范围为0至65 535
uint32 无符号整数,范围为0至2exp32-1
uint64. 无符号整数,范围为0至2exp64-1
float16 半精度浮点数(16位):其中用1位表示正负号,5位表示指数,10位表示尾数
float32 单精度浮点数(32位):其中用1位表示正负号,8位表示指数,23位表示尾数
float64或float 双精度浮点数(64位):其中用1位表示正负号,11位表示指数,52位表示尾数
complex64 复数,分别用两个32位浮点数表示实部和虚部
complex128或complex. 复数,分别用两个64位浮点数表示实部和虚部
在NumPy中,许多函数的参数中可以指定数据类型,通常这个参数是可选的:
>>> arange(7,dtype= uint16)
array([0, 1, 2, 3, 4, 5, 6], dtype=uint16)
数据类型对象
数据类型对象是numpy.dtype类的实例。如前所述,NumPy数组是有数据类型的,更确切 地说,NumPy数组中的每一个元素均为相同的数据类型。
数据类型对象可以给出单个数组元素在 内存中占用的字节数,即dtype类的itemsize属性:
>>> a=array([[1,2],[3,4]])
>>> a.dtype.itemsize
8
>>> a =arange(7,dtype= uint16)
>>> a.dtype.itemsize
2
字符编码.
整数 i
无符号整数 u
单精度浮点数 f
双精度浮点数 d
布尔值 b
复数 D
字符串 S
unicode字符串 U
void (空) V
>>> from numpy import *
>>> arange(7,dtype('D'))
Traceback (most recent call last): File "", line 1,
in TypeError: unsupported operand type(s) for -: 'numpy.dtype' and 'int'
>>> arange(7,dtype='D')
array([ 0.+0.j, 1.+0.j, 2.+0.j, 3.+0.j, 4.+0.j, 5.+0.j, 6.+0.j])
>>> arange(7,dtype='f')
array([ 0., 1., 2., 3., 4., 5., 6.], dtype=float32)
dtype类的属性 获取数据类型的字符编码 数组元素的数据类型 str属性可以给出数据类型的字符串表示,该字符串的首个字符表示字节序(endianness), 后面如果还有字符的话,将是一个字符编码,接着一个数字表示每个数组元素存储所需的字节数。 这里,字节序是指位长为32或64的字(word)存储的顺序,包括大端序(big-endian)和小端序 (little-endian)。大端序是将最高位字节存储在最低的内存地址处,用>表示;与之相反,小端序 是将最低位字节存储在最低的内存地址处,用<表示
>>> t=dtype('Float64')
>>> t.char
'd'
>>> t.type <type 'numpy.float64'>
>>> t.str
'<f8'
1.2 创建自定义数据类型
自定义数据类型是一种异构数据类型,可以当做用来记录电子表格或数据库中一行数据的结 构。 我们用一个长度为40个字 符的字符串来记录商品名称,用一个32位的整数来记录商品的库存数量,最后用一个32位的单精 度浮点数来记录商品价格。下面是具体的步骤。
>>> t = dtype([('name',str,40),('numitems',int32),('price',float32)])
>>> t dtype([('name', 'S40'), ('numitems', '<i4'), ('price', '<f4')])
>>> t['name'] dtype('S40')
>>> itemz=array([('python',40,3.333),('php',333,2.22)],dtpye=t)
Traceback (most recent call last): File "", line 1, in
TypeError: 'dtpye' is an invalid keyword argument for this function
>>> itemz=array([('python',40,3.333),('php',333,2.22)],dtype=t)
>>> itemz[1]
('php', 333, 2.2200000286102295)
我们创建了一种自定义的异构数据类型,该数据类型包括一个用字符串记录的名字、一个用 整数记录的数字以及一个用浮点数记录的价格。
1.3索引和切片
一维数组的索引和切片
用下标3~7来选取元素3~6 下标0~7,以2为步长选取元素 利用负数下标翻转数组
>>> a =arange(9)
>>> a[3:7]
array([3, 4, 5, 6])
>>> a[:7:2]
array([0, 2, 4, 6])
>>> a[::-1]
array([8, 7, 6, 5, 4, 3, 2, 1, 0])
多维数组的切片和索引
ndarray支持在多维数组上的切片操作。为了方便起见,我们可以用一个省略号(...)来表示遍历剩下的维度。
我们先用arange函数创建一个数组并改变其维度,使之变成一个三维数组:
>>> a=arange(24).reshape(2,3,4)
>>> a.shape (2, 3, 4)
>>> a
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]
]])
我们可以形象地把它 看做一个两层楼建筑,每层楼有12个房间,并排列成3行4列 各种方法对一个NumPy多维数组进行了切片操作:
选取第1层楼的所有房间
>>> a[0]
array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])
我们还可以这样写,选取第1层楼的所有房间
>>> a[0,:,:]
array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])
多个冒号可以用一个省略号(...)来代替
>>> a[0,...]
array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])
进而可以选取第1层楼、第2排的所有房间
>>> a[0,1]
array([4, 5, 6, 7])
再进一步,我们可以在上面的数组切片中间隔地选定元素
>>> a[0,1,::2]
array([4, 6])
我们可以选取所有位于第2行的房间,而不指定楼层和列号
>>> a[:,1]
array([[ 4, 5, 6, 7], [16, 17, 18, 19]])
如果要选取第1层楼的所有位于第2列的房间,在对应的两个维度上指定即可
>>> a[0,:,1]
array([1, 5, 9])
如果要选取第1层楼的最后一列的所有房间,使用如下代码
>>> a [0,:,-1]
array([ 3, 7, 11])
如果要反向选取第1层楼的最后一列的所有房间,使用如下代码
>>> a[0,::-1,-1]
array([11, 7, 3])
在该数组切片中间隔地选定元素:
>>> a[0,::2,-1]
array([ 3, 11])
如果在多维数组中执行翻转一维数组的命令,将在最前面的维度上翻转元素的顺序,
在我们 的例子中将把第1层楼和第2层楼的房间交换:
>>> a[::-1]
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.4改变数组的维度
已经学习了怎样使用reshape函数,现在来学习一下怎样将数组展平 ravel
我们可以用ravel函数完成展平的操作
>>> a
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]]])
>>> a.ravel()
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]) f
latten 这个函数恰如其名,flatten就是展平的意思,与ravel函数的功能相同。不过,flatten函数会请求分配内存来保存结果,而ravel函数只是返回数组的一个视图(view) >>> a.flatten()
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])
用元组设置维度 除了可以使用reshape函数,我们也可以直接用一个正整数元组来设置数组的维度
>>> a.shape=(6,4)
>>> a
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成了一个6×4的多维数组。
transpose 在线性代数中,转置矩阵是很常见的操作。
>>> a.transpose()
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]])
1.5数组的组合
NumPy数组有水平组合、垂直组合和深度组合等多种组合方式,我们将使用vstack、 dstack、hstack、column_stack、row_stack以及concatenate函数来完成数组的组合。
组合数组:
>>> a=arange(9).reshape(3,3)
>>> a
array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
>>> b=2*a
>>> b
array([[ 0, 2, 4], [ 6, 8, 10], [12, 14, 16]])
水平组合 我们先从水平组合开始练习。将ndarray对象构成的元组作为参数,传给 hstack函数。
>>> c=hstack((a,b))
>>> c
array([[ 0, 1, 2, 0, 2, 4], [ 3, 4, 5, 6, 8, 10], [ 6, 7, 8, 12, 14, 16]])
也可以用concatenate函数来实现同样的效果
>>> d=concatenate((a,b),axis=1)
>>> d
array([[ 0, 1, 2, 0, 2, 4], [ 3, 4, 5, 6, 8, 10], [ 6, 7, 8, 12, 14, 16]])
垂直组合
垂直组合同样需要构造一个元组作为参数,只不过这次的函数变成了 vstack。
>>> e=vstack((a,b))
>>> e
array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 0, 2, 4], [ 6, 8, 10], [12, 14, 16]])
我们将concatenate函数的axis参数设置为0即可实现同样的效果。这也是axis参 数的默认值:
>>> f=concatenate((a,b),axis=0)
>>> f
array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 0, 2, 4], [ 6, 8, 10], [12, 14, 16]])
深度组合 将相同的元组作为参数传给dstack函数,即可完成数组的深度组合。
深度组合,就是将一系列数组沿着纵轴(深度)方向进行层叠组合。 举个例子,有若干张二维平面内的图像点阵数据,我们可以将这些图像数据沿纵轴方向层叠在一起,这就形象地解释了什么 是深度组合。
>>> g=dstack((a,b))
>>> g
array([[[ 0, 0], [ 1, 2], [ 2, 4]], [[ 3, 6], [ 4, 8], [ 5, 10]], [[ 6, 12], [ 7, 14], [ 8, 16]]])
列组合
column_stack函数对于一维数组将按列方向进行组合,而对于二维数组,column_stack与hstack的效果是相同的
>>> h=column_stack((a,b))
>>> h
array([[ 0, 1, 2, 0, 2, 4], [ 3, 4, 5, 6, 8, 10], [ 6, 7, 8, 12, 14, 16]])
行组合
当然,NumPy中也有按行方向进行组合的函数,它就是row_stack。
对于两个一维数组,将直接层叠起来组合成一个二维数组。对于二维数组,row_stack与vstack的效果是相同的.
>>> i=row_stack((a,b))
>>> i
array([[ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 0, 2, 4], [ 6, 8, 10], [12, 14, 16]])
1.6数组的分割
>>> a=arange(9).reshape(3,3)
>>> a
array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
水平分割
下面的代码将把数组沿着水平方向分割为3个相同大小的子数组:
>>> hsplit(a,3)
[array([[0], [3], [6]]), array([[1], [4], [7]]), array([[2], [5], [8]])]
对同样的数组,等同调用split函数并在参数中指定参数axis=1
>>> split(a,3,axis=1)
[array([[0], [3], [6]]), array([[1], [4], [7]]), array([[2], [5], [8]])]
垂直分割 vsplit函数将把数组沿着垂直方向分割:
>>> vsplit(a,3)
[array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
调用split函数并在参数中指定参数axis=0,也可以得到同样的结果
>>> split(a,3,axis=0)
[array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]
深度分割
不出所料,dsplit函数将按深度方向分割数组。我们先创建一个三维数组
>>> c = arange(27).reshape(3, 3, 3)
>>> c
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]]])
>>> dsplit(c,3)
[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]]])]
1.7数组的属性
除了shape和dtype属性以外,ndarray对象还有很多其他的属性,在下面一一列出。
ndim属性,给出数组的维数,或数组轴的个数:
>>> a=arange(10).reshape(2,5)
>>> a
array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
>>> a.ndim
2
size属性,给出数组元素的总个数,如下所示:
>>> a.size
10
itemsize属性,给出数组中的元素在内存中所占的字节数:
>>> a.itemsize
8
如果你想知道整个数组所占的存储空间,可以用nbytes属性来查看。这个属性的值是itemsize和size属性值的乘积:
>>> a.nbytes
80
T属性的效果和transpose函数一样,如下所示:
>>> a.T
array([[0, 5], [1, 6], [2, 7], [3, 8], [4, 9]])
在NumPy中,复数的虚部是用j表示的。例如,我们可以创建一个由复数构成的数组:
>>> b=array([1.j+1,2.j+3])
>>> b
array([ 1.+1.j, 3.+2.j])
real属性,给出复数数组的实部。如果数组中只包含实数元素,则其real属性将输出原 数组:
>>> b.real
array([ 1., 3.])
imag属性,给出复数数组的虚部:
>>> b.imag
array([ 1., 2.])
如果数组中包含复数元素,则其数据类型自动变为复数型:
>>> b.dtype
dtype('complex128')
>>> b.dtype.str '<c16'
flat属性将返回一个numpy.flatiter对象,这是获得flatiter对象的唯一方式——我 们无法访问flatiter的构造函数。这个所谓的“扁平迭代器”可以让我们像遍历一维数 组一样去遍历任意的多维数组
>>> c=arange(9).reshape(3,3)
>>> c array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
>>> c.flat
>>> d =c.flat
>>> d
>>> for item in d : print item ...
0 1 2 3 4 5 6 7 8
我们还可以用flatiter对象直接获取一个数组元素:
>>> d[3]
3
1.8 数组的转换
使用tolist函数将NumPy数组转换成Python列表。
>>> c
array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
>>> c.tolist
>>> c.tolist()
[[0, 1, 2], [3, 4, 5], [6, 7, 8]]
astype函数可以在转换数组时指定数据类型:
>>> c.astype(float)
array([[ 0., 1., 2.], [ 3., 4., 5.], [ 6., 7., 8.]])