当前位置: 首页 > news >正文

NumPy全面学习笔记

NumPy(Numerical Python)是Python科学计算的核心库,提供高效的多维数组对象(ndarray)及丰富的数值计算工具。相比Python原生列表,NumPy数组具备同构数据存储连续内存布局向量化运算三大优势,运算速度提升10-100倍,是数据分析、机器学习、科学计算的基石。

1. NumPy数组基础:类型与转换规则

1.1 整数数组与浮点数数组

NumPy数组的核心特性之一是数据类型同构(所有元素类型一致),其中整数(integer)和浮点数(float)是最常用的两种类型,对应不同的应用场景:

类型分类常见 dtype特点应用场景
整数数组int8/int16/int32/int64无小数部分,范围随位数增加而扩大索引、计数、离散值存储(如标签)
浮点数数组float16/float32/float64支持小数,精度随位数增加而提高科学计算、连续值存储(如温度、坐标)
核心操作示例:
import numpy as np# 1. 创建整数数组(指定dtype)
int_arr = np.array([1, 2, 3, 4], dtype=np.int32)
print("整数数组类型:", int_arr.dtype)  # 输出: int32
print("整数数组形状:", int_arr.shape)  # 输出: (4,)# 2. 创建浮点数数组(自动推断或指定)
float_arr1 = np.array([1.1, 2.2, 3.3])  # 自动推断为float64
float_arr2 = np.array([4, 5, 6], dtype=np.float16)  # 强制指定为float16
print("float_arr1类型:", float_arr1.dtype)  # 输出: float64# 3. 类型转换(astype返回新数组,原数组不变)
converted_arr = int_arr.astype(np.float64)
print("转换后类型:", converted_arr.dtype)  # 输出: float64
print("原数组类型:", int_arr.dtype)        # 输出: int32(不变)

1.2 同化定理(类型提升规则)

当不同类型的NumPy数组进行运算时,结果的类型会向精度更高、范围更广的类型“同化”,以避免数据丢失,这一规则称为“同化定理”。

核心规则与示例:
  1. 低精度 → 高精度:int8 + int32int32
  2. 整数 → 浮点数:int64 + float32float64
  3. 特殊类型优先:bool(本质是1位整数)与其他类型运算 → 转为对应类型
# 示例1:整数与浮点数同化
a = np.array([1, 2], dtype=np.int32)
b = np.array([3.1, 4.2], dtype=np.float32)
c = a + b
print("a + b 类型:", c.dtype)  # 输出: float64(向更高精度同化)# 示例2:低精度与高精度同化
d = np.array([5, 6], dtype=np.int8)  # 范围: -128~127
e = np.array([7, 8], dtype=np.int64) # 范围: -9e18~9e18
f = d * e
print("d * e 类型:", f.dtype)  # 输出: int64(向更广范围同化)

1.3 共同改变定理(类型与形状协同转换)

“共同改变定理”指NumPy数组的类型转换形状调整需遵循“元素总数守恒”和“数据兼容性”原则,两者可协同操作,但需避免数据丢失或逻辑错误。

核心操作与约束:
  1. 形状调整(reshape):需保证调整前后元素总数一致np.prod(原shape) = np.prod(新shape)
  2. 类型与形状协同:先确保类型兼容(如float转int会丢失小数),再调整形状
  3. 视图(view)与副本(copy):reshape可能返回视图(共享内存),astype始终返回副本(独立内存)
# 示例:类型与形状协同转换
# 1. 原始数组(2行3列,int32)
arr = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)
print("原始形状:", arr.shape)  # 输出: (2, 3),元素总数: 6# 2. 先转类型(int32→float64),再调整形状(2,3)→(3,2)
step1 = arr.astype(np.float64)  # 副本,类型改变
step2 = step1.reshape((3, 2))   # 视图(内存连续),形状改变
print("最终形状:", step2.shape)  # 输出: (3, 2)
print("最终类型:", step2.dtype)  # 输出: float64# 3. 错误示例:形状调整元素总数不匹配
try:arr.reshape((2, 4))  # 2*4=8 ≠ 6,报错
except ValueError as e:print("错误:", e)  # 输出: cannot reshape array of size 6 into shape (2,4)

2. 数组维度:表示、形状与转换

2.1 数组维度(表示及形状)

NumPy中“维度”(Dimension)又称“轴”(Axis),是数组的层级结构描述。维度通过ndim属性获取,形状通过shape属性(元组形式)表示,元组中每个元素对应某一轴的元素数量

不同维度数组的表示:
维度名称用途shape示例轴的含义(以shape=(N,C,H,W)为例)
0D标量(Scalar)单个数值()无轴,仅1个元素
1D向量(Vector)一维数据(5,)轴0:5个元素(如时间序列)
2D矩阵(Matrix)二维表格(3,4)轴0:3行,轴1:4列(如数据表)
3D张量(Tensor)三维数据(2,3,4)轴0:2个矩阵,轴1:3行,轴2:4列(如RGB图像)
4D高维张量批量数据(10,3,224,224)轴0:10张图,轴1:3通道(RGB),轴2:224高,轴3:224宽
核心属性示例:
# 0D数组(标量)
scalar = np.array(5)
print("0D - ndim:", scalar.ndim, "shape:", scalar.shape, "size:", scalar.size)
# 输出: 0D - ndim: 0 shape: () size: 1# 3D数组(2个2行3列的矩阵)
tensor = np.array([[[1,2,3],[4,5,6]], [[7,8,9],[10,11,12]]])
print("3D - ndim:", tensor.ndim, "shape:", tensor.shape, "size:", tensor.size)
# 输出: 3D - ndim: 3 shape: (2, 2, 3) size: 12(2*2*3=12)

2.2 不同维度数组的转换

维度转换是NumPy的核心操作,分为升维(增加轴)、降维(删除轴)、维度调整(改变轴的元素数量)三类,需结合业务场景选择合适方法。

