Python中Numpy库的学习
1.Numpy的基础
1.1Numpy的概念
NumPy(Numerical Python)是一个用于科学计算的开源库,它为 Python 提供了支持大型多维数组和矩阵操作的功能,并包含了大量数学函数库,用于执行各种数值运算。
1.2Numpy的优点
Numpy包含了大量的数学函数,支持基本的算数运算,线性代数,矩阵等;
Numpy与其他的科学计算与数据分析库可以无缝兼容,例如Pandas、Matplotlib。用户可以方便地结合使用多个库进行数据处理和可视化。
NumPy 的广播机制允许对不同形状的数组进行算术运算,而无需显式地复制数据。这使得对数组进行元素级运算更加简洁和高效。
1.3Numpy的安装
用到代码:(-i 后的内容为清华镜像地址,下载速度会更快,比直接pip install numpy快很多)
pip install numpy==1.26.0 -i https://pypi.tuna.tsinghua.edu.cn/simple/
2.Ndarray
Numpy定义了一个n维数组对象,ndarray对象采用了数组的索引机制,将数组的每个元素投影到内存块上,并按照一定的布局进行排列,常见的布局方式有两种,按行排列(Row-major Order,C-style 数组的行是连续的)或按列排列(Column-major Order,Fortran-style 数组的列是连续的)
ndarray是通过array函数或者其他Numpy函数(zeros、ones、arange)创建的;array函数接受一个序列作为输入,并返回一个ndarray对象
2.1array创建对象
在使用array函数之前,我们需要导入numpy包,最好命名为np
import numpy as np
array的语法格式如下:
numpy.array(object, dtype = None, copy = True, order = None,ndmin = 0)
object:表示一个数组序列
dtype:可选参数,可以使用它改变数组的数据类型
copy:可选参数,表示数组是否可以被复制,默认是True
order:数组的内存布局(默认是C行排列)
ndmin:用于指定数组的维度
接下来我们来创建一个一维数组
array_one = np.array([1, 2, 3, 4], dtype=int, order= 'F', ndmin=1)
print ("创建一个数组:",array_one)
print ("创建一维数组:", type(array_one))
print("ndim 查看、指定数组维度:",array_one.ndim)
print(array_one.dtype)
结果如下:
创建一个数组: [1 2 3 4]
创建一维数组: <class 'numpy.ndarray'>
ndim 查看、指定数组维度: 1
int32
接下来创建一个二维数组
array_two = np.array([[1,1,1,1], [1,0,0,0]], dtype = float
, order= 'F')
print("创建一个二维数组:\n", array_two)
print("类型:", type(array_two))
print(array_two.dtype)
print("维度:", array_two.ndim)
结果如下:
创建一个二维数组:
[[1. 1. 1. 1.]
[1. 0. 0. 0.]]
类型: <class 'numpy.ndarray'>
float64
维度: 2
2.2指定/查看数组的维度
数组的维度就是一个数组中的某个元素,当用数组下标表示的时候,需要用几个数字来表示才能唯一确定这个元素,这个数组就是几维
ndmin:用于指定数组的维度,创建数组时指定最小维度的参数,可以确保生成的数组至少是几维的。
ndim:是 NumPy 数组的一个属性,用于返回数组的维度数(即数组的秩)。它表示数组有多少个维度。
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("数组形状:", arr.shape)
print("数组维度:", arr.ndim)
在这个例子中:
arr.shape 返回的数组形状(3, 3),表示3行3列
arr.ndim 返回的数组维度是2
2.3数组变维
可以通过直接设置shape属性来修改数组的维度
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 修改数组形状为一维数组
arr.shape = (9,)
print("修改后的数组:", arr)
print("数组形状:", arr.shape)
结果如下:
修改后的数组:[1 2 3 4 5 6 7 8 9]
数组形状:(9,)
也可以使用reshape方法修改数组的维度
reshape() 函数允许你在不改变数组数据的情况下,改变数组的维度。
reshape() 返回的是一个新的数组,原数组的形状不会被修改。reshape() 可以用于多维数组,例如将一个一维数组重塑为二维数组。
但是,reshape后产生的新数组是原数组的一个视图,即它与原数组共享相同的数据,但可以有不同的形状或维度,且对视图的修改会直接影响原数组。
元素总数必须匹配:新形状中的元素总数必须与原数组中的元素总数相同。
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 修改数组形状为 (1, 9)
arr_reshaped = arr.reshape((1, 9))
print("修改后的数组:", arr_reshaped)
print("数组形状:", arr_reshaped.shape)
结果如下:
修改后的数组:[[1 2 3 4 5 6 7 8 9]]
数组形状:(1, 9)
-1 作为占位符:你可以使用 -1 作为占位符,让 numpy 自动计算某个维度的大小。
import numpy as np
# 创建一维数组
arr = np.array([1, 2, 3, 4, 5, 6])
# 使用 -1 作为占位符,重塑为 2 行
arr_reshaped = arr.reshape(2, -1)
print
[[1 2 3]
[4 5 6]]
reshape() 还可以将一维数组重塑为三维数组:
# 创建一个一维数组
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
# 使用 reshape() 函数将其转换为三维数组
reshaped_arr = arr.reshape((2, 3, 2))
print(reshaped_arr)
print("ndim:", reshaped_arr.ndim)
[[[ 1 2]
[ 3 4]
[ 5 6]]
[[ 7 8]
[ 9 10]
[11 12]]]
ndim: 3
reshape((2, 3, 2))表示将数组重塑为一个三维数组,其形状为 (2, 3, 2),具体来说,这个形状表示:
第一个维度:也叫做层维度,有 2 个元素。
第二个维度:也叫做行维度,每个元素有 3 个元素。
第三个维度:也叫做列维度,每个元素有 2 个元素。
具体过程:
首先,将一维数组分成 2 个部分:
[1, 2, 3, 4, 5, 6] 和 [7, 8, 9, 10, 11, 12]
然后,将每个部分分成 3 个部分:
[1, 2], [3, 4], [5, 6] 和 [7, 8], [9, 10], [11, 12]
最后,将每个部分分成 2 个部分,如:
[1, 2]
注意:形状 (2, 3, 2)中的参数个数相乘要等于数组中元素的个数,如:数组[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]有12个元素,形状(2,3,2)的参数相乘:2x3x2=12。
3.数据类型
NumPy 提供了比 Python 更加丰富的数据类型,如下所示:
序号 |
数据类型 | 语言描述 |
---|---|---|
1 | bool_ | 布尔型数据类型(True 或者 False) |
2 | int_ | 默认整数类型,类似于 C 语言中的 long,取值为 int32 或 int64 |
3 | intc | 和 C 语言的 int 类型一样,一般是 int32 或 int 64 |
4 | intp | 用于索引的整数类型(类似于 C 的 ssize_t,通常为 int32 或 int64) |
5 | int8 | 代表与1字节相同的8位整数。值的范围是-128到127 |
6 | int16 | 代表 2 字节(16位)的整数。范围是-32768至32767 |
7 | int32 | 代表 4 字节(32位)整数。范围是-2147483648至2147483647 |
8 | int64 | 表示 8 字节(64位)整数。范围是-9223372036854775808至9223372036854775807 |
9 | uint8 | 1字节(8位)无符号整数 |
10 | uint16 | 2 字节(16位)无符号整数 |
11 | uint32 | 4 字节(32位)无符号整数 |
12 | uint64 | 8 字节(64位)无符号整数 |
13 | float_ | float64 类型的简写 |
14 | float16 | 半精度浮点数,包括:1 个符号位,5 个指数位,10个尾数位 |
15 | float32 | 单精度浮点数,包括:1 个符号位,8 个指数位,23个尾数位 |
16 | float64 | 双精度浮点数,包括:1 个符号位,11 个指数位,52个尾数位 |
17 | complex_ | 复数类型,与 complex128 类型相同 |
18 | complex64 | 表示实部和虚部共享 32 位的复数 |
19 | complex128 | 表示实部和虚部共享 64 位的复数 |
20 | str_ | 表示字符串类型,等价于unicode_ |
21 | bytes_ | 表示字节串类型,基于字节 |
22 | string_ | 表示字节串类型,等价于bytes_ ,基于字节,NumPy 2.0以后版本被移除,使用bytes_ 代替 |
23 | unicode_ | 表示字节串类型,基于字符,NumPy 2.0以后版本被移除,使用str_`代替 |
3.1 数据类型对象
数据类型对象(Data Type Object)又称 dtype 对象,是用来描述与数组对应的内存区域如何使用。
1.可以在创建数组时指定 dtype 参数来定义数组中元素的数据类型。
import numpy as np
# 创建一个 int32 类型的数组
arr_int = np.array([1, 2, 3], dtype=np.int32)
print(arr_int.dtype) # 输出: int32
# 创建一个 float64 类型的数组
arr_float = np.array([1, 2, 3], dtype=np.float64)
print(arr_float.dtype) # 输出: float64
2.可以使用数组的 dtype 属性来获取数组中元素的数据类型。
arr = np.array([1, 2, 3])
print(arr.dtype) # 输出: int32
3.可以使用 astype() 方法来转换数组中元素的数据类型。
arr = np.array([1, 2, 3])
arr_float = arr.astype(np.float64)
print(arr_float.dtype) # 输出: float64
3.2 数据类型标识码
NumPy 中每种数据类型都有一个唯一标识的字符码,int8, int16, int32, int64 四种数据类型可以使用字符串 'i1', 'i2','i4','i8' 代替,如下所示:
字符 | 对应类型 |
---|---|
b | 代表布尔型 |
i | 带符号整型 |
u | 无符号整型 |
f | 浮点型 |
c | 复数浮点型 |
m | 时间间隔(timedelta) |
M | datatime(日期时间) |
O | Python对象 |
S,a | 字节串(S)与字符串(a) |
U | Unicode |
V | 原始数据(void) |
整数类型
数据类型 | 标识码 | 描述 |
---|---|---|
int8 | i1 | 8 位有符号整数 |
int16 | i2 | 16 位有符号整数 |
int32 | i4 | 32 位有符号整数 |
int64 | i8 | 64 位有符号整数 |
uint8 | u1 | 8 位无符号整数 |
uint16 | u2 | 16 位无符号整数 |
uint32 | u4 | 32 位无符号整数 |
uint64 | u8 | 64 位无符号整数 |
浮点数类型
数据类型 | 标识码 | 描述 |
---|---|---|
float16 | f2 | 16 位浮点数(半精度) |
float32 | f4 | 32 位浮点数(单精度) |
float64 | f8 | 64 位浮点数(双精度) |
复数类型
数据类型 | 标识码 | 描述 |
---|---|---|
complex64 | c8 | 64 位复数(单精度) |
complex128 | c16 | 128 位复数(双精度) |
布尔类型
数据类型 | 标识码 | 描述 |
---|---|---|
bool | b1 | 布尔类型 |
字符串类型
数据类型 | 标识码 | 描述 |
---|---|---|
bytes | S10 | 长度为 10 的字节串 |
str | U10 | 长度为 10 的 Unicode 字符串 |
补充知识点:
小端序(Little Endian),在小端序中,数据的低位字节存储在低地址处,高位字节存储在高地址处;大端序(Big Endian),在大端序中,数据的高位字节存储在低地址处,低位字节存储在高地址处。
4.数组属性
4.1 shape
shape属性用于描述数组的维度,返回的是一个元组,包含数组每一维的大小;通过赋值可以调整数组维度的大小
如果使用shape属性修改数组的形状,则修改的是原数组的形状,reshape修改数组的形状会返回一个新数组,不修改原数组的形状。
4.2 ndim
ndim 属性功能:
返回的是数组的维数
4.3 itemsize
itemsize 属性功能:用于描述数组中每个元素的大小(以字节为单位)。表示数组中每个元素所占用的内存空间。
arr_int = np.array([1, 2, 3, 4, 5])
print("整数数组的元素大小:", arr_int.itemsize)
arr_float = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
print("浮点数组的元素大小:", arr_float.itemsize)
结果如下:
整数数组的元素大小: 8
浮点数组的元素大小: 8
4.4 flags
flags 属性功能: 返回 ndarray 数组的内存信息
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.flags)
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : True
ALIGNED : True
WRITEBACKIFCOPY : False
UPDATEIFCOPY : False
C_CONTIGUOUS:表示数组在内存中是 C 风格连续的(行优先)。
如果为 True,则数组是 C 风格连续的。
F_CONTIGUOUS:表示数组在内存中是 Fortran 风格连续的(列优先)。
如果为 True,则数组是 Fortran 风格连续的。
OWNDATA:如果数组拥有它所使用的内存(即数据不是来自视图或另一个数组的部分),则为 True。
WRITEABLE:
如果为 True,则数组是可写的;如果为 False,则数组是只读的。
ALIGNED:
表示数组是否对齐。如果为 True,则数组的数据在内存中是对齐的。
WRITEBACKIFCOPY:如果数组是某个写时复制的视图,则为 True。数组是通过 np.copy 创建的副本,并且需要将更改写回原始数组。
UPDATEIFCOPY:
表示数组是否是通过 np.copy 创建的副本,并且需要将更改写回原始数组。
如果为 True,则数组是通过 np.copy 创建的副本,并且需要将更改写回原始数组。
#一维数组的内存信息,行优先和列优先都为True
5.创建数组的其他方法
5.1 empty()
empty() 方法用来创建一个指定形状(shape)、数据类型(dtype)且未初始化的数组(数组元素为随机值)
格式:
numpy.empty(shape, dtype = float, order = 'C')
shape:数组的形状,可以是整数或者整数元组
dtype:数组的数据类型,默认为float
order:C(行优先)和F(列优先)
arr = np.empty((2, 3), dtype=float)
print("未初始化的数组:\n", arr)
结果类似于
未初始化的数组:
[[1.09576856e-311 1.86512319e-308 1.09575040e-311]
[1.09575552e-311 2.27637712e-091 1.09576856e-311]]
5.2 zeros()
创建指定大小的数组,数组元素以 0 来填充
格式
numpy.zeros(shape, dtype = float, order = 'C')
shape:数组的形状,可以是整数或者整数元组
dtype:数组的数据类型,可选
order:C(行优先)和F(列优先)
import numpy as np
arr = np.zeros((3,3),dtype=int)
print(arr)
[[0 0 0]
[0 0 0]
[0 0 0]]
5.3 ones()
创建指定形状的数组,数组元素以 1 来填充
格式
numpy.ones(shape, dtype = None, order = 'C')
shape:数组的形状,可以是整数或者整数元组
dtype:数组的数据类型,可选
order:C(行优先)和F(列优先)
arr = np.ones((3, 3),dtype=int,order='C')
print(arr)
[[1 1 1]
[1 1 1]
[1 1 1]]
5.4 arange()
numpy.arange函数用于创建一个等差数列的数组。它的功能类似于 Python 内置的 range()
函数,但返回的是一个 NumPy 数组而不是一个列表。
格式:
numpy.arange(start, stop, step, dtype)
start:起始值,默认为0
stop:终止值(不包含)
step:步长,默认为1
dtype:返回 ndarray 的数据类型,如果没有提供,则会使用输入数据的类型
arr0 = np.arange(0, 10, )
print(arr0)
arr1 = np.arange(1, 11, 3)
print(arr1)
[0 1 2 3 4 5 6 7 8 9]
[ 1 4 7 10]
5.5 linspace
函数用于创建一个指定范围内的等间隔数值序列数组。它与numpy.arange类似,但允许用户直接指定生成元素的数量,而不是步长。这在生成特定数量的数值时非常有用。
格式:
np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
start:起始值,默认为0
stop:终止值(不包含)
num:表示要生成多少个均匀的样本量,默认为50
endpoint:默认为True,表示包含终止值,反之不包含
retstep:表示是否返回步长,如果为 True,则返回一个包含数组和步长的元组;如果为 False,则只返回数组。默认为 False
dtype:返回 ndarray 的数据类型,如果没有提供,则会使用输入数据的类型
arr, step = np.linspace(0, 10, 20, endpoint=False, retstep=True)
print(step, arr)
0.5 [0. 0.5 1. 1.5 2. 2.5 3. 3.5 4. 4.5 5. 5.5 6. 6.5 7. 7.5 8. 8.5
9. 9.5]
5.6 full()
full()用于创建一个填充指定值的数组。
格式:
numpy.full(shape, fill_value, dtype=None, order='C')
shape:数组的形状,可以是整数或者整数元组
fill_value:填充的值
dtype:数组的数据类型,可选
order:C(行优先)和F(列优先)
arr = np.full((3, 3), 4)
print(arr)
[[4 4 4]
[4 4 4]
[4 4 4]]
5.7 logspace()
函数用于在对数刻度上生成等间隔的数值序列。它特别适用于生成对数刻度上的数据点,例如用于绘制对数图。以下是lecapsgo函数的详细说明和示例:
格式:
numpy.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None, axis=0)
start:起始值,默认为0
stop:终止值(不包含)
num:表示要生成多少个均匀的样本量,默认为50
endpoint:默认为True,表示包含终止值,反之不包含
base:对数的底数,默认为10
dtype:数组数据类型
axis:沿着指定的轴放置结果,默认为0
arr = np.logspace(1, 3, 4, base=2)
print(arr)
[ 2. 4. 8. 16.]
6.切片slice()
ndarray 对象的内容可以通过索引或切片来访问和修改,与 Python 中 list 的切片操作一样;
slice 操作也可通过 [start:stop:step] 的形式来实现
start:起始值,默认为0
stop:终止值(不包含)
step:步长,选取元素的间隔
import numpy as np
def np_slice():
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr)
print('_______________')
#按照行切片
arr1 = arr[0:2]
print(arr1)
#按照列切片
arr2 = arr[::, 0:2]
print(arr2)
#行列都切片
arr3 = arr[0:2, 0:2]
print(arr3)
#'...'切片是保留所有行或者所有列
"""arr4 = arr[0:2, ...]
print(arr4)"""
#可变的数据类型,切片得到的新数组是原数组的浅拷贝(,或者是视图),修改视图中的数据会影响原数组
arr1[0][0] = 100
print(arr1)
print(arr)
if __name__=='__main__':
np_slice()
[[1 2 3]
[4 5 6]
[7 8 9]]
_______________
[[1 2 3]
[4 5 6]]
[[1 2]
[4 5]
[7 8]]
[[1 2]
[4 5]]
[[100 2 3]
[ 4 5 6]]
[[100 2 3]
[ 4 5 6]
[ 7 8 9]]
冒号 : 的作用
表示范围: 冒号用于表示一个范围。例如,array[1:3] 表示从索引 1 到索引 3(不包括 3)的元素。
表示所有元素: 单独使用冒号表示所有元素。例如,array[:, 1] 表示所有行的第 1 列。
步长: 双冒号后面可以跟一个步长值,表示每隔多少个元素取一个。例如,array[::2] 表示每隔一个元素取一个。
省略号 (...
) 的作用
省略号用于在切片中表示多个冒号,用于省略不想显式书写的维度。
7.高级索引
NumPy的高级索引功能非常强大,允许你用多种方式选择和操作数组中的元素。相比于基本索引,高级索引可以访问到数组中的任意元素,并且可以用来对数组进行复杂的操作和修改。
7.1整数数组索引
整数数组索引是指使用一个数组来访问另一个数组的元素。这个数组中的每个元素都是目标数组中某个维度上的索引值。
这是一维数组的高级索引方式
arr = np.array([10, 20, 30, 40, 50])
index_arr = np.array([0, 2, 4])
print(arr[index_arr])
# 输出: [10 30 50]
这是多维数组的高级索引方式;[0,1,2]代表行索引、[1,0,1]代表列索引;即取出索引坐标 (0,0)、(1,1)、(0,2) 的元素
arr = np.array([[1, 2], [3, 4], [5, 6]])
rows = np.array([0, 1, 2])
cols = np.array([1, 0, 1])
print(arr[rows, cols])
# 输出: [2 3 6]
7.2布尔索引
布尔索引通过布尔运算(如:比较运算符)来获取符合指定条件的元素的数组。
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
bool_idx = arr > 5
print(bool_idx)
# 输出: [False False False False False True True True True True]
print(arr[bool_idx])
# 输出: [ 6 7 8 9]
多维数组的布尔索引
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
bool_idx = arr > 5
print(bool_idx)
# 输出:
# [[False False False]
# [False False True]
# [ True True True]]
print(arr[bool_idx])
# 输出: [6 7 8 9]
使用逻辑运算符(如 &、|、~)组合多个条件。
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
# 使用布尔索引筛选大于 5 且小于 9 的元素
bool_idx = (arr > 5) & (arr < 9)
print(bool_idx)
# 输出: [False False False False False True True True False False]
# 使用布尔索引获取满足条件的元素
print(arr[bool_idx])
# 输出: [6 7 8]
7.3 高级索引补充
test01():
data = np.arange(1,13).reshape(3,4)
#行级别的数组整数索引列表
#通过广播机制将行索引数组和列索引数组转换为相同的形状,然后在按照数组的整数索引获取对应的元素。
print(data[[[1],[2]],[0,1,2]])
#输出
[[ 5 6 7]
[ 9 10 11]]
8.广播(*)
广播(Broadcasting)是一种强大的机制,它允许不同形状的数组进行算术运算,这种机制的核心是对形状较小的数组,在横向或纵向上进行一定次数的重复,使其与形状较大的数组拥有相同的维度。广播使得NumPy在处理数组时更加灵活和高效。
广播规则
1.维度匹配:如果两个数组的维度数不同,维度数较少的数组会在前面补上长度为 1 的维度。
a = np.array([[1, 2, 3], [4, 5, 6]]) # 形状: (2, 3)
b = np.array([10, 20, 30]) # 形状: (3,)
c = a + b
print(c)
# 输出:
# [[11 22 33]
# [14 25 36]]
# 两个数组中最大行和最大列
a = np.array([[1], [2]])
b = np.array([100, 200, 300])
c = a + b
print(c)
#输出:
[[101 201 301]
[102 202 302]]
2.形状匹配:如果两个数组在某个维度上的长度不同,但其中一个数组在该维度上的长度为 1,则该数组会沿着该维度进行广播。
a = np.arange(1,5)
b = np.arange(1,5).reshape(1,4).T
# a 的形状为(4,1),被广播为(4,4)
# b 的形状为(1,4),被广播为(4,4)
# 形状相同后进行对应元素的运算
c = a + b
print(c)
#输出:
[[2 3 4 5]
[3 4 5 6]
[4 5 6 7]
[5 6 7 8]]
3.不匹配:如果两个数组在某个维度上的长度既不相同也不为 1,则广播失败,抛出 ValueError。
9.遍历数组
9.1遍历数组的第一维度
arr = np.array([[1,2,3],[4,5,6]])
#只遍历数组中的第一维元素
for i in arr:
print(i)
#输出:
[1 2 3]
[4 5 6]
for i in arr:遍历数组的第一维度,即按行或列的顺序逐个访问元素。
返回的是数组的子数组(如行或列),而不是单个元素。
9.2 nditer逐个访问元素
nditer 是 NumPy 中的一个强大的迭代器对象,用于高效地遍历多维数组。nditer 提供了多种选项和控制参数,使得数组的迭代更加灵活和高效。
参数:
order:C(行优先)和F(列优先)
flags:用于指定迭代器的额外行为。
multi_index: 返回每个元素的多维索引。
external_loop: 返回一维数组而不是单个元素,减少函数调用的次数,从而提高性能。
op_flags:用于指定操作数的行为。
readonly: 只读操作数。
readwrite: 读写操作数。
writeonly: 只写操作数。
arr = np.arange(1,7).reshape(2,3)
iter = np.nditer(arr, flags=['multi_index'])
for i in iter:
print(i , iter.multi_index)
iter1 = np.nditer(arr, flags=['external_loop'])
for i in iter1:
print(i)
iter2 = np.nditer(arr, flags=['external_loop'], order='F')
for i in iter2:
print(i)
#输出:
1 (0, 0)
2 (0, 1)
3 (0, 2)
4 (1, 0)
5 (1, 1)
6 (1, 2)
[1 2 3 4 5 6]
[1 4]
[2 5]
[3 6]
arr = np.arange(1, 7).reshape(2, 3)
for x in np.nditer(arr, op_flags=['readwrite']):
x[...] = x * 2
print(x)
#输出:
2
4
6
8
10
12
9.3 X[…]
是 NumPy 中的一种索引方式,表示获取数组 x
的一个视图,对数组 x
进行原地修改,而不是创建一个新的数组。 返回一个可写视图(writable view),允许直接修改原数组中的元素。
注意:当你使用 x[…] 时,x 必须是一个数组或数组的视图,而不是一个标量。
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 使用读写操作数遍历数组
# x[...] = x * 2 将数组 arr 中的每个元素乘以 2,并写回到原数组中。
# x实际返回一个包含当前元素的数组,而不是标量,所以可以使用x[...]
for x in np.nditer(arr, op_flags=['readwrite']):
x[...] = 2 * x
print(arr)
# 输出:
# [[ 2 4 6]
# [ 8 10 12]]
10.数组操作
10.1数组变维
函数名称 | 函数介绍 |
---|---|
reshape | 在不改变数组元素的条件下,修改数组的形状 |
flat属性 | 返回是一个迭代器,可以用 for 循环遍历其中的每一个元素 |
flatten | 以一维数组的形式返回一份数组的副本,对副本的操作不会影响到原数组 |
ravel | 返回一个连续的扁平数组(即展开的一维数组),与 flatten不同,它返回的是数组视图(修改视图会影响原数组) |
10.1.1 flat
返回一个一维迭代器,用于遍历数组中的所有元素。无论数组的维度如何,ndarray.flat属性都会将数组视为一个扁平化的一维数组,按行优先的顺序遍历所有元素。
格式:
ndarray.flat
array_one = np.arange(4).reshape(2,2)
print("原数组元素:")
for i in array_one:
print(i,end=" ")
print()
print("使用flat属性,遍历数组:")
for i in array_one.flat:
print(i,end=" ")
#输出
原数组元素:
[0 1] [2 3]
使用flat属性,遍历数组:
0 1 2 3
进程已结束,退出代码为 0
10.1.2 flatten()
用于将多维数组转换为一维数组。flatten() 返回的是原数组的一个拷贝,因此对返回的数组进行修改不会影响原数组。
格式:
ndarray.flatten(order='C')
案例:
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 使用 flatten 方法按行优先顺序展开
flat_arr = arr.flatten(order='C')
print(flat_arr)
# 输出:
# [1 2 3 4 5 6]
order:如果是'A'的话,按照元素在内存中的顺序展开
10.1.3 ravel()
用于将多维数组转换为一维数组。与 flatten() 不同,ravel() 返回的是原数组的一个视图(view),而不是副本。因此,对返回的数组进行修改会影响原数组。
格式:
ndarray.ravel()
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 使用 ravel 方法按行优先顺序展开
ravel_arr = arr.ravel()
print(ravel_arr)
# 输出:
# [1 2 3 4 5 6]
ravel_arr[-1] = 7
print(arr)
# 输出:
# [[1 2 3]
# [4 5 7]]
10.2数组转置
函数名称 | 说明 |
---|---|
transpose | 将数组的维度值进行对换,比如二维数组维度(2,4)使用该方法后为(4,2) |
ndarray.T | 与 transpose 方法相同 |
案例:
import numpy as np
def test01():
#transpose():数组装置,返回原数组的视图
#T属性:数组装置,返回的原数组的视图
arr = np.arange(1,13).reshape(-1,4)
arr1 = arr.T
print(arr1)
arr1[1][1] = 100
print(arr)
print('_________________________________________________________________model')
arr2 = arr.transpose()
print(arr2)
arr2[1][1] = 50
print(arr)
if __name__=='__main__':
test01()
#输出:
[[ 1 5 9]
[ 2 6 10]
[ 3 7 11]
[ 4 8 12]]
[[ 1 2 3 4]
[ 5 100 7 8]
[ 9 10 11 12]]
_________________________________________________________________model
[[ 1 5 9]
[ 2 100 10]
[ 3 7 11]
[ 4 8 12]]
[[ 1 2 3 4]
[ 5 50 7 8]
[ 9 10 11 12]]
10.3修改数组维度
多维数组(也称为 ndarray)的维度(或轴)是从外向内编号的。这意味着最外层的维度是轴0,然后是轴1,依此类推。
函数名称 | 参数 | 说明 |
---|---|---|
expand_dims(arr, axis) | arr:输入数组 axis:新轴插入的位置 | 在指定位置插入新的轴(相对于结果数组而言),从而扩展数组的维度 |
squeeze(arr, axis) | arr:输入数的组 axis:取值为整数或整数元组,用于指定需要删除的维度所在轴,指定的维度值必须为 1 ,否则将会报错,若为 None,则删除数组维度中所有为 1 的项 | 删除数组中维度为 1 的项 |
arr = np.array([1,2,3,4])
arr1 = np.expand_dims(arr, axis=0)
arr2 = np.expand_dims(arr, axis=1)
print(arr1)
print(arr2)
#输出:
[[1 2 3 4]]
[[1]
[2]
[3]
[4]]
#np.squeeze():数组降维,如果指定axis,则按照axis删除维度,前提:该纬度值必须唯一,否则异常
#如果不指定axis, 则自动判断维度是否为1,并删除维度为1的维度
arr = np.array([[[1,2,3]]])
print(arr.shape)
arr1 = np.squeeze(arr, axis=0)
print(arr1)
arr2 = np.squeeze(arr, axis=1)
print(arr2)
arr3 = np.squeeze(arr)
print(arr3)
#输出:
(1, 1, 3)
[[1 2 3]]
[[1 2 3]]
[1 2 3]
增加数组维度的操作类似:
test03():
arr = np.array([1,2,3])
#newaxis:在数组的指定位置添加一个维度,可以在行或列添加维度
arr1 = arr[np.newaxis,:]
arr2 = arr[:, np.newaxis]
print(arr1)
print(arr2)
#输出:
[[1 2 3]]
[[1]
[2]
[3]]
10.4数组拼接
函数名称 | 参数 | 说明 |
---|---|---|
hstack(tup) | tup:可以是元组,列表,或者numpy数组,返回结果为numpy的数组 | 按水平顺序堆叠序列中数组(列方向) |
vstack(tup) | tup:可以是元组,列表,或者numpy数组,返回结果为numpy的数组 | 按垂直方向堆叠序列中数组(行方向) |
hstack:如果行维度不一致,将无法执行堆叠操作。
test01():
a = np.array([[1,2,3],[4,5,6]])
b = np.array([[1,1],[2,2]])
#b = np.array([[7,8],[1,2],[3,4]])
#hstack:水平方向(按列)拼接数组, 前提:数组行数一致
print(a.shape, b.shape)
c = np.hstack((a, b))
print(c)
#输出:
(2, 3) (2, 2)
[[1 2 3 1 1]
[4 5 6 2 2]]
vstack:如果列维度不一致,将无法执行堆叠操作。
test02():
a = np.array([[1,2],[3,4],[5,6]])
b = np.array([[7,8],[9,10]])
#vstack:垂直方向(按行)拼接数组, 前提:数组列数一致
c = np.vstack((a,b))
print(c)
#输出:
[[ 1 2]
[ 3 4]
[ 5 6]
[ 7 8]
[ 9 10]]
10.5切割数组
函数名称 | 参数 | 说明 |
---|---|---|
hsplit(ary, indices_or_sections) | ary:原数组 indices_or_sections:按列分割的索引位置 | 将一个数组水平分割为多个子数组(按列) |
vsplit(ary, indices_or_sections) | ary:原数组 indices_or_sections:按行分割的索引位置 | 将一个数组垂直分割为多个子数组(按行) |
hsplit:
test01():
arr = np.arange(1,13).reshape(-1,4)
print(arr)
#hsplit(arr):按照水平方向切割数组,按列切割
#ary:要切割的数组
#indecies_or_sections:表示要切割的索引下标(不包含下标值)
resutl = np.hsplit(arr,[1, 3])
print(resutl[0])
print(resutl[1])
print(resutl[2])
#输出:
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
[[1]
[5]
[9]]
[[ 2 3]
[ 6 7]
[10 11]]
[[ 4]
[ 8]
[12]]
vsplit:
test02():
arr = np.arange(1,13).reshape(-1,3)
# vsplit(arr):按照垂直方向切割数组,按行切割
# ary:要切割的数组
# indecies_or_sections:表示要切割的索引下标(不包含下标值)
print(arr)
result = np.vsplit(arr, [2])
print(result[0])
print(result[1])
#输出:
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
[[1 2 3]
[4 5 6]]
[[ 7 8 9]
[10 11 12]]
10.6矩阵运算
np.dot
是一个通用的点积函数,适用于多种维度的数组。
对于二维数组(矩阵),np.dot
等价于矩阵乘法。
对于一维数组(向量),np.dot
计算的是向量的点积(内积)。
test01():
a = np.arange(1,5)
b = np.arange(5,9)
#np.dot:当数组是一维数组时,该方法是点积运算;
# 当数组是二维数组时,该方法是矩阵乘法
print(np.dot(a,b))
#输出:70
test02():
a = np.arange(1,5).reshape(2,2)
b = np.arange(5,9).reshape(2,2)
print(np.dot(a,b))
#输出:
[[19 22]
[43 50]]
np.linalg.det
计算一个方阵(行数和列数相等的矩阵)的行列式。
test03():
a = np.array([[1,2,3],[3,4,3],[1,2,1]])
det = np.linalg.det(a)
print(det)
#输出:
4.000000000000001
结果不是4,这是由于浮点数的二进制表示和计算过程中的舍入误差导致的。
np.matmul
是专门用于矩阵乘法的函数,适用于二维及更高维度的数组。用法和np.dot类似
11.数组元素的增删查改
11.1 resize
函数名称 | 参数 | 说明 |
---|---|---|
resize(a, new_shape) | a:操作的数组 new_shape:返回的数组的形状,如果元素数量不够,重复数组元素来填充新的形状 | 返回指定形状的新数组 |
test01():
a = np.arange(1,7).reshape(2,3)
b = np.resize(a, (3, 3))
# np.resize(array, new_shape):数组修改形状,如果原数组的元素不够,则重新遍历原数组的元素不够,
#和reshape()的区别,reshape要求新数组和原数组的元素总数相同,resize方法不受约束。
print(b)
#输出:
[[1 2 3]
[4 5 6]
[1 2 3]]
11.2 append
函数名称 | 参数 | 说明 |
---|---|---|
append(arr, values, axis=None) | arr:输入的数组 values:向 arr 数组中添加的值,需要和 arr 数组的形状保持一致 axis:默认为 None,返回的是一维数组;当 axis =0 时,追加的值会被添加到行,而列数保持不变,若 axis=1 则与其恰好相反 | 在数组的末尾添加值,返回一个一维数组 |
test02():
a = np.arange(1,7).reshape(2,3)
# axis为None, 返回的是一个一维数组,添加的值在数组尾部
b = np.append(a, [7,8,9])
print(b)
# axis为0,按行添加数值到数组尾部
#注意,values数组维度数要和原来的维度数一致,
# 在添加行时,values的列数要和原数组一致,否则报异常
c = np.append(a, [[7,8,9]], axis=0)
print(c)
# axis为1,按列添加数值到数组尾部
#注意,values数组维度数要和原来的维度数保持一致,
# 在添加列时,values的行数要和原来的一致
d = np.append(a,[[7,9], [8,10]], axis=1)
print(d)
#输出:
[1 2 3 4 5 6 7 8 9]
[[1 2 3]
[4 5 6]
[7 8 9]]
[[ 1 2 3 7 9]
[ 4 5 6 8 10]]
11.3 insert
函数名称 | 参数 | 说明 |
---|---|---|
insert(arr, obj, values, axis) | arr:输入的数组 obj:表示索引值,在该索引值之前插入 values 值 values:要插入的值 axis:默认为 None,返回的是一维数组;当 axis =0 时,追加的值会被添加到行,而列数保持不变,若 axis=1 则与其恰好相反 | 沿规定的轴将元素值插入到指定的元素前 |
test03():
# insert 方法:在原数组指定的索引前面插入元素
#注意:axis为None,返回一维数组;axis=0,行插入;axis=1, 列插入
a = np.arange(1,7).reshape(2,3)
b = np.insert(a,[2],100,axis=0)
print(b)
#输出:
[[ 1 2 3]
[ 4 5 6]
[100 100 100]]
如果obj为-1,表示插入在倒数第一个元素之前,不是在最后一列。
11.4 delete
函数名称 | 参数 | 说明 |
---|---|---|
delete(arr, obj, axis) | arr:输入的数组 obj:表示索引值,要删除数据的索引 axis:默认为 None,返回的是一维数组;当 axis =0 时,删除指定的行,若 axis=1 则与其恰好相反 | 删掉某个轴上的子数组,并返回删除后的新数组 |
test04():
#np.delete(arr,obj,axis):按照指定的object(索引)删除对应的元素
# axis为None,返回一维数组,删除对应索引的元素;
# axis=0,按行删除;axis=1,按列删除
a = np.arange(1,7).reshape(2,3)
b = np.delete(a,[0],0)
print(b)
#输出:
[[4 5 6]]
11.5 argwhere
返回数组中非 0 元素的索引,若是多维数组则返回行、列索引组成的索引坐标
test05():
a = np.arange(6).reshape(2,3)
#np.argwhere(arr):返回数组中非零元素对应的索引下标
#也可以通过布尔索引获取满足布尔条件的索引下标
print(np.argwhere(a))
print(np.argwhere(a>4))
#输出:
[[0 1]
[0 2]
[1 0]
[1 1]
[1 2]]
[[1 2]]
where:
语法:np.where(condition, x, y)
功能:根据条件返回对应元素。如果满足条件,则返回 x 否则返回 y。
返回值:一个与输入数组形状相同的数组。
argwhere:
语法:np.argwhere(condition)
功能:返回满足条件的元素的索引。
返回值:一个二维数组,每一行表示满足条件的元素的索引。
11.6 unique
函数名称 | 参数 | 说明 |
---|---|---|
unique(ar, return_index=False, return_inverse=False, return_counts=False, axis=None) | ar:输入的数组 return_index:如果为 True,则返回新数组元素在原数组中的位置(索引) return_inverse:如果为 True,则返回原数组元素在新数组中的位置(逆索引) return_counts:如果为 True,则返回去重后的数组元素在原数组中出现的次数 | 删掉某个轴上的子数组,并返回删除后的新数组 |
test06():
a = np.array([1, 2, 2, 3, 4, 4, 5])
# np.unique():数组元素去重
#return_index:如果为Ture,返回新数组元素在原数组中索引位置
#return_inverse:如果为Ture,返回原数组元素在新数组元素中索引位置
#return_counts:如果为True,返回元素在数组中的出现次数
b, idx = np.unique(a, return_index = True)
arr = np.array([1, 2, 2, 5, 5, 5, 4, 4, 4, 4])
b2, idx2 = np.unique(arr,return_inverse=True)
c, count = np.unique(a,return_counts=True)
print(b2)
print(idx2)
print(count)
#输出:
[1 2 4 5]
[0 1 1 3 3 3 2 2 2 2]
[1 2 1 2 1]
12.统计函数
12.1amin()和amax()
计算数组沿指定轴的最小值与最大值,并以数组形式返回
对于二维数组来说,axis=1 表示沿着水平方向,axis=0 表示沿着垂直方向
test01():
a = np.array([[1,2,3],[4,5,6]])
# amax():求数组最大值
# amin():求数组最小值
# axis=none,求整个数组最大值或最小值
# axis=0,按列求最大值或最小值
# axis=1,按行求最大值或最小值
print(np.amax(a, axis=0))
print(np.amin(a, axis=0))
print(np.amax(a, axis=1))
print(np.amin(a, axis=1))
print(np.amax(a))
print(np.amin(a))
#输出:
[4 5 6]
[1 2 3]
[3 6]
[1 4]
6
1
12.2 ptp()
计算数组元素中最值之差值,即最大值 – 最小值
对于二维数组来说,axis=1 表示沿着水平方向,axis=0 表示沿着垂直方向
a = np.arange(1,7).reshape(2,3)
# np.ptp():amax() - amin().最大值减去最小值
# axis=none,求整个数组最大值或最小值
# axis=0,按列求最大值或最小值
# axis=1,按行求最大值或最小值
print(np.ptp(a))
print(np.ptp(a, axis=1))
#输出:
5
[2 2]
12.3 median()
用于计算中位数,中位数是指将数组中的数据按从小到大的顺序排列后,位于中间位置的值。如果数组的长度是偶数,则中位数是中间两个数的平均值。
a = np.arange(1,7).reshape(-1,3)
#np.madian():求数组的中位数
# axis=none,求整个数组中位数
# axis=0,按列求中位数
# axis=1,按行求中位数
print(np.median(a, axis=0))
print(np.median(a, axis=1))
#输出:
[2.5 3.5 4.5]
[2. 5.]
12.4mean()
沿指定的轴,计算数组中元素的算术平均值(即元素之总和除以元素数量)
test04():
a = np.array([[1,2,3],[4,5,6]])
print(np.mean(a))
print(np.mean(a, axis=0))
print(np.mean(a, axis=1))
#输出:
3.5
[2.5 3.5 4.5]
[2. 5.]
12.5 average()
加权平均值是将数组中各数值乘以相应的权数,然后再对权重值求总和,最后以权重的总和除以总的单位数(即因子个数);根据在数组中给出的权重,计算数组元素的加权平均值。该函数可以接受一个轴参数 axis,如果未指定,则数组被展开为一维数组。
其中 xi是数组中的元素,wi是对应的权重。
如果所有元素的权重之和等于1,则表示为数学中的期望值。
a = np.array([1,2,3,4,5])
w = np.array([0.1,0.2,0.3,0.2,0.2])
#np.average():计算数组的加权平均值:所有元素值乘以对应的权重相加,除以所有权重之和
print(np.average(a, weights=w))
#输出:
3.2
12.6 var()和std()
在 NumPy 中,计算方差时使用的是统计学中的方差公式,而不是概率论中的方差公式,主要是因为 NumPy 的设计目标是处理实际数据集,而不是概率分布。
np.var 函数默认计算的是总体方差(Population Variance),而不是样本方差(Sample Variance)。
总体方差:
对于一个总体数据集 X={x1,x2,…,xN},总体方差的计算公式为:
$$
$$
其中:
– N是总体数据点的总数。
– μ是总体的均值。
标准差是方差的算术平方根,用来描述一组数据平均值的分散程度。若一组数据的标准差较大,说明大部分的数值和其平均值之间差异较大;若标准差较小,则代表这组数值比较接近平均值
test06():
a = np.arange(1,6)
#np.var():计算数组元素的方差
#参数:ddof:默认使用总体方差,如果设置为1,使用样本方差
print(np.var(a,ddof=1))
#np.std():计算标准差
print(np.std(a,ddof=0))
#输出:
2.5
1.4142135623730951
作者:inquisitor.dom