【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.2 ndarray解剖课:多维数组的底层实现
1.2 《ndarray解剖课:多维数组的底层实现》
内容介绍
NumPy 的 ndarray
是其核心数据结构,用于高效处理多维数组。在这篇文章中,我们将深入解析 ndarray
的底层实现,探讨其内存结构、维度、数据类型、步长等关键概念,并通过实验验证这些概念的实际应用。
1.2.1 ndarray与Python列表的核心差异
ndarray
和 Python 列表是两种不同的数据结构,它们在内存布局和性能上有显著的差异。下面是 ndarray
和 Python 列表的核心差异对比表:
特性 | ndarray | Python 列表 |
---|---|---|
内存布局 | 连续的内存块(固定大小) | 动态分配的内存(指向对象的指针) |
数据类型 | 统一的数据类型(dtype) | 混合的数据类型(可以包含任意类型的对象) |
访问速度 | 高效的向量化操作 | 较慢的迭代访问 |
修改成本 | 低(视图和副本) | 高(需要重新分配内存) |
支持的运算 | 广泛的数学和科学计算功能 | 有限的列表操作 |
数据对齐 | 自动对齐(通过步长) | 无对齐 |
计算性能 | 高(利用C/C++实现) | 低(纯Python实现) |
文件读写 | 支持 .npy 和 .npz 文件格式 | 不支持二进制文件格式,需要额外的库支持 |
集成性 | 与 Pandas、Scikit-learn 等科学计算库高度集成 | 与标准库高度集成,但与其他科学计算库集成度较低 |
1.2.2 ndarray内存结构3D示意图
为了更好地理解 ndarray
的内存结构,我们绘制一个 3D 示意图,展示 ndarray
如何在内存中存储多维数组。
内存布局示意图(三维数组示例)
内存地址 | 0x1000 | 0x1004 | 0x1008 | 0x100C | 0x1010 | 0x1014 | … |
---|---|---|---|---|---|---|---|
三维索引 | [0,0,0] | [0,0,1] | [0,1,0] | [0,1,1] | [1,0,0] | [1,0,1] | … |
二维展开 | [0,0] | [0,1] | [1,0] | [1,1] | [2,0] | [2,1] | … |
一维展开 | 0 | 1 | 2 | 3 | 4 | 5 | … |
内存布局验证实验
import numpy as np# 创建基础数组
base_arr = np.arange(6, dtype=np.int32)
print(f"原始数组ID: {id(base_arr)}") # 输出原始数组内存地址# 创建视图
view_arr = base_arr[::2] # 步长切片创建视图
print(f"视图数组ID: {id(view_arr)}") # 地址不同但共享数据# 创建副本
copy_arr = base_arr.copy() # 完整内存复制
print(f"副本数组ID: {id(copy_arr)}") # 全新内存地址# 修改视图影响原始数组
view_arr[0] = 100
print("修改视图后的原始数组:", base_arr) # 输出[100 1 2 3 4 5]
1.2.3 维度(shape)、数据类型(dtype)、步长(strides)的关联关系
ndarray
的三个关键属性是 shape
(维度)、dtype
(数据类型)和 strides
(步长)。它们之间的关系如下:
- shape:表示数组的形状,即每个维度的大小。例如,
shape=(3, 3)
表示一个 3x3 的二维数组。 - dtype:表示数组中每个元素的数据类型。例如,
dtype=np.float64
表示数组中的元素是 64 位浮点数。 - strides:表示在内存中从一个元素移动到下一个元素所需的字节数。例如,在一个
shape=(3, 3)
、dtype=np.float64
的数组中,步长strides=(24, 8)
表示从一个行到下一个行需要移动 24 个字节,从一个列到下一个列需要移动 8 个字节。
步长计算公式推导:
对于形状为 ( d 1 , d 2 , . . . , d n ) (d_1,d_2,...,d_n) (d1,d2,...,dn)的数组,第 k k k维步长:
s t r i d e k = ( ∏ i = k + 1 n d i ) × i t e m s i z e stride_k = \left( \prod_{i=k+1}^{n} d_i \right) \times itemsize stridek=(i=k+1∏ndi)×itemsize
示例:三维数组(2,3,4),数据类型int32(4字节)
axis0_stride = 3*4*4 = 48 字节
axis1_stride = 4*4 = 16 字节
axis2_stride = 4 字节
1.2.4 不同初始化方式的内存分配对比(zeros vs empty)
NumPy 提供了多种初始化数组的方法,其中 np.zeros
和 np.empty
是两个常用的方法。我们将通过实验对比它们的内存分配方式。
import numpy as np# 创建一个 3x3 的零数组
zeros_array = np.zeros((3, 3), dtype=np.float64)
print("零数组:")
print(zeros_array)# 创建一个 3x3 的未初始化数组
empty_array = np.empty((3, 3), dtype=np.float64)
print("未初始化数组:")
print(empty_array)# 验证两个数组的内存地址
print("零数组的内存地址:", id(zeros_array))
print("未初始化数组的内存地址:", id(empty_array))# 验证两个数组的相同元素是否共享内存
a = zeros_array[0, 0]
b = empty_array[0, 0]
print("零数组的首元素内存地址:", id(a))
print("未初始化数组的首元素内存地址:", id(b))
注释:
# 导入 NumPy 库,并将其别名为 np
import numpy as np# 创建一个 3x3 的零数组
# np.zeros 是 NumPy 中用于创建全零数组的函数
# 传入数组的形状和数据类型作为参数
zeros_array = np.zeros((3, 3), dtype=np.float64)
print("零数组:") # 打印零数组
print(zeros_array)# 创建一个 3x3 的未初始化数组
# np.empty 是 NumPy 中用于创建未初始化数组的函数
# 传入数组的形状和数据类型作为参数
empty_array = np.empty((3, 3), dtype=np.float64)
print("未初始化数组:") # 打印未初始化数组
print(empty_array)# 验证两个数组的内存地址
# id() 函数用于获取对象的内存地址
print("零数组的内存地址:", id(zeros_array))
print("未初始化数组的内存地址:", id(empty_array))# 验证两个数组的相同元素是否共享内存
# 获取零数组和未初始化数组的首元素
a = zeros_array[0, 0]
b = empty_array[0, 0]
print("零数组的首元素内存地址:", id(a))
print("未初始化数组的首元素内存地址:", id(b))
1.2.5 数组元属性操作实验(shape修改的边界条件)
ndarray
的 shape
属性可以动态修改,但有一些边界条件需要遵守。我们将通过实验验证这些边界条件。
import numpy as np# 创建一个 3x3 的数组
array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float64)
print("原始数组:")
print(array)# 修改数组的形状为 1x9
array.shape = (1, 9)
print("修改后的数组(1x9):")
print(array)# 修改数组的形状为 9x1
array.shape = (9, 1)
print("修改后的数组(9x1):")
print(array)# 尝试修改数组的形状为 4x3
try:array.shape = (4, 3)
except ValueError as e:print("尝试修改形状为 4x3 时的错误:", e)# 尝试修改数组的形状为 3x3x3
try:array.shape = (3, 3, 3)
except ValueError as e:print("尝试修改形状为 3x3x3 时的错误:", e)# 修改数组的形状为 3x3
array.shape = (3, 3)
print("恢复数组形状为 3x3:")
print(array)
注释:
# 导入 NumPy 库,并将其别名为 np
import numpy as np# 创建一个 3x3 的数组
# np.array 是 NumPy 中用于创建数组的函数
# 传入二维列表,每个子列表代表数组的一行,指定数据类型为 64 位浮点数
array = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.float64)
print("原始数组:") # 打印原始数组
print(array)# 修改数组的形状为 1x9
# .shape 属性用于获取或设置数组的形状
array.shape = (1, 9)
print("修改后的数组(1x9):") # 打印修改后的数组
print(array)# 修改数组的形状为 9x1
array.shape = (9, 1)
print("修改后的数组(9x1):") # 打印修改后的数组
print(array)# 尝试修改数组的形状为 4x3
# 这将导致 ValueError,因为数组的总元素数(9)不等于目标形状的总元素数(12)
try:array.shape = (4, 3)
except ValueError as e:print("尝试修改形状为 4x3 时的错误:", e)# 尝试修改数组的形状为 3x3x3
# 这将导致 ValueError,因为数组的总元素数(9)不等于目标形状的总元素数(27)
try:array.shape = (3, 3, 3)
except ValueError as e:print("尝试修改形状为 3x3x3 时的错误:", e)# 修改数组的形状为 3x3
# 成功修改回原形状
array.shape = (3, 3)
print("恢复数组形状为 3x3:") # 打印恢复后的数组
print(array)
总结
通过这篇文章,我们深入解析了 NumPy 的 ndarray
的底层实现,探讨了其内存结构、维度、数据类型、步长等关键概念,并通过实验验证了这些概念的实际应用。希望这些内容能帮助你更好地理解和使用 NumPy。
参考文献或资料
参考资料名称 | 链接 |
---|---|
NumPy 官方文档 | https://numpy.org/doc/ |
Python 官方文档 | https://docs.python.org/3/ |
NumPy 入门指南 | https://numpy.org/devdocs/user/quickstart.html |
NumPy 源码分析 | https://github.com/numpy/numpy |
NumPy 速查表 | https://www.kaggle.com/learn/overview |
NumPy 实战案例 | https://www.tensorflow.org/tutorials/quickstart/beginner |
NumPy 书籍推荐 | https://www.springer.com/gp/book/9781484242452 |
NumPy 视频教程 | https://www.youtube.com/watch?v=QUT1VHiLmmI |
NumPy 交互式学习 | https://colab.research.google.com/ |
Python 内存管理 | https://docs.python.org/3/c-api/memory.html |
C 语言内存管理 | https://en.wikipedia.org/wiki/C_memory_allocation |
数据结构与算法 | https://www.geeksforgeeks.org/ |
深度学习中的数组操作 | https://pytorch.org/tutorials/beginner/basics/tensorqs_tutorial.html |
科学计算库对比 | https://www.tensorflow.org/compare |
高效计算技术 | https://en.wikipedia.org/wiki/High-performance_computing |
编程社区讨论 | https://stackoverflow.com/questions/tagged/numpy |
希望这篇文章能帮助你在 NumPy 的学习和使用中更进一步。这篇文章包含了详细的原理介绍、代码示例、源码注释以及案例等。希望这对您有帮助。如果有任何问题请随私信或评论告诉我。
相关文章:

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.2 ndarray解剖课:多维数组的底层实现
1.2 《ndarray解剖课:多维数组的底层实现》 内容介绍 NumPy 的 ndarray 是其核心数据结构,用于高效处理多维数组。在这篇文章中,我们将深入解析 ndarray 的底层实现,探讨其内存结构、维度、数据类型、步长等关键概念,…...