1. 升维(增加轴)

通过np.newaxis(关键字)或np.expand_dims(函数)在指定位置插入新轴(长度为1),常用于广播运算前的维度对齐。

# 原始1D数组
arr = np.array([1, 2, 3])  # shape: (3,)# 方法1:np.newaxis升维(轴0插入新轴)
arr_2d_axis0 = arr[np.newaxis, :]  # shape: (1, 3)(1行3列)
# 方法2:np.newaxis升维(轴1插入新轴)
arr_2d_axis1 = arr[:, np.newaxis]  # shape: (3, 1)(3行1列)# 方法3:np.expand_dims(指定axis参数)
arr_3d = np.expand_dims(arr, axis=1)  # shape: (3, 1)
print("arr_2d_axis0 shape:", arr_2d_axis0.shape)  # 输出: (1, 3)
print("arr_3d shape:", arr_3d.shape)              # 输出: (3, 1)
2. 降维(删除轴)

通过np.squeeze删除所有长度为1的轴,或指定axis删除特定长度为1的轴;通过reshape(-1)将任意维度转为1D数组(-1表示自动计算元素数量)。

# 原始3D数组(shape: (1, 3, 1))
arr = np.array([[[1], [2], [3]]])# 方法1:np.squeeze删除所有长度为1的轴
arr_squeezed = np.squeeze(arr)  # shape: (3,)
# 方法2:np.squeeze指定删除轴0
arr_squeeze_axis0 = np.squeeze(arr, axis=0)  # shape: (3, 1)# 方法3:reshape(-1)转为1D
arr_1d = arr.reshape(-1)  # shape: (3,)
print("arr_squeezed shape:", arr_squeezed.shape)  # 输出: (3,)
print("arr_1d shape:", arr_1d.shape)              # 输出: (3,)
3. 维度调整(reshape

核心原则:调整前后元素总数一致,支持“自动计算”(-1仅可出现一次)。

# 原始2D数组(shape: (4, 3),元素总数12)
arr = np.arange(12).reshape(4, 3)  # np.arange生成0-11的连续整数# 调整为3D数组(2个2行3列的矩阵)
arr_3d = arr.reshape(2, 2, 3)  # shape: (2, 2, 3)
# 调整为1D数组(自动计算长度)
arr_1d = arr.reshape(-1)       # shape: (12,)
# 调整为2D数组(自动计算列数)
arr_2d_auto = arr.reshape(6, -1)  # shape: (6, 2)(12/6=2)
print("arr_2d_auto shape:", arr_2d_auto.shape)  # 输出: (6, 2)

3. 数组索引与切片:精准获取数据

3.1 数组索引(基础索引 + 花式索引)

索引是通过“位置”或“条件”获取数组元素的操作,NumPy支持基础索引(单元素/连续范围)和花式索引(离散位置/布尔条件),两者核心区别是返回结果是否为副本(花式索引返回副本,基础索引返回视图)。

1. 基础索引(按位置索引)

适用于获取单个元素或连续范围的元素,语法与Python列表类似,但支持多轴同时索引(用逗号分隔各轴)。

# 1D数组索引
arr_1d = np.array([10, 20, 30, 40, 50])
print("1D[2]:", arr_1d[2])       # 输出: 30(正索引)
print("1D[-1]:", arr_1d[-1])     # 输出: 50(负索引,倒数第一个)# 2D数组索引(轴0:行,轴1:列)
arr_2d = np.array([[1,2,3], [4,5,6], [7,8,9]])
print("2D[1,2]:", arr_2d[1, 2])  # 输出: 6(第2行第3列,行索引1,列索引2)
print("2D[0]:", arr_2d[0])       # 输出: [1 2 3](第1行所有列)# 3D数组索引(轴0:矩阵,轴1:行,轴2:列)
arr_3d = np.array([[[1,2],[3,4]], [[5,6],[7,8]]])  # shape: (2,2,2)
print("3D[1,0,1]:", arr_3d[1, 0, 1])  # 输出: 6(第2个矩阵,第1行,第2列)
2. 花式索引(按离散位置/布尔条件索引)
  • 整数数组索引:用整数数组指定离散位置,返回与索引数组形状一致的结果
  • 布尔索引:用布尔数组指定条件,返回所有True对应的元素(1D数组)
# 示例1:整数数组索引(2D数组)
arr_2d = np.array([[1,2,3], [4,5,6], [7,8,9]])
row_idx = [0, 2]    # 行索引:第1、3行
col_idx = [1, 2]    # 列索引:第2、3列
# 方式1:获取(0,1)、(2,2)两个元素
print("整数索引1:", arr_2d[row_idx, col_idx])  # 输出: [2 9]
# 方式2:获取第1、3行的第2、3列(子矩阵)
print("整数索引2:\n", arr_2d[row_idx][:, col_idx])  
# 输出:
# [[2 3]
#  [8 9]]# 示例2:布尔索引(筛选条件元素)
arr = np.array([1, 2, 3, 4, 5, 6])
# 条件:元素为偶数
bool_mask = arr % 2 == 0  
print("布尔索引结果:", arr[bool_mask])  # 输出: [2 4 6]# 2D数组布尔索引(筛选行)
bool_row = arr_2d.sum(axis=1) > 10  # 行求和大于10的行(第2、3行)
print("筛选行结果:\n", arr_2d[bool_row])
# 输出:
# [[4 5 6]
#  [7 8 9]]

3.2 矩阵切片(获取子数组)

切片是获取数组连续子范围的操作,语法为arr[start:end:step](左闭右开区间),支持多轴同时切片,且返回结果为视图(修改切片会影响原数组),这与Python列表切片的行为一致,但效率更高。

核心规则与示例:
  1. start:起始位置(默认0)
  2. end:结束位置(默认数组长度,不包含)
  3. step:步长(默认1,负数表示反向切片)
  4. 多轴切片:用逗号分隔各轴的切片规则
  5. 省略号(...):代替多个:,表示“剩余所有轴”
# 1D数组切片
arr_1d = np.array([10,20,30,40,50,60])
print("1D[1:4]:", arr_1d[1:4])    # 输出: [20 30 40](索引1-3)
print("1D[::2]:", arr_1d[::2])    # 输出: [10 30 50](步长2,隔一个取一个)
print("1D[::-1]:", arr_1d[::-1])  # 输出: [60 50 40 30 20 10](反向切片)# 2D数组切片(行切片, 列切片)
arr_2d = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
# 切片1:第2-3行,第2-4列(索引1-2行,1-3列)
slice1 = arr_2d[1:3, 1:4]  
print("slice1:\n", slice1)
# 输出:
# [[ 6  7  8]
#  [10 11 12]]# 切片2:所有行,第1、3列(步长2)
slice2 = arr_2d[:, ::2]  
print("slice2:\n", slice2)
# 输出:
# [[ 1  3]
#  [ 5  7]
#  [ 9 11]]# 3D数组切片(省略号用法)
arr_3d = np.array([[[1,2],[3,4]], [[5,6],[7,8]], [[9,10],[11,12]]])  # shape: (3,2,2)
# ... 代替前两个轴(轴0和轴1),切片轴2的第2个元素
slice3 = arr_3d[..., 1]  
print("slice3 shape:", slice3.shape)  # 输出: (3, 2)
print("slice3:\n", slice3)
# 输出:
# [[ 2  4]
#  [ 6  8]
#  [10 12]]# 关键特性:切片是视图,修改影响原数组
slice1[0, 0] = 999  # 修改切片的(0,0)元素
print("修改后原数组:\n", arr_2d)
# 输出(原数组第2行第2列变为999):
# [[  1   2   3   4]
#  [  5 999   7   8]
#  [  9  10  11  12]]

4. 数组高级操作:转置、翻转、拼接与分裂

4.1 转置、翻转、重置、拼接、分裂

这类操作用于调整数组的结构(轴顺序、元素顺序、维度组合),是数据预处理的核心工具,需重点掌握各操作的适用场景与轴参数设置。

1. 转置(Transpose):交换轴的顺序

转置是改变轴的排列顺序,核心函数为np.transpose(支持指定轴顺序)和arr.T(仅适用于2D数组,等价于np.transpose(arr, (1,0)))。

# 2D数组转置(矩阵转置:行变列,列变行)
arr_2d = np.array([[1,2,3], [4,5,6]])  # shape: (2,3)
transpose_2d = arr_2d.T  # 等价于 np.transpose(arr_2d)
print("2D转置 shape:", transpose_2d.shape)  # 输出: (3,2)
print("2D转置:\n", transpose_2d)
# 输出:
# [[1 4]
#  [2 5]
#  [3 6]]# 3D数组转置(指定轴顺序)
arr_3d = np.array([[[1,2],[3,4]], [[5,6],[7,8]]])  # shape: (2,2,2)
# 交换轴0和轴1(原shape: (2,2,2) → 新shape: (2,2,2))
transpose_3d = np.transpose(arr_3d, (1,0,2))  
print("3D转置 shape:", transpose_3d.shape)  # 输出: (2,2,2)
print("3D转置[0,1]:", transpose_3d[0,1])  # 输出: [5 6](原arr_3d[1,0])
2. 翻转(Flip):沿轴反转元素顺序

翻转是沿指定轴反向排列元素,核心函数包括np.flip(任意轴)、np.flipud(垂直翻转,轴0)、np.fliplr(水平翻转,轴1)。

arr_2d = np.array([[1,2,3], [4,5,6], [7,8,9]])# 垂直翻转(轴0:行顺序反转)
flip_ud = np.flipud(arr_2d)
print("垂直翻转:\n", flip_ud)
# 输出:
# [[7 8 9]
#  [4 5 6]
#  [1 2 3]]# 水平翻转(轴1:列顺序反转)
flip_lr = np.fliplr(arr_2d)
print("水平翻转:\n", flip_lr)
# 输出:
# [[3 2 1]
#  [6 5 4]
#  [9 8 7]]# 沿轴1翻转(等价于水平翻转)
flip_axis1 = np.flip(arr_2d, axis=1)
print("沿轴1翻转:\n", flip_axis1)  # 与flip_lr结果一致
3. 重置(Reshape/Resize/Pad):调整形状与填充
  • reshape:固定元素总数,调整形状(前已讲)
  • np.resize:灵活调整形状,元素不足时重复填充,超出时截断
  • np.pad:给数组添加“ padding ”(边缘填充),支持多种填充模式
# np.resize示例(元素不足时重复)
arr = np.array([1,2,3])
resized = np.resize(arr, (2,3))  # 目标shape: (2,3),需6个元素
print("np.resize结果:\n", resized)
# 输出(原数组[1,2,3]重复为[1,2,3,1,2,3]):
# [[1 2 3]
#  [1 2 3]]# np.pad示例(周围填充1层0)
arr_2d = np.array([[1,2],[3,4]])
# pad_width: 各轴填充层数((上,下), (左,右))
padded = np.pad(arr_2d, pad_width=((1,1), (1,1)), mode='constant', constant_values=0)
print("np.pad结果:\n", padded)
# 输出:
# [[0 0 0 0]
#  [0 1 2 0]
#  [0 3 4 0]
#  [0 0 0 0]]
4. 拼接(Concatenate):合并多个数组

拼接是将多个形状兼容的数组沿指定轴合并,核心函数包括np.concatenate(通用)、np.vstack(垂直拼接,轴0)、np.hstack(水平拼接,轴1),关键约束:除拼接轴外,其他轴的形状必须完全一致。

# 准备两个形状兼容的数组(shape: (2,3))
arr1 = np.array([[1,2,3], [4,5,6]])
arr2 = np.array([[7,8,9], [10,11,12]])# 1. 垂直拼接(轴0:行数增加,列数不变)
v_stack = np.vstack((arr1, arr2))  # 等价于 np.concatenate((arr1, arr2), axis=0)
print("垂直拼接 shape:", v_stack.shape)  # 输出: (4,3)
print("垂直拼接:\n", v_stack)
# 输出:
# [[ 1  2  3]
#  [ 4  5  6]
#  [ 7  8  9]
#  [10 11 12]]# 2. 水平拼接(轴1:列数增加,行数不变)
h_stack = np.hstack((arr1, arr2))  # 等价于 np.concatenate((arr1, arr2), axis=1)
print("水平拼接 shape:", h_stack.shape)  # 输出: (2,6)
print("水平拼接:\n", h_stack)
# 输出:
# [[ 1  2  3  7  8  9]
#  [ 4  5  6 10 11 12]]
5. 分裂(Split):拆分一个数组

分裂是将一个数组沿指定轴拆分为多个子数组,核心函数包括np.split(通用)、np.vsplit(垂直分裂,轴0)、np.hsplit(水平分裂,轴1),关键约束:拆分后的子数组元素数量需整除原数组对应轴的长度(或指定拆分位置)。

# 原始数组(shape: (4,3))
arr = np.array([[1,2,3], [4,5,6], [7,8,9], [10,11,12]])# 1. 垂直分裂为2个等长数组(轴0:4行→2行+2行)
vsplit1 = np.vsplit(arr, 2)  # 等价于 np.split(arr, 2, axis=0)
print("垂直分裂1 - 子数组1 shape:", vsplit1[0].shape)  # 输出: (2,3)
print("垂直分裂1 - 子数组2:\n", vsplit1[1])
# 输出:
# [[ 7  8  9]
#  [10 11 12]]# 2. 按指定位置分裂(轴1:3列→1列+2列)
hsplit2 = np.hsplit(arr, [1])  # 等价于 np.split(arr, [1], axis=1)
print("水平分裂2 - 子数组1 shape:", hsplit2[0].shape)  # 输出: (4,1)
print("水平分裂2 - 子数组2:\n", hsplit2[1])
# 输出:
# [[ 2  3]
#  [ 5  6]
#  [ 8  9]
#  [11 12]]

5. 数组运算:元素级、广播与矩阵运算

5.1 数组与系数之间的运算

“系数”指单个数值(标量),数组与系数的运算属于元素级运算(系数与数组每个元素逐一运算),无需循环,直接通过运算符或NumPy函数实现,效率极高。

支持的运算类型:
运算类别运算符NumPy函数示例
加法+np.addarr + 5
减法-np.subtractarr - 2
乘法*np.multiplyarr * 3
除法/np.dividearr / 2
地板除//np.floor_dividearr // 2
取余%np.modarr % 3
幂运算**np.powerarr ** 2
示例:
arr = np.array([[1,2,3], [4,5,6]], dtype=np.float64)
coeff = 2  # 系数# 加法:每个元素加2
add_res = arr + coeff
print("数组+系数:\n", add_res)
# 输出:
# [[3. 4. 5.]
#  [6. 7. 8.]]# 幂运算:每个元素平方
power_res = np.power(arr, coeff)  # 等价于 arr ** 2
print("数组平方:\n", power_res)
# 输出:
# [[ 1.  4.  9.]
#  [16. 25. 36.]]# in-place运算(直接修改原数组,节省内存)
arr *= coeff  # 等价于 np.multiply(arr, coeff, out=arr)
print("in-place乘法后原数组:\n", arr)
# 输出:
# [[ 2.  4.  6.]
#  [ 8. 10. 12.]]

5.2 数组与数组之间的运算

数组与数组的运算分为元素级运算(Hadamard积)和矩阵运算(点积),前者要求数组形状完全一致,后者要求前数组列数等于后数组行数。

1. 元素级运算(Hadamard积)

对应位置元素逐一运算,形状必须完全相同,运算规则与“数组-系数”运算一致。

arr1 = np.array([[1,2,3], [4,5,6]])
arr2 = np.array([[7,8,9], [10,11,12]])# 元素级加法
add_res = arr1 + arr2
print("元素级加法:\n", add_res)
# 输出:
# [[ 8 10 12]
#  [14 16 18]]# 元素级乘法(非矩阵乘法)
mul_res = arr1 * arr2
print("元素级乘法:\n", mul_res)
# 输出(1*7, 2*8, ..., 6*12):
# [[ 7 16 27]
#  [40 55 72]]# 元素级比较运算(返回布尔数组)
cmp_res = arr1 > arr2
print("元素级比较:\n", cmp_res)
# 输出:
# [[False False False]
#  [False False False]]
2. 矩阵运算(点积)

线性代数中的矩阵乘法,核心函数为np.matmul(或@运算符),规则:若A(m,n)矩阵,B(n,p)矩阵,则结果C(m,p)矩阵,且C[i,j] = sum(A[i,k] * B[k,j])k从0到n-1)。

