📋 本章概述

数组索引与切片是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)}")

📝 本章小结

🎯 核心知识点

  1. 基础索引: 单个元素和切片选择
  2. 多维索引: 处理高维数组的索引技术
  3. 布尔索引: 基于条件的数据选择
  4. 花式索引: 使用数组进行复杂选择
  5. 组合技术: 多种索引方法的结合使用

💡 最佳实践

  • 优先使用向量化的布尔索引
  • 理解视图和副本的区别
  • 避免在大数组上使用列表推导
  • 合理使用np.where进行条件操作
  • 注意索引操作的内存效率

🚀 下一步学习

  • 学习数学运算和统计函数
  • 掌握通用函数(ufunc)的使用
  • 理解广播机制的原理

🎯 练习题

  1. 基础练习: 使用不同索引方法选择数组元素
  2. 条件选择: 实现复杂的数据筛选逻辑
  3. 性能对比: 比较不同索引方法的性能
  4. 实际应用: 处理真实数据集的索引需求

🎉 恭喜!您已经掌握了NumPy的索引与切片技术!

👉 下一章: 第4章:数学运算与统计函数


本章完成时间: 约45-60分钟
难度等级: ⭐⭐⭐⭐☆