首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >人工智能之数据分析 numpy:第十章 副本视图

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

原创
作者头像
咚咚王
发布2025-11-23 19:05:12
发布2025-11-23 19:05:12
160
举报

人工智能之数据分析 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,后续会逐步更新,主要受时间原因限制,当然自己也可以克隆到本地学习拓展。

资料关注

公众号:咚咚王

《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》

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 人工智能之数据分析 numpy
  • 前言
    • 一、核心概念
    • 二、如何判断是副本还是视图?
    • 三、常见操作:返回视图 vs 副本
      • ✅ 返回 视图 的操作(共享数据)
      • ✅ 返回 副本 的操作(独立数据)
    • 四、reshape() 和 ravel() 的细节对比
    • 五、实战陷阱:意外修改原数组
      • ❌ 错误示例:以为切片是副本
      • ✅ 正确做法:明确需要副本时用 .copy()
    • 六、何时用视图?何时用副本?
    • 七、总结速查表
    • 八、最佳实践建议
  • 后续
  • 资料关注
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档