# 2D数组(矩阵)点积
A = np.array([[1,2], [3,4]])  # shape: (2,2)
B = np.array([[5,6], [7,8]])  # shape: (2,2)# 方法1:np.matmul
dot1 = np.matmul(A, B)
# 方法2:@运算符(Python 3.5+)
dot2 = A @ B
print("矩阵点积:\n", dot1)
# 输出(按矩阵乘法规则计算):
# [[1*5+2*7, 1*6+2*8],
#  [3*5+4*7, 3*6+4*8]]
# → [[19 22]
#    [43 50]]# 错误示例:形状不兼容(A列数≠B行数)
C = np.array([[1,2,3], [4,5,6]])  # shape: (2,3)
try:np.matmul(A, C)  # A列数2 ≠ C行数2?实际兼容(结果shape=(2,3))# 若C是(3,2),则A@C会报错(2≠3)
except ValueError as e:print("错误:", e)

5.3 广播(Broadcasting):形状不同数组的运算

广播是NumPy的核心特性,用于解决形状不同但兼容的数组运算问题,通过“虚拟复制”(逻辑上扩展数组,不实际占用内存)实现元素级运算,大幅简化代码并节省内存。

广播的核心规则(3条):
  1. 维度补齐:将两个数组的形状元组“左对齐”,在较短形状前补1,使维度数相同。
    例:(3,) → (1,3)(2,3) → (2,3)(1,2,3) → (1,2,3)(4,1,3) → (4,1,3)
  2. 维度兼容检查:对补齐后的每个维度,若两个数组的维度大小相同其中一个为1,则兼容;否则报错。
  3. 虚拟扩展:将维度大小为1的轴“复制”到与另一数组对应维度相同的大小,然后进行元素级运算。
