二维数据结构:列表与数组对比学习

(date: 2025-11-13)

1. 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]]

基本操作

# 访问元素
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()

列表运算的限制

# 尝试向量运算会出错
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?

解决二维列表在数值计算中的局限性。

创建二维数组

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)  # 范围数组

基本操作对比

# 访问元素对比
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:])                # 简洁

强大的向量化运算

# 创建测试数据
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]

内存效率

存储对象引用,开销大

紧凑存储,效率高

数据类型

可混合类型

要求统一类型

运算支持

需手动循环实现

内置向量化运算

功能扩展

基础操作

丰富数学函数库

性能对比测试

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} 倍")

适用场景指南

使用二维列表的情况:

# 混合数据类型
mixed_data = [
    ["Alice", 25, "Engineer"],
    ["Bob", 30, "Designer"],
    ["Charlie", 35, "Manager"]
]

# 不规则结构
irregular = [
    [1, 2],
    [3, 4, 5],
    [6, 7, 8, 9]
]

使用 NumPy 数组的情况:

# 数值计算
matrix_ops = arr1 @ arr2 + arr3 * 2

# 科学计算
result = np.sin(arr) + np.log(arr + 1)

# 数据处理
filtered = arr[arr > 5]  # 条件筛选

相互转换

# 列表 → 数组
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 的随机数矩阵,比较两种结构的运算性能。

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:实际应用场景

学生成绩管理系统中有以下数据:

# 学生成绩数据(姓名, 数学, 英语, 物理)
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 灰度图像:

# 图像像素数据(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()


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()

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()