--- tid: 32a861 title: 2d List Vs Numpy Array --- # 二维数据结构:列表与数组对比学习 (date: 2025-11-13) ## 1. Python 二维列表 ### 什么是二维列表? 二维列表是列表的列表,用于存储表格状数据。 ### 创建二维列表 ```python # 直接创建 matrix_2d = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # 动态创建 3x3 矩阵 rows, cols = 3, 3 matrix = [[0 for _ in range(cols)] for _ in range(rows)] print(matrix) # [[0, 0, 0], [0, 0, 0], [0, 0, 0]] ``` ### 基本操作 ```python # 访问元素 print(matrix_2d[0][1]) # 2 (第1行第2列) print(matrix_2d[1][0]) # 4 (第2行第1列) # 修改元素 matrix_2d[0][1] = 10 # 修改单个元素 matrix_2d[1] = [40, 50, 60] # 修改整行 # 遍历 for row in matrix_2d: for element in row: print(element, end=' ') print() ``` ### 列表运算的限制 ```python # 尝试向量运算会出错 a = [[1, 2], [3, 4]] b = [[5, 6], [7, 8]] # 以下操作都不支持! # result = a + 10 # 错误! # result = a * 2 # 错误! # result = a + b # 这不是矩阵加法! # 必须手动实现 result = [] for i in range(len(a)): row = [] for j in range(len(a[i])): row.append(a[i][j] + b[i][j]) result.append(row) print(result) # [[6, 8], [10, 12]] ``` ## 2 NumPy 二维数组 ### 为什么需要 NumPy? 解决二维列表在数值计算中的局限性。 ### 创建二维数组 ```python import numpy as np # 从列表转换 lst = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] arr = np.array(lst) print(arr) # 输出: # [[1 2 3] # [4 5 6] # [7 8 9]] # 专用创建方法 zeros_arr = np.zeros((3, 3)) # 全零数组 ones_arr = np.ones((2, 4)) # 全一数组 range_arr = np.arange(9).reshape(3, 3) # 范围数组 ``` ### 基本操作对比 ```python # 访问元素对比 print("列表访问:", lst[0][1]) # 需要两个括号 print("数组访问:", arr[0, 1]) # 一个括号,逗号分隔 # 修改元素对比 lst[0][1] = 10 # 列表修改 arr[0, 1] = 10 # 数组修改 # 切片操作对比 print("列表切片:", [row[1:] for row in lst]) # 复杂 print("数组切片:", arr[:, 1:]) # 简洁 ``` ### 强大的向量化运算 ```python # 创建测试数据 lst = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] arr = np.array(lst) # 标量运算 - 一行搞定! print("数组标量运算:") print(arr + 10) # 每个元素加10 print(arr * 2) # 每个元素乘2 print(arr ** 2) # 每个元素平方 # 矩阵运算 print("转置:\n", arr.T) print("求和:", arr.sum()) print("均值:", arr.mean()) # 矩阵乘法 b = np.array([[2, 0, 1], [1, 2, 3], [0, 1, 2]]) print("矩阵乘法:\n", arr @ b) # 矩阵乘法运算符 ``` ## 3 对比分析 ### 核心差异总结 | 特性 | 二维列表 | NumPy 二维数组 | |------|----------|----------------| | **创建语法** | `[[1,2],[3,4]]` | `np.array([[1,2],[3,4]])` | | **元素访问** | `list[i][j]` | `array[i,j]` | | **内存效率** | 存储对象引用,开销大 | 紧凑存储,效率高 | | **数据类型** | 可混合类型 | 要求统一类型 | | **运算支持** | 需手动循环实现 | 内置向量化运算 | | **功能扩展** | 基础操作 | 丰富数学函数库 | ### 性能对比测试 ```python import numpy as np import time # 大规模数据测试 size = 1000 data = [[i + j for j in range(size)] for i in range(size)] # 列表运算时间 start = time.time() result_list = [[x * 2 for x in row] for row in data] list_time = time.time() - start # NumPy 运算时间 arr = np.array(data) start = time.time() result_arr = arr * 2 numpy_time = time.time() - start print(f"1000x1000 矩阵标量乘法:") print(f"二维列表: {list_time:.4f} 秒") print(f"NumPy数组: {numpy_time:.4f} 秒") print(f"性能提升: {list_time/numpy_time:.1f} 倍") ``` ### 适用场景指南 **使用二维列表的情况:** ```python # 混合数据类型 mixed_data = [ ["Alice", 25, "Engineer"], ["Bob", 30, "Designer"], ["Charlie", 35, "Manager"] ] # 不规则结构 irregular = [ [1, 2], [3, 4, 5], [6, 7, 8, 9] ] ``` **使用 NumPy 数组的情况:** ```python # 数值计算 matrix_ops = arr1 @ arr2 + arr3 * 2 # 科学计算 result = np.sin(arr) + np.log(arr + 1) # 数据处理 filtered = arr[arr > 5] # 条件筛选 ``` ### 相互转换 ```python # 列表 → 数组 python_list = [[1, 2, 3], [4, 5, 6]] numpy_array = np.array(python_list) # 数组 → 列表 back_to_list = numpy_array.tolist() print("原始列表:", python_list) print("NumPy数组:\n", numpy_array) print("转换回列表:", back_to_list) ``` ## 4. 练习 ### 练习1:性能测试实践 创建一个 100x100 的随机数矩阵,比较两种结构的运算性能。 ```python import random import numpy as np import time # 生成 100x100 的随机数据 data = [[random.randint(1, 100) for _ in range(100)] for _ in range(100)] ``` **任务要求:** 1. 分别使用二维列表和 NumPy 数组实现矩阵的标量乘法(乘以 5) 2. 测量并比较两种方法的执行时间 3. 分析性能差异的原因 要点: - NumPy 通常快 10-100 倍 - 原因:向量化运算、C语言底层实现、内存连续存储 ### 练习2:实际应用场景 学生成绩管理系统中有以下数据: ```python # 学生成绩数据(姓名, 数学, 英语, 物理) students_list = [ ["Alice", 85, 92, 78], ["Bob", 76, 88, 90], ["Charlie", 92, 85, 88], ["Diana", 68, 72, 80] ] ``` **任务要求:** 1. 分析这种数据结构适合用二维列表还是 NumPy 数组?为什么? 2. 如果需要计算每个学生的平均分,你会选择哪种结构?请实现 3. 如果只需要处理数值成绩(不含姓名),哪种结构更合适?请转换并计算各科平均分 要点: - 混合数据类型适合用二维列表 - 纯数值计算适合用 NumPy 数组 ### 练习3:图像处理综合应用 图像处理中经常使用二维数组。假设我们有一个简单的 4x4 灰度图像: ```python # 图像像素数据(0-255 表示灰度值) image_list = [ [100, 120, 130, 110], [115, 125, 135, 105], [105, 115, 140, 120], [125, 135, 125, 115] ] ``` **任务要求:** 1. 将数据转换为 NumPy 数组 2. 实现图像亮度调整:将所有像素值增加 50(注意不能超过 255) 3. 实现图像对比度调整:将所有像素值乘以 1.2(注意边界处理) 4. 提取图像的中央 2x2 区域 5. 计算图像的平均亮度 提示:使用 np.clip 处理边界,np.mean 计算平均值等 #### 图像可视化方法1: imshow() ```python import numpy as np import matplotlib.pyplot as plt img = ... plt.imshow(img, cmap='gray') plt.show() plt.imshow(img + 50, cmap='gray') plt.show() plt.imshow(img * 1.2, cmap='gray') plt.show() ``` #### 图像可视化方法2: subplot() ```python import numpy as np import matplotlib.pyplot as plt # 原始图像数据 image_arr = ... # 图像处理 brightened = image_arr + 50 contrasted = image_arr * 1.2 # 最简单的可视化 plt.figure(figsize=(10, 3)) plt.subplot(1, 3, 1) plt.imshow(image_arr, cmap='gray') plt.title('Original') plt.subplot(1, 3, 2) plt.imshow(brightened, cmap='gray') plt.title('Brightness +50') plt.subplot(1, 3, 3) plt.imshow(contrasted, cmap='gray') plt.title('Contrast ×1.2') plt.show() ```