广播示例:
# 示例1:1D数组与2D数组广播
arr1 = np.array([1,2,3])  # shape: (3,) → 补齐后(1,3)
arr2 = np.array([[4], [5], [6]])  # shape: (3,1) → 补齐后(3,1)
# 广播后:arr1→(3,3),arr2→(3,3),元素级加法
broadcast_res = arr1 + arr2
print("广播结果 shape:", broadcast_res.shape)  # 输出: (3,3)
print("广播结果:\n", broadcast_res)
# 输出:
# [[5 6 7]
#  [6 7 8]
#  [7 8 9]]# 示例2:3D数组广播
arr3 = np.array([[[1,2]], [[3,4]]])  # shape: (2,1,2)
arr4 = np.array([[5,6], [7,8]])      # shape: (2,2) → 补齐后(1,2,2)
# 广播后:arr3→(2,2,2),arr4→(2,2,2),元素级乘法
broadcast_mul = arr3 * arr4
print("3D广播结果 shape:", broadcast_mul.shape)  # 输出: (2,2,2)
print("3D广播结果[0,1]:", broadcast_mul[0,1])  # 输出: [14 16](2*7, 2*8)# 错误示例:维度不兼容
arr5 = np.array([[1,2],[3,4]])  # shape: (2,2)
arr6 = np.array([[5,6,7],[8,9,10]])  # shape: (2,3)
try:arr5 + arr6  # 补齐后(2,2) vs (2,3),轴1大小2≠3,不兼容
except ValueError as e:print("广播错误:", e)  # 输出: operands could not be broadcast together with shapes (2,2) (2,3)

