Professional Documents
Culture Documents
1.Numpy简介
ndarray:
2.数组的创建:
2.1 从Python的序列容器创建数组
数组有以下常用属性:
维度: arr_2d.ndim # 2
形状: arr_2d.shape # (2,3) 是各维度拥有元素个数组成的元组
元素总数: arr_2d.size # 6
元素数据类型: arr_2d.dtype # int32
2.2使用numpy预置的函数创建数组
前注:
NumPy 创建数组的函数一般还可接受名为 dtype 的参数,用于指定元素的数据类型。可选的类型可以参见此链接。例如:
2.2.1 一维数组创建函数
arange(start=0, stop, step=1) : 类似于 python 中的 range ,创建以 start 起(含)至 stop (不含),步长为 step
(可以为负,代表从后向前列) 的数组。最后的参数dtype若不指定,由系统自动推断
NOTICE:注意是 arange 不是 arrange (这个函数名经常搞错)
linspace(start, stop, num=50, endpoint=True) : 创建从 start 开始(含)至 stop (是否包含取决于 endpoint ),由
num 个均匀散布(线性空间中均匀分布)的元素组成的数组。
logspace(start, stop, num=50, endpoint=True, base=10.0) : 创建从 base ** start 开始(含)至 base ** stop 结束
(是否包含取决于 endpoint ),由 num 个在对数尺度上均匀散布的元素组成的数组。(也就是对num线性)
print(np.arange(3)) # [0 1 2]
print(np.arange(1, 7, 2)) # [1 3 5]
print(np.arange(10, 0, -2)) # [10 8 6 4 2]
print(np.linspace(0, 50, 5, endpoint=True)) # [ 0. 12.5 25. 37.5 50. ]
print(np.logspace(0, 3, 4)) # [ 1. 10. 100. 1000.]
2.2.2 二维数组创建函数
常用的二维数组创建函数包括:
np.eye(3,4) # array([ [1., 0., 0., 0.] , [0., 1., 0., 0.] , [0., 0., 1., 0.] ])
print(np.diag([1,2,3])) # [[1 0 0] [0 2 0] [0 0 3]]
print( np.diag( (1,2,3) ) ) # [[1 0 0] [0 2 0] [0 0 3]]
print( np.diag( range(1,3) ) ) # [[1 0] [0 2]]
2.2.3通用数组创建函数
该类函数在创建数组时,通常需要指定数组的形状,或者给定一个参考数组。常见的通用数组创建函数包括:
PS:注意到直接把数组写出来元素之间带逗号,前面还有格式 array
但用print打印出来就没有逗号
3.数组的索引
3.1切片
PS:可以使用reshape()函数改变数组形状
arr = np.arange(11, 36).reshape((5, 5))
print(arr[0, 1:4]) # 注意维度变化,原来的第 0 维被压缩了
print(arr[1:4, 0]) # 注意维度变化,原来的第 1 维被压缩了
print(arr[::2, ::2]) # 指定步长
print(arr[:, 1]) # 第 0 维全选
'''
第一个切片`a[ 0 , 1:4 ]`是只对第一行切片(第一个参数指行数),`1:4`是从第二个到第五个(不含第五个)
第二个切片和第一个正好相反
第三个切片`a[ : : 2 , : : 2 ]`是对列和行都进行从头到尾(含尾)步长为2的切片
第四个`a[ : , 1 ]`是只取第一列,行数全取
'''
注意!通过切片选择返回的数组是原始数组的一个视图 (view),并未发生数据的拷贝。在视图上做的修改都会反馈到原始数组
上。比如:
用 ndarray.copy或copy 完成对数组数据的深拷贝
# arr还是[[1 9 3] [4 5 6]]
view = arr[:, 1].copy()
view[0] = 7
print(arr) # [[1 9 3] [4 5 6]] view的改变对arr没有任何影响
3.2 整数数组索引
我们可以使用整数数组进行索引。通过为每一个维度提供一个坐标数组,可以选取任意位置的元素。此时返回的数组不再是一个
view 了。(相当于经过了一次copy)
3.3布尔数组索引
4.数组的运算
4.1算数运算
x = np.array([[1,2],[3,4]], dtype=np.float32)
y = np.array([[5,6],[7,8]], dtype=np.float32)
print(x + y) # np.add(x, y)
# [[ 6. 8.] [10. 12.]]
print(x * y) # np.multiply(x, y)
# [[ 5. 12.] [21. 32.]]
print(x / y) # np.divide(x, y)
# [[0.2 0.33333334]
[0.42857143 0.5 ]] (写成两行的形式更容易分辨)
print(x ** 2) # np.power(x, 2)
# [[ 1. 4.] [ 9. 16.]]
补充:BroadCasting(广播机制)
x = np.arange(8).reshape((2, 2, 2))
y = np.array([[10, 20], [30, 40]])
print(x)
print(x + y) # 小数组广播为大数组(2*2*2的数组)
# x= [ [[0 1] [2 3]]
[[4 5] [6 7]] ]
x+y = [ [[10 21] [32 43]]
[[14 25] [36 47]] ]
m = np.random.randn(8, 1, 6, 1)
n = np.random.randn(7, 1, 5)
print(m.shape)
print(n.shape)
print((m + n).shape) # 一般广播规则:维度从后往前匹配,维度兼容的条件:相等或其中1个是1
# (8, 1, 6, 1) (7, 1, 5) (8, 7, 6, 5) # (7,1,5)也可看成(7,1,5,1)
k = np.random.randn(8, 1, 6, 6)
l = np.random.randn(7, 1, 5)
print((k+l).shape) # 不满足一般广播规则,在最后一维失配,会报错
一般广播规则:维度从后往前匹配,维度兼容的条件:相等或其中1个是1(只有是1才能复制扩充,否则就不知道应该怎么扩充,
因此会报错)
4.2常用数学函数
4.2.1 单点运算
NumPy 中预置了例如求绝对值、(反)三角函数、(反)双曲函数、指数、对数、取整、截断等常用函数,这些函数也都是逐元
素运算的。下面是一些示例:
4.2.2 统计量
sum : 求和。
prod : 求积。
mean : 求均值。
std : 求标准差。
var : 求方差。
amax : 求最大值。也可以通过 max 调用。
amin : 求最小值。也可以通过 min 调用。
例如:
4.3 向量、矩阵运算
前面提到,数组的 * 运算为逐元素相乘,并不是矩阵乘法。对于矩阵乘法,应当使用 @ 运算符,或者 matmul 函数。当两
个数组都是二维时,也可以使用 dot 。
x = np.array([[1,2],[3,4]], dtype=np.float32)
y = np.array([[5,6],[7,8]], dtype=np.float32)
x @ y # equivalent to `np.matmul(x, y)`
# array([[19., 22.], [43., 50.]], dtype=float32)
x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
print(np.cross(x,y)) # [-3 6 -3]
x = np.array([1, 1])
print(np.linalg.norm(x)) # 求向量 x 的2范数 1.4142135623730951
y = np.array([[1, 2], [3, 4]])
print(np.linalg.norm(y, axis=1)) # 求 y 的每一行的2范数
使用 linalg.inv 求矩阵的逆。
x = np.array([[1,2],[3,4]], dtype=np.float32)
y = np.linalg.inv(x)
print(y) # [[-2. 1. ] [ 1.5 -0.5]]
print(np.matmul(x, y)) # [[1. 0.] [0. 1.]] 验证确实是逆矩阵
4.4排序和查找
4.4.1 排序
排序常用的函数是:
z =np.array([[1,2,3],[0,1,2]])
print(np.argsort(z)) # [[0 1 2] [0 1 2]]
# 第一个[0 1 2]表示第一行就是按从小到大排列的,因为没有指定axis,默认是从最后一维(在这里是第1维,也就是行)第二个同理
print(np.argsort(z, axis=0)) # [[1 1 1] [0 0 0]]
# 对列排列,结果也要从列来看,每一列都是[1 0]说明每一列都是从大到小排列,所以需要反过来排列
x = [[0 3] [4 2]]
print(np.take_along_axis(x, np.argsort(x, axis=0), axis=0)) # [[0 2] [4 3]]
NOTICE:
如果axis=None,会对所有元素进行排序
print(np.argsort(x,axis=None)) # [0 3 1 2]
我们发现,对所有元素进行排序返回的索引是一个一维数组,这是因为原数组在排序时被展平为了一个一维数组。那么如何根据这
个索引得到元素在原数组中的多维的索引呢?这里需要用到 unravel_index(indices, shape) 函数。输入一维索引数组和原数组
的形状,该函数会将一维索引转换为多维索引。(返回多个一维数组,代表了原数组各个维度上的索引)
4.4.2 查找
常用的查找函数包括:
5.数组的操作
5.1 改变数组形状:
指定变化:
x = np.array([[1], [2]])
print(x, x.shape) # [[1] [2]] (2, 1)
y = x.squeeze(1)
print(y, y.shape) # [1 2] (2,)
z = np.expand_dims(x, axis=0)
print(z, z.shape) # [[[1] [2]]] (1, 2, 1) (2,1) --> (1,2,1) 前面增加了一维
NOTICE:添加的新维度的值都是1
5.2转置
x = np.arange(6).reshape((1, 2, 3))
print(x, x.shape) # [[[0 1 2] [3 4 5]]] (1, 2, 3)
y = x.transpose((1, 2, 0)) # (0,1,2)是原本正常的维度顺序,1,2,0就是维度全部前移一位
print(y, y.shape) # [[[0] [1] [2]] [[3] [4] [5]]] (2, 3, 1)
5.3改变数据类型
ndarray.astype(dtype) : 复制并转换数组到指定的数据类型。
5.4 数组的拼接与堆叠
6. 数组的文件I/O
有时,我们需要将某个数组保存到文件,或是从文件中读取数组。通常使用如下函数:
x = np.random.random((2, 2))
print(x)
np.save('x.npy', x)
x_loaded = np.load('x.npy')
print(x_loaded)
y = np.random.random((2, 2))
print(y)
np.savez('arrays.npz', x=x, y=y)
# x=x 的意思是将数组 x 保存为关键字 'x' 。
data = np.load('arrays.npz')
x_loaded, y_loaded = data['x'], data['y'] # 使用'x'作为关键词参数引用data中的x数组
print(x_loaded)
print(y_loaded)
# 综上,`x=x` 在 `np.savez` 函数调用中指定了保存数组时的关键字,而在加载 `.npz` 文件时使用 `'x'`(作为字符串)来引用这个关键字
并检索相应的数组。