NumPy教程–学习笔记1
文章目录
1. 前言介绍
NumPy 简介
NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。NumPy 是一个运行速度非常快的数学库,主要用于数组计算,包含:
- 一个强大的N维数组对象 ndarray
- 广播功能函数
- 整合 C/C++/Fortran 代码的工具
- 线性代数、傅里叶变换、随机数生成等功能
NumPy 应用
NumPy 通常与 SciPy(Scientific Python)和 Matplotlib(绘图库)一起使用, 这种组合广泛用于替代 MatLab,是一个强大的科学计算环境,有助于我们通过 Python 学习数据科学或者机器学习。
SciPy 是一个开源的 Python 算法库和数学工具包。
SciPy 包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。
Matplotlib 是 Python 编程语言及其数值数学扩展包 NumPy 的可视化操作界面。它为利用通用的图形用户界面工具包,如 Tkinter, wxPython, Qt 或 GTK+ 向应用程序嵌入式绘图提供了应用程序接口(API)。
相关链接
- 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 安装
Anaconda: 免费 Python 发行版,用于进行大规模数据处理、预测分析,和科学计算,致力于简化包的管理和部署。支持 Linux, Windows 和 Mac 系统。
2. NumPy Ndarray对象
N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。
ndarray 对象是用于存放同类型元素的多维数组。
ndarray 中的每个元素在内存中都有相同存储大小的区域。
ndarray 内部由以下内容组成:
- 一个指向数据(内存或内存映射文件中的一块数据)的指针。
- 数据类型或 dtype,描述在数组中的固定大小值的格子。
- 一个表示数组形状(shape)的元组,表示各维度大小的元组。
- 一个跨度元组(stride),其中的整数指的是为了前进到当前维度下一个元素需要"跨过"的字节数。
创建一个 ndarray 只需调用 NumPy 的 array 函数:
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
# object 表示数组或嵌套的数列
# dtype 表示数组元素的数据类型,可选
# copy 表示对象是否需要复制,可选
# order 表示创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
# subok 表示默认返回一个与基类类型一致的数组
# ndmin 表示指定生成数组的最小维度
# 示例
import numpy as np
a = np.array([1,2,3])
print (a)
3. NumPy 数据类型
numpy 支持的数据类型比 Python 内置的类型要多很多,基本上可以和 C 语言的数据类型对应上
数据类型对象 (dtype)
数据类型对象(numpy.dtype 类的实例)用来描述与数组对应的内存区域是如何使用,它描述了数据的以下几个方面::
- 数据的类型(整数,浮点数或者 Python 对象)
- 数据的大小(例如, 整数使用多少个字节存储)
- 数据的字节顺序(小端法或大端法)
- 在结构化类型的情况下,字段的名称、每个字段的数据类型和每个字段所取的内存块的部分
- 如果数据类型是子数组,那么它的形状和数据类型是什么。
字节顺序是通过对数据类型预先设定 < 或 > 来决定的。 < 意味着小端法 (最小值存储在最小的地址,即低位组放在最前面)。> 意味着大端法 (最重要的字节存储在最小的地址,即高位组放在最前面)。
dtype 对象是使用以下语法构造的:
numpy.dtype(object, align, copy)
- object - 要转换为的数据类型对象
- align - 如果为 true,填充字段使其类似 C 的结构体。
- copy - 复制 dtype 对象 ,如果为 false,则是对内置数据类型对象的引用
实例:
import numpy as np
# 使用标量类型
dt = np.dtype(np.int32)
print(dt)
import numpy as np
# int8, int16, int32, int64 四种数据类型可以使用字符串 'i1', 'i2','i4','i8' 代替
dt = np.dtype('i4')
print(dt)
import numpy as np
# 字节顺序标注
dt = np.dtype('<i4')
print(dt)
下面实例展示结构化数据类型的使用,类型字段和对应的实际类型将被创建。
# 首先创建结构化数据类型
import numpy as np
dt = np.dtype([('age',np.int8)])
print(dt)
>>
[('age', 'i1')]
# 将数据类型应用于 ndarray 对象
import numpy as np
dt = np.dtype([('age',np.int8)])
a = np.array([(10,),(20,),(30,)], dtype = dt)
print(a)
>>
[(10,) (20,) (30,)]
# 类型字段名可以用于存取实际的age列
import numpy as np
dt = np.dtype([('age',np.int8)])
a = np.array([(10,),(20,),(30,)], dtype = dt)
print(a['age'])
>>
[10 20 30]
下面的示例定义一个结构化数据类型 student,包含字符串字段 name,整数字段 age,及浮点字段 marks,并将这个 dtype 应用到 ndarray 对象。
import numpy as np
student = np.dtype([('name','S20'),('age','i1'),('marks','f4')])
a = np.array([('abc',21,50),('xyz',18,25)],dtype = student)
print(student)
print(a)
>>
[('name', 'S20'), ('age', 'i1'), ('marks', 'f4')]
[('abc', 21, 50.0), ('xyz', 18, 75.0)]
每个内建类型都有一个唯一定义它的字符代码,如下:
字符 | 对应类型 |
---|---|
b | 布尔型 |
i | (有符号) 整型 |
u | 无符号整型 integer |
f | 浮点型 |
c | 复数浮点型 |
m | timedelta(时间间隔) |
M | datetime(日期时间) |
O | (Python) 对象 |
S, a | (byte-)字符串 |
U | Unicode |
V | 原始数据 (void) |
4. NumPy 数组属性
NumPy 数组的维数称为秩(rank),秩就是轴的数量,即数组的维度,一维数组的秩为 1,二维数组的秩为 2,以此类推。
在 NumPy中,每一个线性的数组称为是一个轴(axis),也就是维度(dimensions)。比如说,二维数组相当于是两个一维数组,其中第一个一维数组中每个元素又是一个一维数组。所以一维数组就是 NumPy 中的轴(axis),第一个轴相当于是底层数组,第二个轴是底层数组里的数组。而轴的数量——秩,就是数组的维数。
很多时候可以声明 axis。axis=0,表示沿着第 0 轴进行操作,即对每一列进行操作;axis=1,表示沿着第1轴进行操作,即对每一行进行操作。
NumPy 的数组中比较重要 ndarray 对象属性有:
属性 | 说明 |
---|---|
ndarray.ndim | 秩,即轴的数量或维度的数量 |
ndarray.shape | 数组的维度,对于矩阵,n 行 m 列 |
ndarray.reshape | 给数组一个新的形状而不改变其数据,注释 |
ndarray.size | 数组元素的总个数,相当于 .shape 中n*m 的值 |
ndarray.resize | 两种用法,见下注释 |
ndarray.dtype | ndarray 对象的元素类型 |
ndarray.itemsize | ndarray 对象中每个元素的大小,以字节为单位 |
ndarray.flags | ndarray 对象的内存信息 |
ndarray.real | ndarray元素的实部 |
ndarray.imag | ndarray 元素的虚部 |
ndarray.data | 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。 |
1)ndarray.ndim–秩
ndarray.ndim 用于返回数组的维数,等于秩。
实例:
import numpy as np
a = np.arange(24)
# arange()像内置函数range,返回的是ndarray数组而不是一个列表
print(a)
# a = [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]
print (a.ndim) # a 现只有一个维度 ,结果为1
# 现在调整其大小
b = a.reshape(2,4,3) # b 现在拥有三个维度 2*4*3,2个数组,每个都是4行3列的
print (b.ndim) # 结果为3
print(b)
>>
[[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
[[12 13 14]
[15 16 17]
[18 19 20]
[21 22 23]]]
2)arange 创建数组
import numpy as np
a = np.arange(10)
b = np.arange(10, 20)
c = np.arange(10, 20, 2)
print(a)
print(b)
print(c)
>>
[0 1 2 3 4 5 6 7 8 9]
[10 11 12 13 14 15 16 17 18 19]
[10 12 14 16 18]
3)ndarray.shape–维度(行,列)
ndarray.shape 表示数组的维度,返回一个元组,这个元组的长度就是维度的数目,即 ndim 属性(秩)。比如,一个二维数组,其维度表示"行数"和"列数"。
import numpy as np
data = np.array([(9.5256, -2.4601, -8.8565), (5.6385, 2.3794, 9.104)])
print(data*10) # 各元素乘10
print(data + data) # 各元素相加即乘2
print(data.shape) # 返回元组的维度,(2,3)
print(data.dtype) # 返回对象的数据类型 float64
ndarray.shape 也可以用于调整数组大小。
a = np.array([[1,2,3],[4,5,6]])
a.shape = (3,2)
print (a)
>>
[[1 2]
[3 4]
[5 6]]
4)ndarray.resize–修改数据
resize有两种使用方式,一种是没有返回值的,直接对原始的数据进行修改,还有一种用法是有返回值的,所以不会修改原有的数组值。
# 1.1有返回值,不对原始数据进行修改
import numpy as np
X=np.array([[1,2,3,4],
[5,6,7,8],
[9,10,11,12]])
X_new=np.resize(X,(3,3)) # do not change the original X
print("X:\n",X) # original X
print("X_new:\n",X_new) # new X
>>
X:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
X_new:
[[1 2 3]
[4 5 6]
[7 8 9]]
# 1.2无返回值,直接修改原始数组的大小
X_2=X.resize((3,3)) #change the original X ,and do not return a value
print("X:\n",X) # change the original X
print("X_2:\n",X_2) # return None
>>
X:
[[1 2 3]
[4 5 6]
[7 8 9]]
X_2:
None
5)ndarray.itemsize–返回元素的字节大小
ndarray.itemsize 以字节的形式返回数组中每一个元素的大小。
例如,一个元素类型为 float64 的数组 itemsize 属性值为 8(float64 占用 64 个 bits,每个字节长度为 8,所以 64/8,占用 8 个字节),又如,一个元素类型为 complex32 的数组 item 属性为 4(32/8)。
6)ndarray.flags–内存
ndarray.flags 返回 ndarray 对象的内存信息,包含以下属性:
属性 | 描述 |
---|---|
C_CONTIGUOUS © | 数据是在一个单一的C风格的连续段中,行 |
F_CONTIGUOUS (F) | 数据是在一个单一的Fortran风格的连续段中,列 |
OWNDATA (O) | 数组拥有它所使用的内存或从另一个对象中借用它 |
WRITEABLE (W) | 数据区域可以被写入,将该值设置为 False,则数据为只读 |
ALIGNED (A) | 数据和所有元素都适当地对齐到硬件上 |
UPDATEIFCOPY (U) | 这个数组是其它数组的一个副本,当这个数组被释放时,原数组的内容将被更新 |
x = np.array(([1, 2, 3, 4, 5], [6, 7, 8, 9, 10]))
print(x.flags)
>>
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False
5. NumPy 创建数组
ndarray 数组除了可以使用底层 ndarray 构造器来创建外,也可以通过以下几种方式来创建。默认浮点数
函数 | 描述 | 格式 |
---|---|---|
numpy.empty | 用来创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组: | numpy.empty(shape, dtype = float, order = ‘C’) |
numpy.zeros | 创建指定大小的数组,数组元素以 0 来填充: | numpy.zeros(shape, dtype = float, order = ‘C’) |
numpy.ones | 创建指定形状的数组,数组元素以 1 来填充 | numpy.ones(shape, dtype = None, order = ‘C’) |
numpy.eye | 创建单位矩阵 | a = numpy.eye(5) |
y = np.zeros((5,), dtype=np.int, order='F')
print(y)
z = np.zeros((2, 4), dtype=[('x', 'f4'), ('y', 'i4')]) # 1
# z = np.zeros((2, 4), dtype=np.int) # 2
print(z)
>>1
[0 0 0 0 0]
[[(0., 0) (0., 0) (0., 0) (0., 0)]
[(0., 0) (0., 0) (0., 0) (0., 0)]]
>>2
[[0 0 0 0]
[0 0 0 0]]
order 中的 C 应该是从低维度开始读写,而 F 顺序则是从高维度开始读写。
>>> import numpy as np
>>> a = np.array([[[1, 2],[3, 4],[5,6]],[[7, 8],[9,10],[11,12]]])
>>> print(a.shape)
(2, 3, 2)
>>> a
array([[[ 1, 2],
[ 3, 4],
[ 5, 6]],
[[ 7, 8],
[ 9, 10],
[11, 12]]])
>>> np.reshape(a, (4, 3)) # 这里默认 order 为 C
array([[ 1, 2, 3],
[ 4, 5, 6],
[ 7, 8, 9],
[10, 11, 12]])
>>> np.reshape(a, (4, 3), order='F')
array([[ 1, 5, 4],
[ 7, 11, 10],
[ 3, 2, 6],
[ 9, 8, 12]])
>>>F从外层1开始7 3 9 5 11 2 8 4 10 6 12,
6. NumPy 从已有的数组创建数组
1)numpy.asarray
numpy.asarray 类似 numpy.array,但 numpy.asarray 参数只有三个,比 numpy.array 少两个。
numpy.asarray(a, dtype = None, order = None)
参数说明:
参数 | 描述 |
---|---|
a | 任意形式的输入参数,可以是,列表, 列表的元组, 元组, 元组的元组, 元组的列表,多维数组 |
dtype | 数据类型,可选 |
order | 可选,有"C"和"F"两个选项,分别代表,行优先和列优先,在计算机内存中的存储元素的顺序。 |
import numpy as np
# 1.将列表转换为 ndarray:
x = [1,2,3]
a = np.asarray(x)
print (a)
>>[1 2 3]
# 2.将元组列表转换为 ndarray:
x = [(1,2,3),(4,5)]
a = np.asarray(x)
print (a)
>>[(1, 2, 3) (4, 5)]
# 3.设置了 dtype 参数:
x = [1,2,3]
a = np.asarray(x, dtype = float)
print (a)
>>[ 1. 2. 3.]
2)numpy.frombuffer–动态数组
numpy.frombuffer 用于实现动态数组。
numpy.frombuffer 接受 buffer 输入参数,以流的形式读入转化成 ndarray 对象。
numpy.frombuffer(buffer, dtype = float, count = -1, offset = 0)
注意:buffer 是字符串时,Python3 默认 str 是 Unicode 类型,所以要转成 bytestring 在原 str 前加上 b。
参数说明:
参数 | 描述 |
---|---|
buffer | 可以是任意对象,会以流的形式读入。 |
dtype | 返回数组的数据类型,可选 |
count | 读取的数据数量,默认为-1,读取所有数据。 |
offset | 读取的起始位置,默认为0。 |
# Python3.x 实例
import numpy as np
s = b'Hello World'
a = np.frombuffer(s, dtype = 'S1')
print (a)
>>[b'H' b'e' b'l' b'l' b'o' b' ' b'W' b'o' b'r' b'l' b'd']
3)numpy.fromiter–返回一维数组
numpy.fromiter 方法从可迭代对象中建立 ndarray 对象,返回一维数组。
numpy.fromiter(iterable, dtype, count=-1)
参数 | 描述 |
---|---|
iterable | 可迭代对象 |
dtype | 返回数组的数据类型 |
count | 读取的数据数量,默认为-1,读取所有数据 |
import numpy as np
# 使用 range 函数创建列表对象
list=range(5)
it=iter(list)
# 使用迭代器创建 ndarray
x=np.fromiter(it, dtype=float)
print(x)
>>[0. 1. 2. 3. 4.]
7. NumPy 从数值范围创建数组
1)numpy.arange–指定范围创建数组
numpy 包中的使用 arange 函数创建数值范围并返回 ndarray 对象,函数格式如下:
numpy.arange(start, stop, step, dtype)
根据 start 与 stop 指定的范围以及 step 设定的步长,生成一个 ndarray。
参数说明:
参数 | 描述 |
---|---|
start | 起始值,默认为0 |
stop | 终止值(不包含) |
step | 步长,默认为1 |
dtype | 返回ndarray 的数据类型,如果没有提供,则会使用输入数据的类型。 |
实例:生成 0 到 5 的数组:
import numpy as np
x = np.arange(5)
print (x)
>>[0 1 2 3 4]
# 设置返回类型位 float:
x = np.arange(5, dtype = float)
print (x)
>>[0. 1. 2. 3. 4.]
# 设置了起始值、终止值及步长:
x = np.arange(10,20,2)
print (x)
>>[10 12 14 16 18]
2)numpy.linspace–创建等差数列一维数组
numpy.linspace
函数用于创建一个一维数组,数组是一个等差数列构成的,格式如下:
np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
参数说明:
参数 | 描述 |
---|---|
start | 序列的起始值 |
stop | 序列的终止值,如果endpoint 为true ,该值包含于数列中 |
num | 要生成的等步长的样本数量,默认为50 , 50个数 |
endpoint | 该值为 true 时,数列中包含stop 值,反之不包含,默认是True。 |
retstep | 如果为 True 时,生成的数组中会显示间距,反之不显示。 |
dtype | ndarray 的数据类型,默认浮点数 |
以下实例用到三个参数,设置起始点为 1 ,终止点为 10,数列个数为 10。
import numpy as np
a = np.linspace(10, 20, 5, endpoint=False) # 1 不包含20,公差为(20-10)/5=2
b = np.linspace(10, 20, 5) # 2 包含20,公差为(20-10)/4=2.5
>>[10. 12. 14. 16. 18.] # 1
[10. 12.5 15. 17.5 20. ] # 2
以下实例设置间距。
import numpy as np
a =np.linspace(1, 10, 10, retstep=True)
print(a)
>>(array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.]), 1.0)
b =np.linspace(1,10,10).reshape([10,1]) # 10行1列
print(b)
>>[[ 1.]
[ 2.]
[ 3.]
[ 4.]
[ 5.]
[ 6.]
[ 7.]
[ 8.]
[ 9.]
[10.]]
3)numpy.logspace–创建等比数列数组
numpy.logspace 函数用于创建一个于等比数列。格式如下:
np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)
base 参数意思是取对数的时候 log 的下标。
参数 | 描述 |
---|---|
start | 序列的起始值为:base ** start |
stop | 序列的终止值为:base ** stop。如果endpoint 为true ,该值包含于数列中 |
num | 要生成的等步长的样本数量,默认为50 |
endpoint | 该值为 true 时,数列中中包含stop 值,反之不包含,默认是True。 |
base | 对数 log 的底数,默认底数是10 |
dtype | ndarray 的数据类型,默认浮点数 |
import numpy as np
# 默认底数是 10
a = np.logspace(1.0, 2.0, num = 10)
print (a)
>>
[ 10. 12.91549665 16.68100537 21.5443469 27.82559402
35.93813664 46.41588834 59.94842503 77.42636827 100. ]
# 将对数的底数设置为 2
a = np.logspace(0,9,10,base=2)
print (a)
>>
[ 1. 2. 4. 8. 16. 32. 64. 128. 256. 512.]
8. NumPy 切片和索引
ndarray对象的内容可以通过索引或切片来访问和修改,与 Python 中 list 的切片操作一样。
ndarray 数组可以基于 0 - n 的下标进行索引,切片对象可以通过内置的 slice
函数,并设置 start, stop 及 step 参数进行,从原数组中切割出一个新数组。
import numpy as np
a = np.arange(10)
s = slice(2,7,2) # 从索引 2 开始到索引 7 停止,间隔为2
print (a[s])
>>[2 4 6]
# 首先通过 arange() 函数创建 ndarray 对象。 然后,分别设置起始,终止和步长的参数为 2,7 和 2。
# 我们也可以通过冒号分隔切片参数 start:stop:step 来进行切片操作:
b = a[2:7:2] # 从索引 2 开始到索引 7 停止,间隔为 2
print(b)
冒号 :
的解释:如果只放置一个参数,如 [2],将返回与该索引相对应的单个元素。如果为 [2:],表示从该索引开始以后的所有项都将被提取。如果使用了两个参数,如 [2:7],那么则提取两个索引(不包括停止索引)之间的项。
import numpy as np
a = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
print(a[5])
print(a[2:])
print(a[2:5])
多维数组同样适用上述索引提取方法:
import numpy as np
a = np.array([[1,2,3],[3,4,5],[4,5,6]])
print(a)
# 从某个索引处开始切割
print('从数组索引 a[1:] 处开始切割')
print(a[1:]) # 从第2行开始索引到最后
9. NumPy 高级索引
1)整数数组索引
切片还可以包括==省略号 …
,==来使选择元组的长度与数组的维度相同。 如果在行位置使用省略号,它将返回包含行中元素的 ndarray。
import numpy as np
a = np.array([[1,2,3],[3,4,5],[4,5,6]])
print (a[...,1]) # 第2列元素 1
print (a[1,...]) # 第2行元素 2
print (a[...,1:]) # 第2列及剩下的所有元素 3
>>
[2 4 5] # 1
[3 4 5] # 2
[[2 3] # 3
[4 5]
[5 6]]
在多维数组的切片中,使用 , 区分维数。
实例如下:可以把冒号左边的数看成是横坐标,右边的数看成是纵坐标,四个坐标做笛卡尔积,即取数组 a 下标是 (0,1),(0,2),(1,1),(1,2) 四个位置的数。
import numpy as np
a=np.arange(0,12)
a.shape=(3,4)
print(a)
print(a[0:2,1:3])
>>
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[1 2]
[5 6]]
2)花式索引
花式索引指的是利用整数数组进行索引。
花式索引根据索引数组的值作为目标数组的某个轴的下标来取值。对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应位置的元素;如果目标是二维数组,那么就是对应下标的行。
花式索引跟切片不一样,它总是将数据复制到新数组中。
- 在多维数组中,非连续索引切片:
import numpy as np
a = np.arange(0, 6)
b = np.arange(0, 25)
b.shape = (5, 5)
#切片向量既可以为array,也可以为list类型
r = np.array([0,1,4]) #r = [0,1,4]
c = [1, 2, 4] #c = np.array([1,2,4])
print("a:\n", a)
>>
a:
[0 1 2 3 4 5]
print("a_slice:\n", a[r])
>>
a_slice:
[0 1 4]
print("b:\n", b)
>>
b:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]
[20 21 22 23 24]]
print("b_slice:\n", b[r, :][:, c])
>>
b_slice:
[[ 1 2 4]
[ 6 7 9]
[21 22 24]]
传入多个索引数组(要使用np.ix_)
np.xi_ 中输入两个列表,则第一个列表存的是待提取元素的行标,第二个列表存的是待提取元素的列标,第一个列表中的每个元素都会遍历第二个列表中的每个值,构成新矩阵的一行元素。
import numpy as np
x=np.arange(32).reshape((8,4))
print (x[np.ix_([1,5,7,2],[0,3,1,2])])
注:
索引取的是 n 维数组中对应下标的对象,一个下标的索引,表示取最底层维度第几个元素(ndarray 逻辑结构:数组的数组),类似得到更高维的索引方法,所以索引是会改变维度的。
切片是取原来 ndarray 的所有维度某个部分相交的的那些元素构成新的 ndarray,切片不会改变维度。
3)布尔索引
我们可以通过一个布尔数组来索引目标数组。
布尔索引通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。
以下实例获取大于 5 的元素:
import numpy as np
x = np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])
print ('我们的数组是:')
print (x)
print ('\n')
# 现在我们会打印出大于 5 的元素
print ('大于 5 的元素是:')
print (x[x > 5])
>>我们的数组是:
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
大于 5 的元素是:
[ 6 7 8 9 10 11]
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
data1 = np.random.randn(7, 4)
print(names)
>>['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']
print(data1)
>>[[ 0.79007111 0.09005904 1.85265972 0.73032129]
[ 0.49709718 0.97492253 -0.47840068 -1.23104259]
[-0.49207821 0.21118008 -0.8302265 0.719803 ]
[ 0.32500646 -0.93189548 -1.30305323 -0.60352264]
[-1.76777326 -0.64362345 0.69227173 -0.70358696]
[-0.19276892 -1.34919915 -1.32264887 1.86805609]
[-0.91641428 -0.44416229 -0.11006937 -0.80059356]]
print(names == 'Bob') b # 选择与Bob匹配的行
>>[ True False False True False False False]
print(data1[names == 'Bob'])
>>[[ 0.79007111 0.09005904 1.85265972 0.73032129]
[ 0.32500646 -0.93189548 -1.30305323 -0.60352264]]
print(data1[names != 'Bob'])
print(data1[(names == 'Bob') | (names == 'Will')])
data1[data1 < 0] = 0 # 过滤掉<0的数,并设置为0,输出
print(data1)
以下实例使用了 ~(取补运算符)来过滤 NaN,可以 使用 != 或 ~ 对条件进行否定
import numpy as np
a = np.array([np.nan, 1,2,np.nan,3,4,5])
print (a[~np.isnan(a)])
>>[ 1. 2. 3. 4. 5.]
以下实例演示如何从数组中过滤掉非复数元素。
import numpy as np
a = np.array([1, 2+6j, 5, 3.5+5j])
print (a[np.iscomplex(a)])
>>[2.0+6.j 3.5+5.j]
10. NumPy 广播(Broadcast)
广播(Broadcast)是 numpy 对==不同形状(shape)==的数组进行数值计算的方式, 对数组的算术运算通常在相应的元素上进行。
如果两个数组 a 和 b 形状相同,即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求维数相同,且各维度的长度相同。
import numpy as np
a = np.array([1,2,3,4])
b = np.array([10,20,30,40])
c = a * b
print (c)
>>[ 10 40 90 160]
当运算中的 2 个数组的形状不同时,numpy 将自动触发广播机制。如:
import numpy as np
a = np.array([[ 0, 0, 0],
[10,10,10],
[20,20,20],
[30,30,30]])
b = np.array([1,2,3])
print(a + b)
>>[[ 1 2 3]
[11 12 13]
[21 22 23]
[31 32 33]]
下面的图片展示了数组 b 如何通过广播来与数组 a 兼容。
4x3 的二维数组与长为 3 的一维数组相加,等效于把数组 b 在二维上重复 4 次再运算:
import numpy as np
a = np.array([[ 0, 0, 0],
[10,10,10],
[20,20,20],
[30,30,30]])
b = np.array([1,2,3])
bb = np.tile(b, (4, 1)) # 重复 b 的各个维度
print(a + bb)
tile() 函数,就是将原矩阵横向、纵向地复制。
b = np.array( [1,2] ) # 表示有 1 行,2 列
c = np.array( [ [1], [2] ] )
bb = np.tile( b, (3,1)) # 表示把 b 在行方向复制为 3 行
cc = np.tile( c, (1,3)) # 表示把 c 在列方向复制为 3 列
广播的规则:
- 让所有输入数组都向其中形状最长的数组看齐,形状中不足的部分都通过在前面加 1 补齐。
- 输出数组的形状是输入数组形状的各个维度上的最大值。
- 如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错。
- 当输入数组的某个维度的长度为 1 时,沿着此维度运算时都用此维度上的第一组值。
简单理解:对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:
- 数组拥有相同形状。
- 当前维度的值相等。
- 当前维度的值有一个是 1。
若条件不满足,抛出 “ValueError: frames are not aligned” 异常。
numpy.broadcast–返回模仿广播的对象
numpy.broadcast 用于模仿广播的对象,它返回一个对象,该对象封装了将一个数组广播到另一个数组的结果。以下代码解释了broadcast内部怎么进行广播的:
# numpy.broadcast的用法
x = np.array([[1], [2], [3]])
y = np.array([4, 5, 6])
# 对Y广播x
b = np.broadcast(x, y)
# 它拥有iterator属性,基于自身组件的迭代器元组
print("对y广播x:")
r, c = b.iters
# Python3.x 为 next(context) ,Python2.x 为 context.next()
print(next(r), next(c)) # (1,4)
print(next(r), next(c)) # (1,5)每次打印会输出两个数组想对象位置的值
print('\n')
>>对 y 广播 x:
1 4
1 5
# shape 属性返回广播对象的形状
print('广播对象的形状:')
print(b.shape) # (3, 3)
print('\n')
# 手动使用 broadcast 将 x 与 y 相加
b = np.broadcast(x, y)
c = np.empty(b.shape)
print('手动使用 broadcast 将 x 与 y 相加:')
print(c.shape) # (3, 3)
print('\n')
c.flat = [u + v for (u, v) in b]
print('调用 flat 函数:')
print(c)
print('\n')
# 获得了和 NumPy 内建的广播支持相同的结果
print('x 与 y 的和:')
print(x + y)
调用 flat 函数:
[[5. 6. 7.]
[6. 7. 8.]
[7. 8. 9.]]
x 与 y 的和:
[[5 6 7]
[6 7 8]
[7 8 9]]
numpy.broadcast_to–将数组广播到新形状
numpy.broadcast_to 函数将数组广播到新形状。它在原始数组上返回只读视图。 它通常不连续。 如果新形状不符合 NumPy 的广播规则,该函数可能会抛出ValueError。
numpy.broadcast_to(array, shape, subok)
# 实例
import numpy as np
a = np.arange(4).reshape(1,4)
print ('原数组:')
print (a)
print ('\n')
>>
原数组:
[[0 1 2 3]]
print ('调用 broadcast_to 函数之后:')
print (np.broadcast_to(a,(4,4)))
>>
调用 broadcast_to 函数之后:
[[0 1 2 3]
[0 1 2 3]
[0 1 2 3]
[0 1 2 3]]
11. NumPy 迭代数组
NumPy 迭代器对象numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式。
迭代器最基本的任务的可以完成对数组元素的访问。
接下来我们使用 arange() 函数创建一个 2X3 数组,并使用 nditer 对它进行迭代。
import numpy as np
a = np.arange(6).reshape(2, 3)
print("原始数组为:")
print(a)
print("迭代输出元素是:")
for x in np.nditer(a):
print(x, end=', ')
print('\n')
>>原始数组是:
[[0 1 2]
[3 4 5]]
迭代输出元素:
0, 1, 2, 3, 4, 5,
以上实例不是使用标准 C 或者 Fortran 顺序,选择的顺序是和数组内存布局一致的,这样做是为了提升访问的效率,默认是行序优先(row-major order,或者说是 C-order)。
这反映了默认情况下只需访问每个元素,而无需考虑其特定顺序。我们可以通过迭代上述数组的转置来看到这一点,并与以 C 顺序访问数组转置的 copy 方式做对比,如下实例:
import numpy as np
a = np.arange(6).reshape(2, 3)
for x in np.nditer(a.T):
print(x, end=", ")
print('\n')
for x in np.nditer(a.T.copy(order='C')):
print(x, end=", ")
print('\n')
>>a.T
[[0 3]
[1 4]
[2 5]]
0, 1, 2, 3, 4, 5,
0, 3, 1, 4, 2, 5,
从上述例子可以看出,a 和 a.T 的遍历顺序是一样的,也就是他们在内存中的存储顺序也是一样的,但是 a.T.copy(order = ‘C’) 的遍历结果是不同的,那是因为它和前两种的存储方式是不一样的,默认是按行访问。numpy 实例(也就是一个多维数组)本身的存储顺序不会因为转置或 order = ‘C’ 或 ‘F’ 而改变。numpy.copy 做了特殊处理,它拷贝的时候不是直接把对方的内存复制,而是按照上面 order 指定的顺序逐一拷贝。
控制遍历顺序
for x in np.nditer(a, order='F'):
Fortran order,即是列序优先;for x in np.nditer(a.T, order='C'):
C order,即是行序优先;
import numpy as np
a = np.arange(0,60,5)
a = a.reshape(3,4)
print ('原始数组是:')
print (a)
print ('\n')
print ('以 C 风格顺序排序:')
for x in np.nditer(a, order = 'C'):
print (x, end=", " )
print ('\n')
print ('以 F 风格顺序排序:')
for x in np.nditer(a, order = 'F'):
print (x, end=", " )
>>
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
以 C 风格顺序排序:
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55,
以 F 风格顺序排序:
0, 20, 40, 5, 25, 45, 10, 30, 50, 15, 35, 55,
1)修改数组中元素的值
nditer 对象有另一个可选参数 op_flags。 默认情况下,nditer 将视待迭代遍历的数组为只读对象(read-only),为了在遍历数组的同时,实现对数组元素值得修改,必须指定 read-write 或者 write-only 的模式
import numpy as np
a = np.arange(0, 60, 5)
a = a.reshape(3, 4)
print('原始数组是:')
print(a)
print('\n')
for x in np.nditer(a, op_flags=['readwrite']):
x[...] = 2*x # x[...] 是修改原 numpy 元素,x 只是个拷贝。
print('修改后的数组是:')
print(a)
>>
原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
修改后的数组是:
[[ 0 10 20 30]
[ 40 50 60 70]
[ 80 90 100 110]]
2)使用外部循环
nditer类的构造器拥有flags参数,它可以接受下列值:
参数 | 描述 |
---|---|
c_index | 可以跟踪 C 顺序的索引 |
f_index | 可以跟踪 Fortran 顺序的索引 |
multi-index | 每次迭代可以跟踪一种索引类型 |
external_loop | 给出的值是具有多个值的一维数组,而不是零维数组 |
在下面的实例中,迭代器遍历对应于每列,并组合为一维数组。
import numpy as np
a = np.arange(0,60,5)
a = a.reshape(3,4)
print ('原始数组是:')
print (a)
print ('\n')
print ('修改后的数组是:')
for x in np.nditer(a, flags = ['external_loop'], order = 'F'):
print (x, end=", " )
>>原始数组是:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
修改后的数组是:
[ 0 20 40], [ 5 25 45], [10 30 50], [15 35 55],
3)广播迭代
如果两个数组是可广播的,nditer 组合对象能够同时迭代它们。 假设数组 a 的维度为 3X4,数组 b 的维度为 1X4 ,则使用以下迭代器(数组 b 被广播到 a 的大小)
import numpy as np
a = np.arange(0,60,5)
a = a.reshape(3,4)
print ('第一个数组为:')
print (a)
print ('\n')
print ('第二个数组为:')
b = np.array([1, 2, 3, 4], dtype = int)
print (b)
print ('\n')
print ('修改后的数组为:')
for x,y in np.nditer([a,b]):
print ("%d:%d" % (x,y), end=", " )
>>
第一个数组为:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
第二个数组为:
[1 2 3 4]
修改后的数组为:
0:1, 5:2, 10:3, 15:4, 20:1, 25:2, 30:3, 35:4, 40:1, 45:2, 50:3, 55:4,
12. Numpy 数组操作
Numpy 中包含了一些函数用于处理数组,大概可分为以下几类:
- 修改数组形状
- 翻转数组
- 修改数组维度
- 连接数组
- 分割数组
- 数组元素的添加与删除
1)修改数组形状
函数 | 描述 |
---|---|
reshape | 不改变数据的条件下修改形状 |
flat | 数组元素迭代器 |
flatten | 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组 |
ravel | 返回展开数组 |
numpy.reshape–修改形状
numpy.reshape 函数可以在不改变数据的条件下修改形状,格式如下:
numpy.reshape(arr, newshape, order=‘C’)
arr
:要修改形状的数组newshape
:整数或者整数数组,新的形状应当兼容原有形状- order:‘C’ – 按行,‘F’ – 按列,‘A’ – 原顺序,‘k’ – 元素在内存中的出现顺序。
numpy.ndarray.flat–数组元素迭代器
numpy.ndarray.flat 是一个数组元素迭代器,
import numpy as np
a = np.arange(9).reshape(3,3)
print ('原始数组:')
for row in a:
print (row)
#对数组中每个元素都进行处理,可以使用flat属性,该属性是一个数组元素迭代器:
print ('迭代后的数组:')
for element in a.flat:
print (element)
numpy.ndarray.flatten–拷贝
numpy.ndarray.flatten 返回一份数组拷贝,与copy格式一致,对拷贝所做的修改不会影响原始数组,格式如下:
ndarray.flatten(order='C')
numpy.ravel
numpy.ravel() 展平的数组元素,顺序通常是"C风格",返回的是数组视图(view,有点类似 C/C++引用reference的意味),修改会影响原始数组。
该函数接收两个参数:
numpy.ravel(a, order='C')
2)翻转数组
函数 | 描述 |
---|---|
transpose | 对换数组的维度 |
ndarray.T | 和 self.transpose() 相同 |
rollaxis | 向后滚动指定的轴 |
swapaxes | 对换数组的两个轴 |
numpy.transpose–调换维度
numpy.transpose 函数用于对换数组的维度,格式如下:
numpy.transpose(arr, axes)
参数说明:
arr
:要操作的数组axes
:整数列表,对应维度,通常所有维度都会对换。
numpy.ndarray.T–转置
类似 numpy.transpose
numpy.rollaxis–轴向后滚动到特定位置
numpy.rollaxis 函数向后滚动特定的轴到一个特定位置,格式如下:
numpy.rollaxis(arr, axis, start)
参数说明:看单个元素,可以看出轴的滚动位置
arr
:数组axis
:要向后滚动的轴,其它轴的相对位置不会改变start
:默认为零,表示完整的滚动。会滚动到特定位置。
三列分别对应三个轴方向(0,1,2),axis为要滚动的轴,b = np.rollaxis(a,2,0)代表轴2滚动到轴0的位置,其他轴相对位置不变。 数组arr所对应的*axis*轴 放在* start*轴的前面,start轴往后移一“列”
import numpy as np
# 创建了三维的 ndarray
a = np.arange(8).reshape(2,2,2)
print ('原数组:')
print (a)
print ('获取数组中一个值:')
print(np.where(a==6))
print(a[1,1,0]) # 为 6
print ('\n')
# 将轴 2 滚动到轴 0(宽度到深度)
print ('调用 rollaxis 函数:')
b = np.rollaxis(a,2,0)
print (b)
# 查看元素 a[1,1,0],即 6 的坐标,变成 [0, 1, 1]
# 最后一个 0 移动到最前面
print(np.where(b==6))
print ('\n')
# 将轴 2 滚动到轴 1:(宽度到高度)
print ('调用 rollaxis 函数:')
c = np.rollaxis(a,2,1)
print (c)
# 查看元素 a[1,1,0],即 6 的坐标,变成 [1, 0, 1]
# 最后的 0 和 它前面的 1 对换位置
print(np.where(c==6))
print ('\n')
>>
原数组:
[[[0 1]
[2 3]]
[[4 5]
[6 7]]]
获取数组中一个值:
(array([1], dtype=int64), array([1], dtype=int64), array([0], dtype=int64))
6
# 调用 rollaxis 函数:
[[[0 2]
[4 6]]
[[1 3]
[5 7]]]
(array([0], dtype=int64), array([1], dtype=int64), array([1], dtype=int64))
# 调用 rollaxis 函数:
[[[0 2]
[1 3]]
[[4 6]
[5 7]]]
(array([1], dtype=int64), array([0], dtype=int64), array([1], dtype=int64))
numpy.swapaxes–交换两个轴
numpy.swapaxes 函数用于交换数组的两个轴,格式如下:
numpy.swapaxes(arr, axis1, axis2)
-
arr
:输入的数组 -
axis1
:对应第一个轴的整数 -
axis2
:对应第二个轴的整数
NUMPY中矩阵相关乘法总结
- 对位乘积:两个矩阵shape相同,将矩阵中相同位置的元素相乘,结果还是矩阵(相同shape)
- 矩阵乘法:数学上的矩阵乘法
- 向量内积:对应元素相乘,再相加,得到一 个数值(一维数组)
numpy中可用的乘法运算操作:
矩阵乘法 | 维度 | 类型 |
---|---|---|
a * b | a,b必须有相同的shape | 对位乘积 |
numpy.multiply(a,b) | a,b必须有相同的shape | 对位乘积 |
numpy.matmul(a,b) | 数学上的矩阵乘法 | 矩阵乘法 |
a @ b | 数学上的矩阵乘法 | 矩阵乘法 |
numpy.dot(a,b) | (1)当a,b都是一维数组(矩阵)时; (2)当a,b是矩阵时(不都是一维),需要符合数学中关于矩阵的约束 | (1)向量内积(2)矩阵乘法 |
import numpy as np
# 1.矩阵乘法
A = np.array([[1, 0], [-3, 2]])
B = np.array([[-1, 4], [3, 5]])
print(A@B)
print(np.dot(A, B))
print(A.dot(B))
print(np.matmul(A, B))
# 2.Hadamard乘积,将矩阵中相同位置的元素相乘
print(A*B)
print(np.multiply(A, B))
>>
[[-1 4]
[ 9 -2]] # 1.矩阵乘法,三个结果一样
[[-1 0]
[-9 10]] # 2.Hadamard乘积,将矩阵中相同位置的元素相乘,三个结果一样
3)修改数组维度
维度 | 描述 |
---|---|
broadcast | 产生模仿广播的对象,见[10.] |
broadcast_to | 将数组广播到新形状,见[10.] |
expand_dims | 扩展数组的形状 |
squeeze | 从数组的形状中删除一维条目 |
numpy.expand_dims–插入新轴
numpy.expand_dims 函数通过在指定位置插入新的轴来扩展数组形状,函数格式如下:
参数说明:
arr
:输入数组axis
:新轴插入的位置
numpy.expand_dims(arr, axis) # 格式
# 实例
import numpy as np
x = np.array(([1,2],[3,4]))
print ('数组 x:')
print (x)
>>
[[1 2]
[3 4]]
print ('\n')
y = np.expand_dims(x, axis = 0) # 在哪里插轴就扩展那个轴
# 原数组轴为(2,2),插入新的轴之后变成(1,2,2)
print ('数组 y:')
print (y)
print ('\n')
>>
[[[1 2]
[3 4]]]
print ('数组 x 和 y 的形状:')
print (x.shape, y.shape) # 数组 x 和 y 的形状:(2, 2) (1, 2, 2)
print ('\n')
# 在位置 1 插入轴
y = np.expand_dims(x, axis = 1)
# 原数组轴为(2,2),插入新的轴之后变成(2,1,2)
print ('在位置 1 插入轴之后的数组 y:')
print (y)
>>
[[[1 2]]
[[3 4]]]
print ('\n')
print ('x.ndim 和 y.ndim:')
print (x.ndim,y.ndim)
print ('\n')
print ('x.shape 和 y.shape:')
print (x.shape, y.shape) # (2, 2) (2, 1, 2)
numpy.squeeze–删除一维轴
numpy.squeeze 函数从给定数组的形状中==删除一维的条目(一维的轴),函数格式如下:
numpy.squeeze(arr, axis) # 格式
# 实例
import numpy as np
x = np.arange(9).reshape(1,3,3) # 删除1轴,变成(3,3)
print ('数组 x:')
print (x)
print ('\n')
>>数组 x:
[[[0 1 2]
[3 4 5]
[6 7 8]]]
y = np.squeeze(x)
print ('数组 y:')
print (y)
print ('\n')
>>数组 y:
[[0 1 2]
[3 4 5]
[6 7 8]]
print ('数组 x 和 y 的形状:')
print (x.shape, y.shape)
>>数组 x 和 y 的形状:
(1, 3, 3) (3, 3)
4)连接数组
函数 | 描述 |
---|---|
concatenate | 连接沿现有轴的数组序列 |
stack | 沿着新的轴加入一系列数组。 |
hstack | 水平堆叠序列中的数组(列方向) |
vstack | 竖直堆叠序列中的数组(行方向) |
numpy.concatenate–沿指定轴连接相同形状的数组
numpy.concatenate 函数用于==沿指定轴连接相同形状的两个或多个数组==,格式如下:
参数说明:
a1, a2, ...
:相同类型的数组axis
:沿着它连接数组的轴,默认为 0
numpy.concatenate((a1, a2, ...), axis) # 格式
# 实例二维数组连接
import numpy as np
a = np.array([[1,2],[3,4]])
print ('第一个数组:')
print (a)
print ('\n')
>>第一个数组:
[[1,2]
[3,4]]
b = np.array([[5,6],[7,8]])
print ('第二个数组:')
print (b)
print ('\n')
>>第一个数组:
[[5,6]
[7,8]]
# 两个数组的维度相同
print ('沿轴 0 连接两个数组:')
print (np.concatenate((a,b)))
print ('\n')
>>沿轴 0 连接两个数组: # 沿行扩展
[[1 2]
[3 4]
[5 6]
[7 8]]
print ('沿轴 1 连接两个数组:')
print (np.concatenate((a,b),axis = 1))
>>沿轴 1 连接两个数组: # 沿列扩展
[[1 2 5 6]
[3 4 7 8]]
# 三维数组连接
a1 = np.array([[[0, 1, 2], [3, 4, 5], [6, 7, 8]]])
b1 = np.array([[[0, 1, 2], [3, 4, 5], [6, 7, 8]]])
print(a1) #(1,3,3)
>>
[[[0 1 2]
[3 4 5]
[6 7 8]]]
print(np.concatenate((a1, b1), axis=0)) # 连接x轴 (2,3,3)
>>
[[[0 1 2]
[3 4 5]
[6 7 8]]
[[0 1 2]
[3 4 5]
[6 7 8]]]
print(np.concatenate((a1, b1), axis=1)) # 连接y轴 (1,6,3)
>>
[[[0 1 2]
[3 4 5]
[6 7 8]
[0 1 2]
[3 4 5]
[6 7 8]]]
print(np.concatenate((a1, b1), axis=2)) # 连接z轴 (1,3,6)
>>
[[[0 1 2 0 1 2]
[3 4 5 3 4 5]
[6 7 8 6 7 8]]]
numpy.stack–沿某个轴堆叠
numpy.stack 函数用于沿新轴连接数组序列,格式如下:
参数说明:
arrays
:相同形状的数组序列axis
:返回数组中的轴,输入数组沿着它来堆叠
numpy.stack(arrays, axis)
# 四个二维数组实例
import numpy
a=numpy.arange(1, 7).reshape((2, 3))
b=numpy.arange(7, 13).reshape((2, 3))
c=numpy.arange(13, 19).reshape((2, 3))
d=numpy.arange(19, 25).reshape((2, 3))
# axis=0
print(numpy.stack([a, b,c,d], axis=0))
print(numpy.stack([a, b,c,d], axis=0).shape)
# axis=1
print(numpy.stack([a, b,c,d], axis=1))
print(numpy.stack([a, b,c,d], axis=1).shape)
# axis=2
print(numpy.stack([a, b,c,d], axis=2))
print(numpy.stack([a, b,c,d], axis=2).shape)
axis等于几就说明在哪个维度上进行堆叠,几个数组堆叠,在那个维度上就扩展成几,再看堆叠方式
1、axis=0:简单的物理罗列,在0维度上堆叠(2,3)→(4,2,3),如下图所示
2、axis=1:对于1维堆叠,4个2行3列的数组,各自拿出自己的一行组成按行排列,(2,3)→(2,4,3)
3、axis=2:对于2维堆叠,4个2行3列的数组,各自拿出自己的一行组成按列排列,(2,3)→(2,3,4)
区别:concatenate()函数实现数组的拼接,stack()会增加数组的维度,而concatenate()不会增加数组的维度。
numpy.hstack–水平堆叠
numpy.vstack–竖直堆叠
import numpy as np
a = np.array([[1,2],[3,4]])
print ('第一个数组:')
print (a)
print ('\n')
b = np.array([[5,6],[7,8]])
print ('第二个数组:')
print (b)
print ('\n')
print ('水平堆叠:')
c1 = np.hstack((a,b))
print (c1)
print ('\n')
print ('竖直堆叠:')
c2 = np.vstack((a,b))
print (c2)
水平堆叠:行数必须相同,列数可以不同
竖直堆叠:列数必须相同,行数可以不同
5)分割数组
函数 | 数组及操作 |
---|---|
split | 将一个数组分割为多个子数组 |
hsplit | 将一个数组水平分割为多个子数组(按列) |
vsplit | 将一个数组垂直分割为多个子数组(按行) |
numpy.split–沿特定轴分割
numpy.split 函数沿特定的轴将数组分割为子数组,格式如下:
numpy.split(ary, indices_or_sections, axis)
参数说明:
ary
:被分割的数组indices_or_sections
:果是一个整数,就用该数平均切分,如果是一个数组,为沿轴切分的位置(左开右闭)axis
:设置沿着哪个方向进行切分,默认为 0,横向切分,即水平方向。为 1 时,纵向切分,即竖直方向。
import numpy as np
a = np.arange(9)
print('第一个数组:')
print(a)
print('\n')
print('将数组分为三个大小相等的子数组:')
b = np.split(a, 3)
print(b)
print('\n')
>>将数组分为三个大小相等的子数组:
[array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]
print('将数组在一维数组中表明的位置分割:')
b = np.split(a,[4,7])
print(b)
>>将数组在一维数组中表明的位置分割:
[array([0, 1, 2, 3]), array([4, 5, 6]), array([7, 8])]
1、纵向分割, 分成两部分, 按列分割:np.split(A, 2, axis = 1)
# 输出结果
[array([[0, 1],
[4, 5],
[8, 9]]), array([[ 2, 3],
[ 6, 7],
[10, 11]])]
2、横向分割, 分成三部分, 按行分割:np.split(A, 3, axis = 0)
# 输出结果
[array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]]), array([[ 8, 9, 10, 11]])]
3、np.vsplit 垂直方向分割:np.vsplit(A, 3)
# 输出结果
[array([[0, 1, 2, 3]]), array([[4, 5, 6, 7]]), array([[ 8, 9, 10, 11]])]
4、np.hsplit 水平方向分割:np.hsplit(A, 2)
# 输出结果
[array([[0, 1],
[4, 5],
[8, 9]]), array([[ 2, 3],
[ 6, 7],
[10, 11]])]
6)数组元素的添加与删除
函数 | 元素及描述 |
---|---|
resize | 返回指定形状的新数组 |
append | 将值添加到数组末尾 |
insert | 沿指定轴将值插入到指定下标之前 |
delete | 删掉某个轴的子数组,并返回删除后的新数组 |
unique | 查找数组内的唯一元素 |
numpy.resize–返回新数组
numpy.resize 函数返回指定大小的新数组。
如果新数组大小大于原始大小,则包含原始数组中的元素的副本。
numpy.resize(arr, shape)
参数说明:
arr
:要修改大小的数组shape
:返回数组的新形状
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
>>a.shape=(2,3)
[[1 2 3]
[4 5 6]]
b1 = np.resize(a, (3,2))
>>b1.shape=(3,2)
[[1 2]
[3 4]
[5 6]]
b2 = np.resize(a,(3,3)) # 要注意 a 的第一行在 b 中重复出现,因为尺寸变大了
>>b2.shape=(3,3)
[[1 2 3]
[4 5 6]
[1 2 3]]
numpy.append–在数组末尾添加值
numpy.append 函数在数组的末尾添加值。 追加操作会分配整个数组,并把原来的数组复制到新数组中。 此外,输入数组的维度必须匹配否则将生成ValueError。
append 函数返回的始终是一个一维数组。
numpy.append(arr, values, axis=None)
参数说明:
arr
:输入数组values
:要向arr
添加的值,需要和arr
形状相同(除了要添加的轴)axis
:默认为 None。当axis无定义时,是横向加成,返回总是为一维数组!当axis有定义,当axis为0的时候(列数要相同)。当axis为1时,数组是加在右边(行数要相同)。
import numpy as np
a = np.array([[1,2,3],[4,5,6]])
>>
[[1 2 3]
[4 5 6]]
print ('向数组添加元素:')
print (np.append(a, [7,8,9])) # 不指定轴的时候返回以为数组
print ('\n')
>>
[1 2 3 4 5 6 7 8 9]
print ('沿轴 0 添加元素:')
print (np.append(a, [[7,8,9]],axis = 0)) # 列数必须相同
print ('\n')
>>
[[1 2 3]
[4 5 6]
[7 8 9]]
print ('沿轴 1 添加元素:')
print (np.append(a, [[5,5,5],[7,8,9]],axis = 1)) # 行数必须相同
>>
[[1 2 3 5 5 5]
[4 5 6 7 8 9]]
numpy.insert–沿给定轴插入值
numpy.insert 函数在给定索引之前,沿给定轴在输入数组中插入值。
如果值的类型转换为要插入,则它与输入数组不同。 插入没有原地的,函数会返回一个新数组。 此外,如果未提供轴,则输入数组会被展开。
numpy.insert(arr, obj, values, axis)
参数说明:
arr
:输入数组obj
:在其之前插入值的索引values
:要插入的值axis
:沿着它插入的轴,如果未提供,则输入数组会被展开
import numpy as np
a = np.array([[1, 2], [3, 4], [5, 6]])
# 1.未传递 Axis 参数。 在插入之前输入数组会被展开。
print(np.insert(a, 3, [11, 12]))
>> [ 1 2 3 11 12 4 5 6]
# 2.沿轴 0 广播:
print(np.insert(a, 1, [11], axis=0))
>>
[[ 1 2]
[11 11]
[ 3 4]
[ 5 6]]
# 3.沿轴 1 广播:
print(np.insert(a, 0, 11, axis=1))
>>
[[ 1 11 2]
[ 3 11 4]
[ 5 11 6]]
图示:
numpy.delete–删除指定子数组
numpy.delete 函数返回从输入数组中删除指定子数组的新数组。 与 insert() 函数的情况一样,如果未提供轴参数,则输入数组将展开。
Numpy.delete(arr, obj, axis)
参数说明:
arr
:输入数组obj
:**待删除的对象,**可以被切片,整数或者整数数组,表明要从输入数组删除的子数组,如果在第二个参数obj中指定列表或切片,则可以一次删除多个行或列axis
:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开
import numpy as np
# 二维数组
a = np.arange(12).reshape(3, 4)
print(np.delete(a, 5)) # 删除第6个元素
# 未传递 Axis 参数。 在插入之前输入数组会被展开
>>[ 0 1 2 3 4 6 7 8 9 10 11]
print(np.delete(a, 1, axis=1)) # 沿轴1,删除第二列,删除多列np.delete(a, [0,1], axis=1)
>>
[[ 0 2 3]
[ 4 6 7]
[ 8 10 11]]
# 一维数组
aa = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(np.delete(aa, np.s_[::2])) # 指定删除参数为切片,2为步长
>>[ 2 4 6 8 10]
切片索引:np.slice(2,7,2) ----slice(初值,终值,步长/间隔)==np.s_(2,7,2)
numpy.unique–去重复元素
numpy.unique 函数用于去除数组中的重复元素,保留数组中不同的值,返回两个参数(输入数组及后三个中的一个)
numpy.unique(arr, return_index, return_inverse, return_counts)
arr
:输入数组,如果不是一维数组则会展开return_index
:如果为true
,返回新列表元素在旧列表中的位置(下标),并以列表形式存储return_inverse
:如果为true
,返回旧列表元素在新列表中的位置(下标),并以列表形式存储return_counts
:如果为true
,返回去重数组中的元素在原数组中的出现次数
import numpy as np
a = np.array([5,2,6,2,7,5,6,8,2,9])
u = np.unique(a)
print (u)
>>[2 5 6 7 8 9]
# 去重数组的索引数组:对应去重后的新列表元素在就列表中的位置
u,indices = np.unique(a, return_index = True)
print (indices)
>>[1 0 2 4 7 9]
# 去重数组的下标:对应所有旧列表元素在新列表中的位置
u,indices = np.unique(a,return_inverse = True)
print (indices)
>>[1 0 2 0 3 1 2 4 0 5]
# 使用下标重构原数组:
print (u[indices])
>>[5 2 6 2 7 5 6 8 2 9]
# 返回去重元素的重复数量:重复次数
u,indices = np.unique(a,return_counts = True)
print (u)
print (indices)
>>
[2 5 6 7 8 9]
[3 2 2 1 1 1]
image-20210518085321991.png" alt="image-20210518085321991" style="zoom:80%;" /> →→ <img src="C:\Users\user\AppData\Roaming\Typora\typora-user-images\image-20210518085426881.png" alt="image-20210518085426881" style="zoom:80%;" />
##### numpy.delete--删除指定子数组
numpy.delete 函数返回从输入数组中删除指定子数组的新数组。 与 insert() 函数的情况一样,如果未提供轴参数,则输入数组将展开。
```python
Numpy.delete(arr, obj, axis)
参数说明:
arr
:输入数组obj
:待删除的对象,可以被切片,整数或者整数数组,表明要从输入数组删除的子数组,如果在第二个参数obj中指定列表或切片,则可以一次删除多个行或列axis
:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开
import numpy as np
# 二维数组
a = np.arange(12).reshape(3, 4)
print(np.delete(a, 5)) # 删除第6个元素
# 未传递 Axis 参数。 在插入之前输入数组会被展开
>>[ 0 1 2 3 4 6 7 8 9 10 11]
print(np.delete(a, 1, axis=1)) # 沿轴1,删除第二列,删除多列np.delete(a, [0,1], axis=1)
>>
[[ 0 2 3]
[ 4 6 7]
[ 8 10 11]]
# 一维数组
aa = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(np.delete(aa, np.s_[::2])) # 指定删除参数为切片,2为步长
>>[ 2 4 6 8 10]
切片索引:np.slice(2,7,2) ----slice(初值,终值,步长/间隔)==np.s_(2,7,2)
numpy.unique–去重复元素
numpy.unique 函数用于去除数组中的重复元素,保留数组中不同的值,返回两个参数(输入数组及后三个中的一个)
numpy.unique(arr, return_index, return_inverse, return_counts)
arr
:输入数组,如果不是一维数组则会展开return_index
:如果为true
,返回新列表元素在旧列表中的位置(下标),并以列表形式存储return_inverse
:如果为true
,返回旧列表元素在新列表中的位置(下标),并以列表形式存储return_counts
:如果为true
,返回去重数组中的元素在原数组中的出现次数
import numpy as np
a = np.array([5,2,6,2,7,5,6,8,2,9])
u = np.unique(a)
print (u)
>>[2 5 6 7 8 9]
# 去重数组的索引数组:对应去重后的新列表元素在就列表中的位置
u,indices = np.unique(a, return_index = True)
print (indices)
>>[1 0 2 4 7 9]
# 去重数组的下标:对应所有旧列表元素在新列表中的位置
u,indices = np.unique(a,return_inverse = True)
print (indices)
>>[1 0 2 0 3 1 2 4 0 5]
# 使用下标重构原数组:
print (u[indices])
>>[5 2 6 2 7 5 6 8 2 9]
# 返回去重元素的重复数量:重复次数
u,indices = np.unique(a,return_counts = True)
print (u)
print (indices)
>>
[2 5 6 7 8 9]
[3 2 2 1 1 1]