6. 矩阵高级运算与复合函数

6.1 矩阵乘积(线性代数运算)

除基础矩阵点积外,NumPy的np.linalg模块提供了丰富的线性代数运算,涵盖矩阵求逆、行列式、特征值等,是科学计算的核心工具。

核心线性代数函数:
函数功能示例
np.linalg.inv求方阵的逆矩阵(要求行列式≠0)inv_A = np.linalg.inv(A)
np.linalg.det计算方阵的行列式det_A = np.linalg.det(A)
np.linalg.eig计算方阵的特征值与特征向量eig_vals, eig_vecs = np.linalg.eig(A)
np.linalg.solve求解线性方程组Ax = bx = np.linalg.solve(A, b)
np.linalg.norm计算矩阵/向量的范数(如L2范数)norm_A = np.linalg.norm(A, ord=2)
示例:
# 1. 矩阵求逆与行列式
A = np.array([[1,2], [3,4]])  # 2阶方阵
det_A = np.linalg.det(A)      # 计算行列式(1*4 - 2*3 = -2)
inv_A = np.linalg.inv(A)      # 求逆矩阵
print("行列式det(A):", det_A)  # 输出: -2.0
print("逆矩阵inv(A):\n", inv_A)
# 输出:
# [[-2.   1. ]
#  [ 1.5 -0.5]]# 验证:A @ inv(A) ≈ 单位矩阵(浮点误差可忽略)
identity = A @ inv_A
print("A @ inv(A) ≈ 单位矩阵:\n", identity)
# 输出:
# [[1.00000000e+00 1.11022302e-16]
#  [0.00000000e+00 1.00000000e+00]]# 2. 求解线性方程组 Ax = b
b = np.array([5, 11])  # 方程组:1x1 + 2x2 =5;3x1 +4x2=11
x = np.linalg.solve(A, b)  # 求解x1, x2
print("方程组解x:", x)  # 输出: [1. 2.](x1=1, x2=2)
print("验证A@x == b:", np.allclose(A @ x, b))  # 输出: True(验证正确)

6.2 复合函数

复合函数指多个NumPy函数的组合使用,或自定义函数通过“向量化”适配数组运算。NumPy内置函数均为向量化函数(直接作用于数组所有元素,无需循环),效率远高于Python原生循环。

1. 内置函数复合示例

NumPy提供三角函数、指数对数、聚合函数等,可直接组合使用:

arr = np.array([1, 2, 3, 4], dtype=np.float64)# 复合1:指数→正弦→平方
comp1 = np.sin(np.exp(arr)) ** 2
print("exp→sin→平方:", np.round(comp1, 4))  # 输出: [0.9093 0.0141 0.9999 0.9854]# 复合2:绝对值→对数→均值(避免log(0)或负数值)
arr2 = np.array([-5, 0, 5, 10])
comp2 = np.mean(np.log(np.abs(arr2) + 1))  # +1避免log(0)
print("abs→log→均值:", np.round(comp2, 4))  # 输出: 1.5601
2. 自定义函数向量化

通过np.vectorize将普通Python函数转为向量化函数,可直接作用于数组(注意:np.vectorize本质是循环,效率低于内置函数,仅用于简单场景)。

