NumPy 多维数组入门到精通
一 前言
NumPy 通常与 SciPy(Scientific Python)和 Matplotlib(绘图库)一起组合使用, 这种组合广泛用于替代 MatLab,是一个强大的科学计算环境,有助于我们通过 Python 学习数据科学或者机器学习;
公众号:知识追寻者
知识追寻者(Inheriting the spirit of open source, Spreading technology knowledge;)
二 NumPy介绍
Numpy是进行科学计算的基础包,其核心功能就是支持对python数组的处理,高效而便捷;其功能包括如下
- 具有功能强大N维数组对象
- 精密的广播功能函数
- 集成 C /C++ 的和 fortran代码工具
- 支持线性代数,傅里叶变化和随机函数等
三 NumPy安装
可以直接使用pip安装也可以使用Anaconda发行的Windwos安装
pip安装示例
pip install numpy
Anaconda 安装示例
conda install numpy
四 Ndarray介绍
ndarray 对象是用于创建N维数组的的数据集对象;创建的数组大小固定,与python的列表最大不同就是python列表大小不固定;其核属性如下
- dtype 每个ndarray都有一个数据类型,比如全是整型的一维数组
- ndim,轴的数量是秩(python中使用 rank称呼)
- shape 表示数组维度的大小,一般统称数组的维是轴(axes),轴的数量是秩(rank);比如(n,m)表示具有n行,m列的矩阵;
- size,数组元素的总个数,相当于 .shape 中 n*m 的值
- itemsize,ndarray 对象中每个元素的大小,以字节为单位
- flags,ndarray 对象的内存信息
- real,ndarray元素的实部
- imag,ndarray 元素的虚部
Ndarray函数如下
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
参数介绍如下:
参数 | 含义 |
---|---|
object | 数组 |
dtype | 数据类型 |
copy | 是否启用复制 |
order | 创建数组的方向,C为行方向,F为列方向,A为任意方向 |
subok | 返回一个与基类类型一致的数组 |
ndmin | 指定生成数组的最小维度 |
五 dtype 概览
数据类型 | 含义 |
---|---|
np.int8 | 字节(-128到127) |
np.int16 | 整数(-32768至32767) |
np.int32 | 整数(-2147483648至2147483647) |
np.int64 | 整数(-9223372036854775808至9223372036854775807) |
np.uint8 | 无符号整数(0到255) |
np.uint16 | 无符号整数(0到65535) |
np.uint32 | 无符号整数(0到4294967295) |
np.uint64 | 无符号整数(0到18446744073709551615) |
np.intp | 用于索引的整数,通常与索引相同 ssize_t |
np.uintp | 整数大到足以容纳指针 |
np.float32 | 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位 |
np.float64/float_ | 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位 |
np.complex64 | 复数,表示双 32 位浮点数 |
np.complex12/complex_ | 复数,表示双 64 位浮点数 |
六 创建数组
6.1 构造函数方式
构造函数方式创建比较自由,完全由用户自定义多维数组作为入参;
创建一维数组
# -*- coding: utf-8 -*-
import numpy as np
# 一维数据
za = np.array([0,5,10,15])
# 打印数组
print(za)
输出
[ 0 5 10 15]
创建二维数组
# -*- coding: utf-8 -*-
import numpy as np
# 一维数据
za = np.array([[0,2,4,6],[1,3,5,7]])
# 打印数组
print(za)
输出
[[0 2 4 6]
[1 3 5 7]]
6.2 随机数方式
创建一个一个2行3列的数组(2*3)
# -*- coding: utf-8 -*-
import numpy as np
# 随机数生成多维数组
nz = np.random.randn(2,3) # 一个2行3列的数组
print(nz)
输出
[[ 1.28315417 0.45088654 -0.85996385]
[ 0.69196783 -1.18493407 -0.68383036]]
6.3 zeros创建全0数组
创建一个2行5列的全0数组(2*5)
# -*- coding: utf-8 -*-
import numpy as np
# 全0数组
print(np.zeros((2,5),dtype=np.int))
输出
[[0 0 0 0 0]
[0 0 0 0 0]]
6.4 ones创建全1 数组
创建一个2行5列的全1数组(2*5)
# -*- coding: utf-8 -*-
import numpy as np
# 全1数组
print(np.ones((2,5),dtype=np.int))
输出
[[1 1 1 1 1]
[1 1 1 1 1]]
6.5 使用empty创建数组
创建一个3个2行4列的数组(3*2*4
)
# -*- coding: utf-8 -*-
import numpy as np
print(np.empty((3,2,4),dtype=np.float64))
输出
[[[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]]]
6.6使用内置板块创建数组
创建一个1*10的数组
# -*- coding: utf-8 -*-
import numpy as np
# 内置数组板块
arr = np.arange(10)
print(arr)
输出
[0 1 2 3 4 5 6 7 8 9]
创建一个一维数组,元素从10-30之间选取,步长为5
arr = np.arange(10,30,5)
print(arr)
输出
[10 15 20 25]
七数组属性
7.1 数组维度
创建一个3*2*3
的数组
# -*- coding: utf-8 -*-
import numpy as np
arr = np.empty((3,2,3),dtype=np.int8)
# 打印数组
print(arr)
# 打印数组维度
print(arr.ndim)
输出
[[[ 69 0 110]
[ 0 97 0]]
[[ 98 0 108]
[ 0 101 0]]
[[100 0 0]
[ 0 73 0]]]
3
7.2 数组形状
# -*- coding: utf-8 -*-
import numpy as np
arr = np.empty((3,2,3),dtype=np.int8)
# 打印数组
print(arr)
#打印数组形状
print(arr.shape)
输出
[[[ 69 0 110]
[ 0 97 0]]
[[ 98 0 108]
[ 0 101 0]]
[[100 0 0]
[ 0 73 0]]]
(3, 2, 3)
7.3 数组字节数
itemsize 返回的是每个数组中每个元素的字节大小,指定了int8表示8bit为1个字节;
# -*- coding: utf-8 -*-
import numpy as np
arr = np.empty((3,2,3),dtype=np.int8)
# 打印数组
print(arr)
# 打印数组字节数
print(arr.itemsize)
输出
[[[ 69 0 110]
[ 0 97 0]]
[[ 98 0 108]
[ 0 101 0]]
[[100 0 0]
[ 0 73 0]]]
1
7.4 打印内存对象
# -*- coding: utf-8 -*-
import numpy as np
arr = np.empty((3,2,3),dtype=np.int8)
# 打印内存对象
print(arr.flags)
输出
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False
7.5数组数据类型
# -*- coding: utf-8 -*-
import numpy as np
arr = np.empty((3,2,3),dtype=np.int8)
# 打印数组
print(arr)
# 打印数组数据类型
print(arr.dtype)
输出
[[[ 0 0 0]
[124 0 106]]
[[ 0 124 1]
[106 0 107]]
[[ 3 114 62]
[100 1 -96]]]
int8
八 数组基本操作
8.1 算术运算
数组的算术运算会应运到数组的每个元素;如果是2个矩阵间的运算就会在对应的位置进行符号运算;那么如下操作中都是元素级操作;
【加法】
# -*- coding: utf-8 -*-
import numpy as np
# 一维数组
arr = np.array([0,2,4,6])
# 数组加2
plus = arr+2
print(plus)
输出
[2 4 6 8]
矩阵间
# -*- coding: utf-8 -*-
import numpy as np
# 一维数组
arr1 = np.array([0,2,4,6])
arr2 = np.array([1,3,5,7])
arr = arr2 + arr1
print(arr)
输出
[ 1 5 9 13]
【减法】
# -*- coding: utf-8 -*-
import numpy as np
# 一维数组
arr = np.array([0,2,4,6])
# 数组减2
sub = arr-2
print(sub)
输出
[-2 0 2 4]
矩阵间
# -*- coding: utf-8 -*-
import numpy as np
# 一维数组
arr1 = np.array([0,2,4,6])
arr2 = np.array([1,3,5,7])
arr = arr2 - arr1
print(arr)
输出
[1 1 1 1]
【乘法】
# -*- coding: utf-8 -*-
import numpy as np
# 一维数组
arr = np.array([0,2,4,6])
# 数组乘2
sub = arr*2
print(sub)
输出
[ 0 4 8 12]
矩阵间
# -*- coding: utf-8 -*-
import numpy as np
# 一维数组
arr1 = np.array([0,2,4,6])
arr2 = np.array([1,3,5,7])
arr = arr2 * arr1
print(arr)
输出
[ 0 6 20 42]
【除法】
# -*- coding: utf-8 -*-
import numpy as np
# 一维数组
arr = np.array([0,2,4,6])
# 数组除法
sub = arr/3
print(sub)
输出
[0. 0.66666667 1.33333333 2. ]
【平方】
# -*- coding: utf-8 -*-
import numpy as np
# 一维数组
arr = np.array([0,2,4,6])
# 数组平方
sub = arr**2
print(sub)
输出
[ 0 4 16 36]
【正弦】
# -*- coding: utf-8 -*-
import numpy as np
# 一维数组
arr1 = np.array([0,2,4,6])
arr2 = np.array([1,3,5,7])
arr = arr2 * np.sin(arr1)
print(arr)
输出
[ 0. 2.72789228 -3.78401248 -1.95590849]
【平方根】
# -*- coding: utf-8 -*-
import numpy as np
# 一维数组
arr1 = np.array([0,2,4,6])
arr2 = np.array([1,3,5,7])
arr = arr2 * np.sqrt(arr1)
print(arr)
输出
[ 0. 4.24264069 10. 17.1464282 ]
8.2 矩阵积
矩阵积也就是线性代数的矩阵运算方式,如下方式中是 3*3
的矩阵运算方式
A*B <=> np.dot(A,B)
# -*- coding: utf-8 -*-
import numpy as np
arr1 = np.array([
[1,1,1],
[2,2,2],
[3,3,3]
])
arr2 = np.array([
[1,2,3],
[4,5,6],
[7,8,9]
])
arr = np.dot(arr1,arr2)
print(arr)
输出
[[12 15 18]
[24 30 36]
[36 45 54]]
B*A <=> np.dot(B,A)
# -*- coding: utf-8 -*-
import numpy as np
arr1 = np.array([
[1,1,1],
[2,2,2],
[3,3,3]
])
arr2 = np.array([
[1,2,3],
[4,5,6],
[7,8,9]
])
arr = np.dot(arr2,arr1)
print(arr)
输出
[[14 14 14]
[32 32 32]
[50 50 50]]
8.3 自增自减操作
自增,自减也是针对元素级操作
【自减】
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([1,1,1])
arr -= 1
print(arr)
输出
[0 0 0]
【自增】
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([1,1,1])
arr += 1
print(arr)
输出
[2 2 2]
8.4 通用函数
NumPy 提供了很多通用函数,知识追寻者在这边示例只是部分,读者使用到时应该查阅官方文档;
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([1,1,1])
# 求和
sum = np.sum(arr)
print(sum)
# 指数e
exp = np.exp(arr)
print(exp)
# 平方根
sqr = np.sqrt(arr)
print(sqr)
# 加
add = np.add(arr,np.array([2,2,2]))
print(add)
输出
3
[2.71828183 2.71828183 2.71828183]
[1. 1. 1.]
[3 3 3]
8.5 布尔操作
直接使用关系运算符操作,应用于元素级别
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([
[1,2,3,4,5],
[2,3,4,5,6],
[3,4,5,6,7]
])
print(arr>5)
输出
[[False False False False False]
[False False False False True]
[False False False True True]]
九 索引切片
数组的索引也是和字符串类似,比如[1,1,1]这个数组的正向索引就是0,1,2;负向索引就是-3,-2,-1;
9.1一维数组切片
取索引1到3(不包括3)
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([1,2,3,4,5])
print(arr[1:3])
输出
[2 3]
取 索引1到数组末尾
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([1,2,3,4,5])
print(arr[1:])
输出
[2 3 4 5]
取索引-3到-1
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([1,2,3,4,5])
print(arr[-3:-1])
输出
[3 4]
9.2二维索引切片
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([
[1,2,3,4,5],
[2,3,4,5,6],
[3,4,5,6,7]
])
# 获取第一行
print(arr[0])
# 获取第一行第三列
print(arr[0,2])
# 获取1-2行
print(arr[0:2])
# 获取1-2行 每行的前2个元素
print(arr[0:2,0:2])
输出
[1 2 3 4 5]
3
[[1 2 3 4 5]
[2 3 4 5 6]]
[[1 2]
[2 3]]
十数组迭代
10.1 一维数组迭代
一维数组迭代直接使用for循环
# -*- coding: utf-8 -*-
import numpy as np
arr = np.arange(10,dtype=np.int8)
for i in arr:
print(i)
输出
0
1
2
3
4
5
6
7
8
9
10.2 二维数组迭代
二维数组迭代,内嵌一个for循环
# -*- coding: utf-8 -*-
import numpy as np
arr = np.empty((2,3),dtype=np.int8)
print(arr)
for row in arr:
for column in row:
print(column)
输出
[[0 0 5]
[0 0 0]]
0
0
5
0
0
0
10.3 使用函数迭代
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([
[1,2,3,4,5],
[2,3,4,5,6],
[3,4,5,6,7]
])
# 0 轴 代表行索引
max = np.apply_along_axis(np.max,axis=0,arr=arr)
# 1 轴代表列索引
min = np.apply_along_axis(np.min,axis=1,arr=arr)
print(max)
print(min)
输出
[3 4 5 6 7]
[1 2 3]
十一 形状操作
11.1 形状调整
重新调整大小的规则是shape各个属性的积一致;比如 2*2*3
= 3*6
# -*- coding: utf-8 -*-
import numpy as np
arr = np.empty((3,2,3),dtype=np.int8)
# 打印数组
print(arr)
# 调整形状大小
re = arr.reshape(3,6)
print(re)
输出
[[[ 69 0 110]
[ 0 97 0]]
[[ 98 0 108]
[ 0 101 0]]
[[100 0 0]
[ 0 73 0]]]
[[ 69 0 110 0 97 0]
[ 98 0 108 0 101 0]
[100 0 0 0 73 0]]
注 使用resize 会改变数组本身
11.2 形状可逆
将一个 3*4
的矩阵改变为2*6
, 使用ravel()函数后会为一维数组
# -*- coding: utf-8 -*-
import numpy as np
arr = np.random.random((3,4))
# 改变形状
res = arr.reshape(2,6)
# 可逆
vel = res.ravel()
print(vel)
输出
[0.31196361 0.21399829 0.7420462 0.07945804 0.44684642 0.15533381
0.39328725 0.33091821 0.36530517 0.99345252 0.44964442 0.23923565]
11.3 行列交换
将矩阵的行转与列互换
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([[ 2., 8., 0., 6.],
[ 4., 5., 1., 1.],
[ 8., 9., 3., 6.]])
print(arr.transpose())
输出
[[2. 4. 8.]
[8. 5. 9.]
[0. 1. 3.]
[6. 1. 6.]]
十二叠加操作
12.1hstack
将第二个数组作为列叠加至第一个数组
# -*- coding: utf-8 -*-
import numpy as np
arr1 = np.ones((3,3))
arr2 = np.zeros((3,3))
# 将arr2作为列叠加至arr1
print(np.hstack((arr1,arr2)))
输出
[[1. 1. 1. 0. 0. 0.]
[1. 1. 1. 0. 0. 0.]
[1. 1. 1. 0. 0. 0.]]
12.2 vstack
将第二个数组作为行叠加至第一个数组
# -*- coding: utf-8 -*-
import numpy as np
arr1 = np.ones((3,3))
arr2 = np.zeros((3,3))
# 将arr2作为行叠加至arr1
print(np.vstack((arr1,arr2)))
输出
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
12.3 column_stack
将一维数组作为列形成新的二维数组(1D变2D)
# -*- coding: utf-8 -*-
import numpy as np
arr1 = np.ones((1,3))
arr2 = np.zeros((1,3))
print(np.column_stack((arr1,arr2)))
输出
[[1. 1. 1. 0. 0. 0.]]
12.4 row_stack
将一维数组作为行形成新的二维数组(1D变2D)
# -*- coding: utf-8 -*-
import numpy as np
arr1 = np.ones((1,3))
arr2 = np.zeros((1,3))
print(np.row_stack((arr1,arr2)))
输出
[[1. 1. 1.]
[0. 0. 0.]]
十三 数组切分
13.1 水平切分
将一个4*4
的矩阵按照宽度切分为两个 4*2
# -*- coding: utf-8 -*-
import numpy as np
arr = np.ones((4,4))
[A,B]= np.hsplit(arr,2)
print(A)
print(B)
输出
[[1. 1.]
[1. 1.]
[1. 1.]
[1. 1.]]
[[1. 1.]
[1. 1.]
[1. 1.]
[1. 1.]]
13.2 垂直切分
将一个4*4
的矩阵按照高度切分为两个 2*4
# -*- coding: utf-8 -*-
import numpy as np
arr = np.ones((4,4))
[A,B]= np.vsplit(arr,2)
print(A)
print(B)
输出
[[1. 1. 1. 1.]
[1. 1. 1. 1.]]
[[1. 1. 1. 1.]
[1. 1. 1. 1.]]
13.3 指定切分
指定切分是指按照轴切分矩阵为多个小矩阵;如下示例中按照行索引轴切分,分别切分为三个部分;[1,3]会被切分为[:1],[1:3],[3:]
# -*- coding: utf-8 -*-
import numpy as np
arr = np.ones((4,4))
[A,B,C]= np.split(arr,[1,3],axis=0)
print(A)
print(B)
print(C)
输出
[[1. 1. 1. 1.]]
[[1. 1. 1. 1.]
[1. 1. 1. 1.]]
[[1. 1. 1. 1.]]
十四 副本与视图
视图
是指对数据的引用,在操作视图的同时也会改变元数据,如上操作的切片都是视图操作,会对原数据产生影响;副本
是指对数据完整的拷贝,副本拥有独立的内存空间,故对副本进行修改不会改变原来的数据;
14.1 视图
如下示例中改变视图数组第一个元素,原数组的第一个元素也会被改变;
# -*- coding: utf-8 -*-
import numpy as np
arr = np.arange(10)
print(arr)
vw = arr.view()
vw[0]= 100
print(arr)
输出
[0 1 2 3 4 5 6 7 8 9]
[100 1 2 3 4 5 6 7 8 9]
14.2 副本
如下示例中改变副本数组第一个元素,原数组的第一个元素不会被改变;
# -*- coding: utf-8 -*-
import numpy as np
arr = np.arange(10)
print(arr)
vw = arr.copy()
vw[0]= 100
print(arr)
输出
[0 1 2 3 4 5 6 7 8 9]
[0 1 2 3 4 5 6 7 8 9]
十五 广播规则
在不同形状的数组进行运算时需要遵守广播规则;通常情况下都是shape形同,那么对应位置的元数进行算术操作即可;
- 当输入的数组具有不同数量的的维度时,会将1 预先填充至位置,直到数组的形状形同;
- 如果元素缺失,则会用已有的元素进行替换填充;
如下示例中 数组B 是 1 * 3
经过规则一后面两行会变为全是1 ,此时应该是 3 * 3
; 经过规则二后 会变为元素都是全是2 的3 * 3
矩阵;
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
B = np.array([2,2,2])
print(arr * B)
输出
[[ 2 4 6]
[ 8 10 12]
[14 16 18]]
十六 数组的读取和保存
16.1 二进制形式保存数组
保存单个数组时可以调用save方法,自动添加后缀.npy
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
np.save('dirs/numpy_z',arr)
保存多个数组时调用savez方法,自动添加后缀.npz
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
arr2 = np.arange(10)
np.savez('dirs/numpy_zz',arr,arr2)
16.2 文件中读取数组
读取【.npy】
arr = np.load('dirs/numpy_z.npy')
print(arr)
输出
[[1 2 3]
[4 5 6]
[7 8 9]]
读取【.npz】
# -*- coding: utf-8 -*-
import numpy as np
arr = np.load('dirs/numpy_zz.npz')
print(arr.files)
print(arr['arr_0'])
输出
['arr_0', 'arr_1']
[[1 2 3]
[4 5 6]
[7 8 9]]
16.3 保存和读取txt文本数组
# -*- coding: utf-8 -*-
import numpy as np
arr = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
# 保存为txt,十进制形式,分格符为逗号
np.savetxt('dirs/numpy_z.txt',arr,fmt="%d", delimiter=",")
# 读取文件以整数形式,分格符为逗号
val = np.loadtxt('dirs/numpy_z.txt',dtype=int, delimiter=',')
print(val)
输出
[[1 2 3]
[4 5 6]
[7 8 9]]
还支持 csv格式读者可以参考官方文档进行学习;