冯诺依曼架构和哈佛架构的主要区别?
冯诺依曼架构(Von Neumann Architecture)和哈佛架构(Harvard Architecture)是两种计算机体系结构,它们在存储器组织、指令处理和数据存取等方面有明显的不同。以下是它们的主要区别: 1.存储器结构 冯诺依曼…...

Gurobi基础语法之字典
Python中的字典:dict 我们先来介绍一下Python语法中的 dict 类型, 字典中可以通过任意键值来对数据进行映射,任何无法修改的python对象都可以当作键值来使用,这些无法修改的Python对象包括:整数(比如:1),浮…...

ceph新增节点,OSD设备,标签管理(二)
一、访问客户端集群方式 方式一: 使用cephadm shell交互式配置 [rootceph141 ~]# cephadm shell # 注意,此命令会启动一个新的容器,运行玩后会退出! Inferring fsid c153209c-d8a0-11ef-a0ed-bdb84668ed01 Inferring config /var/lib/ce…...

利用metaGPT多智能体框架实现智能体-2
1.一些帮助理解的概念 智能体 在MetaGPT看来,可以将智能体想象成环境中的数字人,其中 智能体 大语言模型(LLM) 观察 思考 行动 记忆 这个公式概括了智能体的功能本质。为了理解每个组成部分,让我们将其与人类进…...

