【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 的底层实现,探讨其内存结构、维度、数据类型、步长等关键概念,…...
计算机网络 (61)移动IP
前言 移动IP(Mobile IP)是由Internet工程任务小组(Internet Engineering Task Force,IETF)提出的一个协议,旨在解决移动设备在不同网络间切换时的通信问题,确保移动设备可以在离开原有网络或子网…...
css粘性定位超出指定宽度失效问题
展示效果 解决办法:外层容器添加display:grid即可 完整代码 <template><div class"box"><div class"line" v-for"items in 10"><div class"item" v-for"item in 8">drgg</div>&…...
10 Hyperledger Fabric 介绍
简介 HypeLedger(超级账本)是由Linux基金会2015年创建的首个面向企业应用场景的开源分布式账本平台。 HypeLedger Fabric是HypeLedger种的区块链项目之一HypeLedger Fabric引入权限管理在架构设计上支持可插拔、可扩展是首个面向联盟链场景的开源项目 …...
AI Agent的多轮对话:提升用户体验的关键技巧
在前面的文章中,我们讨论了 AI Agent 的各个核心系统。今天,我想聊聊如何实现一个好用的多轮对话系统。说实话,这个话题我琢磨了很久,因为它直接影响到用户体验。 从一个槽点说起 还记得我最开始做对话系统时的一个典型场景&…...
分布式光纤应变监测是一种高精度、分布式的监测技术
一、土木工程领域 桥梁结构健康监测 主跨应变监测:在大跨度桥梁的主跨部分,如悬索桥的主缆、斜拉桥的斜拉索和主梁,分布式光纤应变传感器可以沿着这些关键结构部件进行铺设。通过实时监测应变情况,能够精确捕捉到车辆荷载、风荷…...
机器学习10-解读CNN代码Pytorch版
机器学习10-解读CNN代码Pytorch版 我个人是Java程序员,关于Python代码的使用过程中的相关代码事项,在此进行记录 文章目录 机器学习10-解读CNN代码Pytorch版1-核心逻辑脉络2-参考网址3-解读CNN代码Pytorch版本1-MNIST数据集读取2-CNN网络的定义1-无注释版…...
面向程序员的Lean 4教程(2) - 数组和列表
面向程序员的Lean 4教程(2) - 数组和列表 上一节我们介绍了Lean4的基本语法,因为大部分程序员都有一定的编程基础,所以并没有介绍过细。这一节我们介绍Lean4中的线性表结构:数组和列表,顺带复习一下上一节的流程控制等内容。 数…...
【C++高并发服务器WebServer】-7:共享内存
本文目录 一、共享内存1.1 shmget函数1.2 shmat1.3 shmdt1.4 shmctl1.5 ftok1.6 共享内存和内存映射的关联1.7 小demo 二、共享内存操作命令 一、共享内存 共享内存允许两个或者多个进程共享物理内存的同一块区域(通常被称为段)。由于一个共享内存段会称…...
【力扣Hot 100】链表1
1. 相交链表 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 图示两个链表在节点 c1 开始相交**:** !https://assets.leetcode-cn.com/aliyun-lc-upload/uplo…...
稀土抗菌剂:提升产品质量,保障公共健康
随着全球对抗菌技术需求的不断增长,传统的抗菌剂逐渐暴露出其局限性,包括耐药性、环境污染及副作用等问题。在此背景下,稀土抗菌剂作为一种新兴的抗菌材料,凭借其卓越的抗菌性能、环保特性以及应用多样性,正在成为各行…...
机器学习11-学习路径推荐
机器学习11-学习路径推荐 本文希望摒除AI学习商业宣传要素,推荐一条极简的AI学习路线!推荐内容均为在线免费内容,如果有条件可以咨询专业的培训机构! 文章目录 机器学习11-学习路径推荐[toc] 1-AI培训路线第一阶段 Python-人工智能…...
postgresql根据主键ID字段分批删除表数据
生产环境针对大表的处理相对比较麻烦。 方案1、直接truncate,可能会遇到系统卡主的情况,因为truncate的过程中会对表进行加锁,会导致数据不能正常的写入 方案2、创建一个同结构的表结构,rename旧表,不停业务rename表担…...
《边界感知的分而治之方法:基于扩散模型的无监督阴影去除解决方案》学习笔记
paper:Boundary-Aware Divide and Conquer: A Diffusion-Based Solution for Unsupervised Shadow Removal 目录 摘要 1、介绍 2、相关工作 2.1 阴影去除 2.2 去噪扩散概率模型(Denoising Diffusion Probabilistic Models, DDPM) 3、方…...
java后端之事务管理
Transactional注解:作用于业务层的方法、类、接口上,将当前方法交给spring进行事务管理,执行前开启事务,成功执行则提交事务,执行异常回滚事务 spring事务管理日志: 默认情况下,只有出现Runti…...
深入浅出 SQLSugar:快速掌握高效 .NET ORM 框架
SQLSugar 是一个高效、易用的 .NET ORM 框架,支持多种数据库(如 SQL Server、MySQL、PostgreSQL 等)。它提供了丰富的功能,包括 CRUD 操作、事务管理、动态表名、多表联查等,开发者可以通过简单的链式操作实现复杂的数…...
数据结构——概念与时间空间复杂度
目录 前言 一相关概念 1什么是数据结构 2什么是算法 二算法效率 1如何衡量算法效率的好坏 2算法的复杂度 三时间复杂度 1时间复杂度表示 2计算时间复杂度 2.1题一 2.2题二 2.3题三 2.4题四 2.5题五 2.6题六 2.7题七 2.8题八 四空间复杂度 1题一 2题二 3…...
浅谈在AI时代GIS的发展方向和建议
在AI时代,GIS(地理信息系统)的发展正经历着深刻的变革,随着人工智能技术的进步,GIS不再仅仅是传统的地图和空间数据处理工具,而是向更加智能化、自动化、精准化的方向发展。作为一名GIS开发工程师ÿ…...
牛客周赛 Round 78 A-C
A.时间表查询! 链接:https://ac.nowcoder.com/acm/contest/100671/A 来源:牛客网 题目描述 今天是2025年1月25日,今年的六场牛客寒假算法基础集训营中,前两场比赛已经依次于 20250121、20250123 举行;而…...
Java I/O 流介绍
Java学习资料 Java学习资料 Java学习资料 一、引言 在 Java 编程中,I/O(Input/Output)流是处理输入和输出操作的核心机制。它允许程序与外部设备(如文件、网络连接、键盘、显示器等)进行数据交互。通过使用 I/O 流&…...
linux 内核学习方向以及职位
### 学习路径 1. 基础阶段: - C语言高级特性 - 指针和内存管理 - 数据结构实现 - 位操作 - 多线程编程 - Linux系统编程 - 文件I/O操作 - 进程管理 - 信号处理 - IPC机制 - Socket编程 - 必备知识 - 操作系统原理 - 计算机体系结构 - …...
HTML-新浪新闻-实现标题-样式1
用css进行样式控制 css引入方式: --行内样式:写在标签的style属性中(不推荐) --内嵌样式:写在style标签中(可以写在页面任何位置,但通常约定写在head标签中) --外联样式…...
【电磁兼容】CE 传导骚扰
一。是什么? 传导骚扰是指电气或电子设备产生的不需要的电磁能量,这些能量通过导线或其他金属路径传播到其他设备或者系统中。这种类型的干扰通常发生在同一电源线路连接的不同装置之间,或者是共享相同布线系统的组件间。 传导骚扰可以分为两…...
能说说MyBatis的工作原理吗?
大家好,我是锋哥。今天分享关于【Redis为什么这么快?】面试题。希望对大家有帮助; 能说说MyBatis的工作原理吗? MyBatis 是一款流行的持久层框架,它通过简化数据库操作,帮助开发者更高效地与数据库进行交互。MyBatis…...
詳細講一下RN(React Native)中的列表組件FlatList和SectionList
1. FlatList 基礎使用 import React from react; import { View, Text, FlatList, StyleSheet } from react-native;export const SimpleListDemo: React.FC () > {// 1. 準備數據const data [{ id: 1, title: 項目 1 },{ id: 2, title: 項目 2 },{ id: 3, title: 項目 3…...
LabVIEW进行可靠性测试时有哪些常见的问题
在进行LabVIEW开发和测试时,尤其是用于可靠性测试,可能会遇到一些常见的问题。以下是一些常见问题及其解决方法: 1. 数据采集卡与硬件兼容性问题 问题描述:某些数据采集卡(DAQ)与硬件设备的兼容性问题可能…...
MFC程序设计(四)窗口创建机制
钩子函数 钩子属于win32技术,具有优先勾取消息的权利:当一个消息产生时,钩子勾取消息进行处理,然后消息才送回程序 接下来以一个勾取窗口创建消息的钩子为例进行讲解 钩子类型有键盘钩子,鼠标钩子,WH_CBT…...
【JavaEE进阶】Spring留言板实现
目录 🎍预期结果 🍀前端代码 🎄约定前后端交互接口 🚩需求分析 🚩接口定义 🌳实现服务器端代码 🚩lombok介绍 🚩代码实现 🌴运行测试 🎄前端代码实…...
Unity开发一个单人FPS游戏的教程总结
这个系列的前几篇文章介绍了如何从头开始用Unity开发一个FPS游戏,感兴趣的朋友可以回顾一下。这个系列的文章如下: Unity开发一个FPS游戏_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个FPS游戏之二_unity 模仿开发fps 游戏-CSDN博客 Unity开发一个F…...
论文速读|Is Cosine-Similarity of Embeddings Really About Similarity?WWW24
论文地址: https://arxiv.org/abs/2403.05440 https://dl.acm.org/doi/abs/10.1145/3589335.3651526 bib引用: inproceedings{Steck_2024, series{WWW ’24},title{Is Cosine-Similarity of Embeddings Really About Similarity?},url{http://dx.doi.o…...
