一、Numpy介绍
1、介绍
NumPy 是一个运行速度非常快的数学库,主要用于数组计算,包含:
- 一个强大的N维数组对象 ndarray
- 广播功能函数
- 整合 C/C++/Fortran 代码的工具
- 线性代数、傅里叶变换、随机数生成等功能
2、应用
NumPy 通常与 SciPy(Scientific Python)和 Matplotlib(绘图库)一起使用, 这种组合广泛用于替代 MatLab,是一个强大的科学计算环境,有助于我们通过 Python 学习数据科学或者机器学习。
SciPy 是一个开源的 Python 算法库和数学工具包。
SciPy 包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。
Matplotlib 是 Python 编程语言及其数值数学扩展包 NumPy 的可视化操作界面。它为利用通用的图形用户界面工具包,如 Tkinter, wxPython, Qt 或 GTK+ 向应用程序嵌入式绘图提供了应用程序接口(API)。
3、相关链接
- NumPy 官网 http://www.numpy.org/
- NumPy 源代码:https://github.com/numpy/numpy
- SciPy 官网:https://www.scipy.org/
- SciPy 源代码:https://github.com/scipy/scipy
- Matplotlib 官网:https://matplotlib.org/
- Matplotlib 源代码:https://github.com/matplotlib/matplotlib
二、Numpy之ndarray的创建
1、使用np.array()创建数组
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
参数说明:
名称 | 描述 |
---|---|
object | 数组或嵌套的数列 |
dtype | 数组元素的数据类型,可选 |
copy | 对象是否需要复制,可选 |
order | 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认) |
subok | 默认返回一个与基类类型一致的数组 |
ndmin | 指定生成数组的最小维度 |
1.一维数组创建 import numpy as np np.array([1,2,3,4,5],dtype=int) # dtype是指定数组元素的类型 # 结果:array([1, 2, 3, 4, 5])
2.二维数组创建 np.array([[1,2,3],[4,5,6],[7.7,8,9]]) # 结果 array([[1. , 2. , 3. ], [4. , 5. , 6. ], [7.7, 8. , 9. ]]) 注意: numpy默认ndarray的所有元素的类型是相同的 如果传进来的列表中包含不同的类型,则会自定统一为同一类型,优先级:str>float>int
3.最小维度
np.array([1, 2, 3],ndmin=2)
# 结果
[[1,2,3]]
4.使用matplotlib.pyplot获取一个numpy数组,数据来源于一张图片 import matplotlib.pyplot as plt img_arr = plt.imread('meinv.jpg') # 把meinv.jpg这张图片读取成一个三维数组 plt.imshow(img_arr) # 展示这张图片
操作该numpy数据,该操作会同步到图片中
new_arr = img_arr - 100 # 把图片的所有像素减去100
plt.imshow(new_arr)
img_arr.shape # shape:形状(各维度的长度)
# 结果:(353, 626, 3)
2、ndarray 对象属性
属性 | 说明 |
---|---|
ndarray.ndim | 秩,即轴的数量或维度的数量 |
ndarray.shape | 数组的维度,对于矩阵,n 行 m 列 |
ndarray.size | 数组元素的总个数,相当于 .shape 中 n*m 的值 |
ndarray.dtype | ndarray 对象的元素类型 |
ndarray.itemsize | ndarray 对象中每个元素的大小,以字节为单位 |
ndarray.flags | ndarray 对象的内存信息 |
ndarray.real | ndarray元素的实部 |
ndarray.imag | ndarray 元素的虚部 |
ndarray.data | 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。 |
3、使用np的routines函数创建
1. np.ones(shape, dtype=None, order='C') # 创建元素都是1的4行5列的数组 np.ones(shape=(4,5),dtype=float) # 结果 array([[1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.], [1., 1., 1., 1., 1.]])
2. np.zeros(shape, dtype=None, order='C') # 创建元素都是0的4行5列的数组 np.zeros(shape=(4,5),dtype=int) 结果 array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]])
3. np.full(shape, fill_value, dtype=None, order='C') # 第一个参数shape是数组形状,第二个参数fill_value填充的常数 # 创建一个三维数组,有3个元素,每个元素是4行2列的二维数组 np.full(shape=(3,4,2),fill_value=88) # 结果 array([[[88, 88], [88, 88], [88, 88], [88, 88]], [[88, 88], [88, 88], [88, 88], [88, 88]], [[88, 88], [88, 88], [88, 88], [88, 88]]])
4. np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None) 等差数列 # 从0开始直到100,有20个数的等差数列 np.linspace(0,100,20,dtype=int) # 结果 array([ 0, 5, 10, 15, 21, 26, 31, 36, 42, 47, 52, 57, 63, 68, 73, 78, 84, 89, 94, 100])
5. np.arange([start, ]stop, [step, ]dtype=None) # 从0开始直到100(半开半闭区间,不含100),公差为2的等差数列 np.arange(0,100,2) # 结果 array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98])
6. np.random.randint(low, high=None, size=None, dtype='l') 随机生成 # 生成一个3行4列的二维数组,元素值在0到100内随机取 np.random.randint(0,100,size=(3,4)) # 每次结果都不一样的,因为元素是随机的 array([[69, 13, 25, 13], [92, 86, 30, 30], [89, 12, 65, 31]]) # 若想随机生成一次,后面每次都是这个数组,可以这么做 np.random.seed(10) # 那时间固定一次,后面每次随机都只会生成一种结果 np.random.randint(0,100,size=(3,4)) # 无论多少次,结果都是这个 array([[ 9, 15, 64, 28], [89, 93, 29, 8], [73, 0, 40, 36]])
7. np.random.random(size=None) 生成0到1的随机数,左闭右开[0,1) np.random.random(size=(3,4)) # 每次结果都是随机的,每次都不一样 array([[0.33549965, 0.41118255, 0.0768555 , 0.85304299], [0.43998746, 0.12195415, 0.73173462, 0.13878247], [0.76688005, 0.83198977, 0.30977806, 0.59758229]]) # 若想随机生成一次,后面每次都是这个数组,可以这么做 np.random.seed(10) np.random.random(size=(3,4)) # 结果 array([[0.77132064, 0.02075195, 0.63364823, 0.74880388], [0.49850701, 0.22479665, 0.19806286, 0.76053071], [0.16911084, 0.08833981, 0.68535982, 0.95339335]])
三、ndarray的基本操作
1、索引
根据索引修改数据 np.random.seed(1) arr = np.random.randint(0,100,size=(5,5)) # arr的值 array([[37, 12, 72, 9, 75], [ 5, 79, 64, 16, 1], [76, 71, 6, 25, 50], [20, 18, 84, 11, 28], [29, 14, 50, 68, 87]]) # 索引从0开始 arr[1][2] = 55555 # 把索引为1的那行的索引为2的那个数改成55555 # 结果 array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]])
2、切片
# 数组arr array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]]) # 1.获取二维数组前两行 arr[0:2] # 结果 array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1]]) # 2.获取二维数组前两列 arr[:,0:2] # 逗号前面切的是行,后面切的是列,不写代表不切 # 结果 array([[37, 12], [ 5, 79], [76, 71], [20, 18], [29, 14]]) # 3.获取二维数组前两行和前两列数据 arr[0:2,0:2] # 结果 array([[37, 12], [ 5, 79]])
3、切片倒序
将数据反转使用 :: # arr数组 array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]]) # 1.将数组的所有行倒序 arr[::-1] # 结果 array([[ 29, 14, 50, 68, 87], [ 20, 18, 84, 11, 28], [ 76, 71, 6, 25, 50], [ 5, 79, 55555, 16, 1], [ 37, 12, 72, 9, 75]]) # 2.将数组索引为2的行开始倒序 arr[2::-1] # 结果 array([[ 76, 71, 6, 25, 50], [ 5, 79, 55555, 16, 1], [ 37, 12, 72, 9, 75]]) # 3.将数组的所有列倒序 arr[:,::-1] # 结果 array([[ 75, 9, 72, 12, 37], [ 1, 16, 55555, 79, 5], [ 50, 25, 6, 71, 76], [ 28, 11, 84, 18, 20], [ 87, 68, 50, 14, 29]]) # 4.将数组索引为2的列开始倒序 arr[:,2::-1] # 结果 array([[ 72, 12, 37], [55555, 79, 5], [ 6, 71, 76], [ 84, 18, 20], [ 50, 14, 29]]) # 5.全部倒序 arr[::-1,::-1] # 结果 array([[ 87, 68, 50, 14, 29], [ 28, 11, 84, 18, 20], [ 50, 25, 6, 71, 76], [ 1, 16, 55555, 79, 5], [ 75, 9, 72, 12, 37]])
4、变形
使用arr.reshape()函数,注意参数是一个tuple! 新数组的shape属性应该要与原来数组的一致,即新数组元素数量与原数组元素数量要相等。一个参数为-1时,那么reshape函数会根据另一个参数的维度计算出数组的另外一个shape属性值。 # arr array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]]) # 查看arr的维度和大小 arr.shape # (5, 5) 代表是5行5列的二维数组 arr.size # 25 即5*5=25 共25个元素 # 1.变形成25行1列的数组 arr.reshape((25,-1)) # -1表示的是自动计算行或列 # 等同于 arr.reshape((25,1)) # 结果 array([[ 37], [ 12], [ 72], [ 9], [ 75], [ 5], [ 79], [55555], [ 16], [ 1], [ 76], [ 71], [ 6], [ 25], [ 50], [ 20], [ 18], [ 84], [ 11], [ 28], [ 29], [ 14], [ 50], [ 68], [ 87]]) # 2.变形成1行25列 arr.reshape((-1,25)) arr.reshape((1,25)) # 结果 array([[ 37, 12, 72, 9, 75, 5, 79, 55555, 16, 1, 76, 71, 6, 25, 50, 20, 18, 84, 11, 28, 29, 14, 50, 68, 87]]) # 3.图片倒置 # 使用上面那个meinv.jpg # 查看图片原本的形状 img_arr.shape # (353, 626, 3) # 查看图片的大小 img_arr.size # 662934 # 将原数据三维数组变形成一维数组 arr_1 = img_arr.reshape((662934,-1)) # 将arr_1元素倒置 arr_1 = arr_1[::-1] # 再将arr_1重新变形成三维数组 a_img = arr_1.reshape((353, 626, 3)) # 查看结果 plt.imshow(a_img)
5、级联
按轴axis连接array组成一个新的array,0代表纵轴,1代表横轴 # arr数组 array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]]) # arr数组 array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]]) # 1.安照横轴把两个arr拼接成新的数组 np.concatenate((arr,arr),axis=1) # 结果 array([[ 37, 12, 72, 9, 75, 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1, 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50, 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28, 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87, 29, 14, 50, 68, 87]]) # 2.安照横轴把arr和arr1拼接成新的数组 arr1 = np.random.randint(0,100,size=(5,4)) # arr1如下 array([[87, 94, 96, 86], [13, 9, 7, 63], [61, 22, 57, 1], [ 0, 60, 81, 8], [88, 13, 47, 72]]) # 拼接arr和arr1 np.concatenate((arr,arr1),axis=1) # 结果 array([[ 37, 12, 72, 9, 75, 87, 94, 96, 86], [ 5, 79, 55555, 16, 1, 13, 9, 7, 63], [ 76, 71, 6, 25, 50, 61, 22, 57, 1], [ 20, 18, 84, 11, 28, 0, 60, 81, 8], [ 29, 14, 50, 68, 87, 88, 13, 47, 72]]) # 3.按照纵轴拼接两个arr np.concatenate((arr,arr),axis=0) # 结果 array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87], [ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]]) # 4.合并两张照片 img_3 = np.concatenate((img_arr,img_arr,img_arr),axis=1) # 先横轴把照片拼接3次 img_9 = np.concatenate((img_3,img_3,img_3),axis=0) # 再把上面合并后的照片再纵轴合并三次 plt.imshow(img_9)
# 5.np.hstack与np.vstack np.hstack与np.vstack只能拼接数组,不能拼接图片 np.hstack横轴拼接 np.vstack纵轴拼接 np.hstack((arr,arr)) # 结果 array([[ 37, 12, 72, 9, 75, 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1, 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50, 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28, 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87, 29, 14, 50, 68, 87]]) np.vstack((arr,arr)) # 结果 array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87], [ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]]) # 6.级联需要注意的点: 级联的参数是列表:一定要加中括号或小括号 维度必须相同 形状相符:在维度保持一致的前提下,如果进行横向(axis=1)级联,必须保证进行级联的数组行数保持一致。如果进行纵向(axis=0)级联,必须保证进行级联的数组列数保持一致。 可通过axis参数改变级联的方向
6、切分
# 与级联类似,三个函数完成切分工作: np.split(arr,行/列号,轴):参数2是一个列表类型 np.vsplit np.hsplit # 参数 split(arr, indices_or_sections, axis=0) # 把一个数组从左到右按顺序切分 arr:要切分的数组 indices_or_sections:如果是一个整数,就用该数平均切分,如果是一个数组,为沿轴切分的位置 axis:沿着哪个维度进行切向,默认为0,横向切分 # 1. 按整数切分 A = np.arange(16).reshape(4,4) # A的值 array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15]]) # 切横轴,即切成纵向的两个数组 np.split(A,2,axis = 1) # 结果 [array([[ 0, 1], [ 4, 5], [ 8, 9], [12, 13]]), array([[ 2, 3], [ 6, 7], [10, 11], [14, 15]])] # 切纵轴,即切成横向的两个数组 np.split(A,2,axis = 0) # 结果 [array([[0, 1, 2, 3], [4, 5, 6, 7]]), array([[ 8, 9, 10, 11], [12, 13, 14, 15]])] # 2.按元组位置切割 # arr的值 array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]]) # 按照第2行第三列切 np.split(arr,(2,3),axis=1) # 结果 [array([[37, 12], [ 5, 79], [76, 71], [20, 18], [29, 14]]), array([[ 72], [55555], [ 6], [ 84], [ 50]]), array([[ 9, 75], [16, 1], [25, 50], [11, 28], [68, 87]])] # 3.切分照片 plt.imshow(img_arr)
# 按照第300行,切纵轴,切成横向的两部分 plt.imshow(np.split(img_arr,(300,),axis=0)[0])
plt.imshow(np.split(img_arr,(300,),axis=0)[1])
7、副本
可使用copy()函数创建副本 修改操作对副本进行,原数据不会变化 c_arr = arr.copy() c_arr[1][4] = 10010 # arr array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]])
8、ndarray的聚合操作
# 1.求和sum # arr array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]]) # 按照横轴相加 arr.sum(axis=1) # 结果 array([ 205, 55656, 228, 161, 248]) # 按照纵轴相加 arr.sum(axis=0) # 结果 array([ 167, 194, 55767, 129, 241]) # 2. 最大最小值: max/ min # 每行中取最大的值 arr.max(axis=1) # 结果 array([ 75, 55555, 76, 84, 87]) # 每列中取最小的值 arr.min(axis=0) # 结果 array([ 5, 12, 6, 9, 1]) # 3.平均值:mean() # 每行的平均值 arr.mean(axis=1) # 结果 array([ 41. , 11131.2, 45.6, 32.2, 49.6]) # 4.其他聚合函数 Function Name NaN-safe Version Description np.sum np.nansum Compute sum of elements np.prod np.nanprod Compute product of elements np.mean np.nanmean Compute mean of elements np.std np.nanstd Compute standard deviation np.var np.nanvar Compute variance np.min np.nanmin Find minimum value np.max np.nanmax Find maximum value np.argmin np.nanargmin Find index of minimum value np.argmax np.nanargmax Find index of maximum value np.median np.nanmedian Compute median of elements np.percentile np.nanpercentile Compute rank-based statistics of elements np.any N/A Evaluate whether any elements are true np.all N/A Evaluate whether all elements are true np.power 幂运算
四、广播机制
【重要】ndarray广播机制的三条规则:缺失维度的数组将维度补充成进行运算的数组的维度。缺失的数组元素使用已有元素进行补充。
- 规则一:为缺失的维度补1(进行运算的两个数组之间的维度只能相差一个维度)
- 规则二:缺失元素用已有值填充
- 规则三:缺失维度的数组只能有一行或者一列
# 例1: m = np.ones((2, 3)) a = np.arange(3) 求m+a m = np.ones((2, 3)) a = np.arange(3) display(m,a) # m和a array([[1., 1., 1.], [1., 1., 1.]]) array([0, 1, 2]) m+a # 等于这样的相加 array([[1., 1., 1.], [1., 1., 1.]]) array([0, 1, 2], [0, 1, 2]) # 结果 array([[1., 2., 3.], [1., 2., 3.]]) # 例2: a = np.arange(3).reshape((3, 1)) b = np.arange(3) 求a+b a = np.arange(3).reshape(3,1) b = np.arange(3) display(a,b) # a和b的值 array([[0], [1], [2]]) array([0, 1, 2]) a+b # 等于这样相加 array([[0, 0, 0], [1, 1, 1], [2, 2, 2]]) array([0, 1, 2], [0, 1, 2]], [0, 1, 2]]) # 结果 array([[0, 1, 2], [1, 2, 3], [2, 3, 4]])
五、ndarray的排序
np.sort()与ndarray.sort()都可以,但有区别:
- np.sort()不改变输入
- ndarray.sort()本地处理,不占用空间,但改变输入
# arr array([[ 37, 12, 72, 9, 75], [ 5, 79, 55555, 16, 1], [ 76, 71, 6, 25, 50], [ 20, 18, 84, 11, 28], [ 29, 14, 50, 68, 87]]) # 按纵轴排序,且原本的arr数组已经改变了 arr.sort(axis=0) arr # 结果 array([[ 5, 12, 6, 9, 1], [ 20, 14, 50, 11, 28], [ 29, 18, 72, 16, 50], [ 37, 71, 84, 25, 75], [ 76, 79, 55555, 68, 87]]) # 按横轴排序,原本的arr数组不变 np.sort(arr,axis=1) # 结果 array([[ 1, 5, 6, 9, 12], [ 11, 14, 20, 28, 50], [ 16, 18, 29, 50, 72], [ 25, 37, 71, 75, 84], [ 68, 76, 79, 87, 55555]]) # 再查看arr array([[ 5, 12, 6, 9, 1], [ 20, 14, 50, 11, 28], [ 29, 18, 72, 16, 50], [ 37, 71, 84, 25, 75], [ 76, 79, 55555, 68, 87]])