📌 写在前面
大家好!👋
欢迎来到**【一起学Python】**的第80天!🎉
恭喜大家坚持到了第80天!前79天,我们从安装环境开始,一步步掌握了数据类型、数组属性、创建方法以及基础的切片索引。
🤔 为什么要学高级索引?
- ✅ 精准打击:从海量数据中瞬间提取你想要的“那一小撮”。
- ✅ 数据清洗神器:基于条件(布尔索引)快速过滤异常值。
- ✅ 避坑指南:理解“视图”机制,防止修改数据时意外破坏原数组!
- ✅ 组合拳:将切片、布尔、花式索引结合,实现复杂的提取逻辑。
今天,我们将深入高级索引的世界,让你对数据的掌控力提升一个Level!🚀
一、获取子数组:精准定位的艺术 🎯
高级索引的基础是灵活使用切片。无论是1维还是多维数组,NumPy都提供了极简的语法。
1.1 一维数组的子数组
import numpy as npone_d_array = np.array([10, 20, 30, 40, 50])# 获取从索引1到索引4(不包括4)的子数组sub_array = one_d_array[1:4] print("一维数组的子数组:", sub_array) # 输出: [20 30 40]
1.2 二维数组的子数组
对于二维数组,我们可以通过指定行和列的切片来提取矩形区域。two_d_array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# 获取前两行(0:2)和第二、第三列(1:3)的子数组sub_array_2d = two_d_array[0:2, 1:3] print("二维数组的子数组:\n", sub_array_2d)# 输出:# [[2 3]# [5 6]]
二、核心陷阱:修改子数组会怎样?⚠️
这是新手最容易踩的坑!🕳️
2.1 视图(View)机制
在NumPy中,通过切片获取的子数组通常是对原始数组的视图(View),而不是副本。
这意味着:修改子数组,原始数组也会跟着变!
# 创建一个原始数组original_array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# 获取子数组(视图)sub_array = original_array[1:3, 0:2] print("原始子数组:\n", sub_array)# 修改子数组的值sub_array[0, 0] = 99print("修改后的子数组:\n", sub_array)print("修改后的原始数组:\n", original_array) # ⚠️ 注意:original_array 中的 4 也变成了 99!
💡 避坑指南:如何避免误伤?
如果你希望修改子数组而不影响原始数据,请使用 .copy() 方法创建独立副本。
# 创建独立副本safe_sub = original_array[1:3, 0:2].copy()safe_sub[0, 0] = 888 # 这里改,原数组不会变 ✅
三、复杂数据选择与操作:组合拳 🥊
当简单的切片无法满足需求时,我们可以使用布尔索引、花式索引以及它们的组合。
3.1 布尔索引:按条件筛选
通过逻辑表达式生成布尔数组,直接提取符合条件的元素。
data = np.array([1, 2, 3, 4, 5, 6])condition = data % 2 == 0 # 条件:选择偶数even_numbers = data[condition]print("选择的偶数:", even_numbers) # 输出: [2 4 6]
3.2 花式索引(Fancy Indexing):按位置提取
使用整数数组来选择特定的行或列,非常灵活!
two_d_array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])row_indices = np.array([0, 2]) # 选择第一行和第三行selected_rows = two_d_array[row_indices]print("选择的行:\n", selected_rows)# 输出:# [[1 2 3]# [7 8 9]]
3.3 综合使用:切片 + 布尔索引
你可以将多种索引方式结合使用,实现超级复杂的数据提取。
arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])# 场景1:选择大于5的元素result = arr[arr > 5]print("大于5的元素:", result) # 输出: [6 7 8 9]# 场景2:结合切片和布尔条件# 先取前两行,再从中选出大于3的数sub_result = arr[:2, :][arr[:2, :] > 3]print("前两行中大于3的数:", sub_result) # 输出: [4 5 6]
四、实战演练代码 💻
把今天学的知识点串联起来,看看这段代码,你能完全看懂吗?
import numpy as np# 1. 创建数据array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])print("原始数组:\n", array)# 2. 获取子数组(视图)sub_array = array[0:2, 1:3] print("\n子数组:\n", sub_array)# 3. 修改子数组(原数组会被影响!)sub_array[0, 0] = 99print("\n修改后的子数组:\n", sub_array)print("修改后原始数组:\n", array) # 4. 布尔索引:选择特定元素bool_condition = array > 5selected_elements = array[bool_condition]print("\n选择的元素(大于5): ", selected_elements)# 5. 花式索引:选择特定行row_indices = np.array([0, 2])selected_rows = array[row_indices]print("\n选择的行:\n ", selected_rows)# 6. 综合使用result = array[array < 5]print("\n选择的元素(小于5): ", result) # 输出: [1 2 3 4]
今日作业
基础题 ⭐
- 创建一个3×3的数组,提取右上角的2×2子数组。
- 修改提取出的子数组中的某个值,并观察原始数组是否发生变化。
- 使用布尔索引找出数组中所有能被3整除的元素。
进阶题 ⭐⭐
- 创建一个10×10的随机整数矩阵(0-100)。
- 提取所有大于80的元素,并计算它们的平均值。
- 使用花式索引提取矩阵的第1、3、5行。
挑战题 ⭐⭐⭐
- 模拟成绩单:创建一个包含5名学生、3门课程成绩的数组。
- 筛选出数学成绩(第3列)大于90分的学生,并提取他们的所有科目成绩。
- 尝试使用
.copy() 创建一个子数组的副本,修改副本后验证原数组不受影响。
💡 参考代码(挑战题):
# 假设列顺序:语文,数学,英语scores = np.array([ [80, 85, 90], [90, 95, 92], [70, 75, 80], [88, 91, 89], [95, 98, 96]])# 筛选数学 > 90 (第3列索引为2)high_math_students = scores[scores[:, 2] > 90]print("数学大于90的学生成绩:\n", high_math_students)
🎓 明日预告
第81天:NumPy数组运算与广播机制
你将学到:
- 🔸 数组的加减乘除数学运算
- 广播机制(Broadcasting):不同形状数组如何运算?
- 🔸 矩阵乘法 vs 元素级乘法
- 🔸 实战:一行代码完成复杂计算
敬请期待! 🚀
💡 学习小贴士
- 视图 vs 副本:
- 切片(
:)通常返回视图,修改会影响原数组。 - 索引(
[])或 .copy() 返回副本,修改不影响原数组。 - 不确定时,养成用
.copy() 的习惯!
- 调试技巧:
- 数据不对?先
print(arr.shape) 和 print(arr)。 - 提取空数组?检查布尔条件是否正确。
- 性能优化:
- 尽量使用NumPy内置的索引和切片,避免写
for 循环遍历数组。
📚 学习路线图
第74天:NumPy安装 ✓第75天:ndarray对象 ✓第76天:数据类型 ✓第77天:数组属性 ✓第78天:创建数组 ✓第79天:切片和索引 ✓第80天:高级索引 ✓ ← 你今天在这里第81天:数组运算第82天:广播机制...
💬 写在最后
高级索引是NumPy最强大的功能之一。掌握它,你就能像外科医生一样精准地操作数据!
今天重点掌握:
- ✅ 多维子数组的提取方法。
- ✅ 视图机制(修改子数组的影响)。
- ✅ 布尔索引与花式索引的灵活使用。
如果觉得有用,记得:
- 👍 点赞支持一下
- ⭐ 收藏方便复习
- 📤 分享给更多小伙伴
完成作业的同学,欢迎在评论区打卡! 💪
【一起学Python】每天进步一点点,365天后遇见更优秀的自己!
👉 关注公众号,不错过每天的学习内容!
🎯 今日金句:
"数据就像矿藏,索引就是你的探测器。精准的索引,让有价值的信息无处遁形!" 💎
明天见!