# 自定义Python函数(仅支持标量输入)
def custom_func(x):if x > 0:return x ** 2 + np.sin(x)else:return -x + np.cos(x)# 转为向量化函数
vec_func = np.vectorize(custom_func)# 作用于数组
arr = np.array([-2, -1, 0, 1, 2])
res = vec_func(arr)
print("自定义向量化函数结果:", np.round(res, 4))
# 输出: [3.5838 1.5403 1.     1.8415 4.9093]
3. 聚合函数复合

聚合函数(如summeanmax)沿指定轴压缩数组维度,可与元素级函数复合使用:

arr_2d = np.array([[1,2,3], [4,5,6], [7,8,9]])# 复合:每行元素平方后求和
row_sum_sq = np.sum(arr_2d ** 2, axis=1)
print("每行平方和:", row_sum_sq)  # 输出: [14 77 194]# 复合:每列元素正弦后求最大值
col_max_sin = np.max(np.sin(arr_2d), axis=0)
print("每列正弦最大值:", np.round(col_max_sin, 4))  # 输出: [0.6570 0.9894 0.4121]

7. 布尔型数组

布尔型数组(dtype为bool)是元素仅为True(1)或False(0)的特殊数组,主要用于条件筛选计数统计逻辑运算,是NumPy数据清洗的核心工具。

7.1 布尔数组的创建

常见创建方式包括元素级比较运算特殊检测函数

arr = np.array([1, 2, 3, 4, 5, 6])
arr2 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# 1. 比较运算创建
bool1 = arr > 3          # 元素>3 → [False False False  True  True  True]
bool2 = arr2 % 2 == 0    # 偶数元素 → [[False  True False], [ True False  True], [False  True False]]# 2. 特殊检测函数创建
arr3 = np.array([1.0, np.nan, 3.0, np.inf, -np.inf])
bool3 = np.isnan(arr3)   # 检测NaN → [False  True False False False]
bool4 = np.isinf(arr3)   # 检测无穷大 → [False False False  True  True]print("bool2:\n", bool2)
# 输出:
# [[False  True False]
#  [ True False  True]
#  [False  True False]]

7.2 布尔数组的核心用途

1. 条件筛选(布尔索引)

通过布尔数组筛选出True对应的元素,返回1D数组(副本):

arr = np.array([10, 20, 30, 40, 50])
bool_mask = (arr > 20) & (arr < 50)  # 20<元素<50 → [False False  True  True False]
filtered = arr[bool_mask]
print("筛选结果:", filtered)  # 输出: [30 40]# 2D数组筛选(保留满足条件的行)
arr2 = np.array([[1,2,3], [4,5,6], [7,8,9]])
row_mask = arr2.sum(axis=1) > 10  # 行求和>10 → [False  True  True]
filtered_rows = arr2[row_mask]
print("筛选行结果:\n", filtered_rows)
# 输出:
# [[4 5 6]
#  [7 8 9]]
2. 计数与逻辑判断

通过np.sum(统计True数量,因True=1False=0)、np.any(存在至少一个True返回True)、np.all(所有元素为True返回True)实现统计与判断:

arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])
bool_mask = arr % 2 == 0  # 偶数掩码 → [F T F T F T F T]# 统计True数量(偶数个数)
true_count = np.sum(bool_mask)
print("偶数个数:", true_count)  # 输出: 4# 逻辑判断:是否存在偶数(any)
has_even = np.any(bool_mask)
print("存在偶数:", has_even)  # 输出: True# 逻辑判断:是否全为偶数(all)
all_even = np.all(bool_mask)
print("全为偶数:", all_even)  # 输出: False# 2D数组逻辑判断(按行/列)
arr2 = np.array([[1,2,3], [4,5,6], [7,8,9]])
row_has_even = np.any(arr2 % 2 == 0, axis=1)  # 每行是否有偶数
print("每行是否有偶数:", row_has_even)  # 输出: [True True True]
3. 布尔运算组合

通过&(与)、|(或)、~(非)实现多条件组合(注意:需用括号包裹单个条件):

arr = np.array([1, 2, 3, 4, 5, 6])
# 条件1:元素>2;条件2:元素<5 → 组合条件:2<元素<5
comb_mask = (arr > 2) & (arr < 5)
print("2<元素<5的结果:", arr[comb_mask])  # 输出: [3 4]# 条件1:元素是偶数;条件2:元素>4 → 组合条件:偶数或>4
comb_mask2 = (arr % 2 == 0) | (arr > 4)
print("偶数或>4的结果:", arr[comb_mask2])  # 输出: [2 4 5 6]# 非运算:排除偶数
not_even = ~(arr % 2 == 0)
print("非偶数结果:", arr[not_even])  # 输出: [1 3 5]

8. 数组与张量(相同点和不同点)

在数值计算领域,“数组”(NumPy ndarray)和“张量”(Tensor)是两个密切相关但不完全等同的概念,需明确两者的联系与区别,避免混淆。

8.1 核心定义

  • NumPy数组(ndarray):NumPy库中的多维数据容器,支持同构数据存储、向量化运算和基础维度操作,是Python中“低维张量”的实现载体(通常指0D-4D)。
  • 张量(Tensor):数学概念,指“任意维度的数组”,可描述0D(标量)、1D(向量)、2D(矩阵)、3D及以上的高维数据,在深度学习框架(如TensorFlow、PyTorch)中被扩展为支持自动微分、GPU加速的计算单元。

8.2 相同点