Hadoop 与 Spark:大数据处理的比较
💖 欢迎来到我的博客! 非常高兴能在这里与您相遇。在这里,您不仅能获得有趣的技术分享,还能感受到轻松愉快的氛围。无论您是编程新手,还是资深开发者,都能在这里找到属于您的知识宝藏,学习和成长…...

Django 日志配置实战指南
日志是 Django 项目中不可或缺的一部分,它帮助我们记录应用程序的运行状态、调试信息、错误信息等。通过合理配置日志,我们可以更好地监控和调试应用程序。本文将详细介绍如何在 Django 项目中实现日志文件分割、日志级别控制以及多环境日志配置,并结合最佳实践和代码示例,…...

传输层协议TCP与UDP:深入解析与对比
传输层协议TCP与UDP:深入解析与对比 目录 传输层协议TCP与UDP:深入解析与对比引言1. 传输层协议概述2. TCP协议详解2.1 TCP的特点2.2 TCP的三次握手与四次挥手三次握手四次挥手 2.3 TCP的流量控制与拥塞控制2.4 TCP的可靠性机制 3. UDP协议详解3.1 UDP的…...

doris:JSON导入数据
本文介绍如何在 Doris 中导入 JSON 格式的数据文件。Doris 支持导入标准 JSON 格式数据,通过配置相关参数,可以灵活地处理不同的 JSON 数据结构,并支持从 JSON 数据中抽取字段、处理嵌套结构等场景。 导入方式 以下导入方式支持 JSON 格式…...

