文章目录
- 6.1 使用布尔索引和条件选取
- 6.1.1 基础知识
- 6.1.2 完整案例:筛选股市数据
- 6.1.3 拓展案例 1:筛选健康数据
- 6.1.4 拓展案例 2:筛选和替换
- 6.2 缺失数据和无效数据处理
- 6.2.1 基础知识
- 6.2.2 完整案例:气象数据处理
- 6.2.3 拓展案例 1:金融数据清理
- 6.2.4 拓展案例 2:处理含有无穷值的数据
- 6.3 数组的内存布局
- 6.3.1 基础知识
- 6.3.2 完整案例:分析数组内存布局
- 6.3.3 拓展案例 1:优化数组操作
- 6.3.4 拓展案例 2:创建有效的数组视图
6.1 使用布尔索引和条件选取
6.1.1 基础知识
布尔索引是 Numpy 中处理数组的强大手段之一,它允许我们根据条件快速选取数组中的元素。这种方法使用布尔数组(即由 True
和 False
组成的数组)作为索引,以此来选取符合特定条件的元素。
- 布尔运算:可以对数组进行比较运算(如
>
,<
,==
等),结果是一个布尔数组。 - 条件选取:使用布尔数组作为索引来选取原数组中的元素。
6.1.2 完整案例:筛选股市数据
假设你有一组股市数据,你想筛选出所有收盘价高于平均值的日子。
import numpy as np# 假设这是 10 天的股市收盘价
closing_prices = np.array([120, 125, 130, 135, 140, 135, 130, 125, 120, 115])# 计算平均收盘价
mean_price = np.mean(closing_prices)# 使用布尔索引选取高于平均收盘价的日子
above_mean = closing_prices[closing_prices > mean_price]print("Days with Closing Prices Above Mean:", above_mean)
在这个案例中,我们首先计算了平均收盘价,然后使用布尔索引选取了所有高于该平均值的收盘价。
6.1.3 拓展案例 1:筛选健康数据
假设你正在处理一组人群的健康数据,需要筛选出所有血压在正常范围内的个体。
# 假设这是一组血压数据(收缩压)
blood_pressures = np.array([120, 125, 130, 140, 135, 150, 110, 115, 120, 125])# 定义血压正常范围
normal_bp_low, normal_bp_high = 110, 130# 使用布尔索引筛选正常血压的数据
normal_bp = blood_pressures[(blood_pressures >= normal_bp_low) & (blood_pressures <= normal_bp_high)]print("Individuals with Normal Blood Pressure:", normal_bp)
在这个案例中,我们使用了组合条件的布尔索引来筛选出处于正常血压范围内的个体。
6.1.4 拓展案例 2:筛选和替换
有时我们不仅要筛选数据,还要对这些数据进行替换。
# 假设这是一组产品评分数据
ratings = np.array([4, 3, 1, 5, 4, 2, 1, 5, 5, 3])# 将所有低于 3 分的评分提升为 3 分
ratings[ratings < 3] = 3print("Adjusted Ratings:", ratings)
在这个案例中,我们先筛选出所有低于 3 分的评分,然后将它们提升到 3 分,这种操作在数据清洗和预处理中非常常见。
通过这些案例,我们可以看到布尔索引和条件选取在数据处理中的强大应用。它们不仅能帮助我们快速筛选出感兴趣的数据,还能方便地对数据进行修改和管理。掌握这些技巧,你将能够更加自如地驾驭复杂的数据集。
6.2 缺失数据和无效数据处理
6.2.1 基础知识
在现实世界的数据集中,缺失数据和无效数据是常见的问题。它们可能源于数据收集错误、传输问题或其他原因。处理这些数据是数据预处理的重要部分。
- 识别缺失/无效数据:Numpy 中可以使用
np.isnan()
或np.isfinite()
等函数来识别缺失或无效数据。 - 处理方法:对于缺失或无效的数据,常见的处理方法包括删除这些数据、填充默认值或使用统计方法(如平均值、中位数等)填充。
6.2.2 完整案例:气象数据处理
假设你正在处理一组气象数据,其中包含一些缺失的温度读数。
import numpy as np# 假设这是一组温度数据,其中 np.nan 表示缺失数据
temperatures = np.array([22.5, 23.0, np.nan, 24.5, 25.0, np.nan, 23.5])# 检查哪些是缺失值
missing_values = np.isnan(temperatures)# 计算缺失数据之外的平均温度
mean_temp = np.nanmean(temperatures)# 用平均温度替换缺失值
temperatures[missing_values] = mean_tempprint("Processed Temperatures:", temperatures)
在这个案例中,我们首先识别了缺失的温度读数,然后计算了剩余数据的平均温度,并用这个平均值替换了缺失的数据。
6.2.3 拓展案例 1:金融数据清理
在处理金融数据时,异常值的处理同样重要。
# 假设这是一组股票价格,其中一些价格是无效的
stock_prices = np.array([120, 125, -999, 130, -999, 135, 140])# 将无效的股票价格标记为 np.nan
stock_prices[stock_prices < 0] = np.nan# 使用前一个有效值替换无效值
valid_prices = np.where(np.isnan(stock_prices), np.nan_to_num(stock_prices, nan=np.nanmean(stock_prices)), stock_prices)print("Cleaned Stock Prices:", valid_prices)
在这个案例中,我们首先将无效的股价标记为 np.nan
,然后使用 np.where()
和 np.nan_to_num()
将无效值替换为前一个有效值。
6.2.4 拓展案例 2:处理含有无穷值的数据
处理包含无穷大或无穷小值的数据集也很重要。
# 创建一个含有无穷值的数组
data_with_infinity = np.array([1, 2, np.inf, 3, -np.inf, 4])# 替换无穷大和无穷小值为最大值和最小值
max_value = np.finfo(data_with_infinity.dtype).max
min_value = np.finfo(data_with_infinity.dtype).min
data_with_infinity = np.clip(data_with_infinity, min_value, max_value)print("Data without Infinity:", data_with_infinity)
在这个案例中,我们使用 np.clip()
函数将无穷大值替换为数据类型允许的最大值,将无穷小值替换为最小值。
处理缺失数据和无效数据是数据分析中的一个重要环节。掌握这些技巧可以帮助我们清理和准备数据,为后续的分析工作打下坚实的基础。
6.3 数组的内存布局
6.3.1 基础知识
了解 Numpy 数组在内存中的布局是优化性能的关键。数组的内存布局决定了数据是如何存储和访问的。
- 连续性(Contiguity):在内存中,一个连续的数组可以提高数据处理的速度。Numpy 提供了
C
风格(行优先)和F
风格(列优先)的数据存储。 - 步长(Stride):步长是一个元组,表示为了到达当前维度下一个元素需要跨越的字节数。了解步长可以帮助我们更好地理解数组的内存布局。
- 数据副本(Copy)与视图(View):在处理数组时,区分创建数据的副本还是视图是非常重要的。副本占用额外内存,但不会影响原始数据;视图不占用额外内存,但对视图的修改会影响原始数据。
6.3.2 完整案例:分析数组内存布局
假设你有一个二维数组,你想分析它的内存布局。
import numpy as np# 创建一个二维数组
matrix = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int32)# 获取数组的步长
strides = matrix.strides# 检查数组是否为 C 连续
c_contiguous = matrix.flags['C_CONTIGUOUS']# 检查数组是否为 F 连续
f_contiguous = matrix.flags['F_CONTIGUOUS']print("Strides:", strides)
print("C contiguous:", c_contiguous)
print("F contiguous:", f_contiguous)
在这个案例中,我们创建了一个二维数组,并分析了它的步长和连续性。
6.3.3 拓展案例 1:优化数组操作
理解内存布局可以帮助我们优化数组操作。
# 创建一个大型二维数组
large_matrix = np.random.rand(10000, 10000)# 创建一个 C 风格连续的副本
c_matrix = np.array(large_matrix, order='C')# 创建一个 F 风格连续的副本
f_matrix = np.array(large_matrix, order='F')# 比较操作性能
%timeit np.sum(c_matrix)
%timeit np.sum(f_matrix)
在这个案例中,我们比较了 C 风格和 F 风格连续数组的操作性能。
6.3.4 拓展案例 2:创建有效的数组视图
利用视图可以在不创建数据副本的情况下进行高效的数组操作。
# 创建原始数组
original_array = np.array([1, 2, 3, 4, 5, 6])# 创建一个视图
array_view = original_array[::2]# 修改视图
array_view[1] = 10print("Original Array:", original_array)
print("Array View:", array_view)
在这个案例中,我们创建了原始数组的一个视图,并演示了如何修改这个视图会影响原始数组。
通过对数组的内存布局有深入的理解,我们可以更加有效地管理和操作大型数据集。这不仅有助于提升性能,还可以使我们在数据处理中更加灵活。