--- tid: 32ticq Lab2.1 高效学习NumPy实验 --- # Lab 2.1 高效学习NumPy实验 (date: 2025-11-24) 通过这个2小时的实验,你可以快速掌握NumPy的核心功能。NumPy是Python科学计算的基础库,主要用于数组操作和数学运算。 在本实验中,你会需要先阅读和运行基础示例,然后按 [step] 要求修改代码完成实验。 ## 实验环境准备 ```python # 安装NumPy(如果尚未安装) # pip install numpy import numpy as np import time print("NumPy版本:", np.__version__) ``` ## 第1部分:NumPy数组基础 ### 数组属性 [step 1] 要求: 在 analysis.md 中问答 arr2 的形状、维度、元素总数、数据类型分别是什么(每行一个答案)? ```python # 从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] 要求: 1. 将 arr2 改变为形状为 (6, 1) 的数组,并打印重塑后的数组。再转换成 (1,6) 的数组,并打印。 1. 在 analysis.md 中问答:(6, 1) 的数组和 (1,6) 的数组,形状和维度是否相同? ```python # 数组属性 arr = np.array([[1, 2, 3], [4, 5, 6]]) print("原始数组:\n", arr) # 改变形状 reshaped = arr.reshape(3, 2) print("重塑后:\n", reshaped) ``` ### 数值类型转换 [step 3] 要求: 将 float_arr 的数据类型转换为复数,并打印转换后的数组及其数据类型。 ```python arr = np.array([[1, 2, 3], [4, 5, 6]]) # 数据类型转换 float_arr = arr.astype(np.float64) print("转换为浮点数:", float_arr.dtype) ``` ### 特殊数组创建方法 [step 4] 要求: 1. 创建一个形状为 (4, 2) 的全0数组,并打印。 1. 创建一个形状为 (3, 3) 的全5数组,并打印。 1. 创建一个从 0 到 9,步长为 2 的数组,并打印。 1. 创建一个从 0 到 1,等间距有5个元素的数组,并打印。 ```python # 特殊数组创建方法 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] 要求: 1. 对于 arr,打印前2个元素;打印后4个元素;打印每隔3个取一个元素。 1. 对于 arr_2d,打印首行;打印第2行第1列;打印后两行的前两列。 1. 对于 arr_2d,打印大于5的元素。 ```python 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)] ```python # 创建示例数组 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]] 1. 计算 x = a 和 a.T 的矩阵乘法,以及 y = a.T 和 a 的矩阵乘法 2. 计算 x 的所有元素之和, y 的所有元素之和 3. x 和 y 的所有元素之后哪个大?为什么? [在 analysis.md 中回答] ```python # 矩阵运算 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]],计算: 1. x 的平均值、标准差、最大值、求和 2. x*x 的平均值、标准差、最大值、求和 3. x在 axis = 0 上的平均值、标准差、最大值、求和 4. x在 axis = 1 上的平均值、标准差、最大值、求和 5. 分析指定axis 和不指定 axis 的结果有何区别? [在analysis.md中回答] ```python # 统计运算 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 数组 ```python # 广播示例1:标量与数组 arr = np.array([[1, 2, 3], [4, 5, 6]]) result = arr + 10 # 标量10被广播到整个数组 print("数组加标量:\n", result) ``` #### 广播示例2:不同形状数组 [step 10] 要求: 1. 计算 a * b 2. 在[analysis.md] 分析 a*b 的广播规则与 a+b 有何异同 ```python # 广播示例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 分析说明下面的代码所完成的实际运算的数学表达式 ```python # 广播示例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] 1. a,b,c 三者 vstack 2. a,b,c 三者 hstack ```python # 堆叠数组 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. 建立有 1 到 24 组成的 4x6 的数组 2. 划分成上下两个一样大的数组 3. 划分成左右两个一样大的数组 ```python # 分割数组 arr = np.arange(12).reshape(3, 4) print("原数组:\n", arr) print("水平分割:\n", np.hsplit(arr, 2)) print("垂直分割:\n", np.vsplit(arr, 3)) ``` #### 排序和搜索 [step 14] 要求: 1. 最小的数是多少? 2. 最小的数在哪个位置? 3. 用最小的数的位置取出最小的数,验证它是不是最小 ```python # 排序和搜索 random_data = np.random.randint(0, 100, 10) print("原始数据:", random_data) print("排序后:", np.sort(random_data)) print("最大值索引:", np.argmax(random_data)) ``` #### 条件操作 [step 15] 要求: 1. 找到所有大于等于3的成员 2. 找到所有小于3的成员 3. 将所有大于等于3的置为1 4. 将所在小于3的成员置0 5. 同时将所有大于等于3的置为1,将所在小于3的成员置0 ```python # 条件操作 arr = np.array([1, 2, 3, 4, 5, 6]) print("条件筛选:", np.where(arr > 3, arr, -1)) ``` ## 第3部分:实战应用-图像处理模拟 [step 16] #### 图像处理示例 运行并学习这段示例代码 ```python # 模拟灰度图像处理 # 创建一个模拟的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种字符来表示不同的亮度级别。 ``` ' ' → 最暗 '.' → 较暗 '-' → 中等 '+' → 较亮 '#' → 最亮 ``` 下面是相应的量化及终端打印函数: ```python 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种不同的处理,看看字符显示如何变化: 1. **基础版本** - 直接显示原图 2. **调亮版本** - 让整张图变得更亮 3. **调暗版本** - 让整张图变得更暗 4. **增强对比度** - 让亮的更亮、暗的更暗 5. **局部特写** - 只显示图像的中心区域 #### 第3步:预期打印效果示例 最终你会看到5组字符画,每组都是一个32×32的字符方阵(除了特写版本是8×8),能够清晰地看出: - 积木块的分块结构 - 不同处理方式对亮度分布的影响 - 字符如何有效地表示灰度层次 ```python ........########-------- ........########-------- ........########-------- ........########-------- ........########-------- ........########-------- ........########-------- ........########-------- ++++++++######## ........ ++++++++######## ........ ++++++++######## ........ ++++++++######## ........ ++++++++######## ........ ++++++++######## ........ ++++++++######## ........ ++++++++######## ........ ........######## ######## ........######## ######## ........######## ######## ........######## ######## ........######## ######## ........######## ######## ........######## ######## ........######## ######## ----------------################ ----------------################ ----------------################ ----------------################ ----------------################ ----------------################ ----------------################ ----------------################ ```