运用数组和矩阵对数据进行存取和运算——NumPy模块 之六
目录
NumPy模块介绍
3.6.1 数组之间的运算
3.6.2 算术运算
3.6.3 比较运算
3.6.4 逻辑运算
3.6.5 矩阵运算
3.6.6 广播运算
3.6.7 聚合运算
3.6.8 三角函数与指数对数运算
3.6.9 位运算
3.6.10 条件运算
3.6.11 数组的统计运算
3.6.12 关键问题:数组之间的运算对数组的维度有要求吗?
3.6.13 总结
NumPy模块介绍
NumPy 是 Python 科学计算领域的重要基石,与当前 “躺吃旅行” 话题看似不相关,但在数据处理分析上意义重大。我将从它的核心功能、应用场景和优势等方面展开介绍。
NumPy(Numerical Python)是 Python 语言中用于科学计算的基础库,它提供了高性能的多维数组对象以及大量用于对数组进行操作的函数,是数据科学、机器学习、人工智能等领域不可或缺的工具。NumPy 的核心数据结构是ndarray(多维数组),这种数组允许在内存中以连续的方式存储同类型的数据,相较于 Python 原生列表,它在存储和运算效率上有着显著提升。通过 NumPy,用户可以轻松实现数组的创建、索引、切片、变形,以及各种数学运算,如矩阵乘法、统计计算、傅里叶变换等。
在实际应用中,NumPy 广泛应用于数据分析、机器学习算法的底层实现、图像和信号处理等领域。例如,在机器学习中,数据集通常会被加载并转换为 NumPy 数组进行预处理和模型训练;在图像处理中,图像数据也会被表示为多维数组,借助 NumPy 提供的函数完成图像的滤波、变换等操作。此外,NumPy 还与众多科学计算库紧密集成,如 SciPy、Pandas 等,共同构建起强大的 Python 科学计算生态,极大地提升了数据处理和分析的效率。
3.6.1 数组之间的运算
在 NumPy 中,数组之间的运算可以分为以下几种类型,每种类型都有其独特的应用场景和计算规则:
3.6.2 算术运算
对数组元素执行逐元素的数学运算,包括:
- 基本运算符:+、-、*、/、//(整除)、%(取余)、**(幂运算)
- 对应函数:add()、subtract()、multiply()、divide()、floor_divide()、mod()、power()
示例:
import numpy as npa = np.array([1, 2, 3])
b = np.array([4, 5, 6])print(a + b) # 输出: [5 7 9]
print(a * b) # 输出: [4 10 18]
print(np.power(a, 2)) # 输出: [1 4 9]
3.6.3 比较运算
对数组元素执行逐元素的比较,返回布尔数组,包括:
- 比较运算符:>、<、>=、<=、==、!=
- 对应函数:greater()、less()、greater_equal()、less_equal()、equal()、not_equal()
示例:
a = np.array([1, 2, 3])
b = np.array([2, 2, 2])print(a > b) # 输出: [False False True]
print(a == b) # 输出: [False True False]
数组之间的比较运算在实际运用中还是比较广泛的,为了加深同学们对这一块知识的理解,我编写了两个案例,供大家学习掌握,并能在实际编程中灵活运用。
示例 1:检测学生成绩是否达标
假设有两个班级的数学考试成绩,需要比较哪些学生的成绩达到了 80 分的优秀标准。
import numpy as np# 创建两个班级的成绩数组
class_a = np.array([78, 85, 92, 65, 88])
class_b = np.array([82, 76, 90, 85, 89])# 比较成绩是否达到80分
excellent_a = class_a >= 80
excellent_b = class_b >= 80print("班级A优秀学生:", excellent_a) # [False True True False True]
print("班级B优秀学生:", excellent_b) # [ True False True True True]# 统计优秀学生人数
print("班级A优秀人数:", np.sum(excellent_a)) # 3
print("班级B优秀人数:", np.sum(excellent_b)) # 4
示例 2:筛选符合条件的二维数据
假设有一个二维数组表示商品的价格和销量,需要筛选出价格高于 50 且销量大于 100 的商品。
import numpy as np# 创建商品数据:每行表示 [价格, 销量]
products = np.array([[60, 120],[45, 80],[70, 150],[55, 90],[80, 200]
])# 比较价格和销量
price_high = products[:, 0] > 50 # 价格列
sales_high = products[:, 1] > 100 # 销量列# 同时满足两个条件
both_high = price_high & sales_highprint("价格>50的商品:", price_high) # [ True False True True True]
print("销量>100的商品:", sales_high) # [ True False True False True]
print("符合条件的商品:", both_high) # [ True False True False True]# 筛选符合条件的商品数据
selected_products = products[both_high]
print("筛选结果:\n", selected_products)
# 输出:
# [[ 60 120]
# [ 70 150]
# [ 80 200]]
关键要点
- 比较运算返回布尔数组:可直接用于统计或筛选。
- 多维数组按元素比较:通过索引选择特定维度(如products[:, 0])。
- 逻辑组合条件:使用&(与)、|(或)、~(非)连接多个比较结果。
3.6.4 逻辑运算
对布尔数组执行逐元素的逻辑操作,包括:
- 逻辑运算符:&(与)、|(或)、~(非)、^(异或)
- 对应函数:logical_and()、logical_or()、logical_not()、logical_xor()
示例:
x = np.array([True, False, True])
y = np.array([False, True, True])print(x & y) # 输出: [False False True]
print(np.logical_or(x, y)) # 输出: [ True True True]
这里编辑两个典型案例,供大家加深理解。
案例 1:筛选符合多条件的数据集(逻辑与 &)
场景:某电商平台需要筛选同时满足 “价格低于 50 元” 且 “销量高于 1000” 的商品。
import numpy as np# 创建商品数据:每行表示 [价格, 销量]
products = np.array([[45, 1200], # 符合条件[60, 800], # 不符合条件[30, 1500], # 符合条件[55, 900], # 不符合条件[20, 2000] # 符合条件
])# 条件1:价格低于50
price_mask = products[:, 0] < 50 # [ True False True False True]# 条件2:销量高于1000
sales_mask = products[:, 1] > 1000 # [ True False True False True]# 逻辑与:同时满足两个条件
valid_mask = price_mask & sales_mask # [ True False True False True]# 筛选符合条件的商品
valid_products = products[valid_mask]print("筛选条件:价格 <50 且 销量 >1000")
print("符合条件的商品:\n", valid_products)
# 输出:
# [[ 45 1200]
# [ 30 1500]
# [ 20 2000]]
案例 2:排除异常数据(逻辑非 ~)
场景:某传感器采集的数据中,需要排除所有 “温度低于 0℃” 或 “湿度高于 100%” 的异常值。
import numpy as np# 创建传感器数据:每行表示 [温度, 湿度]
sensor_data = np.array([[25, 60], # 正常[-5, 80], # 温度异常[30, 105], # 湿度异常[18, 90], # 正常[40, 110] # 湿度异常
])# 条件1:温度低于0
temp_anomaly = sensor_data[:, 0] < 0 # [False True False False False]# 条件2:湿度高于100
humid_anomaly = sensor_data[:, 1] > 100 # [False False True False True]# 逻辑或:温度异常 或 湿度异常
anomaly_mask = temp_anomaly | humid_anomaly # [False True True False True]# 逻辑非:排除异常数据
valid_mask = ~anomaly_mask # [ True False False True False]# 筛选正常数据
valid_data = sensor_data[valid_mask]print("筛选条件:排除 温度<0 或 湿度>100 的数据")
print("正常数据:\n", valid_data)
# 输出:
# [[25 60]
# [18 90]]
关键要点总结
1. 逻辑运算符:
- &(与):同时满足多个条件
- |(或):满足任意一个条件
- ~(非):取反操作
- ^(异或):条件互斥时使用
2. 应用场景:
- 数据筛选:通过布尔掩码过滤多维数组
- 异常处理:排除不符合条件的无效数据
- 条件组合:构建复杂的逻辑判断表达式
3. 性能优势:
逻辑运算采用向量化实现,避免显式循环,处理大规模数据时效率极高。
3.6.5 矩阵运算
针对二维数组(矩阵)的线性代数运算,包括:
- 矩阵乘法:@ 运算符或 dot() 函数
- 矩阵转置:array.T 或 transpose() 函数
- 矩阵求逆:np.linalg.inv()
- 行列式计算:np.linalg.det()
- 特征值与特征向量:np.linalg.eig()
示例:
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])print(A @ B) # 矩阵乘法,输出: [[19 22], [43 50]]
print(A.T) # 矩阵转置,输出: [[1 3], [2 4]]
3.6.6 广播运算
当数组形状不同时,NumPy 会自动 “广播” 较小的数组,使其形状与较大数组兼容,从而执行运算。
规则:
- 从右向左比较数组维度,若维度相等或其中一个为 1,则可广播。
- 广播会在缺失维度或维度为 1 的方向上复制元素。
示例:
a = np.array([1, 2, 3]) # 形状: (3,)
b = 2 # 标量,形状: () → 广播为 [2, 2, 2]print(a * b) # 输出: [2 4 6]c = np.array([[1, 2, 3], [4, 5, 6]]) # 形状: (2, 3)
d = np.array([10, 20, 30]) # 形状: (3,) → 广播为 [[10, 20, 30], [10, 20, 30]]print(c + d) # 输出: [[11 22 33], [14 25 36]]
3.6.7 聚合运算
对数组元素进行统计计算,返回标量或降维数组,包括:
- 全局聚合:sum()、mean()、std()、var()、min()、max()、argmin()、argmax()
- 轴向聚合:通过指定 axis 参数对特定轴进行计算
示例:
arr = np.array([[1, 2, 3], [4, 5, 6]])print(arr.sum()) # 全局求和,输出: 21
print(arr.mean(axis=0)) # 按列求均值,输出: [2.5 3.5 4.5]
print(arr.max(axis=1)) # 按行求最大值,输出: [3 6]
3.6.8 三角函数与指数对数运算
对数组元素执行逐元素的数学函数计算,包括:
- 三角函数:sin()、cos()、tan()、arcsin() 等
- 指数对数:exp()、log()、log10()、log2() 等
- 其他函数:sqrt()、abs()、ceil()、floor() 等
示例:
x = np.array([0, np.pi/2, np.pi])print(np.sin(x)) # 输出: [0. 1. 0.]
print(np.exp(x)) # 输出: [1.00000000e+00, 4.81047738e+00, 2.31406926e+01]
3.6.9 位运算
对整数数组的元素执行逐元素的位操作,包括:
- 位运算符:&(按位与)、|(按位或)、~(按位取反)、^(按位异或)、<<(左移)、>>(右移)
- 对应函数:bitwise_and()、bitwise_or() 等
示例:
a = np.array([5, 6, 7]) # 二进制: [101, 110, 111]
b = np.array([3, 3, 3]) # 二进制: [011, 011, 011]print(a & b) # 按位与,输出: [1 2 3]
print(a << 2) # 左移2位,输出: [20 24 28]
3.6.10 条件运算
使用 np.where() 根据条件对数组元素进行选择性操作。
示例:
arr = np.array([-1, 2, -3, 4, -5])# 将负数替换为0,正数保持不变
result = np.where(arr < 0, 0, arr)
print(result) # 输出: [0 2 0 4 0]
3.6.11 数组的统计运算
在 NumPy 中,统计运算是对数组元素进行汇总和分析的重要功能。以下是常见的统计运算及其案例说明:
一、求和运算(sum())
计算数组中所有元素的总和,可通过axis参数指定维度方向。
案例 1:一维数组求和
import numpy as nparr = np.array([1, 2, 3, 4, 5])
total = arr.sum()
print("总和:", total) # 输出: 15
案例 2:二维数组按行 / 列求和
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])# 按列求和(每列元素相加)
col_sum = arr_2d.sum(axis=0)
print("列和:", col_sum) # 输出: [5 7 9]# 按行求和(每行元素相加)
row_sum = arr_2d.sum(axis=1)
print("行和:", row_sum) # 输出: [6 15]
二、求平均值运算(mean())
计算数组元素的平均值,同样支持axis参数。
案例 1:一维数组求均值
arr = np.array([10, 20, 30, 40])
avg = arr.mean()
print("平均值:", avg) # 输出: 25.0
案例 2:二维数组按维度求均值
arr_2d = np.array([[1, 2], [3, 4], [5, 6]])# 按列求均值(每列元素的均值)
col_mean = arr_2d.mean(axis=0)
print("列均值:", col_mean) # 输出: [3. 4.]# 按行求均值(每行元素的均值)
row_mean = arr_2d.mean(axis=1)
print("行均值:", row_mean) # 输出: [1.5 3.5 5.5]
三、求最值运算
包括求最大值(max())、最小值(min())、最大值索引(argmax())和最小值索引(argmin())。
案例 1:一维数组求最值
arr = np.array([5, 3, 9, 1, 7])max_val = arr.max() # 最大值
min_val = arr.min() # 最小值
max_idx = arr.argmax() # 最大值的索引
min_idx = arr.argmin() # 最小值的索引print(f"最大值: {max_val} (索引: {max_idx})") # 输出: 9 (索引: 2)
print(f"最小值: {min_val} (索引: {min_idx})") # 输出: 1 (索引: 3)
案例 2:二维数组按维度求最值
arr_2d = np.array([[5, 2, 8], [1, 9, 3], [4, 7, 6]])# 按列求最大值(每列的最大值)
col_max = arr_2d.max(axis=0)
print("列最大值:", col_max) # 输出: [5 9 8]# 按行求最小值(每行的最小值)
row_min = arr_2d.min(axis=1)
print("行最小值:", row_min) # 输出: [2 1 4]# 全局最大值的索引(展平后)
global_max_idx = arr_2d.argmax()
print("全局最大值索引:", global_max_idx) # 输出: 4(对应元素9)
四、实战案例:分析学生成绩
假设有一个班级的考试成绩数据,包含 3 名学生的 4 门课程分数,需要分析:
# 创建成绩数组(行:学生,列:课程)
scores = np.array([[85, 92, 78, 90], # 学生1[76, 88, 95, 80], # 学生2[92, 79, 83, 87] # 学生3
])# 1. 计算每个学生的总分和平均分
student_total = scores.sum(axis=1)
student_avg = scores.mean(axis=1)
print("学生总分:", student_total) # 输出: [345 339 341]
print("学生平均分:", student_avg) # 输出: [86.25 84.75 85.25]# 2. 计算每门课程的最高分和最低分
course_max = scores.max(axis=0)
course_min = scores.min(axis=0)
print("课程最高分:", course_max) # 输出: [92 92 95 90]
print("课程最低分:", course_min) # 输出: [76 79 78 80]# 3. 找出班级最高分及其位置
global_max = scores.max()
global_max_pos = np.unravel_index(scores.argmax(), scores.shape)
print(f"班级最高分: {global_max}(学生{global_max_pos[0]+1}的课程{global_max_pos[1]+1})")
# 输出: 班级最高分: 95(学生2的课程3)
关键要点总结
1. 参数axis的作用:
- axis=0:按列方向(垂直)计算
- axis=1:按行方向(水平)计算
- 省略axis:对整个数组计算
2. 常用函数对比:
函数 | 功能 | 返回值类型 |
---|---|---|
sum() | 求和 | 数值或数组 |
mean() | 求均值 | 数值或数组 |
max() | 最大值 | 数值或数组 |
min() | 最小值 | 数值或数组 |
argmax() | 最大值的索引 | 整数或整数数组 |
argmin() | 最小值的索引 | 整数或整数数组 |
3. 多维数组索引转换:
- 使用np.unravel_index()将全局索引转换为多维索引。
这些统计运算可以高效处理大规模数据,是数据分析和科学计算的基础工具。
3.6.12 关键问题:数组之间的运算对数组的维度有要求吗?
在 NumPy 中,数组之间的运算对维度有特定要求,具体规则取决于运算类型。以下是不同运算类型的维度要求总结:
一、逐元素运算(算术、比较、逻辑)
要求:数组维度必须完全相同,或满足广播规则。
1. 维度相同
若两个数组形状相同,则运算按元素对应执行。
a = np.array([1, 2, 3]) # 形状: (3,)
b = np.array([4, 5, 6]) # 形状: (3,)
print(a + b) # 输出: [5 7 9]
2. 广播规则
若维度不同,NumPy 会尝试通过 “广播” 使形状兼容:
- 规则 1:从右向左比较维度,若维度相等或其中一个为 1,则可广播。
- 规则 2:广播会在缺失维度或维度为 1 的方向上复制元素。
示例:
a = np.array([[1, 2, 3], [4, 5, 6]]) # 形状: (2, 3)
b = np.array([10, 20, 30]) # 形状: (3,) → 广播为 [[10, 20, 30], [10, 20, 30]]
print(a + b) # 输出: [[11 22 33], [14 25 36]]
二、矩阵运算(点积、转置等)
要求:维度必须满足线性代数规则。
1. 矩阵乘法(@ 或 dot())
- 若 A 是形状为 (m, n) 的矩阵,B 是形状为 (p, q) 的矩阵,则必须满足 n == p。
- 结果矩阵的形状为 (m, q)。
示例:
A = np.array([[1, 2], [3, 4]]) # 形状: (2, 2)
B = np.array([[5, 6], [7, 8]]) # 形状: (2, 2)
print(A @ B) # 输出: [[19 22], [43 50]],形状: (2, 2)C = np.array([[1], [2], [3]]) # 形状: (3, 1)
D = np.array([[4, 5, 6]]) # 形状: (1, 3)
print(C @ D) # 输出: 3x3矩阵,形状: (3, 3)
三、聚合运算(sum、mean 等)
要求:通过 axis 参数指定要聚合的维度,结果维度会减少。
示例:
arr = np.array([[1, 2, 3], [4, 5, 6]]) # 形状: (2, 3)# 按列求和(聚合第0维)
print(arr.sum(axis=0)) # 输出: [5 7 9],形状: (3,)# 按行求和(聚合第1维)
print(arr.sum(axis=1)) # 输出: [6 15],形状: (2,)
四、拼接与拆分运算
1. 拼接(concatenate、hstack、vstack)
- 除拼接轴外,其他维度必须相同。
- 示例:沿轴 0 拼接两个形状为 (2, 3) 的数组,结果形状为 (4, 3)。
2. 拆分(split、hsplit、vsplit)
- 拆分方向的维度必须能被拆分数整除。
- 示例:形状为 (6,) 的数组可均分为 3 份,每份形状为 (2,)。
五、特殊运算(如 np.where())
要求:输入数组的维度必须完全相同或可通过广播兼容。
示例:
a = np.array([1, -2, 3, -4])
b = np.array([10, 20, 30, 40])
condition = a > 0 # [ True False True False]
print(np.where(condition, a, b)) # 输出: [1 20 3 40]
单元总结
运算类型 | 维度要求 |
---|---|
逐元素运算 | 维度相同或满足广播规则 |
矩阵运算 | 满足线性代数规则(如 A(m,n) @ B(n,p) → C(m,p) ) |
聚合运算 | 通过 axis 指定要减少的维度 |
拼接运算 | 除拼接轴外,其他维度必须相同 |
拆分运算 | 拆分方向的维度必须能被拆分数整除 |
条件运算 | 输入数组维度相同或可广播 |
核心原则:NumPy 通过广播和向量化机制尽量使运算兼容,但需遵循上述规则以避免维度不匹配错误。
3.6.13 总结
NumPy 数组运算的核心优势在于向量化操作,避免了显式循环,从而大幅提升计算效率。理解这些运算类型及其规则(如广播机制)是高效使用 NumPy 的关键。