通过例子展示算术运算、通用函数、统计计算、逻辑运算以及广播在NumPy数组上的应用。请确保已导入 NumPy,通常使用 import numpy as np。准备工作首先,我们创建一些数组来操作。我们将使用简单的数组,以便于理解计算过程。import numpy as np # 表示两个地点5天内的每日温度(摄氏度)的数组 temps_loc_a = np.array([15.0, 17.5, 18.0, 16.5, 19.0]) temps_loc_b = np.array([12.0, 14.0, 13.5, 15.0, 16.0]) # 一个2D数组,表示3个传感器在4个时间点的读数(例如,电压) sensor_readings = np.array([[1.1, 1.2, 1.0, 1.3], [2.0, 2.2, 2.1, 1.9], [0.8, 0.7, 0.9, 0.8]]) print("地点A的温度:", temps_loc_a) print("地点B的温度:", temps_loc_b) print("传感器读数:\n", sensor_readings)1. 算术运算和通用函数 (ufuncs)让我们执行一些基本计算。a) 元素级加法: 计算每天两个地点的平均温度。# 计算每天的温度总和 daily_sum = temps_loc_a + temps_loc_b # 计算每天的平均温度 daily_avg = daily_sum / 2.0 # 或者更直接的方式: daily_avg = (temps_loc_a + temps_loc_b) / 2 print("每日总和:", daily_sum) print("每日平均温度:", daily_avg)请注意,加法 + 和除法 / 运算是如何逐元素应用的。b) 温度转换: 将地点A的温度从摄氏度转换为华氏度。公式是 $F = (C \times 9/5) + 32$。temps_fahrenheit_a = (temps_loc_a * 9/5) + 32 print("地点A的温度 (华氏度):", temps_fahrenheit_a)同样,乘法 * 和加法 + 会自动应用于每个元素。c) 使用通用函数 (ufunc): 计算每个传感器读数的平方根(可能用于数据转换)。我们使用 np.sqrt()。sqrt_readings = np.sqrt(sensor_readings) print("传感器读数的平方根:\n", sqrt_readings)NumPy 的 np.sqrt 函数对整个数组进行高效操作。2. 数学和统计函数现在我们来计算一些汇总统计量。a) 总体统计: 找出地点A记录的总体最低、最高和平均温度。min_temp_a = np.min(temps_loc_a) max_temp_a = np.max(temps_loc_a) avg_temp_a = np.mean(temps_loc_a) std_dev_temp_a = np.std(temps_loc_a) # 标准差 print(f"地点A - 最低温度: {min_temp_a:.2f} C") print(f"地点A - 最高温度: {max_temp_a:.2f} C") print(f"地点A - 平均温度: {avg_temp_a:.2f} C") print(f"地点A - 标准差: {std_dev_temp_a:.2f} C")b) 沿轴统计: 从 sensor_readings 数组中计算每个传感器的平均读数(跨时间)和每个时间点的平均读数(跨传感器)。请记住:axis=0 沿行操作(为每列计算统计量)。axis=1 沿列操作(为每行计算统计量)。# 每个时间点的平均读数(跨传感器)- 行折叠 avg_reading_per_timepoint = np.mean(sensor_readings, axis=0) # 每个传感器的平均读数(跨时间)- 列折叠 avg_reading_per_sensor = np.mean(sensor_readings, axis=1) print("每个时间点的平均读数:", avg_reading_per_timepoint) print("每个传感器的平均读数:", avg_reading_per_sensor)我们可以使用简单的条形图来可视化每个传感器的平均读数。{"data": [{"type": "bar", "x": ["传感器 1", "传感器 2", "传感器 3"], "y": [1.15, 2.05, 0.8], "marker": {"color": ["#228be6", "#15aabf", "#40c057"]}}], "layout": {"title": "每个传感器的平均读数", "xaxis": {"title": "传感器"}, "yaxis": {"title": "平均电压"}, "margin": {"l": 40, "r": 20, "t": 40, "b": 40}}}为每个传感器在所有时间点计算的平均电压读数。3. 逻辑运算让我们找出地点A温度高于17摄氏度的日期。# 根据条件创建布尔数组 hot_days_a = temps_loc_a > 17.0 print("地点A温度高于17摄氏度的日期:", hot_days_a) # 使用布尔索引来选择那些日期的温度 hot_temps_a = temps_loc_a[hot_days_a] # 你也可以一步完成: hot_temps_a = temps_loc_a[temps_loc_a > 17.0] print("地点A高温日期的温度:", hot_temps_a) # 有多少个高温日期? num_hot_days = np.sum(hot_days_a) # True 计为 1,False 计为 0 print("温度高于17摄氏度的天数:", num_hot_days)比较表达式 temps_loc_a > 17.0 返回一个布尔数组 ([False, True, True, False, True])。然后,此数组用作索引,只选择 temps_loc_a 中布尔数组对应值为 True 的元素。4. 广播如果形状兼容,广播允许在不同形状的数组之间进行操作。a) 添加标量: 将一个常数调整值(例如 0.5)添加到所有传感器读数。adjusted_readings = sensor_readings + 0.5 print("调整后的传感器读数:\n", adjusted_readings)在这里,标量 0.5 被有效地“拉伸”或广播,以匹配 sensor_readings 的形状,然后进行加法运算。b) 与一维数组操作: 假设我们为每个时间点设置了一个基线值(可能是前几天的平均值),并希望查看传感器1当前读数与此基线值的差异。baseline_per_timepoint = np.array([1.0, 1.1, 0.9, 1.2]) sensor1_readings = sensor_readings[0, :] # 第一行 difference_sensor1 = sensor1_readings - baseline_per_timepoint print("传感器1读数:", sensor1_readings) print("每个时间点的基线值:", baseline_per_timepoint) print("传感器1的差异:", difference_sensor1)sensor1_readings 和 baseline_per_timepoint 都是相同大小(4个元素)的一维数组,因此逐元素相减可以直接进行。c) 将一维数组广播到二维数组: 现在,让我们从所有传感器读数中减去 baseline_per_timepoint。difference_all_sensors = sensor_readings - baseline_per_timepoint print("所有传感器与基线的差异:\n", difference_all_sensors)这是如何工作的?sensor_readings 的形状是 (3, 4),baseline_per_timepoint 的形状是 (4,)。NumPy 的广播规则从右到左比较维度:最后一个维度匹配(都为 4)。sensor_readings 的下一个维度是 3,但 baseline_per_timepoint 没有更多维度了。 NumPy 会沿着缺失的维度(本例中为行)“拉伸”或复制 baseline_per_timepoint,以有效地创建一个与 sensor_readings 匹配的 (3, 4) 数组。然后进行逐元素相减。就像 NumPy 执行了这样的减法:[[1.1, 1.2, 1.0, 1.3], [[1.0, 1.1, 0.9, 1.2], [2.0, 2.2, 2.1, 1.9], - [1.0, 1.1, 0.9, 1.2], [0.8, 0.7, 0.9, 0.8]] [1.0, 1.1, 0.9, 1.2]]总结在本次动手实践中,你应用了本章介绍的基本数值运算:执行了逐元素的算术运算,如加法和乘法。使用了通用函数 (ufuncs),如 np.sqrt。计算了整个数组和特定轴的统计指标(np.mean、np.min、np.max、np.std)。应用了逻辑运算(>)来创建布尔数组,用于数据过滤(布尔索引)。运用广播在兼容但形状不同的数组之间执行操作(标量与数组,一维与二维)。这些操作是 NumPy 数值计算的核心,也是你将遇到的许多数据分析任务的根本。进一步尝试创建自己的数组,并尝试不同的函数和操作。