pin_drop当前位置:知识文库 ❯ 图文
NumPy数组切片教程 - 视图与副本的区别详解
一、概述
NumPy数组切片是访问子数组的高效方式,语法与Python列表切片类似但功能更强大。切片返回的是原数组的视图(view)而非副本,修改切片会影响原数组,这一特性使得NumPy切片在内存效率上远优于Python列表切片。多维数组切片支持在每个维度上独立指定范围。
二、切片语法
一维切片
代码示例
arr[start:stop:step]多维切片
代码示例
arr[row_start:row_stop:row_step, col_start:col_stop:col_step]省略号切片
代码示例
arr[..., col_slice]三、参数说明
切片语法示例
四、代码示例
示例1:一维数组切片
代码示例
import numpy as np
arr = np.arange(10)
print(f"原数组: {arr}")
# 基本切片
print(f"arr[2:6] = {arr[2:6]}")
print(f"arr[:5] = {arr[:5]}")
print(f"arr[5:] = {arr[5:]}")
print(f"arr[::2] = {arr[::2]}")
print(f"arr[::-1] = {arr[::-1]}")
print(f"arr[1:8:3] = {arr[1:8:3]}")输出:
代码示例
原数组: [0 1 2 3 4 5 6 7 8 9]
arr[2:6] = [2 3 4 5]
arr[:5] = [0 1 2 3 4]
arr[5:] = [5 6 7 8 9]
arr[::2] = [0 2 4 6 8]
arr[::-1] = [9 8 7 6 5 4 3 2 1 0]
arr[1:8:3] = [1 4 7]示例2:二维数组切片
代码示例
import numpy as np
arr = np.arange(20).reshape(4, 5)
print(f"原数组:\n{arr}")
# 行切片
print(f"\n前两行:\n{arr[:2]}")
# 列切片
print(f"\n第2-4列:\n{arr[:, 1:4]}")
# 行列同时切片
print(f"\n第2-3行,第3-5列:\n{arr[1:3, 2:5]}")
# 特定行和列
print(f"\n第1行和第3行:\n{arr[[0, 2]]}")输出:
代码示例
原数组:
[[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]]
前两行:
[[0 1 2 3 4]
[5 6 7 8 9]]
第2-4列:
[[ 1 2 3]
[ 6 7 8]
[11 12 13]
[16 17 18]]
第2-3行,第3-5列:
[[ 7 8 9]
[12 13 14]]
第1行和第3行:
[[ 0 1 2 3 4]
[10 11 12 13 14]]示例3:视图与副本
代码示例
import numpy as np
arr = np.arange(6)
print(f"原数组: {arr}")
# 切片是视图,修改会影响原数组
view = arr[2:5]
view[0] = 99
print(f"修改视图后原数组: {arr}")
# 使用copy()创建副本
arr2 = np.arange(6)
copy = arr2[2:5].copy()
copy[0] = 99
print(f"修改副本后原数组: {arr2}")
# 判断是否共享内存
arr3 = np.arange(6)
view3 = arr3[2:5]
copy3 = arr3[2:5].copy()
print(f"切片共享内存: {np.shares_memory(arr3, view3)}")
print(f"副本共享内存: {np.shares_memory(arr3, copy3)}")输出:
代码示例
原数组: [0 1 2 3 4 5]
修改视图后原数组: [ 0 1 99 3 4 5]
修改副本后原数组: [0 1 2 3 4 5]
切片共享内存: True
副本共享内存: False提示:理解切片是视图还是副本非常重要。视图共享内存,修改切片会影响原数组;副本是独立的数据,修改副本不会影响原数组。使用
.copy()方法可以显式创建副本。
五、实际应用场景
-
时间序列分析:通过切片提取特定时间段的数据
-
图像处理:通过二维切片裁剪图像的感兴趣区域(ROI)
-
数据预处理:通过切片分离训练集和测试集
六、注意事项
注意:NumPy切片返回视图而非副本,修改切片会修改原数组,这是与Python列表切片的重要区别。
注意:如需独立副本,务必使用
.copy()方法。
注意:步长为负数时,start应大于stop,否则返回空数组。
七、切片与索引对比
八、小结
-
基本语法:切片语法为start:stop:step,各参数均可省略
-
多维切片:多维数组在每个维度上独立切片,用逗号分隔
-
视图特性:切片返回视图,修改切片会影响原数组,这是NumPy的重要特性
-
副本创建:需要独立副本时使用.copy()方法
小贴士
NumPy切片返回视图的设计是为了性能优化,避免了不必要的数据复制。在处理大型数组时,这种设计可以显著节省内存。但这也意味着需要格外小心,意外修改切片可能导致原数组被修改。如果不确定是否需要视图还是副本,显式使用.copy()是最安全的做法。更多高级切片技巧可以参考NumPy索引文档。
九、练习题
练习1
创建一个包含0到19的数组,使用切片提取索引5到15的元素,步长为2。
练习2
创建一个5×5的二维数组,使用切片提取中间3×3的子矩阵。
练习3
编写程序,验证NumPy切片是视图而非副本:修改切片后检查原数组是否变化。
常见问题
NumPy切片和Python列表切片有什么区别?
最主要的区别是:NumPy切片返回的是原数组的视图(共享内存),而Python列表切片返回的是新列表(独立副本)。这意味着修改NumPy切片会影响原数组,而修改列表切片不会影响原列表。NumPy的这种设计是为了提高内存效率,特别是在处理大型数组时。
如何在多维数组中使用省略号切片?
省略号...可以代表任意数量的完整维度。例如,对于三维数组arr[3,4,5],arr[..., 2]等价于arr[:, :, 2],arr[1, ...]等价于arr[1, :, :]。这在处理高维数组时可以简化代码。
步长为负数时切片如何使用?
步长为负数时,切片会从右向左取值,此时start应该大于stop。例如arr[5:1:-1]返回索引5、4、3、2的元素。arr[::-1]是最常用的反转数组方式。如果start小于stop且步长为负数,则返回空数组。
为什么有时候切片修改不影响原数组?
通常情况下NumPy切片返回视图,修改会影响原数组。但如果切片操作导致结果无法用视图表示(例如某些花式索引组合、或者经过多次复杂切片后),NumPy可能会返回副本。此外,某些高级索引操作(如布尔索引)总是返回副本。可以使用np.shares_memory()函数检查两个数组是否共享内存。
本文涉及AI创作
内容由AI创作,请仔细甄别