1.Numpy介绍
1.介绍
Numpy是一个非常常见的库,之前我们学习过如何用它来表示矩阵。Numpy是非常的方便的一个库,可以通过它轻松地解决傅里叶变换,以及概率论还有线性代数的计算。如果你之前已经安装了Anaconda,那么理论上Numpy库已经被创建在你的Anaconda里面了,需要使用的时候直接import numpy就行,如果没有也只需要在终端pip install numpy(失败就用conda install numpy)即可。同时,我们总是习惯在import的时候,给numpy起个别称np,方便写代码,像这样:
import numpy as np
2.基本运算单位
就像我们之前学习的pytorch库的基本运算单位是tensor一样,凡是涉及到计算的库,我们如果想要学好它,就需要先学习它的基本单位是什么,我们才知道如何去定义变量进行计算。
在Numpy中,其基本运算单位是Ndarray,定义方法和python的数组没有什么区别,但是python数组允许每个数据的类型不一致,Ndarray则要求每个数据的类型必须是相同的。
3.创建Ndarray数组
创建方式一点都不难,简单到爆炸,因为和我们平时创建普通数组的方法没有任何区别。Ndarray数组的创建方式分为自定义和通过接口创建两种,我们依次介绍。
(1)自定义:自定义的话,我们需要先设置好自己的数组(或者元组)传入np.array()函数,但是要保证所有的数据类型都是一样的,不然会报错。例如
a = [0, 1, 2, 3, 4] # 可以是数组
b = (0, 1, 2, 3, 4) # 可以是元组
A = np.array(a)
B = np.array(b)
这里注意一下,无论你是用哪种形式创建的ndarray,最后类型都是一样的numpy.ndarray类型,所以A,B没有啥区别。
(2)通过接口来定义:
1
◯
\textcircled{1}
1◯np.zeros()函数,需要传入的参数依次有维度(不填默认为1),行数x列数,(这三个一起用元组表示),以及数据类型detype。注意一点,定义维度时,维度是最前面那个,比如4x3x3定义了4个3x3矩阵。举例:
Z = np.zeros((3,3),dtype=int) # 3x3的一个Int类型的0矩阵
Z2 = np.zeros((3,3,3),dtype=float) # 3个3x3float零矩阵(也可以说是3x3x3)
这里附上一个Z2的打印结果:
[
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
]
可以看到是由三个3x3的0矩阵组成的数组,所以可以称为3x3x3的0矩阵
2 ◯ \textcircled{2} 2◯np.ones()生成单位矩阵,用法同上。
O = np.ones((2, 2, 2),dtype=int) #一个2x2x2类型为Int的单位矩阵
3
◯
\textcircled{3}
3◯np,random随机数矩阵大家族,一共有四种,它们都不需要指定类型,因为它们的类型是固定的float(只有一个是int)。但是参数的传入方法不一样。
首先是np.random.rand()和np.random.randn()这两个函数。rand()生成(0,1)范围内的均匀分布随机数矩阵和randn()生成正太分布r的随机数矩阵。这两个的用法和上面不一样,它们只需要传入矩阵规模就行了(行数列数和每个单元数字的数目(每个单元数字的数目可以不填,默认为1))。这里解释一下,什么是每个单元的数字数目,其实前面的单位矩阵和零矩阵每个位置都只有一个数字,不是向量,但是随机矩阵这里是可以指定为向量来做单元的,这里给上例子和结果来理解:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a = np.random.rand(3, 3, 4) # (0,1)均匀分布的随机数
b = np.random.randn(4, 4) # 正太分布随机数
print(f"随机数矩阵1为:\n{a}")
print(f"正态分布的随机数矩阵为:\n{b}")
结果如下:
随机数矩阵1为:
[[[0.86652167 0.43213098 0.496585 0.14152115]
[0.56226326 0.04437779 0.69080454 0.00303111]
[0.96163042 0.35442079 0.13578848 0.69374048]]
[[0.58851887 0.95796226 0.92340012 0.02522456]
[0.0332563 0.22479247 0.69906303 0.95278404]
[0.68927253 0.73203166 0.72147201 0.9109623 ]]
[[0.81081839 0.98984553 0.3185658 0.42967656]
[0.7839857 0.85217938 0.10993794 0.59476716]
[0.32460013 0.98636237 0.29138712 0.44057259]]]
正态分布的随机数矩阵为:
[[ 0.79077707 -1.79275493 0.18175188 0.24232469]
[-0.16919466 -0.80757122 1.16894734 0.01578053]
[ 1.06789608 -0.13294504 0.79147516 -1.55178024]
[ 2.02420851 1.51457941 1.17272312 -0.6959131 ]]
其次是np,random.random(),它生成(0,1)范围内的随机数,且该随机数组,不服从任何特定分布。它的参数也和之前的zeros还有ones没有区别,也是传入元组,且也是(维度x行x列的形式),例子:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a = np.random.random((3, 3, 3)) # (0,1)随机数
print(f"随机数矩阵为:\n+{a}")
输出结果为:
随机数矩阵为:
+[[0.86050578 0.63774575 0.02023288]
[0.65343622 0.8246144 0.20655878]
[0.98017708 0.91932295 0.08390556]]
最后一个是np.random.randint(),它可以生成指定范围的整数随机数矩阵,一共有三个参数,前两个指定整数范围,最后一个和之前一样是元组,且指定大小和维度。例如:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a = np.random.randint(1, 9, (3, 3)) # 生成一个3x3的随机数矩阵,范围在1-9
print(f"随机数矩阵为:\n{a}")
输出结果为:
随机数矩阵为:
[[7 1 3]
[2 4 2]
[1 1 6]]
4. 保存和加载数组
保存方式和之前保存神经网络稍微有一点不一样,神经网络保存时,网络名写前面,地址写后面,这里它地址写前面,数组名称写后面。
具体用法如下:
np.save('保存的路径/名称.后缀', 数组) # 保存为.npy文件
np.savetxt('保存的路径/名称.后缀',数组) # 保存为.txt或者是.csv文件
这里的后缀有三种,分别是.npy 和.txt还有.csv,第一行save()函数,不管你有没有后缀,后缀是什么,都会给你保存成.npy文件,第二种需要指定csv,不然默认保存为txt文件
对应的加载方式也有三种:
np.load('名称') # 加载.npy文件
np.loadtxt('名称') # 加载.txt文件
np.genfromtxt('名称') # 加载.csv文件(这代码其实先将其转为了txt再加载,因为它其实是用txt的方式保存的)
其中只有.npy是无损的,保存进去什么类型的数组,出来还是什么类型,所以我们也多用.npy来处理,至于.csv和.txt文件,它们在处理时都会自动的给转成浮点数。下面是一个实际的例子:
我们先把之前的随机数数组保存一下,记得它是整数型的
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a = np.random.randint(1, 9, (3, 3)) # 生成一个3x3的随机数矩阵,范围在1-9
print(f"随机数矩阵为:\n+{a}")
np.save('a.npy', a)
np.savetxt('a.txt', a)
np.savetxt('a.csv', a)
运行结果是这个:
随机数矩阵为:
[[6 6 6]
[8 7 3]
[3 2 1]]
我们现在把它们加载进来看看:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a = np.load('a.npy') # 加载.npy文件
a1 = np.loadtxt('a.txt') # 加载.txt文件
a2 = np.genfromtxt('a.csv') # 加载.csv文件
print(f"npy文件为:\n{a}")
print(f'txt文件为:\n{a1}')
print(f"csv文件为:\n{a2}")
输出结果如下:
npy文件为:
[[6 6 6]
[8 7 3]
[3 2 1]]
txt文件为:
[[6. 6. 6.]
[8. 7. 3.]
[3. 2. 1.]]
csv文件为:
[[6. 6. 6.]
[8. 7. 3.]
[3. 2. 1.]]
5.输出ndarray中想要的元素
我们有时候,并不要一个数组里面的全部元素,只要其中一部分,方法有两种,分别对应输出一个元素的索引法和输出多个连续元素的切片法:
(1)索引法: 数组名称[维度下标][行下标][列下标],如果只是二维的,那么:
数组名称[行数,列数]的方法也可以,同样的,上面的方法,如果只是一行,列就不用写。举个例子:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a0 = [1, 2, 3, 4]
a1 = [[1, 2], [3, 4]]
A0 = np.array(a0) # 一维向量
A1 = np.array(a1) # 2x2的矩阵
A2 = np.random.randint(1, 9, (4, 3, 3)) # 4个3x3的随机矩阵
print(f"A0是这样的:\n{A0}\n")
print(f"A1是这样的:\n{A1}\n")
print(f"A2是这样的:\n{A2}\n")
print(f"A0的第三个数字是: {A0[2]}\n") # 注意,索引是从0开始的
print(f"A1的第二行,第一个元素是:{A1[1][0]}") # 矩阵的第一种查看法
print(f"A1的第一行,第1个元素是:{A1[0, 0]}\n") # 矩阵的第二种看法
print(f"A2的第3个矩阵的第二行第三个元素是:{A2[2][1][2]}") # 注意看,这里维度是写在最前面的,符合我们的习惯
print(f"A2的第3个矩阵的第二行第三个元素是:{A2[2,1,2]}") # 这样也是一样
输出结果为:
A0是这样的:
[1 2 3 4]
A1是这样的:
[[1 2]
[3 4]]
A2是这样的:
[[[6 3 2]
[6 1 5]
[8 8 7]]
[[5 3 5]
[8 8 7]
[6 7 5]]
[[6 4 6]
[2 5 7]
[4 3 1]]
[[2 3 3]
[5 6 5]
[6 2 6]]]
A0的第三个数字是: 3
A1的第二行,第一个元素是:3
A1的第一行,第1个元素是:1
A2的第3个矩阵的第二行第三个元素是:7
(2)切片法: 切片法查找的是一定范围内的多个元素,用法如下:
数组名称
[
开始的下标
(
开始的索引
)
:
结束的下标(结束的索引
+
1
)
:
步长
]
数组名称[开始的下标(开始的索引):结束的下标(结束的索引+1):步长]
数组名称[开始的下标(开始的索引):结束的下标(结束的索引+1):步长]
其中,开始下标不写默认是0,结束下标不写默认是列尾部元素的索引+1,步长不写,默认为1步。开始下标和结束下标为负数表示倒数,步长为负数表示倒退。上面介绍的是一维的,如果是二维的(矩阵),那我们给矩阵加上x和y坐标轴,查找范围的指定方法为分别指定x坐标上的范围和y坐标上的范围:
数组名称
[
x
开始下标
:
x
结束下标:
x
步长
,
y
开始下标:
y
结束下标,
y
步长
]
数组名称[x开始下标:x结束下标:x步长,y开始下标:y结束下标,y步长]
数组名称[x开始下标:x结束下标:x步长,y开始下标:y结束下标,y步长]
如果是三维及以上,我们就可以把它看着是一个长方形,可以用x,y,z坐标系来描述:
图是这样的:
多维切片的公式:
数组名称
[
x
开始
:
x
结束
:
x
步长
,
y
开始
:
y
结束
:
y
步长
,
z
开始
:
z
结束
:
z
步长
]
数组名称[x开始:x结束:x步长,y开始:y结束:y步长,z开始:z结束:z步长]
数组名称[x开始:x结束:x步长,y开始:y结束:y步长,z开始:z结束:z步长]
如果没有步长没有开始和结束,只需要输入一个数字,和索引是一样的,全要是:,且::之间可以不要逗号,比如[1,::],就是只要x轴的第二行切出来的yz轴组成的平面的数据,如果三个都是数字,就可以退化为索引。举个例子:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a0 = [1, 2, 3, 4]
a1 = [[1, 2, 7], [3, 4, 8], [5, 6, 9]]
A0 = np.array(a0) # 一维向量
A1 = np.array(a1) # 2x2的矩阵
A2 = np.random.randint(1, 9, (4, 3, 3)) # 4个3x3的随机矩阵
print(f"A0是这样的:\n{A0}\n")
print(f"A1是这样的:\n{A1}\n")
print(f"A2是这样的:\n{A2}\n")
# 这里步长全是1
print(f"A0的2到3个元素是: {A0[1:4]}\n") # 开始是从0开始,但是结尾是正常结尾,也就是索引加一
print(f"A1的x轴上的(2-3),y轴上的(1-2)组成的2x2的元素矩阵是:\n{A1[1:3, 0:3]}") # 矩阵切片
print(f"A2的用x=0和x=1切出的两个矩阵是:\n{A2[0:2,::]}") # 多维向量切片,切出的是前两个矩阵
输出结果为:
A0是这样的:
[1 2 3 4]
A1是这样的:
[[1 2 7]
[3 4 8]
[5 6 9]]
A2是这样的:
[[[4 3 7]
[3 5 8]
[3 6 7]]
[[4 1 5]
[6 3 2]
[4 1 3]]
[[6 5 2]
[8 2 6]
[8 6 2]]
[[1 2 3]
[3 8 6]
[1 8 1]]]
A0的2到3个元素是: [2 3 4]
A1的x轴上的(2-3),y轴上的(1-2)组成的2x2的元素矩阵是:
[[3 4 8]
[5 6 9]]
A2的用x=0和x=1切出的两个矩阵是:
[[[4 3 7]
[3 5 8]
[3 6 7]]
[[4 1 5]
[6 3 2]
[4 1 3]]]
6.重塑数组
我们可以用重塑数组的方式,来改变数组的性状,可以把一维变为二维,三维甚至是多维如图所示:
重塑的代码也很简单,使用np.shape(数组名,(维度x行x列))
就可以,但是要注意:原本数组的元素个数必须等于维度x行x列,也就是转换后元素不能多也不能少。举例:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a0 = [1, 2, 3, 4, 5, 6, 7, 8]
A = np.array(a0)
B = np.reshape(A, (2, 2, 2)) # 数组重塑为2个2x2矩阵
C = np.reshape(B, (1, 8)) # 变回去
print(f"原本的数组是:\n{A}\n")
print(f"把原本数组转为两个2x2的矩阵:\n{B}\n")
print(f"把转换后的又转回去成一维向量:\n{C}")
输出结果为:
原本的数组是:
[1 2 3 4 5 6 7 8]
把原本数组转为两个2x2的矩阵:
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
把转换后的又转回去成一维向量:
[[1 2 3 4 5 6 7 8]]
7.数组运算
数组的运算和矩阵的运算不一样,不然numpy也不会设置成两个模块,现在我们来说说ndnarray的计算方法:
(1)和常数的数乘运算:
A
∗
x
A*x
A∗x,其中,
A
A
A是数组,
x
x
x是常数,计算结果和矩阵是一样的,数组的每个元素的乘以
x
x
x,例如:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a0 = [1, 2, 3, 4, 5, 6, 7, 8]
A = np.array(a0)
B = A*3
print(f"原本的数组是:\n{A}\n")
print(f"数乘3以后的数组是:\n{B}")
输出结果为:
原本的数组是:
[1 2 3 4 5 6 7 8]
数乘3以后的数组是:
[ 3 6 9 12 15 18 21 24]
(2)数组和常数的加法计算用法和上面的数乘类似,只不过变成了加号: A + x A+x A+x,加x的意思就是每一个数组的元素都加上x,例子如下:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a0 = [1, 2, 3, 4, 5, 6, 7, 8]
A = np.array(a0)
B = A+3
print(f"原本的数组是:\n{A}\n")
print(f"加3以后的数组是:\n{B}")
输出结果为:
原本的数组是:
[1 2 3 4 5 6 7 8]
加3以后的数组是:
[ 4 5 6 7 8 9 10 11]
这种加一个常数或者乘以一个常数,会和全部的元素相加或者相乘的机制,叫做广播,利用这个特性,我们可以用数乘单位矩阵的方式,快速获得任意数字组成的矩阵(下面的数组间计算讲完一次举例)。
(3)数组和数组之间的计算,数组之间的计算和矩阵的计算规则不一样,矩阵有着加减乘除,且做法也更简单,首先要求做算法的两个矩阵的大小是一样的,之后就可以加减乘除了,计算的时候就是每一个对应的元素都进行加减或者乘除操作。具体操作见下面这个例子:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a0 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
A = np.array(a0)
B = np.ones((3, 3), dtype=int) * 3
C = A + B
D = A - B
E = A * B
F = A / B
print(f"A是一个三乘三的矩阵:\n{A}\n")
print(f"B是一个由3组成的矩阵:\n{B}\n")
print(f"A+B:\n{C}\n")
print(f"A-B:\n{D}\n")
print(f"A*B:\n{E}\n")
print(f"A/B:\n{F}")
输出如下:
A是一个三乘三的矩阵:
[[1 2 3]
[4 5 6]
[7 8 9]]
B是一个由3组成的矩阵:
[[3 3 3]
[3 3 3]
[3 3 3]]
A+B:
[[ 4 5 6]
[ 7 8 9]
[10 11 12]]
A-B:
[[-2 -1 0]
[ 1 2 3]
[ 4 5 6]]
A*B:
[[ 3 6 9]
[12 15 18]
[21 24 27]]
A/B:
[[0.33333333 0.66666667 1.]
[1.33333333 1.66666667 2.]
[2.33333333 2.66666667 3.]]
8.更高级的数组运算
更高级的数组运算包括数组的n次方、倒数、
e
数组
e^{数组}
e数组、
log
e
数组
\log_e^{数组}
loge数组,分别对应的是:
# A是数组
# 次方:
A**n
# 倒数:
1/A
# e的数组次方
np.exp(A)
# e的对数
np.log(A)
它们的计算方式也遵循之前说的广播机制,就是会一个个地进行计算。
拿刚刚的矩阵举例:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a0 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
A = np.array(a0)
C = A**2
D = 1/A
E = np.exp(A)
F = np.log(A)
print(f"A是一个三乘三的矩阵:\n{A}\n")
print(f"A的平方:\n{C}\n")
print(f"A的倒数:\n{D}\n")
print(f"e^A:\n{E}\n")
print(f"ln(A):\n{F}")
输出为:
A是一个三乘三的矩阵:
[[1 2 3]
[4 5 6]
[7 8 9]]
A的平方:
[[ 1 4 9]
[16 25 36]
[49 64 81]]
A的倒数:
[[1. 0.5 0.33333333]
[0.25 0.2 0.16666667]
[0.14285714 0.125 0.11111111]]
e^A:
[[2.71828183e+00 7.38905610e+00 2.00855369e+01]
[5.45981500e+01 1.48413159e+02 4.03428793e+02]
[1.09663316e+03 2.98095799e+03 8.10308393e+03]]
ln(A):
[[0. 0.69314718 1.09861229]
[1.38629436 1.60943791 1.79175947]
[1.94591015 2.07944154 2.19722458]]
在学了这几个操作以后,我们也可以定义自己的SIgmoid,Thn还有交叉熵函数了。
9.比较运算:
Ndarray数组也支持比较运算,就是比大小或者是等于,符合是True,不符合是False,并且它是把数组中的元素一个个比过来。举例说明一下:
"""
@FileName:use_numpy.py
@Description:怎么用numpy的学习
@Author:段鹏浩
@Time:2023/3/11 21:33
"""
import numpy as np
a0 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
a1 = [[1, 3, 3], [7, 5, 6], [7, 10, 9]]
A = np.array(a0)
B = A == 2
C = A > 5
D = np.array(a1)
F = A == D
print(f"A是一个三乘三的矩阵:\n{A}\n")
print(f"A中的每一个元素和1的相等比较结果:\n{B}\n")
print(f'A中的每一个元素是不是比5大的比较结果:\n{C}\n')
print(f"D也是一个3x3的矩阵:\n{D}\n")
print(f"A和D中相等的元素的比较结果:\n{F}")
输出结果为:
A是一个三乘三的矩阵:
[[1 2 3]
[4 5 6]
[7 8 9]]
A中的每一个元素和1的相等比较结果:
[[False True False]
[False False False]
[False False False]]
A中的每一个元素是不是比5大的比较结果:
[[False False False]
[False False True]
[ True True True]]
D也是一个3x3的矩阵:
[[ 1 3 3]
[ 7 5 6]
[ 7 10 9]]
A和D中相等的元素的比较结果:
[[ True False True]
[False True True]
[ True False True]]
我们可以看到,数组和数字比大小,等于在和这个用这个数字为单位的等大小矩阵比较。