相同点说明示例
数据存储结构均为“维度-元素”的层级结构,用shape描述各维度大小,支持同构数据(元素类型一致)NumPy数组shape=(2,3)与PyTorch张量shape=(2,3)均表示2行3列的二维数据
基础维度操作均支持转置、切片、拼接、分裂等维度调整操作,语法高度相似NumPy的np.transpose与PyTorch的torch.transpose功能一致
元素级运算均支持向量化的元素级运算(加法、乘法等),无需循环NumPy的arr1 + arr2与TensorFlow的tf.add(arr1, arr2)均为元素级加法
广播机制低维张量(如NumPy数组)与高维张量均支持广播规则,解决形状不兼容的运算问题NumPy数组(3,1)与PyTorch张量(1,3)可通过广播实现(3,3)的元素级运算
示例:相同操作对比
# NumPy数组操作
np_arr1 = np.array([[1,2],[3,4]])
np_arr2 = np.array([[5,6],[7,8]])
np_transpose = np.transpose(np_arr1)  # 转置
np_add = np_arr1 + np_arr2            # 元素级加法# PyTorch张量操作(与NumPy语法相似)
import torch
torch_tensor1 = torch.tensor([[1,2],[3,4]])
torch_tensor2 = torch.tensor([[5,6],[7,8]])
torch_transpose = torch.transpose(torch_tensor1, 0, 1)  # 转置
torch_add = torch_tensor1 + torch_tensor2                # 元素级加法print("NumPy转置:\n", np_transpose)
print("PyTorch转置:\n", torch_transpose)
# 两者输出一致:
# [[1 3]
#  [2 4]]

8.3 不同点

对比维度NumPy数组(ndarray)张量(以深度学习框架为例)
维度范围主要支持0D-4D,高维(如5D+)操作较少见,效率较低天然支持高维(如5D、6D),适配深度学习场景(如视频数据:batch×time×C×H×W)
计算加速仅支持CPU计算,无内置GPU加速能力(需依赖其他库如CuPy)原生支持GPU加速,可通过cuda()方法将张量转移到GPU,大幅提升高维计算效率
自动微分无自动微分功能,需手动推导梯度(不适用于深度学习训练)核心特性:支持自动微分(如PyTorch的requires_grad=True、TensorFlow的自动梯度带),是反向传播的基础
动态性静态数据结构,创建后维度和数据类型需显式修改部分框架支持动态张量(如PyTorch),可动态调整形状;TensorFlow 2.x支持动态图,更灵活
应用场景适用于科学计算、数据分析、传统机器学习(如数据预处理、特征工程)适用于深度学习(如神经网络训练、图像/视频处理、自然语言处理)
示例:张量特有的GPU加速与自动微分
# 1. GPU加速(PyTorch张量)
torch_tensor = torch.tensor([[1,2],[3,4]]).cuda()  # 转移到GPU
print("GPU张量设备:", torch_tensor.device)  # 输出: cuda:0(表示第1块GPU)# 2. 自动微分(PyTorch张量)
x = torch.tensor([2.0], requires_grad=True)  # 开启梯度追踪
y = x ** 2 + 3*x  # 定义函数y = x² + 3x
y.backward()       # 反向传播求导
print("x的梯度(dy/dx=2x+3):", x.grad)  # 输出: tensor([7.])(2*2+3=7)# NumPy数组无此功能(报错)
try:np_x = np.array([2.0])np_x.requires_grad = True  # NumPy数组无requires_grad属性
except AttributeError as e:print("NumPy错误:", e)  # 输出: 'numpy.ndarray' object has no attribute 'requires_grad'

9. NumPy使用注意事项

在实际使用NumPy时,需注意以下常见问题,避免内存泄漏、运算错误或效率低下:

9.1 视图(View)与副本(Copy)的区别

  • 视图:共享原数组内存,修改视图会同步修改原数组,创建时不占用额外内存(如reshape、切片)。
  • 副本:独立内存空间,修改副本不影响原数组,创建时占用额外内存(如astype、花式索引、np.copy)。

避坑建议:通过arr.base判断是否为视图(视图的base指向原数组,副本的baseNone):

arr = np.array([1,2,3,4])
view = arr[1:3]    # 切片→视图
copy = arr[[1,2]]  # 花式索引→副本view[0] = 999      # 修改视图
print("原数组(视图修改影响):", arr)  # 输出: [  1 999   3   4]copy[0] = 888      # 修改副本
print("原数组(副本修改无影响):", arr)  # 输出: [  1 999   3   4]print("view.base:", view.base is arr)  # 输出: True(视图)
print("copy.base:", copy.base is arr)  # 输出: False(副本)

9.2 数据类型兼容性

  • 整数转浮点数:安全(如int32→float64),但浮点数转整数会丢失小数部分(无四舍五入)。
  • 低精度转高精度:安全(如float16→float64),高精度转低精度可能溢出(如int64→int8,值超过-128~127会出错)。

避坑建议:转换前用np.iinfo(整数)或np.finfo(浮点数)查看类型范围,避免溢出:

# 浮点数转整数(丢失小数)
float_arr = np.array([1.9, 2.1])
int_arr = float_arr.astype(np.int32)
print("浮点数转整数:", int_arr)  # 输出: [1 2](非四舍五入)# 高精度转低精度(溢出)
int64_arr = np.array([200], dtype=np.int64)
int8_arr = int64_arr.astype(np.int8)  # int8范围-128~127
print("int64→int8溢出:", int8_arr)  # 输出: [-56](溢出后错误值)# 查看类型范围
print("int8范围:", np.iinfo(np.int8).min, "~", np.iinfo(np.int8).max)  # 输出: -128 ~ 127

9.3 广播规则的严格性

  • 广播仅适用于“维度补齐后各维度大小相同或其中一个为1”的情况,否则会报错。
  • 避免过度依赖广播,复杂广播逻辑可能降低代码可读性,建议显式用np.expand_dims调整维度。

避坑建议:运算前打印数组shape,验证是否符合广播规则:

arr1 = np.array([[1,2],[3,4]])  # shape: (2,2)
arr2 = np.array([1,2,3])        # shape: (3,)
try:arr1 + arr2  # 补齐后(2,2) vs (1,3),轴1大小2≠3,不兼容
except ValueError as e:print("广播错误:", e)  # 输出: operands could not be broadcast together with shapes (2,2) (3,)# 正确做法:显式调整维度
arr2_expand = np.expand_dims(arr2, axis=0)  # shape: (1,3)
# 仍不兼容,需进一步调整为(2,3)(如重复数据)
arr2_tile = np.tile(arr2_expand, (2,1))  # shape: (2,3)

