人工智能之数据分析 numpy:第十章 副本视图

人工智能之数据分析 numpy

第十章 副本视图


文章目录


前言

在 NumPy 中,副本(copy)视图(view) 是理解数组内存管理、性能优化和避免意外修改的关键概念。它们决定了当你对一个数组进行切片、变形或赋值操作时,​**是否创建了新的数据副本,还是仅仅创建了一个指向原数据的新"窗口"**​。

下面从原理、区别、判断方法到实战示例,详细解析:


一、核心概念

概念 含义 是否共享数据 修改影响
副本(Copy) 完全独立的新数组,拥有自己的内存空间 ❌ 不共享 修改副本不影响原数组
视图(View) 原数组的一个"窗口"或"别名",不复制数据 ✅ 共享 修改视图会改变原数组

💡 ​关键点 ​:NumPy 默认尽可能返回 ​视图​(为了节省内存和提升速度),只有在必要时才返回副本。


二、如何判断是副本还是视图?

使用数组的 .base 属性:

  • 如果 arr.base is None这是一个副本(或原始数组)
  • 如果 arr.base is not None这是一个视图,base 指向原始数组
python 复制代码
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  → 视图(切片是视图!)

三、常见操作:返回视图 vs 副本

✅ 返回 视图 的操作(共享数据)

操作 示例 说明
切片(slicing) a[1:4] 最常见!
np.view() a.view() 显式创建视图
reshape()(当可能时) a.reshape(2,2) 如果不改变数据布局,返回视图
转置 T a.T 对高维数组通常是视图
python 复制代码
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 不同)
python 复制代码
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]

四、reshape() 和 ravel() 的细节对比

方法 是否修改原数组 返回类型 内存行为
arr.reshape(...) 新数组 尽量视图,否则副本
arr.resize(...) 无返回(in-place) 直接修改原数组形状
arr.ravel() 一维数组 尽量视图
arr.flatten() 一维数组 总是副本
python 复制代码
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]]

五、实战陷阱:意外修改原数组

❌ 错误示例:以为切片是副本

python 复制代码
data = np.array([10, 20, 30, 40])
subset = data[1:3]      # 这是视图!
subset[0] = 999         # 你以为只改 subset?
print(data)             # [10, 999, 30, 40] → 原数组被改了!

✅ 正确做法:明确需要副本时用 .copy()

python 复制代码
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() 视图(尽量) 可能 谨慎

八、最佳实践建议

  1. 永远不要假设切片是副本 → 如需独立数据,显式调用 .copy()
  2. 在函数参数中接收数组时,若要修改,先 .copy() 避免副作用
  3. 使用 .base 属性调试内存关系
  4. 处理大型数组时,优先使用视图以节省内存,但要小心写操作

后续

本文主要讲述了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》

相关推荐
Dev7z1 小时前
让阅卷不再繁琐:图像识别与数据分析提升智能答题卡评分效率
人工智能·计算机视觉
咚咚王者1 小时前
人工智能之数据分析 numpy:第十一章 字符串与字节交换
人工智能·数据分析·numpy
数字孪生家族4 小时前
视频孪生与空间智能:重构数字时空认知,定义智能决策新范式
人工智能·重构·空间智能·视频孪生与空间智能
FL171713144 小时前
Pytorch保存pt和pkl
人工智能·pytorch·python
jieshenai4 小时前
5090显卡,基于vllm完成大模型推理
人工智能·自然语言处理
逻极6 小时前
云智融合:AIGC与云计算服务新范式(深度解析)
人工智能·云计算·aigc·云服务
雪兽软件6 小时前
人工智能(AI)的商业模式创新路线图
人工智能
俊哥V7 小时前
AI一周事件(2025年11月12日-11月18日)
人工智能·ai