python中的固定类型数组
python提供的内置的数组array模块可以用于创建同一类型的密集数组
1 import array 2 3 l = list(range(10)) 4 5 a = array.array("i", l) 6 7 a 8 Out[20]: array('i', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
这里的 'i' 是一个数据类型码,表示数据为整型
更实用的是Numpy包中的ndarray对象
python的数组对象提供了数组型数据的有效存储,而Numpy为该数据加上了高效的操作
1 import numpy as np
从Python列表创建数组
1 import numpy as np 2 3 np.array([1,4,5,2,3]) 4 Out[24]: array([1, 4, 5, 2, 3])
注意:不同于python列表,Numpy要求数组必须包含同一类型的数据
若类型不匹配,Numpy将会向上转移(如果可行),这里的整型被转换为浮点型:
1 np.array([3.14, 4, 2 ,3]) 2 Out[25]: array([3.14, 4. , 2. , 3. ])
如果希望明确设置数组的数据类型,可以用dtype关键字:
1 np.array([1,2,3,4], dtype="float32") 2 Out[26]: array([1., 2., 3., 4.], dtype=float32)
Numpy数组可以被指定为多维的
1 # 嵌套列表构成的多维数组 2 3 np.array([range(i, i+3) for i in [2,4,6]]) 4 Out[28]: 5 array([[2, 3, 4], 6 [4, 5, 6], 7 [6, 7, 8]])
从头创建数组
1 # 创建一个长度为10的数组,数组值都为0 2 3 np.zeros(10, dtype=int) 4 Out[30]: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) 5 6 # 创建一个 3 * 5 的浮点型数组,数组的值都为1 7 8 np.ones((3, 5), dtype=float) 9 Out[32]: 10 array([[1., 1., 1., 1., 1.], 11 [1., 1., 1., 1., 1.], 12 [1., 1., 1., 1., 1.]]) 13 14 # 创建一个 3 * 5 的浮点型数组,数组的值都是3.14 15 16 np.full((3, 5), 3.14) 17 Out[34]: 18 array([[3.14, 3.14, 3.14, 3.14, 3.14], 19 [3.14, 3.14, 3.14, 3.14, 3.14], 20 [3.14, 3.14, 3.14, 3.14, 3.14]]) 21 22 # 创建一个线性序列数组;\ 23 # 从0开始,到20结束,步长为2 24 # (它的内置的range函数类似) 25 26 np.arange(0, 20, 2) 27 Out[38]: array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18]) 28 29 # 创建一个5个元素的数组,这5个数均匀地分配到0-1 30 31 np.linspace(0, 1, 5) 32 Out[40]: array([0. , 0.25, 0.5 , 0.75, 1. ]) 33 34 # 创建一个 3 * 3 的,在0-1均匀分布的随机数组成的数组 35 36 np.random.random((3,3)) 37 Out[43]: 38 array([[0.7019541 , 0.00787364, 0.41495839], 39 [0.13411158, 0.95440426, 0.99184209], 40 [0.32671128, 0.80212981, 0.35702935]]) 41 42 # 创建一个3 * 3的,均值为0,标准差为1正态分布的随机数数组 43 44 np.random.normal(0, 1, (3, 3)) 45 Out[45]: 46 array([[-0.76169057, -0.74273207, 0.19062862], 47 [ 0.422799 , -0.94405275, -0.33567806], 48 [ 0.52447272, 1.55895324, -0.49119638]]) 49 50 # 创建一个 3 * 3 的,[0, 10)区间的随机整型数组 51 52 np.random.randint(0, 10, (3, 3)) 53 Out[47]: 54 array([[9, 2, 5], 55 [4, 0, 4], 56 [9, 8, 5]]) 57 58 # 创建一个 3*3的单位矩阵 59 60 np.eye(3) 61 Out[49]: 62 array([[1., 0., 0.], 63 [0., 1., 0.], 64 [0., 0., 1.]]) 65 66 # 创建一个由三个整型组成的未初始化的数组 67 # 数组的值是内存空间的任意值 68 69 np.empty(3) 70 Out[52]: array([1., 1., 1.])
Numpy标准数据类型
Numpy数组包含同一类型的值,因此详细了解数据类型及其限制是非常重要的
Numpy是在C语言基础上开发的,因此运用的都是C语言的数据类型
1 np.zeros(10, dtype='int16') 2 Out[53]: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int16) 3 4 np.zeros(10, dtype=np.int16) #用numpy对象来指定 5 Out[54]: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int16)
二、Numpy数组操作
1.数组的属性:确定数组的大小,形状,存储大小,数据类型
2.数组的索引:获取和设置数组各个元素的值
3.数组的切分:在大的数组中获取或设置更小的子数组
4.数组的变形:改变给定数组的形状
5.数组的拼接和分裂:将多个数组合并为一,以及将一个数组分裂成多个
Numpy数组的属性
定义三个随机数组:一个一维数组,一个二维数组,一个三维数组,将Numpy的随机数生成器设置一组种子值,以确保每次程序执行时都可以生成相同的数组
1 import numpy as np 2 3 np.random.seed(0) # 设置随机数种子 4 5 x1 = np.random.randint(10, size=6) # 一维数组 6 7 x2 = np.random.randint(10, size=(3, 4)) # 二维数组 8 9 x3 = np.random.randint(10, size=(3, 4, 5)) # 三维数组
每个数组有ndim(数组维度),shape(数组每个维度的大小),和size(数组的总大小)属性:
1 print("x1 nidm:", x1.ndim) 2 x1 nidm: 1 3 4 print("x3 shape:", x3.shape) 5 x3 shape: (3, 4, 5) 6 7 print("x2 size:", x3.size) 8 x2 size: 60
另一个有用的属性dtype,数组的数据类型:
1 print("dtype:", x3.dtype) 2 dtype: int32
其他的属性包括表示每个数组元素字节大小的itemsize,以及表示数组总字节大小的属性nbytes:
1 print("itemsize:", x3.itemsize, "bytes") 2 itemsize: 4 bytes 3 4 print("nbytes:", x3.nbytes, "bytes") 5 nbytes: 240 bytes
一般来说,可以认为nbytes跟itemsize和size的乘积大小相等
Numpy数组索引:获取单个元素
与Python标准列表索引一样的使用方式
1 x1 2 Out[70]: array([5, 0, 3, 3, 7, 9]) 3 4 x1[0] 5 Out[71]: 5 6 7 x1[4] 8 Out[72]: 7
为获取数组末尾的索引,可以用负值索引:
1 x1[-1] 2 Out[73]: 9 3 4 x1[-2] 5 Out[74]: 7
在多维数组中,可以使用逗号分隔的索引元组获取元素
1 x2 2 Out[75]: 3 array([[3, 5, 2, 4], 4 [7, 6, 8, 8], 5 [1, 6, 7, 7]]) 6 7 x2[0,0] 8 Out[76]: 3 9 10 x2[2,0] 11 Out[77]: 1 12 13 x2[2,-1] 14 Out[78]: 7
可以用以上索引方式修改元素值
1 x2[0,0] = 12 2 3 x2 4 Out[80]: 5 array([[12, 5, 2, 4], 6 [ 7, 6, 8, 8], 7 [ 1, 6, 7, 7]])
与python列表不同,Numpy数组是固定的类型,当插入一个浮点型到整型数组中去,浮点值会被截短成整形,这种方式是自动完成的,不会提示或者警告,所以需要注意
1 x1[0] = 3.1415926 2 3 x1 4 Out[82]: array([3, 0, 3, 3, 7, 9])
Numpy数组切片:获取子数组
正如前面使用中括号获取数组单个元素,我们也可以使用切片符号获取子数组,切片符号用冒号(:)表示
Numpy切片语法和python列表的标准切片语法相同
1 x[start:stop:step]
默认值start = 0,stop = 维度的大小(size of dimension)和step = 1
1.一维子数组
1 x = np.arange(10) 2 3 x 4 Out[8]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 5 6 x[:5] # 前五个元素 7 Out[9]: array([0, 1, 2, 3, 4]) 8 9 x[5:] # 索引5之后的元素 10 Out[10]: array([5, 6, 7, 8, 9]) 11 12 x[4:7] # 中间的子数组 13 Out[11]: array([4, 5, 6]) 14 15 x[::2] # 每隔一个元素 16 Out[12]: array([0, 2, 4, 6, 8]) 17 18 x[1::2] # 每隔一个元素,从索引1开始 19 Out[13]: array([1, 3, 5, 7, 9]) 20 21 x[::-1] # 所有元素,逆序的 22 Out[14]: array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0]) 23 24 x[5::-2] # 从索引5开始每隔一个元素逆序 25 Out[15]: array([5, 3, 1])
2.二维子数组
多维切片也采用同样的方式处理,用逗号隔开
1 x2 = np.random.randint(10,size=(3,4)) 2 3 x2 4 Out[17]: 5 array([[4, 1, 4, 2], 6 [6, 7, 3, 9], 7 [8, 7, 3, 9]]) 8 9 x2[:2, :3] # 两行,三列 10 Out[18]: 11 array([[4, 1, 4], 12 [6, 7, 3]]) 13 14 x2[:3, ::2] # 所有行,每每隔一列 15 Out[19]: 16 array([[4, 4], 17 [6, 3], 18 [8, 3]]) 19 20 x2[::-1,::-1] # 逆序 21 Out[20]: 22 array([[9, 3, 7, 8], 23 [9, 3, 7, 6], 24 [2, 4, 1, 4]])
3.获取数组的行和列
常见的需求是获取数组的单行和单列,可以将索引和切片结合起来实现,用一个冒号(:)表时空切片
1 x2 2 Out[21]: 3 array([[4, 1, 4, 2], 4 [6, 7, 3, 9], 5 [8, 7, 3, 9]]) 6 7 print(x2[:, 0]) # x2的第一行 8 [4 6 8] 9 10 print(x2[0, :]) # x2的第一列 11 [4 1 4 2] 12 13 print(x2[0]) # 可以省略空的切片,效果一样 14 [4 1 4 2]
4.非副本视图的子数组
python列表中,切片是值的副本
与python列表切片不同,数组切片返回的是数组数据的视图,而不是数值数据的副本
1 x2 2 Out[30]: 3 array([[4, 1, 4, 2], 4 [6, 7, 3, 9], 5 [8, 7, 3, 9]]) 6 7 x2_sub = x2[:2, :2] 8 9 print(x2_sub) 10 [[4 1] 11 [6 7]] 12 13 x2_sub[0, 0] = 99 # 修改子数组 14 15 print(x2_sub) 16 [[99 1] 17 [ 6 7]] 18 19 x2 # 原始数组也被修改了 20 Out[35]: 21 array([[99, 1, 4, 2], 22 [ 6, 7, 3, 9], 23 [ 8, 7, 3, 9]])
5.创建数组的副本
复制数组里的数据或子数组可以通过copy( )方法实现
1 x2_sub_copy = x2[:2, :2].copy() 2 3 print(x2_sub_copy) 4 [[99 1] 5 [ 6 7]] 6 7 x2_sub_copy[0, 0] = 42 # 子数组的元素被修改 8 9 print(x2_sub_copy) 10 [[42 1] 11 [ 6 7]] 12 13 x2 # 原始数组对应元素不发生变化 14 Out[40]: 15 array([[99, 1, 4, 2], 16 [ 6, 7, 3, 9], 17 [ 8, 7, 3, 9]])
数组的变形
通过reshape( )函数来实现数组变形
例如:将数字1~9放入到3 * 3 矩阵中,可以采用以下方法:
1 grid = np.arange(1,10).reshape((3, 3)) 2 3 print(grid) 4 [[1 2 3] 5 [4 5 6] 6 [7 8 9]]
注意:若希望此方法可行,那么原始数组大小必须和变型后的数组大小一致,如果满足,reshape方法将会用到原始数组的一个非副本视图
另一个变形模式是将一个一维数组转变为二维的行或列的矩阵,也可以通过reshape方法实现或者简单地在一个切片操作中利用newwaxis关键字
1 x = np.array([1,2,3]) 2 3 x.reshape((1, 3)) # 通过变型获得的行向量 4 Out[52]: array([[1, 2, 3]]) 5 6 x[np.newaxis, :] # 通过newaxis获取的行向量 7 Out[53]: array([[1, 2, 3]]) 8 9 x.reshape((3, 1)) # 通过变型获得的列向量 10 Out[54]: 11 array([[1], 12 [2], 13 [3]]) 14 15 x[:, np.newaxis] # 通过newaxis获取的列向量 16 Out[56]: 17 array([[1], 18 [2], 19 [3]])
数组拼接和分裂
以上所有的操作都是针对的单一数组的,但有时候需要将多个数组合并为一个,或将一个数组分裂成多个。
1.数组的拼接
拼接或连接Numpy中的两个数组主要是由np.concatenate、np.vstack和np.hstack例程实现
np.concatenate 将数组元组或者数组列表作为第一个参数:
1 x = np.array([1,2,3]) 2 3 y = np.array([3,2,1]) 4 # np.concatenate 将数组元组或者数组列表作为第一个参数 5 np.concatenate([x, y]) 6 Out[60]: array([1, 2, 3, 3, 2, 1]) 7 8 np.concatenate((x, y)) 9 Out[61]: array([1, 2, 3, 3, 2, 1]) 10 11 z = [99, 99, 99] 12 # 一次性拼接两个以上的数组 13 print(np.concatenate([x, y, z])) 14 [ 1 2 3 3 2 1 99 99 99] 15 16 # np.concatenate应用于二维数组的拼接 17 grid = np.array([[1,2,3],[4, 5, 6]]) 18 19 #沿第一个轴拼接 20 np.concatenate([grid,grid]) 21 Out[65]: 22 array([[1, 2, 3], 23 [4, 5, 6], 24 [1, 2, 3], 25 [4, 5, 6]]) 26 # 沿着第二个轴拼接(从0开始索引) 27 np.concatenate([grid, grid], axis=1) 28 Out[67]: 29 array([[1, 2, 3, 1, 2, 3], 30 [4, 5, 6, 4, 5, 6]])
沿着固定维度处理数组时,使用np.vstack(垂直栈)和np.hstack(水平栈)函数更简洁:
1 x = np.array([1,2,3]) 2 3 grid = np.array([[9,8,7],[6,5,4]]) 4 5 #垂直栈数组 6 np.vstack([x, grid]) 7 Out[70]: 8 array([[1, 2, 3], 9 [9, 8, 7], 10 [6, 5, 4]]) 11 12 y = np.array([[99],[99]]) 13 14 #水平栈数组 15 np.hstack([grid, y]) 16 Out[72]: 17 array([[ 9, 8, 7, 99], 18 [ 6, 5, 4, 99]])
与此类似,np.dstack将沿着第三个维度拼接数组
2.数组的分裂
与拼接相反的是分裂
分裂通过np.split、np.hsplit、np.vsplit函数实现
可以向以上函数传递一个索引列表作为参数,索引列表记录的是分裂点位置
1 x = [1,2,3,99,99,3,2,1] 2 3 x1,x2,x3 = np.split(x, [3, 5]) 4 5 print(x1,x2,x3) 6 [1 2 3] [99 99] [3 2 1]
值得注意的是N个分裂点会得到N+1个子数组
1 grid = np.arange(16).reshape((4,4)) 2 3 grid 4 Out[78]: 5 array([[ 0, 1, 2, 3], 6 [ 4, 5, 6, 7], 7 [ 8, 9, 10, 11], 8 [12, 13, 14, 15]]) 9 10 upper, lower = np.vsplit(grid, [2]) 11 12 print(upper) 13 [[0 1 2 3] 14 [4 5 6 7]] 15 16 print(lower) 17 [[ 8 9 10 11] 18 [12 13 14 15]] 19 20 left, right = np.hsplit(grid, [2]) 21 22 print(left) 23 [[ 0 1] 24 [ 4 5] 25 [ 8 9] 26 [12 13]] 27 28 print(right) 29 [[ 2 3] 30 [ 6 7] 31 [10 11] 32 [14 15]]
同样,np.dsplit将数组沿着第三个维度分裂