Numpy科学计算库笔记
一、安装 Anaconda
安装过程中,下面这两个都要一定勾选上。
二、打开jupyter notebook
随便新建一个文件夹,按shif键的同时右键鼠标,选择“在此处打开PowerShell窗口”,然后在打开的窗口中输入:jupyter notebook,此时浏览器会打开一个网页:
打开的PowerShell窗口不要关闭,否则浏览器中的jupyter就不能用了。
三、快捷键
在jupyter notebook里面的快捷键:
- 运行代码:shift+回车
- 代码提示:tab
- 提示方法的属性和使用:shif+tab (使用此快捷键时需要把光标放在方法的括号内)
- 在前面插入空代码行:A
- 在后面插入空代码行:B
- 删除代码行:双击D
四、打印
import numpy as np
list=np.array([1,2,3,5,8])
list
效果:
如上图,jupyter 中执行程序,最后一行代码,默认是输出。
还可以如下图进行打印:
print(list)
display(list)
效果:
display()方法中,如果想打印多个,可以用逗号隔开,如:
五、创建数组
1、列表转数组
import numpy as np
list=np.array([1,2,3,5,8])
2、使用内置函数创建数组
在 NumPy 中,数组是 同质 的,即数组中的所有元素必须是 相同的数据类型。创建数组时,可以通过 dtype 参数指定数组的数据类型。
① np.zeros()
创建全是0的数组。
二维数组:
np.zeros(shape=(2,3),dtype=np.int64)
输出:
② np.ones()
创建全是1的数组。
二维数组:
np.ones(shape=(3,5),dtype=np.float32)
输出:
③ np.full()
用 fill_value=3.1415926 指定元素
np.full(shape=(2,3,5),fill_value=3.1415926)
输出,这是一个三维的数组:
④ np.random.randint()
生成整数的随机数数组。
示例:
生成0到100的整数,包括0,不包括100,size指定生成的个数。
np.random.randint(0,100,size=20)
输出:
⑤ np.random.rand()
生成0到1(包括0,不包括1)的随机数数组。
示例:
生成一个二维数组,里面的元素是随机0到1的小数。包括0,不包括1
np.random.rand(3,4)
输出:
如果方法里面不写参数,则只生成一个0-1的随机数:
np.random.rand()
输出:
⑥ np.random.randn()
生成元素符合标准正态分布的数组。
标准正态分布的均值是 0,标准差是 1
np.random.randn(3,5)
输出:
⑦ np.random.normal()
指定平均值和标准差,生成元素符合正态分布数组。
r=np.random.normal(loc=175,scale=10,size=(3,5)) # 生成符合正态分布的三行五列的二维数组。平均值是175,标准差是10
print(r)
输出:
⑧ np.arange()
生成元素符合等差数列的数组。
np.arange(1,10) #默认步长是1 如果省略第一个参数,默认是从0开始
输出:
可以设置步长:
np.arange(1,10,step=2) # 用step 设置步长
输出:
⑨ np.linspace()
生成元素符合等差数列的数组。
示例:
生成1到10之间(包含1和10)含有五个元素,并且元素之间符合等差数列的数组。
np.linspace(1,10,5)
输出:
六、数组的数据类型
NumPy 提供了丰富的数据类型,用于定义数组中元素的存储方式和精度。
不同的数据类型占用的内存大小不同。例如:
int8 占用 1 字节,int64 占用 8 字节。
float16 占用 2 字节,float64 占用 8 字节。
计算精度: 浮点数类型决定了计算的精度。例如:
float16 的精度较低,适合节省内存但精度要求不高的场景。
float64 的精度较高,适合科学计算。
转换数组的数据类型
① arr.astype()
arr = np.array([1.5, 2.5, 3.5])
arr_int = arr.astype(np.int32) # 转换为 int32 类型
print(arr_int) # 输出: [1 2 3](浮点数被截断为整数)
② np.asarray()
先生成一个数组
arr=np.random.randint(0,100,size=(2,3),dtype=np.int64)
arr
输出:
通过np.asarray()来转变数据类型:
np.asarray(arr,dtype=np.float32)
输出:
七、数组属性
先创建一个三维数组:
import numpy as np
test_arr=np.full(shape=(2,3,5),fill_value=3.1415926)
输出:
1、形状
test_arr.shape # 输出 (2, 3, 5)
2、元素的数据类型
test_arr.dtype # 输出 dtype('float64')
3、元素个数
数组元素个数,一般是shape里面每个数相乘得到的结果。
test_arr.size # 30
4、维度
数组的维度,如二维、三维数组。
test_arr.ndim # 输出 3
5、元素的字节数
表示数组里面每个元素占多少个字节。从 test_arr 这个数组的dtype的属性得知它是64位,由于8位是一个字节,那么这里应该64/8=8个字节。
test_arr.itemsize # 输出 8
八、数组运算
1、基本运算
数组的运算是对应位置相加、减、乘、除或者幂运算。
现在有两个数组
arr1=np.random.randint(0,10,size=5)
arr2=np.random.randint(0,10,size=5)
display(arr1,arr2)
输出:
加
arr1+arr2 # array([14, 6, 6, 18, 10])
减
arr1-arr2 # array([ 0, 2, -2, 0, -2])
乘
arr1*arr2 # array([49, 8, 8, 81, 24])
这里注意一下乘法。 举一个例子:
在python中一个列表乘以一个整数, 意思是会将列表重复 n 次。如:
arr=np.array([1,2,3,4,5]*2)
print(arr) #输出:[1 2 3 4 5 1 2 3 4 5]
而在 NumPy 中,数组与标量的乘法是 逐元素乘法,即每个元素都会乘以标量。如:
arr1 = np.array([1,2,3,4,5])
print(arr1*2) #输出:[ 2 4 6 8 10]
除
arr1/arr2 # array([1. , 2. , 0.5 , 1. , 0.66666667])
幂
arr1**arr2 # 输出 array([ 823543, 16, 16, 387420489, 4096], dtype=int32)
arr1**2 # array([49, 16, 4, 81, 16], dtype=int32)
np.power(arr1,2) # array([49, 16, 4, 81, 16], dtype=int32)
对数
np.log(10) # 底数是 e 结果:2.302585092994046
np.log10(100) # 2.0
np.log2(1024) # 10.0
2、逻辑运算
分别判断数组中对应位置的元素。
arr1 = np.array([1,2,3,4,5])
arr2 = np.array([1,0,2,3,5])
如:
3、数组与标量计算
数组运算的前提是两个数组的形状(shape)必须相同,或者满足广播规则。
标量是一个单独的数值,例如:整数、浮点数、布尔值。标量没有形状。
arr1 = np.array([1,2,3,4,5])
print(arr1+2)
print(arr1-2)
print(arr1*2)
print(arr1/2)
print(2/arr1)
print(arr1**2)
输出:
4、+=,-=和*= (不支持/=)
以上数组运算后会生成一个新对象,原来的数组内容不变。
而对数组进行+=,-=和*=操作会直接改变原来数组。
九、jupyter插件
在命令行窗口中执行下面这个命令来下载拓展插件。
pip install jupyter_contrib_nbextensions -i https://pypi.tuna.tsinghua.edu.cn/simple
下载完成后,重新启动jupyter notebook,点击 Nbextensions
然后勾选下图 框起来的两个:
然后就可以查看目录了:
十、文件IO操作
示例:
先创建两个数组
import numpy as np
rd1=np.random.randint(0,100,size=(3,5))
rd2=np.random.randn(3,5)
print(rd1)
输出:
print(rd2)
输出:
1、写入
① 写入.npy文件
现在把 rd1 数组存到一个文件里面,使用 np.save() 方法 不用写后缀名,会自动生成后缀名:
np.save('./data',rd1)
执行后会在当前目录下生成一个文件:
② 写入.npz文件
除了一次写入一个数组,还可以写多个数组。使用 np.savez() 方法
如把 rd1 和 rd2 这两个数组写入一个文件。
np.savez('./data2',a=rd1,b=rd2) #这里的a和b是key可以自定义命名
执行后会在当前目录下生成一个文件:
如果想写入文件的同时并给它压缩,可以使用 savez_compressed()
np.savez_compressed('./data8',x=rd1,y=rd2)
执行后会在当前目录下生成一个文件:
③ 写入.txt文件
np.savetxt(fname='./data.text', # 指定保存文件的路径和名称
X=rd1,# 要保存的数组
fmt='%0.2f', # 表示将每个元素格式化为浮点数,保留两位小数,不足两位用0填充
delimiter=',') # 指定数组元素之间的分隔符
执行后会在当前目录下生成一个文件:
点开它,内容是这样子的:
④ 写入.csv文件
np.savetxt(fname='./data.csv',
X=rd1,
fmt='%d',
delimiter=',')
执行后会在当前目录下生成一个文件:
点开它,内容是这样子的:
2、读取
注意:这里读取的文件都是上面写入的文件。
① 读.npy文件
由于上面只把一个数组写入 data.npy 文件,可以直接读取:
np.load('./data.npy')
输出:
② 读.npz文件
data2.npz 文件是.npz⽂件,读取之后相当于形成了⼀个key-value类型的变量,通过保存时定义的key来获取相应的array
dict=np.load('./data2.npz')
dict['a']
输出:
dict['b']
输出:
③ 读.txt文件
np.loadtxt('./data.text',delimiter=',')
输出:
数组元素以 . 结尾。这是因为 np.loadtxt() 默认将数据加载为浮点数(float 类型),即使原始数据是整数。
④ 读.csv文件
如果你希望加载的数据保持整数类型,可以通过 dtype 参数显式指定数据类型为 int
np.loadtxt('./data.csv',delimiter=',',dtype=np.int32)
输出:
十一、数组的复制与视图
1、完全没有复制
2、视图、查看或者浅拷贝
通过b.flags.owndata 可以看到b的数据并不属于自己。
所以,在修改b或者a数组元素的值时,两个数组的都发生了变化:
3、深拷贝
可见,copy() 会创建一个新的数组,并将提取的元素复制到新数组中。
这样做是为了避免对 b 的修改影响到原始数组 a。
所以,在分别修改它们元素的值时,互相不受影响:
深拷贝的应用:
当原数组很大,因此会占用很大的内存空间。现在只是想要拷贝其中某些数据,然后把原数组给删除。这时如果使用浅拷贝,然后把原数组删除,这样会导致拷贝出来的数据也会被删除,所以,只能用深拷贝。
a=np.arange(1e8) # 1e8=1 乘以 10 的 8 次方 。科学计数法的一般格式
a
输出:
b=a[[1,3,5,7,9]].copy() # 这里的 [1, 3, 5, 7, 9] 是一个索引列表。b = a[[1, 3, 5, 7, 9]] # b = [a[1], a[3], a[5], a[7], a[9]] = [1, 3, 5, 7, 9]
del a
b
输出:
可见,删除掉a数组后,b数组并没有受到影响。
- 补充一个知识点,科学计数法的格式:数字e指数
数字部分:可以是整数或浮点数。
指数部分:表示 10 的幂次
如:1e8
十二、数组的基本索引和切片
1、对一维数组取值
arr = np.array([0,1,2,3,4,5,6,7,8,9])
arr[5] #索引 输出 5
arr[5:8] #切⽚输出:array([5, 6, 7])
arr[2::2] # 从索引2开始 输出 array([2, 4, 6, 8])
arr[::3] # 不写索引默认从0开始, 输出为 array([0, 3, 6, 9])
arr[1:7:2] # 从索引1开始到索引7结束,左闭右开, 输出 array([1, 3, 5])
arr[::-1] # 倒序 输出 array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
arr[::-2] # 倒序 输出 array([9, 7, 5, 3, 1])
2、对二维数组取值
arr2d = np.array([[1,3,5],[2,4,6],[-2,-7,-9],[6,6,6]]) # ⼆维数组
arr2d[0,-1] #索引 等于arr2d[0][-1] 输出 5
arr2d[0,2] #索引 等于arr2d[0][2] == arr2d[0][-1] 输出 5
arr2d[:2,-2:] #切⽚ 第⼀维和第⼆维都进⾏切⽚ 等于arr2d[:2][:,1:]
arr2d[:2,1:] #切⽚ 1 == -2 ⼀个是正序,另个⼀是倒序,对应相同的位置
# 输出:
#array([[3, 5],
# [4, 6]])
3、切片与视图关系
在numpy中数组切⽚是原始数组的视图,这意味着数据不会被复制,视图上任何数据的修改都会反映到原数组上。
arr=np.arange(10)
arr # array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr1=arr[3:7]
arr1 # array([3, 4, 5, 6])
对切片中的数组进行修改后:
arr1[0]=1024
display(arr,arr1)
输出:
可见,切片中的数组和原来的数组元素都发生的改变。
十三、数组的花式索引和布尔索引
1、花式索引
花式索引,其和切⽚不⼀样,它总是将数据复制到新数组中,也就是深拷贝。
arr2=np.random.randint(5,20,size=8)
arr3=arr2[[0,2,5]] # [0,2,5]是索引列表、花式索引
display(arr2,arr3)
输出:
现在对arr3内的元素进行修改:
arr3[0]=1024
display(arr2,arr3)
输出:
可见,通过花式索引得到的新数组arr3,修改其元素的值,并不会影响到原数组。
2、布尔索引
示例1:现在有10名学生的3们考试成绩,需要筛选出各科成绩都大于120的学生,并显示其各科成绩。
scores=np.random.randint(0,151,size=(10,3))
scores
输出每名学生的成绩如下:
判断每门成绩是否都大于120:
high=scores>=120 # 布尔数组
print(high)
输出:
判断每个学生每门成绩是否都大于120:
real=high[:,0]*high[:,1]*high[:,2]
real
输出:
最后筛选出各科成绩都大于120分的学生,并显示其各科成绩:
scores[real]
输出:
real 的每个布尔值与 scores 的每一行一一对应。
True 表示保留该行,False 表示忽略该行。
最终保留的是 scores 中所有 real 为 True 的行。
示例2:
在上面示例1的10名学生的3们考试成绩基础之上,筛选出成绩都<=80的学生,并显示其各科成绩。
low=scores<=80
scores[low[:,0]*low[:,1]*low[:,2]]
输出:
十四、数组的形状操作
现在有arr数组如下:
arr=np.random.randint(20,size=(2,3))
arr
输出:
1、变形
arr.reshape(3,2)
输出:
arr.reshape(6,1)
输出:
arr.reshape(6,1,1)
输出:
arr.reshape(1,1,6)
输出:
arr.reshape(1,6,1)
输出:
arr.reshape(-1,3) # 和 arr.reshape(2,3) 的输出结果一样
在reshape方法中第一个参数-1 是一个占位符,表示 NumPy 会自动计算该维度的大小,以确保数组的总元素数不变。
第二个参数中,要确保数组元素总数必须是第二个参数的倍数。
最后输出:
2、转置
如,原来arr数组的行和列分别是2和3,转置之后行和列分别是3和2
arr.T
输出:
和数组的变形中arr[3,2]是有区别的。转置取数是向下取的:
① transpose()
numpy数组转置中的一个方法,transpose() 。这是用于调整数组维度(轴)顺序的函数。
② 认识轴
在 NumPy 中,轴(axis)是数组的维度。
一维数组有 1 个轴(axis=0)。
二维数组有 2 个轴(axis=0 和 axis=1)。
三维数组有 3 个轴(axis=0、axis=1 和 axis=2)
轴从外到内编号,axis=0 是最外层,axis=1 是中间层,axis=2 是最内层。
transpose()中可以指定轴顺序,调整轴的顺序可以改变数组的形状,重新排列数据。
现在有一个数组:
arr1=np.random.randint(0,50,size=(2,4,3))
arr1
输出:
使用 transpose() 的第二个参数的元组来指定轴的顺序。
在三维数组 arr1 中,原始轴的顺序是(0,1,2),形状是(2,4,3)
现在把轴顺序改为 (1,2,0),形状也就变为(4,3,2)
在三维数组中,transpose() 可以交换不同维度的数据。
在二维数组中,transpose() 会将行变为列,列变为行。
3、堆叠合并
合并的数组需要注意形状的问题。
现在有两个数组:
① np.concatenate()
按行合并。需要两个数组的形状要一致;或者列数要一致。
按列合并。需要两个数组的形状要一致;或者行数要一致。
② np.hstack() 和 np.vstack()
4、拆分
现有这样一个数组:
① split()
平均分成几等份:
np.split(arr,indices_or_sections=2) # indices_or_sections参数如果直接给1个数字,表示平均分成多少份
输出:
axis 指定按行还是按列分:
np.split(arr,indices_or_sections=2,axis=1) # axis 参数指定按行还是按列拆分,默认是0按行拆分,1表示按列拆分
输出:
以切片的形式拆分:
# 除了可以平均拆分,还可以以切片的形式拆分,遵循左闭右开原则,此时indices_or_sections参数的值是索引列表
np.split(arr,indices_or_sections=[1,2,3])
# 第一个子数组:arr[:1]
#第二个子数组:arr[1:2]
#第三个子数组:arr[2:3]
#第四个子数组:arr[3:]
输出:
② hsplit()
水平拆分,也就是按列拆分。可以想象成,一把刀,从左往右,竖着砍。
np.hsplit(arr,indices_or_sections=2) # h表示水平拆分
输出:
从输出结果可见,和 np.split(arr,indices_or_sections=2,axis=1) 的效果是一样的。
③ vsplit()
垂直拆分,也就是按行拆分。可以想象成,一把刀,从上往下,横着砍。
np.vsplit(arr,indices_or_sections=2) # v表示垂直拆分
输出:
可见,和 np.split(arr,indices_or_sections=2) 的效果是一样的。
十五、数组的广播机制
1、广播的规则和条件
广播规则的关键是从数组形状的最右边(最后一个维度)开始,逐维度比较。如果两个数组的维度数不同,NumPy 会在形状较短的数组的左边补 1,直到它们的维度数相同。
补完1后,在每个维度上,必须满足以下条件之一才可以进行数组之间的运算:
- 两个数组在该维度的大小相等。
- 其中一个数组在该维度的大小为 1
如果以上条件不满足,广播就会失败,NumPy 会抛出 ValueError。
2、扩展的方式
从数组形状的每个维度上来看,如果某个数组的大小为 1,则 NumPy 会将该维度上的数据复制多次(复制多少次需要根据另一个数组对应维度的大小来决定),以匹配另一个数组的大小。
3、案例
import numpy as np
A = np.array([1, 2, 3]) # 形状 (3,)
B = np.array([[4], [5]]) # 形状 (2, 1)
C = A + B # 广播后的形状 (2, 3)
print(C)
输出:
[[5 6 7]
[6 7 8]]
扩展过程:
首先,补 1:
A 的形状是 (3,),B 的形状是 (2, 1)。
A 的维度数较少,NumPy 会在 A 的左边补 1,将其形状变为 (1, 3)。
然后,逐维度扩展:
比较维度 1:
A 的大小为 1,B 的大小为 2。
A 会在第一个维度上复制 2 次,变为:
[[1, 2, 3],
[1, 2, 3]]
比较维度 2:
A 的大小为 3,B 的大小为 1。
B 会在第二个维度上复制 3 次,变为:
[[4, 4, 4],
[5, 5, 5]]
最后,逐元素相加:
A 扩展后:
[[1, 2, 3],
[1, 2, 3]]
B 扩展后:
[[4, 4, 4],
[5, 5, 5]]
结果:
[[1+4, 2+4, 3+4],
[1+5, 2+5, 3+5]]
十六、通⽤函数
1、元素级数字函数
# abs、sqrt、square、exp、log、sin、cos、tan,maxinmum、minimum、all、any、inner、clip、
#round、trace、ceil、floor
import numpy as np
arr1 = np.array([1,4,8,9,16,25])
np.sqrt(arr1) # 开平⽅
np.square(arr1) # 平⽅
np.clip(arr1,2,16) # 输出 array([ 2, 4, 8, 9, 16, 16])
x = np.array([1,5,2,9,3,6,8])
y = np.array([2,4,3,7,1,9,0])
np.maximum(x,y) # 返回两个数组中的⽐较⼤的值
arr2 = np.random.randint(0,10,size = (5,5))
np.inner(arr2[0],arr2) #返回⼀维数组向量内积
2、where函数
例1:
例2:
例3:
3、排序⽅法
① np.sort(arr)
生成新的并且是排好序的数组。
② arr.sort()
直接对原数组进行排序。
③ arr.argsort()
得到了排好序的索引数组后,可以根据花式索引获得原数组中对应索引的数组元素:
如果想倒叙输出:
4、集合运算函数
-
np.intersect1d() 求交集。
-
np.union1d() 求并集。
-
np.setdiff1d() 求差集
5、数学和统计函数
#min、max、mean、median、sum、std、var、cumsum、cumprod、argmin、argmax、
#argwhere、cov、corrcoef
import numpy as np
arr1 = np.array([1,7,2,19,23,0,88,11,6,11])
arr1.min() # 计算最⼩值 0
arr1.argmax() # 计算最⼤值的索引 返回 6
np.argwhere(arr1 > 20) # 返回⼤于20的元素的索引
np.cumsum(arr1) # 计算累加和
arr2 = np.random.randint(0,10,size = (4,5))
arr2.mean(axis = 0) # 计算列的平均值
arr2.mean(axis = 1) # 计算⾏的平均值
np.cov(arr2,rowvar=True) # 协⽅差矩阵
np.corrcoef(arr2,rowvar=True) # 相关性系数
十七、线性代数
矩阵乘积
矩阵乘法不满足交换律,但它满足 结合律。
A⋅B!=B⋅A
(A⋅B)⋅C=A⋅(B⋅C)
#矩阵的乘积
A = np.array([[4,2,3],
[1,3,1]]) # shape(2,3)
B = np.array([[2,7],
[-5,-7],
[9,3]])
# shape(3,2)
np.dot(A,B) # 矩阵运算 A的最后⼀维和B的第⼀维必须⼀致
A @ B # 符号 @ 表示矩阵乘积运算