9.4 浮点数精度问题

  • NumPy浮点数(如float32/float64)存在精度误差,避免直接用==判断浮点数相等。
  • 建议用np.allclose(a, b, rtol=1e-05, atol=1e-08)判断浮点数是否接近(允许微小误差)。

避坑示例

a = np.array([0.1 + 0.2])  # 0.1+0.2=0.30000000000000004(浮点数精度误差)
b = np.array([0.3])print("a == b:", a == b)  # 输出: [False](直接判断错误)
print("np.allclose(a, b):", np.allclose(a, b))  # 输出: True(正确判断)

9.5 维度操作的元素总数守恒

  • reshaperesize等维度调整操作需保证“原数组元素总数 = 新数组元素总数”,否则报错。
  • 高维数组操作前,用arr.size查看元素总数,避免维度不匹配。

避坑示例

arr = np.arange(6)  # size=6,shape=(6,)
try:arr.reshape((2,4))  # 2*4=8≠6,元素总数不守恒
except ValueError as e:print("维度错误:", e)  # 输出: cannot reshape array of size 6 into shape (2,4)# 正确做法:保证元素总数一致
arr_reshape = arr.reshape((2,3))  # 2*3=6,正确

9.6 线性代数运算的形状约束

  • 矩阵点积(np.matmul)要求“前数组列数 = 后数组行数”,否则报错。
  • 求逆矩阵(np.linalg.inv)仅适用于方阵行列式≠0(非奇异矩阵),否则报错。

避坑示例

A = np.array([[1,2],[3,4]])  # shape: (2,2)(方阵)
B = np.array([[1,2,3],[4,5,6]])  # shape: (2,3)# 矩阵点积(A列数2 = B行数2,正确)
dot_correct = np.matmul(A, B)
print("正确点积shape:", dot_correct.shape)  # 输出: (2,3)# 错误:A行数2 ≠ B列数3,形状不兼容
try:dot_wrong = np.matmul(B, A)  # B列数3 ≠ A行数2
except ValueError as e:print("点积错误:", e)  # 输出: matmul: Input operand 1 has a mismatch in its core dimension 0

文章转载自:

http://RfJPl6bD.bzfLd.cn
http://AYIGlUtx.bzfLd.cn
http://Q5HSpTfs.bzfLd.cn
http://MtohBrU7.bzfLd.cn
http://9DUhk98r.bzfLd.cn
http://ojydi60i.bzfLd.cn
http://HkBNoCDN.bzfLd.cn
http://z5rJlWYC.bzfLd.cn
http://aVfKqSgm.bzfLd.cn
http://8cdSb0Dv.bzfLd.cn
http://c2LVLBXh.bzfLd.cn
http://4CbALLUj.bzfLd.cn
http://zmJaCgt7.bzfLd.cn
http://QC8DKu4R.bzfLd.cn
http://jsLCnS5X.bzfLd.cn
http://niaPpctF.bzfLd.cn
http://qJwf1Ew8.bzfLd.cn
http://RywdPAEG.bzfLd.cn
http://khjHLzXi.bzfLd.cn
http://0SJofbIq.bzfLd.cn
http://quGQF3Yb.bzfLd.cn
http://yR5HVPeJ.bzfLd.cn
http://4iY87A77.bzfLd.cn
http://Sk7cFaPb.bzfLd.cn
http://Z43SmZ8x.bzfLd.cn
http://E8MrpWrd.bzfLd.cn
http://iZ2zbhc3.bzfLd.cn
http://iwH2qbJC.bzfLd.cn
http://0MGlTjmh.bzfLd.cn
http://gobWpPUG.bzfLd.cn
http://www.dtcms.com/a/384480.html

相关文章:

  • Java 轻松实现 Markdown 转 Word、PDF、HTML
  • 时序数据库选型指南:Apache IoTDB企业级解决方案深度解析
  • Java 中 ArrayList 扩容机制的深度解析
  • PowerBI与Excel的区别及实时数据报表开发
  • 【无人机】自检arming参数调整选项
  • Apache Paimon 官方文档
  • CentOS7.9绿色安装apache-tomcat-9.0.109
  • 9款热门局域网文档共享系统横向评测 (2025)
  • 终端安全EDR
  • 【层面一】C#语言基础和核心语法-03(泛型/集合/LINQ)
  • 【连载4】 C# MVC 环境差异化配置:异常处理策略
  • 计算机视觉进阶教学之背景建模与光流估计
  • 铝锆中间合金市场报告:深度解析与未来趋势展望
  • 数据库事务:ACID
  • 动态电源路径管理(DPPM)、NVDC动态路径管理
  • 深入理解链表:从基础概念到经典算法
  • 手写MyBatis第60弹: 如何优雅处理各种参数类型,从ParamNameResolver到TypeHandler
  • 【Postman】Postman 自动化测试指南:Token 获取与变量管理实战
  • Java 大视界 -- 基于 Java 的大数据可视化在城市交通拥堵治理与出行效率提升中的应用
  • arcgis中实现四色/五色法制图
  • OpenVLA: An Open-Source Vision-Language-Action Model
  • nvm安装node后出现报错: “npm 不是内部或外部命令,也不是可运行的程序 或批处理文件”
  • iPhone 17 系列与 iPhone Air 对比:硬件
  • Serverless Redis实战:阿里云Tair与AWS MemoryDB深度对比
  • 欢迎来到std::shared_ptr的派对!
  • 计算机操作系统学习(四、文件管理)
  • Open3D-Geometry-15:UV Maps 将2D图像投影到3D模型表面
  • 从pip到UV:新一代包管理器的高效替代方案
  • 基于Matlab的雾霾天气和夜间车牌识别系统
  • 【Unity】高性能的事件分发系统