一、NumPy介绍
NumPy(Numerical Python)是Python的一个开源数值计算库。可用来存储和处理大型矩阵,比python自身的嵌套列表结构要高效得多,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库,包括数学、逻辑、形状操作、排序、选择、输入输出、离散傅里叶变换、基本线性代数、基本统计运算和随机模拟等等。
几乎所有从事python工作的数据分析师都利用NumPy的强大功能
二、创建ndarray
ndarray是NumPy中表示数组的重要类型(nd表示n个维度)。比如图像数据的表示就是一个三维数组,图像通常由像素组成,每一个像素可以有一个或多个通道(Channel),用于表示颜色或深度信息:
- 第一个维度(高度):图像的行数
- 第二个维度(宽度):图像的列数
- 第三个维度(通道):图像的颜色通道数
例如:
- 对于灰度图像,只有一个通道,因此可以表示为一个二维数组
- 对于彩色图像(如RGB图像),通常有三个通道(红、绿、蓝),因此可以表示为一个三维数组。
1、使用np.array()创建
import numpy as np
n = np.array([1,2,3,4])
print(n)
print(type(n)) # 类型
print(n.shape) # 形状,一维数组就是一个元组来表示
[1 2 3 4]
<class 'numpy.ndarray'>
(4,)
注意:
- numpy默认ndarry的所有元素类型是相同的
- 如果传进来的列表中包含不同的类型,则统一为同一类型,优先级:str>float>int
- ndarry的常见的数据类型:
- int:int8、uint8、int16、int32、int64
- float:float16、float32、float64
- str:字符串
import numpy as np
n = np.array([3.14,2,"haha"])
n
array(['3.14', '2', 'haha'], dtype='<U32')
2、使用np的routines函数创建
1)np.ones(shape,dtype=None,order=“C”)
- 创建一个所有元素都为1的数组
参数说明: - shape:形状
- dtype=None:类型
- order:{‘C’,‘F’},可选,默认值:C是否在内存中以行主(C-风格)或列主(Fortran-风格)顺序存储多维数组,一般默认即可。
import numpy as np
n = np.ones((3,4),dtype=np.int8)
# n = np.ones((3,4),dtype=int)
n
array([[1, 1, 1, 1],
[1, 1, 1, 1],
[1, 1, 1, 1]], dtype=int8)
1)np.zeros(shape,dtype=float,order=‘C’)
- 创建一个所有元素都为0的多维数组
import numpy as np
n = np.zeros((3,4),dtype=int)
n
array([[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]])
3)np.full(shape,fill_value,dtype=None,order=‘C’)
- 创建一个所有元素都为指定元素的多维数组,其中fill_value表示填充值。
import numpy as np
n = np.full((3,4),fill_value=6,dtype=int)
n
array([[6, 6, 6, 6],
[6, 6, 6, 6],
[6, 6, 6, 6]])
4)np.eye(N,M=None,k=0,dtype=int)
- 对角线为1其他位置为0的二维数组(单位矩阵)
参数说明:
- N:行数
- M:列数
- k=0:向右偏移0个位置
import numpy as np
n = np.eye(6,k=1,dtype=int)
# 如果M不指定默认与N有相同行数
n
array([[0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0]])
5)np.linspace(start,stop,num=50,endpoint=True,retstep=False,dtype=None)
- 创建一个等差数列
参数说明:
- start:开始值
- stop:结束值
- num=50:等差数列中默认有50个值
- endpoint:是否包含结束值
- retstep:是否返回等差值(步长哪个)
import numpy as np
n = np.linspace(0,100,num=51,endpoint=False,retstep=True)
n
(array([ 0. , 1.96078431, 3.92156863, 5.88235294, 7.84313725,
9.80392157, 11.76470588, 13.7254902 , 15.68627451, 17.64705882,
19.60784314, 21.56862745, 23.52941176, 25.49019608, 27.45098039,
29.41176471, 31.37254902, 33.33333333, 35.29411765, 37.25490196,
39.21568627, 41.17647059, 43.1372549 , 45.09803922, 47.05882353,
49.01960784, 50.98039216, 52.94117647, 54.90196078, 56.8627451 ,
58.82352941, 60.78431373, 62.74509804, 64.70588235, 66.66666667,
68.62745098, 70.58823529, 72.54901961, 74.50980392, 76.47058824,
78.43137255, 80.39215686, 82.35294118, 84.31372549, 86.2745098 ,
88.23529412, 90.19607843, 92.15686275, 94.11764706, 96.07843137,
98.03921569]),
1.9607843137254901)
6)np.arange([start,]stop,[step,]dtype=None)
- 创建一个数值范围数组
- 与python中的range函数功能类似
参数说明:
- start:开始值(可选)
- stop:结束值(不包含)
- step:步长哪个(可选)
import numpy as np
n = np.arange(2,10,2)
n
array([2, 4, 6, 8])
7)np.random.randint(low,high=None,size=None,dtype=None)
- 创建一个随机整数的多维数组
参数说明:
- low:最小值
- high:最大值
- high=None时,生成的数值在[0,low]区间内
- 如果使用high这个值,则生成的数值在[low,high)区间内
- size:数组形状,默认只输出一个随机值
import numpy as np
n = np.random.randint(0,100,(3,4),dtype=int)
n
array([[65, 2, 28, 98],
[83, 87, 95, 77],
[57, 87, 93, 3]])
8)np.random.randn(d0,d1,…,dn)
- 创建一个服从标准正态分布的数组
标准正态分布又称u分布(高斯分布),是以0为均值,以1为标准差的正态分布,记为x~N(0,1)标准正态分布。在0左右出现的概率最大,越远离出现的概率越低。
- 创建一个所有元素都为1的多维数组
参数说明:
- dn:第n个维度的数值
import numpy as np
n = np.random.randn(3,4)
n
array([[-1.16642433, 2.28540892, -0.84647505, 0.70431272],
[-0.01542117, -1.71755485, -2.06617207, 1.49153731],
[ 1.48517881, 0.80147185, 0.49214101, -0.0042536 ]])
9)np.random.normal(loc=0.0,scale=1.0,size=None)
- 创建一个服从正态分布的多维数组
参数说明:
- loc:均值,对应着正态分布的中心
- scale:标准差,对应着分布的宽度,scale越大,正态分布的曲线就越矮胖,scale越小,曲线越高瘦。
- size:数组形状
import numpy as np
n = np.random.normal(loc=100,scale=1,size=(3,4))
n
array([[100.06052885, 101.46798012, 97.93215097, 99.82776279],
[103.24421836, 101.97041366, 98.88515404, 99.00016403],
[100.47565086, 101.99688983, 100.22201324, 100.26000772]])
10)np.random.random(size=None)
- 创建一个元素为0~1(左闭右开)的随机数的多维数组
参数说明:
- size:数组形状
import numpy as np
n = np.random.random((3,4))
n
array([[0.71567305, 0.41808001, 0.0516382 , 0.09077367],
[0.24400181, 0.15027429, 0.04032072, 0.8586849 ],
[0.26922107, 0.98332015, 0.7076481 , 0.98187247]])
11)np.random.rand(d0,d1,…dn)
- 创建一个元素为0~1(左闭右开)的随机数的多维数组
- 这与np.random.random()功能相同
三、ndarray的属性
四个重要属性:
- ndim:维度
- shape:形状
- size:总长度
- dtype:元素类型
四、numpy的基本操作
1、索引操作
一维与列表完全一致,多维时同理
import numpy as np
n = np.random.randint(0,10,size=(3,4))
n,n[1,2] # 也可以这样写:n[1][2]
(array([[6, 8, 4, 7],
[9, 7, 1, 3],
[1, 6, 5, 8]]),
1)
根据索引修改数据
import numpy as np
n = np.random.randint(0,10,size=(3,4))
n[1,2]=120
n
array([[ 2, 1, 6, 6],
[ 5, 0, 120, 6],
[ 2, 7, 4, 6]])
2、切片操作
一维与列表完全一致,多维时同理
import numpy as np
n = np.arange(12)
n[2:6],n[::-1] # 将数组翻转
# 连续取多行数据也需要用到切片操作
import numpy as np
n = np.random.randint(0,10,size=(6,6))
n[1:4]
# 取不连续的多行
n[[1,2,4]]
# 取列
n[:,0]
# 取连续的多列:切片
n[2:5:,1:4]
# 取不连续的多列
n[:,[1,2,4]]
array([[2, 7, 9],
[6, 4, 0],
[6, 1, 4],
[5, 5, 4],
[5, 1, 6],
[8, 8, 4]])
3、变形操作
使用reshape函数
import numpy as np
n = np.arange(12).reshape(3,4)
# 使用-1来表示剩余维度
n1 = np.arange(12).reshape(3,-1)
n,n1
(array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]]),
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]]))
4、级联操作
np.concatenate()
- 参数必须是列表或元组
- 级联的数组维度必须相同
- 可以通过参数axis改变级联的方向
import numpy as np
n1 = np.random.randint(0,100,size=(3,4))
n2 = np.random.randint(0,10,size=(3,4))
n = np.concatenate((n1,n2),axis=1)
n
array([[10, 57, 10, 54, 7, 9, 5, 2],
[83, 75, 2, 90, 0, 8, 8, 2],
[62, 64, 49, 97, 8, 3, 8, 5]])
np.hsrack与np.vstack
- 水平级联与垂直级联(功能与np.concatenate函数功能相同,只需要掌握一个就好)
import numpy as np
n1 = np.random.randint(0,100,size=(3,4))
n2 = np.random.randint(0,50,size=(3,4))
# 水平级联
n3 = np.hstack((n1,n2))
# 垂直级联
n4 = np.vstack((n1,n2))
n3,n4
(array([[41, 38, 92, 85, 44, 47, 30, 1],
[23, 29, 58, 34, 46, 30, 36, 36],
[97, 91, 7, 90, 26, 3, 9, 39]]),
array([[41, 38, 92, 85],
[23, 29, 58, 34],
[97, 91, 7, 90],
[44, 47, 30, 1],
[46, 30, 36, 36],
[26, 3, 9, 39]]))
5、拆分操作
与级联类似,三个函数完成切分工作
- np.split
- np.vsplit
- np.hsplit
np.split函数的功能与np.vsplit、np.hsplit函数功能类似,掌握一个即可
import numpy as np
n = np.random.randint(0,100,size=(6,4))
np.split(n,3,axis=0)
# 也可以根据位置索引来进行拆分
np.split(n,(1,2,4),axis=0)
[array([[87, 70, 57, 89]]),
array([[38, 90, 49, 12]]),
array([[ 5, 22, 29, 84],
[40, 86, 43, 88]]),
array([[ 5, 6, 50, 21],
[17, 93, 82, 12]])]
6、副本/复制/拷贝
拷贝是原数据的一个完整副本,他不共享数据块。修改拷贝中的数据不会影响到原数组,反之亦然。创建拷贝会占用额外的内存。
- copy()函数创建副本
import numpy as np
n = np.arange(10)
n1 = n
n[0]=10
display(n,n1) # 这就会导致n与n1共用同一块内存,赋值操作会把两个之都修改
# 拷贝操作
n2 = n.copy()
n2[0] = 1
display(n2,n)
array([10, 1, 2, 3, 4, 5, 6, 7, 8, 9])
array([10, 1, 2, 3, 4, 5, 6, 7, 8, 9])
array([1, 1, 2, 3, 4, 5, 6, 7, 8, 9])
array([10, 1, 2, 3, 4, 5, 6, 7, 8, 9])
五、ndarrry的聚合操作
- np.sum 求和
- np.min 求最小值
- np.max 求最大值
- np.mean 求平均值
- np.average 求平均值
- np.median 求中位数
- np.percentile 求百分位数
- np.argmin 求最小值对应的下标
- np.argmax 求最大值对应的下标
- np.std 求标准差
- np.var 求方差
- np.power 求次幂
- np.argwhere 按条件查找
import numpy as np
a = np.arange(12).reshape(3,4)
sum_a= np.sum(a1,axis=0) #沿着行方向求和:即每一列的和,如果没有axis参数则代表求所有和
# 结果为:array([12, 15, 18, 21])
max_a = np.max(a) # 结果为11
# 若是数组中有控制的存在,直接用sum是求不出来的,可以用np.nansum函数求
b = np.array([1,2,3,np.nan])
np.nansum(b) # 排除掉nan之后的所有数据之和
# 求平均值
average_a = np.mean(a) # 结果为:5.5,也可以这样写:np.average(a)
# 求中位数
median_a = np.median(a,axis=0) # 结果为array([4., 5., 6., 7.])
# 求百分位数
percentile_a = np.percentile(a,q=50)# 结果为:5.5,q=50表示中位数
# 求最大值对应的下标
a = a.reshape(-1)
display(a)
max_index = np.argmax(a)
# 求最小值对应的下标
min_index = np.argmin(a)
# 但这样会出现一个问题,就是argmax与argmin只会找到第一个与之匹配的下标,对于重复的元素却无法检测出。我们可以用argwhere的方法
np.argwhere(a==np.max(a))
# 求次幂
power_a = np.power(a,3) # 结果为:array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729, 1000, 1331], dtype=int32)
# 也可以直接这样写:a**3
# 求标准差
std_a = np.std(a)
# 求方差
var_a = np.var(a)
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
类似于上述的聚合函数还有很多,这里仅给出比较常用的几个,剩下的就不一一列举了。
六、NumPy的矩阵操作
1、基本矩阵操作
1)算数运算符:
- 加减乘除
import numpy as np
n = np.random.randint(0,10,size=(4,5))
display(n)
# 加法运算
n + 10
# 减法运算
n - 10
# 乘法运算
n * 10
# 除法运算
n / 10
# 整除运算
n // 2
# 取余运算
n % 2
array([[7, 9, 6, 8, 8],
[4, 9, 9, 6, 5],
[0, 3, 4, 3, 8],
[1, 2, 5, 5, 2]])
array([[1, 1, 0, 0, 0],
[0, 1, 1, 0, 1],
[0, 1, 0, 1, 0],
[1, 0, 1, 1, 0]], dtype=int32)
两个矩阵之间同样可以用来做运算。
import numpy as np
n1 = np.random.randint(0,10,size=(4,5))
n2 = np.random.randint(0,10,size=(4,5))
n1 + n2 # 对应元素相加
n1 * n2 # 对应元素元素相乘
array([[ 3, 32, 27, 35, 24],
[ 2, 3, 3, 21, 63],
[27, 16, 45, 32, 21],
[45, 18, 0, 63, 81]])
2)线性代数
- 矩阵积运算np.dot(),这里需要满足一个条件:第一个矩阵的列数等于第二个矩阵的行数才能进行运算
import numpy as np
n1 = np.random.randint(0,10,size=(4,5))
n2 = np.random.randint(0,10,size=(5,4))
np.dot(n1,n2) #也可直接n1 @ n2
array([[139, 52, 152, 52],
[110, 55, 131, 34],
[107, 52, 98, 49],
[126, 56, 147, 50]])
- 线性代数中其他矩阵操作:求逆矩阵、求矩阵转置、求矩阵的秩等
import numpy as np
n = np.array([[1,2,3],[2,5,4],[4,5,6]])
# 求矩阵的逆
np.linalg.inv(n)
# 求矩阵的行列式
np.linalg.det(n)
# 求矩阵的秩
np.linalg.matrix_rank(n)
3
2、广播机制
NumPy的广播机制是一种强大的功能,它允许不同形状的数组进行算术运算。广播机制通过自动扩展较小的数组来匹配较大数组的形状,从而使得逐元素操作成为可能。
广播规则:
- 形状对齐:从最右边的维度开始,比较两个数组的形状。如果两个数组维度大小相等,或者其中一个数组的维度大小为1,则这两个数组在该维度上是兼容的。
- 扩展维度:如果其中一个数组在某个维度上的大小为1,而另一个数组在该维度上的大小大于1,则大小为1的数组会在该维度上扩展一匹配另一个数组的大小。
- 不兼容情况:如果在某个维度上,两个数组的大小都不为1且不相等,则这两个数组在改为都上是不兼容的,无法进行广播。
让我们通过一个例子来说明广播机制:
import numpy as np
a = np.ones((2,3),dtype=int)
b = np.arange(3)
a+b
array([[1, 2, 3],
[1, 2, 3]])
3、其他常见数学操作
- abs、aqrt、square、exp、log、sin、cos、tan、round、ceil、floor、cumsum
import numpy as np
n = np.array([1,4,7,8,9],dtype=int)
# 求绝对值
abs_n = np.abs(n)
# 求平方跟
sqrt_n = np.sqrt(n)
# 求平方
square_n = np.square(n)
# 指数运算
exp_n = np.exp(n)
# 对数运算
ln_n = np.log(n) # 以e为底n的对数
log_n = np.log10(n) # 以10为底,n的对数
# 三角函数运算
sin_n = np.sin(n)
# 四舍五入
round_n = np.round(n)
# 向上取整运算
ceil_n = np.ceil(n)
# 向下取整运算
floor_n = np.floor(n)
# 累加运算
cumsum_n = np.cumsum(n)
七、数组的快速排序
- np.sort():不改变原数组
- ndarray.sort():改变原数组,不多占用内存
import numpy as np
n1 = np.random.randint(0,10,size=6)
n2 = np.sort(n1) # 默认是升序排序,不改变原数组相当于重新开辟了一块空间
display(n1,n2)
n3 = np.random.randint(0,10,size=6)
n3.sort() # 改变原数组
array([0, 3, 8, 9, 1, 4])
array([0, 1, 3, 4, 8, 9])
八、ndarray文件操作
保存数据
- save:保存ndarray到一个npy文件
- savez:将多个array保存到一个npz文件中
import numpy as np
x = np.arange(5)
y = np.arange(10,20)
# save
np.save('x',x)
# savez
np.savez('arr.npz',xarr=x,yarr=y)
读取文件
import numpy as np
# 读取npy文件
np.load('x.npy')
# 读取npz文件
np.load('arr.npz')['yarr']
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
csv、txt文件的读写操作
import numpy as np
n = np.random.randint(0,10,size=(3,4))
# 将数据存储到csv或txt文件中
np.savetxt('arr.csv',n,delimiter=',')
# 从csv文件或txt文件中读取数据
np.loadtxt('arr.csv',delimiter=',',dtype=int)
array([[8, 0, 7, 3],
[6, 3, 2, 4],
[9, 3, 8, 7]])
九、例题
知识点差不多讲完了,然后就是需要练习题来检验学习成果,话不多说,我们直接看题:
1、创建一个长度为10的一维全为0的ndarray对象,然后让第五个元素等于1
import numpy as np
a = np.zeros(10,dtype=int)
a[4]=1
2、创建一个元素从10到49的ndarray对象
import numpy as np
b = np.arange(10,50,dtype=int)
3、将第二题的所有元素翻转
import numpy as np
b = np.arange(10,50,dtype=int)
b[::-1]
array([49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33,
32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
15, 14, 13, 12, 11, 10])
4、使用np.random.random创建一个10*10的ndarray对象,并打印出最大和最小的元素
import numpy as np
c = np.random.random(size=(10,10))
max_c = np.max(c)
min_c = np.min(c)
display(max_c,min_c)
0.9974378508965802
0.007652520100204452
5、创建一个10*10的ndarray对象,且矩阵边界全为1,里面全为0
import numpy as np
d = np.ones((10,10),dtype=int)
d[1:-1,1:-1]=0
# 实现方法二:
e = np.zeros((10,10),dtype=int)
e[[0,-1]]=1
e[:,[0,-1]]=1
6、创建一个每一行都是0到4的5*5矩阵
import numpy as np
f = np.arange(5)
f = np.tile(f,(5,1))
# 方法二
g = [0,1,2,3,4]
g = np.array(g*5)
7、创建一个范围在0~1之间长度为12的等差数列
import numpy as np
h = np.linspace(0,1,12)
8、创建一个长度为10的随机数组并排序
import numpy as np
i = np.random.randint(0,10,10)
i.sort()
9、创建一个长度为10的随机数组,并将最大值替换为0
import numpy as np
j = np.random.randint(0,10,10)
max_indexs = np.argwhere(j==np.max(j)).reshape(-1)
j[max_indexs]=0
10、给定一个4维矩阵,如何得到最后两维的和
import numpy as np
k = np.random.randint(1,10,size=(2,3,4,5))
k.sum(axis=(2,3))
array([[116, 108, 108],
[ 94, 103, 101]])
11、给定数组[1,2,3,4,5],如何得到在这个数组的每一个元素之间插入3个0后的新数组
import numpy as np
l = np.arange(1,6)
m = np.zeros(17,dtype=int)
m[::4] = l
m
array([1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5])
12、给定一个二维矩阵,如何交换其中两行元素
import numpy as np
n = np.random.randint(0,10,size=(4,4))
display(n)
temp = n[0].copy()
n[0]=n[1]
n[1]=temp
# 法二
n[[0,1]]=n[[1,0]]
array([[9, 2, 6, 6],
[6, 1, 3, 2],
[8, 3, 0, 4],
[9, 2, 1, 4]])
13、创建一个长度为10000的随机数组,使用两种方法对其求3次方,并比较所用时间
import numpy as np
p = np.random.randint(0,10,size=10000)
# 法一所用时间
%timeit np.power(p,3)
# 法二所用时间
%timeit p**3
38.4 μs ± 9.18 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
40.7 μs ± 5.17 μs per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
14、创建一个5*3的随机矩阵和一个3*5的随机矩阵,求矩阵积
import numpy as np
n1 = np.random.randint(0,10,size=(5,3))
n2 = np.random.randint(0,10,size=(3,5))
np.dot(n1,n2)
array([[ 83, 62, 114, 82, 53],
[ 95, 64, 136, 76, 69],
[ 41, 21, 50, 40, 28],
[ 79, 76, 115, 87, 44],
[ 45, 33, 53, 59, 23]])
15、矩阵的每一行的元素都减去该行的平均值
import numpy as np
r = np.random.randint(0,10,size=(3,4))
mean_r = np.mean(r,axis=1).reshape(3,1)
r - mean_r
array([[-2. , 5. , -1. , -2. ],
[-4.5 , 1.5 , -0.5 , 3.5 ],
[-1.25, -3.25, -0.25, 4.75]])
16、正则化一个5*5的随机矩阵
- 正则的概念:假设a是矩阵中的一个元素,max、min分别是矩阵元素的最大值和最小值,则正则化后a* = (a-min)/(max-min),也可以叫归一化处理
import numpy as np
n = np.random.randint(0,100,size=(5,5))
display(n)
max_n = np.max(n)
min_n = np.min(n)
display(max_n,min_n)
(n - min_n)/(max_n - min_n)
array([[67, 63, 83, 46, 53],
[14, 5, 9, 69, 94],
[76, 74, 53, 2, 31],
[50, 22, 31, 27, 2],
[34, 26, 23, 99, 94]])
99
2
array([[0.67010309, 0.62886598, 0.83505155, 0.45360825, 0.5257732 ],
[0.12371134, 0.03092784, 0.07216495, 0.69072165, 0.94845361],
[0.7628866 , 0.74226804, 0.5257732 , 0. , 0.29896907],
[0.49484536, 0.20618557, 0.29896907, 0.25773196, 0. ],
[0.32989691, 0.24742268, 0.21649485, 1. , 0.94845361]])