📋 本章概述
数组索引与切片是NumPy中最重要的操作之一。本章将深入学习各种索引技术,包括基础索引、高级索引、布尔索引和花式索引,这些技能对于数据选择和操作至关重要。
🎯 学习目标
- 掌握基础索引和切片操作
- 理解多维数组的索引规则
- 学会布尔索引和条件选择
- 掌握花式索引和高级选择技术
🔍 3.1 基础索引与切片
一维数组索引
import numpy as np
# 创建一维数组
arr = np.arange(10)
print(f"原数组: {arr}")
# 基础索引
print(f"第一个元素: {arr[0]}")
print(f"最后一个元素: {arr[-1]}")
print(f"第三个元素: {arr[2]}")
# 基础切片
print(f"前5个元素: {arr[:5]}")
print(f"后5个元素: {arr[5:]}")
print(f"中间元素: {arr[2:8]}")
print(f"步长为2: {arr[::2]}")
print(f"反向: {arr[::-1]}")
二维数组索引
import numpy as np
# 创建二维数组
arr_2d = np.arange(20).reshape(4, 5)
print(f"二维数组:\n{arr_2d}")
# 行索引
print(f"第一行: {arr_2d[0]}")
print(f"最后一行: {arr_2d[-1]}")
# 元素索引
print(f"第2行第3列: {arr_2d[1, 2]}")
print(f"等价写法: {arr_2d[1][2]}")
# 行列切片
print(f"前两行:\n{arr_2d[:2]}")
print(f"前三列:\n{arr_2d[:, :3]}")
print(f"子矩阵:\n{arr_2d[1:3, 2:4]}")
三维数组索引
import numpy as np
# 创建三维数组
arr_3d = np.arange(24).reshape(2, 3, 4)
print(f"三维数组形状: {arr_3d.shape}")
print(f"三维数组:\n{arr_3d}")
# 三维索引
print(f"第一个2D切片:\n{arr_3d[0]}")
print(f"特定元素: {arr_3d[1, 2, 3]}")
print(f"子立方体:\n{arr_3d[0, 1:, :2]}")
🎯 3.2 布尔索引
条件选择
import numpy as np
# 创建示例数组
arr = np.random.randint(1, 20, 15)
print(f"原数组: {arr}")
# 布尔条件
condition = arr > 10
print(f"大于10的条件: {condition}")
print(f"大于10的元素: {arr[condition]}")
# 多条件组合
complex_condition = (arr > 5) & (arr < 15)
print(f"5-15之间的元素: {arr[complex_condition]}")
# 条件修改
arr_copy = arr.copy()
arr_copy[arr_copy > 15] = 15 # 将大于15的值设为15
print(f"限制最大值后: {arr_copy}")
二维数组布尔索引
import numpy as np
# 创建二维数组
arr_2d = np.random.randint(1, 10, (4, 5))
print(f"二维数组:\n{arr_2d}")
# 布尔索引
mask = arr_2d > 5
print(f"大于5的掩码:\n{mask}")
print(f"大于5的元素: {arr_2d[mask]}")
# 行条件选择
row_sums = np.sum(arr_2d, axis=1)
high_sum_rows = row_sums > 25
print(f"行和大于25的行:\n{arr_2d[high_sum_rows]}")
🌟 3.3 花式索引
整数数组索引
import numpy as np
# 一维花式索引
arr = np.arange(10) ** 2
print(f"原数组: {arr}")
# 使用索引数组
indices = [1, 3, 5, 7]
print(f"选择的元素: {arr[indices]}")
# 二维花式索引
arr_2d = np.arange(20).reshape(4, 5)
print(f"二维数组:\n{arr_2d}")
# 选择特定行
row_indices = [0, 2, 3]
print(f"选择的行:\n{arr_2d[row_indices]}")
# 选择特定元素
row_idx = [0, 1, 2, 3]
col_idx = [1, 2, 3, 4]
print(f"对角线元素: {arr_2d[row_idx, col_idx]}")
组合索引技术
import numpy as np
# 创建示例数据
data = np.random.randn(8, 4)
print(f"数据形状: {data.shape}")
# 组合布尔和花式索引
# 选择前4行中第2列大于0的行
mask = data[:4, 1] > 0
selected_rows = data[:4][mask]
print(f"选择的行数: {len(selected_rows)}")
# 使用np.where
condition = data > 0
positive_indices = np.where(condition)
print(f"正数的位置: {len(positive_indices[0])}个")
# 条件替换
data_modified = np.where(data > 0, data, 0) # 负数设为0
print(f"修改后正数个数: {np.sum(data_modified > 0)}")
🔧 3.4 高级索引技术
多维花式索引
import numpy as np
# 创建3D数组
arr_3d = np.arange(60).reshape(3, 4, 5)
print(f"3D数组形状: {arr_3d.shape}")
# 多维花式索引
# 选择特定的"页面"和位置
pages = [0, 2]
rows = [1, 3]
cols = [2, 4]
# 这会选择 (0,1,2) 和 (2,3,4) 位置的元素
selected = arr_3d[np.ix_(pages, rows, cols)]
print(f"选择的子数组形状: {selected.shape}")
print(f"选择的子数组:\n{selected}")
条件索引与赋值
import numpy as np
# 创建示例数组
arr = np.random.randint(-10, 10, (5, 5))
print(f"原数组:\n{arr}")
# 条件赋值
arr[arr < 0] = 0 # 负数设为0
print(f"负数清零后:\n{arr}")
# 复杂条件赋值
arr = np.random.randint(1, 100, (5, 5))
print(f"新数组:\n{arr}")
# 根据条件分类赋值
arr_classified = np.select(
[arr < 30, arr < 70, arr >= 70],
['低', '中', '高'],
default='未知'
)
print(f"分类结果:\n{arr_classified}")
📊 3.5 实际应用示例
数据清洗
import numpy as np
# 模拟包含异常值的数据
np.random.seed(42)
data = np.random.normal(50, 10, 1000)
# 添加一些异常值
outlier_indices = np.random.choice(1000, 50, replace=False)
data[outlier_indices] = np.random.uniform(200, 300, 50)
print(f"数据统计:")
print(f"均值: {np.mean(data):.2f}")
print(f"标准差: {np.std(data):.2f}")
print(f"最小值: {np.min(data):.2f}")
print(f"最大值: {np.max(data):.2f}")
# 识别异常值(3σ原则)
mean_val = np.mean(data)
std_val = np.std(data)
threshold = 3 * std_val
outliers = np.abs(data - mean_val) > threshold
print(f"异常值数量: {np.sum(outliers)}")
# 清洗数据
cleaned_data = data[~outliers]
print(f"清洗后数据量: {len(cleaned_data)}")
print(f"清洗后均值: {np.mean(cleaned_data):.2f}")
图像处理
import numpy as np
import matplotlib.pyplot as plt
# 创建模拟图像
image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
# 选择特定颜色通道
red_channel = image[:, :, 0]
green_channel = image[:, :, 1]
blue_channel = image[:, :, 2]
# 创建掩码 - 选择红色占主导的像素
red_dominant = (red_channel > green_channel) & (red_channel > blue_channel)
# 应用掩码
red_mask_image = image.copy()
red_mask_image[~red_dominant] = [0, 0, 0] # 非红色区域设为黑色
print(f"原图像形状: {image.shape}")
print(f"红色主导像素数: {np.sum(red_dominant)}")
# 区域选择
center_region = image[25:75, 25:75, :]
print(f"中心区域形状: {center_region.shape}")
🎯 3.6 性能优化
索引性能对比
import numpy as np
import time
# 创建大数组
large_array = np.random.randint(0, 1000, 1000000)
# 方法1: 布尔索引
start = time.time()
result1 = large_array[large_array > 500]
time1 = time.time() - start
# 方法2: np.where
start = time.time()
indices = np.where(large_array > 500)[0]
result2 = large_array[indices]
time2 = time.time() - start
# 方法3: 列表推导(不推荐)
start = time.time()
result3 = np.array([x for x in large_array if x > 500])
time3 = time.time() - start
print(f"布尔索引耗时: {time1:.4f}秒")
print(f"np.where耗时: {time2:.4f}秒")
print(f"列表推导耗时: {time3:.4f}秒")
print(f"结果一致性: {np.array_equal(result1, result2)}")
📝 本章小结
🎯 核心知识点
- 基础索引: 单个元素和切片选择
- 多维索引: 处理高维数组的索引技术
- 布尔索引: 基于条件的数据选择
- 花式索引: 使用数组进行复杂选择
- 组合技术: 多种索引方法的结合使用
💡 最佳实践
- 优先使用向量化的布尔索引
- 理解视图和副本的区别
- 避免在大数组上使用列表推导
- 合理使用np.where进行条件操作
- 注意索引操作的内存效率
🚀 下一步学习
- 学习数学运算和统计函数
- 掌握通用函数(ufunc)的使用
- 理解广播机制的原理
🎯 练习题
- 基础练习: 使用不同索引方法选择数组元素
- 条件选择: 实现复杂的数据筛选逻辑
- 性能对比: 比较不同索引方法的性能
- 实际应用: 处理真实数据集的索引需求
🎉 恭喜!您已经掌握了NumPy的索引与切片技术!
👉 下一章: 第4章:数学运算与统计函数
本章完成时间: 约45-60分钟
难度等级: ⭐⭐⭐⭐☆