Ubuntu18.04 搭建DHCP服务器
在Ubuntu系统中,DHCP(动态主机配置协议)服务通常由isc-dhcp-server软件包提供。要配置和使用DHCP服务,你可以按照以下步骤操作: 1. 安装DHCP服务器 首先,你需要安装isc-dhcp-server。打开终端并输入以下命…...

Spring Boot 邂逅Netty:构建高性能网络应用的奇妙之旅
一、引言 在当今数字化时代,构建高效、可靠的网络应用是开发者面临的重要挑战。Spring Boot 作为一款强大的 Java 开发框架,以其快速开发、简洁配置和丰富的生态支持,深受广大开发者喜爱。而 Netty 作为高性能、异步的网络通信框架ÿ…...

【云安全】云原生-Docker(五)容器逃逸之漏洞利用
漏洞利用逃逸 通过漏洞利用实现逃逸,主要分为以下两种方式: 1、操作系统层面的内核漏洞 这是利用宿主机操作系统内核中的安全漏洞,直接突破容器的隔离机制,获得宿主机的权限。 攻击原理:容器本质上是通过 Linux 的…...

九、CSS工程化方案
一、PostCSS介绍 二、PostCSS插件的使用 项目安装 - npm install postcss-cli 全局安装 - npm install postcss-cli -g postcss-cli地址:GitHub - postcss/postcss-cli: CLI for postcss postcss地址:GitHub - postcss/postcss: Transforming styles…...

