Lab 2.1 高效学习NumPy实验¶
(date: 2025-11-24)
通过这个2小时的实验,你可以快速掌握NumPy的核心功能。NumPy是Python科学计算的基础库,主要用于数组操作和数学运算。
在本实验中,你会需要先阅读和运行基础示例,然后按 [step] 要求修改代码完成实验。
实验环境准备¶
# 安装NumPy(如果尚未安装)
# pip install numpy
import numpy as np
import time
print("NumPy版本:", np.__version__)
第1部分:NumPy数组基础¶
数组属性¶
[step 1] 要求: 在 analysis.md 中问答 arr2 的形状、维度、元素总数、数据类型分别是什么(每行一个答案)?
# 从Python列表创建
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print("一维数组:", arr1)
print("二维数组:\n", arr2)
print("数组形状:", arr2.shape)
print("数组维度:", arr2.ndim)
print("元素总数:", arr2.size)
print("数据类型:", arr2.dtype)
数组改变形状¶
[step 2] 要求:
将 arr2 改变为形状为 (6, 1) 的数组,并打印重塑后的数组。再转换成 (1,6) 的数组,并打印。
在 analysis.md 中问答:(6, 1) 的数组和 (1,6) 的数组,形状和维度是否相同?
# 数组属性
arr = np.array([[1, 2, 3], [4, 5, 6]])
print("原始数组:\n", arr)
# 改变形状
reshaped = arr.reshape(3, 2)
print("重塑后:\n", reshaped)
数值类型转换¶
[step 3] 要求: 将 float_arr 的数据类型转换为复数,并打印转换后的数组及其数据类型。
arr = np.array([[1, 2, 3], [4, 5, 6]])
# 数据类型转换
float_arr = arr.astype(np.float64)
print("转换为浮点数:", float_arr.dtype)
特殊数组创建方法¶
[step 4] 要求:
创建一个形状为 (4, 2) 的全0数组,并打印。
创建一个形状为 (3, 3) 的全5数组,并打印。
创建一个从 0 到 9,步长为 2 的数组,并打印。
创建一个从 0 到 1,等间距有5个元素的数组,并打印。
# 特殊数组创建方法
zeros_arr = np.zeros((3, 4)) # 全0数组
ones_arr = np.ones((2, 3)) # 全1数组
range_arr = np.arange(0, 10, 2) # 类似range
linspace_arr = np.linspace(0, 1, 5) # 等间距数组
random_arr = np.random.random((2, 2)) # 随机数组
print("全0数组:\n", zeros_arr)
print("等间距数组:", linspace_arr)
基本索引和切片¶
[step 5] 要求:
对于 arr,打印前2个元素;打印后4个元素;打印每隔3个取一个元素。
对于 arr_2d,打印首行;打印第2行第1列;打印后两行的前两列。
对于 arr_2d,打印大于5的元素。
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 基本切片
print("前5个元素:", arr[:5])
print("后3个元素:", arr[-3:])
print("每隔2个取一个:", arr[::2])
# 多维数组索引
arr_2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print("第二行:", arr_2d[1])
print("第一行第二列:", arr_2d[0, 1])
print("前两行的后两列:\n", arr_2d[:2, 1:])
# 布尔索引
bool_idx = arr > 5
print("大于5的元素:", arr[bool_idx])
第2部分:NumPy数组操作¶
数学运算¶
1 数组算术运算¶
[step 6] 要求:计算并打印 sin[(a*b)/(a+b)]
# 创建示例数组
a = np.array([1, 2, 3, 4])
b = np.array([5, 6, 7, 8])
# 算术运算
print("加法:", a + b)
print("乘法:", a * b)
print("平方:", a ** 2)
print("三角函数:", np.sin(a))
2 数组矩阵运算¶
[step 7] 要求: 对于数组 a = [[1, 2, 3], [4, 5, 6]]
计算 x = a 和 a.T 的矩阵乘法,以及 y = a.T 和 a 的矩阵乘法
计算 x 的所有元素之和, y 的所有元素之和
x 和 y 的所有元素之后哪个大?为什么? [在 analysis.md 中回答]
# 矩阵运算
matrix_a = np.array([[1, 2], [3, 4]])
matrix_b = np.array([[5, 6], [7, 8]])
print("矩阵乘法:\n", np.dot(matrix_a, matrix_b))
print("矩阵转置:\n", matrix_a.T)
3 数组统计运算¶
[step 8] 要求:先产生数组 x = [[1,2,3],[4,5,6],[7,8,9]],计算:
x 的平均值、标准差、最大值、求和
x*x 的平均值、标准差、最大值、求和
x在 axis = 0 上的平均值、标准差、最大值、求和
x在 axis = 1 上的平均值、标准差、最大值、求和
分析指定axis 和不指定 axis 的结果有何区别? [在analysis.md中回答]
# 统计运算
data = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print("平均值:", np.mean(data))
print("标准差:", np.std(data))
print("最大值:", np.max(data))
print("求和:", np.sum(data))
广播机制¶
广播示例1:标量与数组¶
[step 9] 要求:产生元素均为9的 4x4 数组
# 广播示例1:标量与数组
arr = np.array([[1, 2, 3], [4, 5, 6]])
result = arr + 10 # 标量10被广播到整个数组
print("数组加标量:\n", result)
广播示例2:不同形状数组¶
[step 10] 要求:
计算 a * b
在[analysis.md] 分析 a*b 的广播规则与 a+b 有何异同
# 广播示例2:不同形状数组
a = np.array([[1], [2], [3]]) # 形状 (3, 1)
b = np.array([10, 20, 30]) # 形状 (3,)
result = a + b # 广播为 (3, 3)
print("不同形状数组相加:\n", result)
广播示例3:实际应用¶
[step 11] 要求:在 analysis 分析说明下面的代码所完成的实际运算的数学表达式
# 广播示例3:实际应用
# 计算每个点到原点的距离
points = np.array([[1, 2], [3, 4], [5, 6]])
distances = np.sqrt(np.sum(points**2, axis=1))
print("各点到原点距离:", distances)
数组合并与分割¶
堆叠数组¶
[step 12] 要求: 先建立3个1维数组 a = [1,2], b=[3, 4], c=[5,6]
a,b,c 三者 vstack
a,b,c 三者 hstack
# 堆叠数组
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print("垂直堆叠:\n", np.vstack((a, b)))
print("水平堆叠:\n", np.hstack((a, b)))
分割数组¶
[step 13] 要求:
建立有 1 到 24 组成的 4x6 的数组
划分成上下两个一样大的数组
划分成左右两个一样大的数组
# 分割数组
arr = np.arange(12).reshape(3, 4)
print("原数组:\n", arr)
print("水平分割:\n", np.hsplit(arr, 2))
print("垂直分割:\n", np.vsplit(arr, 3))
排序和搜索¶
[step 14] 要求:
最小的数是多少?
最小的数在哪个位置?
用最小的数的位置取出最小的数,验证它是不是最小
# 排序和搜索
random_data = np.random.randint(0, 100, 10)
print("原始数据:", random_data)
print("排序后:", np.sort(random_data))
print("最大值索引:", np.argmax(random_data))
条件操作¶
[step 15] 要求:
找到所有大于等于3的成员
找到所有小于3的成员
将所有大于等于3的置为1
将所在小于3的成员置0
同时将所有大于等于3的置为1,将所在小于3的成员置0
# 条件操作
arr = np.array([1, 2, 3, 4, 5, 6])
print("条件筛选:", np.where(arr > 3, arr, -1))
第3部分:实战应用-图像处理模拟¶
[step 16]
图像处理示例¶
运行并学习这段示例代码
# 模拟灰度图像处理
# 创建一个模拟的28x28像素图像(灰度值0-255)
image = np.random.randint(0, 256, (28, 28))
print("原始图像形状:", image.shape)
print("像素值范围:", np.min(image), "-", np.max(image))
# 图像处理操作
# 1. 调整亮度
brightened = np.clip(image + 50, 0, 255)
# 2. 图像翻转
flipped = np.fliplr(image)
# 3. 裁剪中心区域
cropped = image[10:18, 10:18]
print("亮度调整后范围:", np.min(brightened), "-", np.max(brightened))
print("裁剪后形状:", cropped.shape)
字符亮度模拟打印¶
用5种字符来表示不同的亮度级别。
' ' → 最暗
'.' → 较暗
'-' → 中等
'+' → 较亮
'#' → 最亮
下面是相应的量化及终端打印函数:
def quantize_to_chars(image, levels=5):
"""
将图像量化为指定级别并用字符表示
"""
# 字符对应亮度:''最暗,'#'最亮
chars = [' ', '.', '-', '+', '#']
# 计算量化边界
min_val = np.min(image)
max_val = np.max(image)
step = (max_val - min_val) / levels
# 创建量化后的字符图像
char_image = []
for i in range(image.shape[0]):
row = []
for j in range(image.shape[1]):
value = image[i, j]
# 确定所属级别
level = min(int((value - min_val) / step), levels - 1)
row.append(chars[level])
char_image.append(''.join(row))
return char_image
# 对原始图像进行5组不同的量化
print("\n" + "="*50)
print("5组不同的量化结果:")
print("="*50)
# 第1组:均匀量化
quantized_1 = quantize_to_chars(image_32x32)
print("\n第1组 - 均匀量化:")
for row in quantized_1:
print(row)
任务描述¶
想象你要创建一个特殊的"乐高风格"数字图像,并用简单的字符来展示它的亮度变化。
第1步:创建特殊图像¶
制作一个 32×32 像素 的字符模拟图像
将这个图像想象成由 4行×4列 的彩色积木块组成
每个积木块大小是 8×8 像素
关键特性:每个积木块内部的所有像素颜色完全一样,但不同积木块的颜色随机变化
第2步:5种不同的处理实验¶
对同一个图像进行5种不同的处理,看看字符显示如何变化:
基础版本 - 直接显示原图
调亮版本 - 让整张图变得更亮
调暗版本 - 让整张图变得更暗
增强对比度 - 让亮的更亮、暗的更暗
局部特写 - 只显示图像的中心区域
第3步:预期打印效果示例¶
最终你会看到5组字符画,每组都是一个32×32的字符方阵(除了特写版本是8×8),能够清晰地看出:
积木块的分块结构
不同处理方式对亮度分布的影响
字符如何有效地表示灰度层次
........########--------
........########--------
........########--------
........########--------
........########--------
........########--------
........########--------
........########--------
++++++++######## ........
++++++++######## ........
++++++++######## ........
++++++++######## ........
++++++++######## ........
++++++++######## ........
++++++++######## ........
++++++++######## ........
........######## ########
........######## ########
........######## ########
........######## ########
........######## ########
........######## ########
........######## ########
........######## ########
----------------################
----------------################
----------------################
----------------################
----------------################
----------------################
----------------################
----------------################