首页 > 人工智能 > 人工智能 > 人工智能之数据分析 numpy:第十章 副本视图
第十章 副本视图
在 NumPy 中, 副本(copy) 和 视图(view) 是理解数组内存管理、性能优化和避免意外修改的关键概念。它们决定了当你对一个数组进行切片、变形或赋值操作时, 是否创建了新的数据副本,还是仅仅创建了一个指向原数据的新“窗口”。
下面从原理、区别、判断方法到实战示例,详细解析:
| 概念 | 含义 | 是否共享数据 | 修改影响 |
| ------------------------ | -------------------------------------------- | -------------- | ---------------------- |
| 副本(Copy) | 完全独立的新数组,拥有自己的内存空间 | ❌ 不共享 | 修改副本不影响原数组 |
| 视图(View) | 原数组的一个“窗口”或“别名”,不复制数据 | ✅ 共享 | 修改视图会改变原数组 |
💡 关键点:NumPy 默认尽可能返回 视图(为了节省内存和提升速度),只有在必要时才返回副本。
使用数组的
.base 属性:
arr.base is None →
这是一个副本(或原始数组)arr.base is not None →
这是一个视图,
base 指向原始数组import numpy as np a = np.array([1, 2, 3, 4]) b = a.view() # 显式创建视图 c = a.copy() # 显式创建副本 d = a[1:3] # 切片(通常返回视图) print(b.base is a) # True → 视图 print(c.base is a) # False → 副本(c.base is None) print(d.base is a) # True → 视图(切片是视图!)
| 操作 | 示例 | 说明 |
| ----------------------------- | ---------------------- | ------------------------------ |
| 切片(slicing) |
a[1:4] | 最常见! |
|
np.view() |
a.view() | 显式创建视图 |
|
reshape()(当可能时) |
a.reshape(2,2) | 如果不改变数据布局,返回视图 |
| 转置
T |
a.T | 对高维数组通常是视图 |
a = np.array([[1, 2], [3, 4]]) b = a.reshape(4,) # 视图(连续内存) b[0] = 99 print(a) # [[99, 2], [3, 4]] → 原数组被修改!
⚠️ 注意:
reshape()不一定总是视图!如果无法在不复制数据的情况下 reshape(如非连续数组),NumPy 会自动返回副本。
| 操作 | 示例 | 说明 |
| ---------------------------- | -------------------- | ------------------------------------------------- |
|
np.copy() |
a.copy() | 显式深拷贝 |
| 花式索引(fancy indexing) |
a[[0, 2, 1]] | 总是副本 |
| 布尔索引 |
a[a > 2] | 总是副本 |
|
flatten() |
a.flatten() | 总是返回副本 |
|
ravel()(有时) |
a.ravel() | 尽量返回视图,不行则副本(与
flatten 不同) |
a = np.array([1, 2, 3, 4]) # 花式索引 → 副本 b = a[[0, 2]] b[0] = 99 print(a) # [1, 2, 3, 4] → 未变 # flatten → 副本 c = a.flatten() c[0] = 88 print(a) # 仍为 [1, 2, 3, 4]
| 方法 | 是否修改原数组 | 返回类型 | 内存行为 |
| ------------------------ | ---------------- | -------------------- | -------------------- |
|
arr.reshape(...) | ❌ | 新数组 | 尽量视图,否则副本 |
|
arr.resize(...) | ✅ | 无返回(in-place) | 直接修改原数组形状 |
|
arr.ravel() | ❌ | 一维数组 | 尽量视图 |
|
arr.flatten() | ❌ | 一维数组 |
总是副本 |
a = np.array([[1, 2], [3, 4]]) # ravel() → 视图(因为 a 是连续的) b = a.ravel() b[0] = 99 print(a) # [[99, 2], [3, 4]] # flatten() → 副本 c = a.flatten() c[0] = 88 print(a) # 仍是 [[99, 2], [3, 4]]
data = np.array([10, 20, 30, 40]) subset = data[1:3] # 这是视图! subset[0] = 999 # 你以为只改 subset? print(data) # [10, 999, 30, 40] → 原数组被改了!
.copy()data = np.array([10, 20, 30, 40]) subset = data[1:3].copy() # 显式创建副本 subset[0] = 999 print(data) # [10, 20, 30, 40] → 安全!
| 场景 | 推荐 |
|---|---|
| 只读访问子数据(如分析某段信号) | 用视图(高效) |
| 需要修改子数据但不想影响原数组 | 用
.copy() |
| 函数内部处理数组,不确定是否会被修改 | 默认
.copy() 更安全 |
| 内存受限,且确定不会修改 | 用视图节省内存 |
| 操作 | 返回 | 是否共享数据 | 安全修改? |
| ---------------------- | -------------- | -------------- | ---------------- |
|
a[:] | 视图 | ✅ | ❌(会影响 a) |
|
a[1:3] | 视图 | ✅ | ❌ |
|
a[[1,2]] | 副本 | ❌ | ✅ |
|
a[a>0] | 副本 | ❌ | ✅ |
|
a.reshape(...) | 视图(尽量) | 可能 | 谨慎 |
|
a.copy() | 副本 | ❌ | ✅ |
|
a.view() | 视图 | ✅ | ❌ |
|
a.flatten() | 副本 | ❌ | ✅ |
|
a.ravel() | 视图(尽量) | 可能 | 谨慎 |
.copy().copy() 避免副作用.base 属性调试内存关系本文主要讲述了numpy数组副本和视图。python过渡项目部分代码已经上传至gitee,后续会逐步更新,主要受时间原因限制,当然自己也可以克隆到本地学习拓展。
公众号:咚咚王 gitee: https://gitee.com/wy18585051844/ai_learning

《Python编程:从入门到实践》 《利用Python进行数据分析》 《算法导论中文第三版》 《概率论与数理统计(第四版) (盛骤) 》 《程序员的数学》 《线性代数应该这样学第3版》 《微积分和数学分析引论》 《(西瓜书)周志华-机器学习》 《TensorFlow机器学习实战指南》 《Sklearn与TensorFlow机器学习实用指南》 《模式识别(第四版)》 《深度学习 deep learning》伊恩·古德费洛著 花书 《Python深度学习第二版(中文版)【纯文本】 (登封大数据 (Francois Choliet)) (Z-Library)》 《深入浅出神经网络与深度学习+(迈克尔·尼尔森(Michael+Nielsen)》 《自然语言处理综论 第2版》 《Natural-Language-Processing-with-PyTorch》 《计算机视觉-算法与应用(中文版)》 《Learning OpenCV 4》 《AIGC:智能创作时代》杜雨+&+张孜铭 《AIGC原理与实践:零基础学大语言模型、扩散模型和多模态模型》 《从零构建大语言模型(中文版)》 《实战AI大模型》 《AI 3.0》
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048224/viewspace-3103061/ ,如需转载,请注明出处,否则将追究法律责任。