gradle创建springboot单项目和多模块项目
文章目录 gradle创建springboot项目gradle多模块项目创建 gradle创建springboot项目 适用IDEA很简单,如下图 gradle多模块项目创建 首选创建父项目,然后删除无用内容至下图 选择父项目目录,右键选择模块,创建子项目(…...

Vue实现div滚动,并且支持top动态滚动
如果你知道距离目标 div 顶部的像素值,并希望通过传入 top 参数来实现滚动到对应区域,可以使用 window.scrollTo 方法。 编写滚动方法 const scrollToDiv (targetDiv, top) > {if (targetDiv) {top top * targetDiv.value.scrollHeight / data.he…...

Elasticsearch 中,分片(Shards)数量上限?副本的数量?
概念 ElasticSearch高可用集群架构实战 分片数量1 在 Elasticsearch 中,分片(Shards)是数据存储和索引的基本单位。创建分片时需要考虑多个因素,包括集群的配置、硬件资源(如磁盘空间、内存等)以及性能要…...

Unity入门1
安装之后无法获得许可证,可以考虑重装 新建项目 单击空白处生成脚本 双击c#文件 会自动打开vstudio 检查引用 如果没有引用,重开vstu,或者重新加载项目 hierarchy层级 scenes场景 assets资产 inspector督察 icon图标 资源链接&…...

网络模型简介:OSI七层模型与TCP/IP模型
计算机网络是现代信息社会的基石,而网络通信的基础在于理解网络模型。网络模型是对通信过程的抽象,它帮助我们理解数据从源到目的地的传输过程。常见的网络模型有 OSI 七层模型 和 TCP/IP 模型,这两种模型在理论和实践中都起着重要作用。 一、…...

软件测试压力太大了怎么办?
本文其实是知乎上针对一个问题的回答: 目前在做软件测试,主要负责的是手机端的项目测试,项目迭代很快,每次上线前验正式都会发现一些之前验测试包时候没有发现的问题,压力太大了,应该怎么调整 看过我之前其…...

微信小程序-点餐(美食屋)02开发实践
目录 概要 整体架构流程 (一)用户注册与登录 (二)菜品浏览与点餐 (三)订单管理 (四)后台管理 部分代码展示 1.index.wxml 2.list.wxml 3.checkout.wxml 4.detail.wxml 小结优点 概要…...

转换算术表达式
文章目录 构造二叉树表示的算术表达式:按先序次序输入二叉树中结点的值(操作数及运算符均以一位字符表示,注意转换), #字符表示空树,如上图的算术表达式 输入2##*3##4## 输入格式 第一行输入表示要计算的算术表达式的二叉树结点的…...

99.17 金融难点通俗解释:归母净利润
目录 0. 承前1. 简述2. 比喻:小明家的小卖部2.1 第一步:计算收到的所有钱2.2 第二步:减去各种支出2.3 第三步:计算能带回家的钱 3. 生活中的例子3.1 好的经营情况3.2 一般的经营情况3.3 不好的经营情况 4. 小朋友要注意4.1 为什么…...

【Flutter】旋转元素(Transform、RotatedBox )
这里写自定义目录标题 Transform旋转元素可以改变宽高约束的旋转 - RotatedBox Transform旋转元素 说明:Transform旋转操作改变了元素的方向,但并没有改变它的布局约束。因此,虽然视觉上元素看起来是旋转了,但它仍然遵循原始的宽…...

MYSQL学习笔记(六):聚合函数、sql语句执行原理简要分析
前言: 学习和使用数据库可以说是程序员必须具备能力,这里将更新关于MYSQL的使用讲解,大概应该会更新30篇,涵盖入门、进阶、高级(一些原理分析);这一篇是内容较少,主要讲解:聚合函数和简要介绍sql语句执行过…...

thinkphp6+swoole使用rabbitMq队列
安装think-swoole安装 composer require php-amqplib/php-amqplib,以支持rabbitMq使用安装rabbitMq延迟队列插件 安装 rabbitmq_delayed_message_exchange 插件,按照以下步骤操作: 下载插件:https://github.com/rabbitmq/rabbitmq-delayed-…...

大模型开发 | RAG在实际开发中可能遇到的坑
近年来,大语言模型 (LLM) 的飞速发展令人瞩目,它们在各个领域展现出强大的应用潜力。然而,LLM 也存在一些固有的局限性,例如知识更新滞后、信息编造 (幻觉) 等问题。为了克服这些挑战,检索增强生成 (Retrieval-Augment…...

mybatis是什么?有什么作用?mybatis的简单使用
mybatis是什么? MyBatis 是一个持久层框架。 有什么作用? 简化了对数据库数据的操作。 如何简化数据操作的? MyBatis 通过提供 SQL 映射、动态 SQL、结果映射、事务管理等功能,我们直接去用就可以了。 怎么使用?&…...

求平均年龄(信息学奥赛一本通-1059)
【题目描述】 班上有学生若干名,给出每名学生的年龄(整数),求班上所有学生的平均年龄,保留到小数点后两位。 【输入】 第一行有一个整数n(1≤n≤100),表示学生的人数。其后n行每行有…...

CY T 4 BB 5 CEB Q 1 A EE GS MCAL配置 - MCU组件
1、ResourceM 配置 选择芯片信号: 2、MCU 配置 2.1 General配置 1) McuDevErrorDetect: - 启用或禁用MCU驱动程序模块的开发错误通知功能。 - 注意:采用DET错误检测机制作为安全机制(故障检测)时,不能禁用开发错误检测。2) McuGetRamStateApi - enable/disable th…...

10 Hyperledger Fabric 介绍
简介 HypeLedger(超级账本)是由Linux基金会2015年创建的首个面向企业应用场景的开源分布式账本平台。 HypeLedger Fabric是HypeLedger种的区块链项目之一HypeLedger Fabric引入权限管理在架构设计上支持可插拔、可扩展是首个面向联盟链场景的开源项目 …...