目录
NumPy模块介绍
NumPy 是 Python 科学计算领域的重要基石,与当前 “躺吃旅行” 话题看似不相关,但在数据处理分析上意义重大。我将从它的核心功能、应用场景和优势等方面展开介绍。
NumPy(Numerical Python)是 Python 语言中用于科学计算的基础库,它提供了高性能的多维数组对象以及大量用于对数组进行操作的函数,是数据科学、机器学习、人工智能等领域不可或缺的工具。NumPy 的核心数据结构是ndarray(多维数组),这种数组允许在内存中以连续的方式存储同类型的数据,相较于 Python 原生列表,它在存储和运算效率上有着显著提升。通过 NumPy,用户可以轻松实现数组的创建、索引、切片、变形,以及各种数学运算,如矩阵乘法、统计计算、傅里叶变换等。
在实际应用中,NumPy 广泛应用于数据分析、机器学习算法的底层实现、图像和信号处理等领域。例如,在机器学习中,数据集通常会被加载并转换为 NumPy 数组进行预处理和模型训练;在图像处理中,图像数据也会被表示为多维数组,借助 NumPy 提供的函数完成图像的滤波、变换等操作。此外,NumPy 还与众多科学计算库紧密集成,如 SciPy、Pandas 等,共同构建起强大的 Python 科学计算生态,极大地提升了数据处理和分析的效率。
本期课程,我将从概念、逻辑、实操、应用4各层面阐释我对这个模块的理解,希望为喜欢Python的学习者提供一个内容详实、逻辑清晰、容易上手的课程。
3.5.1 NumPy 操纵数组元素的逻辑
NumPy 是 Python 中用于科学计算的基础库,其核心是多维数组对象(ndarray)。NumPy 数组操作高效的背后逻辑主要有以下几点:
1. 同质数据类型:NumPy 数组中的元素必须是相同的数据类型(如整数、浮点数等),这使得 NumPy 可以更高效地存储和操作数据。
2. 连续内存块:NumPy 数组在内存中是连续存储的,这使得访问和操作元素的速度远快于 Python 列表。
3. 向量化操作:NumPy 使用向量化操作替代显式循环,大大提高了计算效率。向量化操作是指对整个数组或数组的一部分同时进行操作。
4. 底层实现:NumPy 的核心功能是用 C 语言实现的,避免了 Python 解释器的开销。
3.5.2 添加数组元素操作
1. append() 函数
功能:在数组的末尾添加值,返回一个新数组。
主要参数:
- arr:需要添加元素的数组
- values:需要添加的值,可以是单个值、列表或数组
- axis:指定沿着哪个轴添加元素,默认值为 None,表示先将数组展平
应用举例:
import numpy as np
# 创建一个一维数组
arr = np.array([1, 2, 3])
print("原数组:", arr)
# 在数组末尾添加一个元素
new_arr = np.append(arr, 4)
print("添加元素后的数组:", new_arr)
# 在数组末尾添加多个元素
new_arr = np.append(arr, [4, 5, 6])
print("添加多个元素后的数组:", new_arr)
# 创建一个二维数组
arr_2d = np.array([[1, 2], [3, 4]])
print("\n原二维数组:\n", arr_2d)
# 沿轴 0 添加元素(添加行)
new_arr_2d = np.append(arr_2d, [[5, 6]], axis=0)
print("沿轴 0 添加元素后的数组:\n", new_arr_2d)
# 沿轴 1 添加元素(添加列)
new_arr_2d = np.append(arr_2d, [[5], [6]], axis=1)
print("沿轴 1 添加元素后的数组:\n", new_arr_2d)
2. insert() 函数
功能:在数组的指定位置插入值,返回一个新数组。
主要参数:
- arr:需要插入元素的数组
- obj:插入点的索引位置
- values:需要插入的值
- axis:指定沿着哪个轴插入元素,默认值为 None,表示先将数组展平
应用举例:
import numpy as np
# 创建一个一维数组
arr = np.array([1, 2, 3, 4])
print("原数组:", arr)
# 在索引 2 处插入元素 5
new_arr = np.insert(arr, 2, 5)
print("插入元素后的数组:", new_arr)
# 在索引 2 处插入多个元素
new_arr = np.insert(arr, 2, [5, 6, 7])
print("插入多个元素后的数组:", new_arr)
# 创建一个二维数组
arr_2d = np.array([[1, 2], [3, 4]])
print("\n原二维数组:\n", arr_2d)
# 沿轴 0 在索引 1 处插入一行
new_arr_2d = np.insert(arr_2d, 1, [5, 6], axis=0)
print("沿轴 0 插入元素后的数组:\n", new_arr_2d)
# 沿轴 1 在索引 1 处插入一列
new_arr_2d = np.insert(arr_2d, 1, [5, 6], axis=1)
print("沿轴 1 插入元素后的数组:\n", new_arr_2d)
3.5.3 删除数组元素的操作
delete() 函数
功能:删除数组中指定位置的元素,返回一个新数组。
主要参数:
- arr:需要删除元素的数组
- obj:要删除的元素的索引位置或索引数组
- axis:指定沿着哪个轴删除元素,默认值为 None,表示先将数组展平
应用举例:
import numpy as np
# 创建一个一维数组
arr = np.array([1, 2, 3, 4, 5])
print("原数组:", arr)
# 删除索引 2 处的元素
new_arr = np.delete(arr, 2)
print("删除元素后的数组:", new_arr)
# 删除多个索引处的元素
new_arr = np.delete(arr, [0, 2, 4])
print("删除多个元素后的数组:", new_arr)
# 创建一个二维数组
arr_2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("\n原二维数组:\n", arr_2d)
# 沿轴 0 删除索引 1 处的行
new_arr_2d = np.delete(arr_2d, 1, axis=0)
print("沿轴 0 删除元素后的数组:\n", new_arr_2d)
# 沿轴 1 删除索引 1 处的列
new_arr_2d = np.delete(arr_2d, 1, axis=1)
print("沿轴 1 删除元素后的数组:\n", new_arr_2d)
3.5.4 数组元素缺失情况的处理
isnan() 函数
功能:检测数组中的元素是否为 NaN(Not a Number),返回一个布尔数组。
应用举例:
import numpy as np
# 创建一个包含 NaN 的数组
arr = np.array([1, np.nan, 3, np.nan, 5])
print("原数组:", arr)
# 检测数组中的 NaN
nan_mask = np.isnan(arr)
print("NaN 掩码:", nan_mask)
# 使用掩码替换 NaN 为 0
arr[nan_mask] = 0
print("替换后的数组:", arr)
# 在二维数组中使用
arr_2d = np.array([[1, np.nan, 3], [4, 5, np.nan], [7, 8, 9]])
print("\n原二维数组:\n", arr_2d)
# 检测二维数组中的 NaN
nan_mask_2d = np.isnan(arr_2d)
print("二维数组的 NaN 掩码:\n", nan_mask_2d)
# 替换二维数组中的 NaN 为 0
arr_2d[nan_mask_2d] = 0
print("替换后的二维数组:\n", arr_2d)
3.5.5 处理数组中元素重复情况
unique() 函数
功能:找出数组中的唯一元素,并返回排序后的结果。
应用举例:
import numpy as np
# 创建一个包含重复元素的一维数组
arr = np.array([1, 2, 2, 3, 3, 3, 4, 4, 4, 4])
print("原数组:", arr)
# 找出唯一元素
unique_arr = np.unique(arr)
print("唯一元素:", unique_arr)
# 返回唯一元素及其出现次数
unique_arr, counts = np.unique(arr, return_counts=True)
print("唯一元素:", unique_arr)
print("出现次数:", counts)
# 在二维数组中使用
arr_2d = np.array([[1, 2, 3], [4, 5, 6], [1, 2, 3]])
print("\n原二维数组:\n", arr_2d)
# 找出二维数组的唯一元素
unique_elements = np.unique(arr_2d)
print("二维数组的唯一元素:", unique_elements)
# 按行找出唯一的行
unique_rows = np.unique(arr_2d, axis=0)
print("二维数组的唯一行:\n", unique_rows)
3.5.6 拼接数组操作
1. concatenate() 函数
功能:沿指定轴连接多个数组,返回一个新数组。
主要参数:
- arrays:需要连接的数组序列,可以是列表或元组
- axis:指定沿着哪个轴连接数组,默认值为 0
应用举例:
import numpy as np
# 创建两个一维数组
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
print("原一维数组 1:", arr1)
print("原一维数组 2:", arr2)
# 连接两个一维数组
concatenated_arr = np.concatenate((arr1, arr2))
print("连接后的一维数组:", concatenated_arr)
# 创建两个二维数组
arr1_2d = np.array([[1, 2], [3, 4]])
arr2_2d = np.array([[5, 6], [7, 8]])
print("\n原二维数组 1:\n", arr1_2d)
print("原二维数组 2:\n", arr2_2d)
# 沿轴 0 连接二维数组(垂直堆叠)
concatenated_arr_2d_axis0 = np.concatenate((arr1_2d, arr2_2d), axis=0)
print("沿轴 0 连接后的二维数组:\n", concatenated_arr_2d_axis0)
# 沿轴 1 连接二维数组(水平堆叠)
concatenated_arr_2d_axis1 = np.concatenate((arr1_2d, arr2_2d), axis=1)
print("沿轴 1 连接后的二维数组:\n", concatenated_arr_2d_axis1)
2. hstack() 函数和 vstack() 函数
功能:
- hstack():水平堆叠数组(沿轴 1)
- vstack():垂直堆叠数组(沿轴 0)
应用举例:
import numpy as np
# 创建两个一维数组
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
print("原一维数组 1:", arr1)
print("原一维数组 2:", arr2)
# 水平堆叠一维数组
hstacked_arr = np.hstack((arr1, arr2))
print("水平堆叠后的一维数组:", hstacked_arr)
# 垂直堆叠一维数组(需要将一维数组转换为二维数组)
vstacked_arr = np.vstack((arr1, arr2))
print("垂直堆叠后的二维数组:\n", vstacked_arr)
# 创建两个二维数组
arr1_2d = np.array([[1, 2], [3, 4]])
arr2_2d = np.array([[5, 6], [7, 8]])
print("\n原二维数组 1:\n", arr1_2d)
print("原二维数组 2:\n", arr2_2d)
# 水平堆叠二维数组
hstacked_arr_2d = np.hstack((arr1_2d, arr2_2d))
print("水平堆叠后的二维数组:\n", hstacked_arr_2d)
# 垂直堆叠二维数组
vstacked_arr_2d = np.vstack((arr1_2d, arr2_2d))
print("垂直堆叠后的二维数组:\n", vstacked_arr_2d)
3.5.7 拆分数组操作
1. split() 函数
功能:将数组沿指定轴拆分为多个子数组。
主要参数:
- ary:需要拆分的数组
- indices_or_sections:指定拆分位置的整数或数组
- axis:指定沿着哪个轴拆分,默认值为 0
应用举例:
import numpy as np
# 创建一个一维数组
arr = np.array([1, 2, 3, 4, 5, 6])
print("原一维数组:", arr)
# 将一维数组平均拆分为 3 个子数组
sub_arrays = np.split(arr, 3)
print("拆分后的子数组:", sub_arrays)
# 指定拆分位置
sub_arrays = np.split(arr, [2, 4])
print("按指定位置拆分后的子数组:", sub_arrays)
# 创建一个二维数组
arr_2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
print("\n原二维数组:\n", arr_2d)
# 沿轴 0 平均拆分为 2 个子数组
sub_arrays_axis0 = np.split(arr_2d, 2, axis=0)
print("沿轴 0 拆分后的子数组:")
for sub_arr in sub_arrays_axis0:
print(sub_arr)
# 沿轴 1 拆分为 3 个子数组
sub_arrays_axis1 = np.split(arr_2d, 3, axis=1)
print("沿轴 1 拆分后的子数组:")
for sub_arr in sub_arrays_axis1:
print(sub_arr)
2. hsplit() 函数和 vsplit() 函数
功能:
- hsplit():水平拆分数组(沿轴 1)
- vsplit():垂直拆分数组(沿轴 0)
应用举例:
import numpy as np
# 创建一个二维数组
arr_2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
print("原二维数组:\n", arr_2d)
# 水平拆分为 2 个子数组
h_split_arrays = np.hsplit(arr_2d, 2)
print("水平拆分后的子数组:")
for sub_arr in h_split_arrays:
print(sub_arr)
# 垂直拆分为 3 个子数组
v_split_arrays = np.vsplit(arr_2d, 3)
print("垂直拆分后的子数组:")
for sub_arr in v_split_arrays:
print(sub_arr)
3.5.8 知识点总结与课程回顾
重点内容
- NumPy 数组操作高效的原因:同质数据类型、连续内存块、向量化操作和底层 C 语言实现。
- 数组元素的添加:append() 和 insert() 函数的使用。
- 数组元素的删除:delete() 函数的使用。
- 处理缺失值:isnan() 函数的使用。
- 处理重复值:unique() 函数的使用。
- 数组的拼接:concatenate()、hstack() 和 vstack() 函数的使用。
- 数组的拆分:split()、hsplit() 和 vsplit() 函数的使用。
难点内容
- 理解 NumPy 数组在内存中的存储方式和操作逻辑。
- 正确使用 axis 参数进行多维数组的操作。
- 处理复杂的数组拼接和拆分场景。
趣味案例
- 图像处理中的应用:在图像处理中,常常需要对图像数据(本质上是多维数组)进行裁剪、拼接等操作。例如,将多张图片拼接成一个大的拼贴画,或者从一张图片中裁剪出感兴趣的区域。
- 数据分析中的应用:在数据分析中,经常需要处理包含缺失值的数据。可以使用 NumPy 的 isnan() 函数检测缺失值,并进行相应的处理,如删除包含缺失值的记录或用平均值填充缺失值。
- 机器学习中的应用:在机器学习中,通常需要将数据集分为训练集和测试集。可以使用 NumPy 的数组拆分功能来实现这一目的。另外,在特征工程中,也经常需要对特征矩阵进行拼接、删除等操作。
3.5.9 课后练习题
练习题 1:创建一个形状为 (5, 5) 的二维数组,其主对角线上的元素为 1、2、3、4、5,其余元素为 0。然后在数组的右侧添加一列,该列元素全为 6。
练习题 2:创建一个包含 20 个随机整数的一维数组,范围在 1 到 100 之间。删除数组中所有小于 50 的元素,并将结果数组排序。
练习题 3:创建两个形状为 (3, 3) 的二维数组,一个数组的元素全为 1,另一个数组的元素全为 2。将这两个数组按水平方向拼接,然后将结果数组拆分为 3 个形状相同的子数组。
通过这些练习题,你可以进一步巩固对 NumPy 数组元素操作的理解和掌握。听我课的同学们不要手懒,我每节课都会准备一些趣味案例和课后练习题,大家看完这些内容,可以上手操作一下。可以将自己实操的结果放到评论中,不懂的地方也可以跟我交流,欢迎交流,老师有问必答。