当前位置: 首页 > news >正文

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.2 ndarray解剖课:多维数组的底层实现

在这里插入图片描述

1.2 《ndarray解剖课:多维数组的底层实现》

内容介绍

NumPy 的 ndarray 是其核心数据结构,用于高效处理多维数组。在这篇文章中,我们将深入解析 ndarray 的底层实现,探讨其内存结构、维度、数据类型、步长等关键概念,并通过实验验证这些概念的实际应用。

1.2.1 ndarray与Python列表的核心差异

ndarray 和 Python 列表是两种不同的数据结构,它们在内存布局和性能上有显著的差异。下面是 ndarray 和 Python 列表的核心差异对比表:

特性ndarrayPython 列表
内存布局连续的内存块(固定大小)动态分配的内存(指向对象的指针)
数据类型统一的数据类型(dtype)混合的数据类型(可以包含任意类型的对象)
访问速度高效的向量化操作较慢的迭代访问
修改成本低(视图和副本)高(需要重新分配内存)
支持的运算广泛的数学和科学计算功能有限的列表操作
数据对齐自动对齐(通过步长)无对齐
计算性能高(利用C/C++实现)低(纯Python实现)
文件读写支持 .npy 和 .npz 文件格式不支持二进制文件格式,需要额外的库支持
集成性与 Pandas、Scikit-learn 等科学计算库高度集成与标准库高度集成,但与其他科学计算库集成度较低
1.2.2 ndarray内存结构3D示意图

为了更好地理解 ndarray 的内存结构,我们绘制一个 3D 示意图,展示 ndarray 如何在内存中存储多维数组。

元数据
内存块
3, 3
维度 (shape)
8 (64-bit float)
数据类型 (dtype)
(24, 8)
步长 (strides)
元素1
数据
元素2
元素3
元素4
元素5
元素6
元素7
元素8
元素9
NumPy ndarray
内存块
元数据

内存布局示意图(三维数组示例)

内存地址0x10000x10040x10080x100C0x10100x1014
三维索引[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]
一维展开012345

内存布局验证实验

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+1ndi)×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.zerosnp.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修改的边界条件)

ndarrayshape 属性可以动态修改,但有一些边界条件需要遵守。我们将通过实验验证这些边界条件。

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 的底层实现,探讨其内存结构、维度、数据类型、步长等关键概念&#xff0c…...

冯诺依曼架构和哈佛架构的主要区别?

冯诺依曼架构(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 作为高性能、异步的网络通信框架&#xff…...

【云安全】云原生-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多模块项目创建 首选创建父项目,然后删除无用内容至下图 选择父项目目录,右键选择模块,创建子项目&#xff08…...

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 小结优点 概要…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter

java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用&#xff08;Math::max&#xff09; 2 函数接口…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...

CppCon 2015 学习:Reactive Stream Processing in Industrial IoT using DDS and Rx

“Reactive Stream Processing in Industrial IoT using DDS and Rx” 是指在工业物联网&#xff08;IIoT&#xff09;场景中&#xff0c;结合 DDS&#xff08;Data Distribution Service&#xff09; 和 Rx&#xff08;Reactive Extensions&#xff09; 技术&#xff0c;实现 …...

运动控制--BLDC电机

一、电机的分类 按照供电电源 1.直流电机 1.1 有刷直流电机(BDC) 通过电刷与换向器实现电流方向切换&#xff0c;典型应用于电动工具、玩具等 1.2 无刷直流电机&#xff08;BLDC&#xff09; 电子换向替代机械电刷&#xff0c;具有高可靠性&#xff0c;常用于无人机、高端家电…...

Redis专题-实战篇一-基于Session和Redis实现登录业务

GitHub项目地址&#xff1a;https://github.com/whltaoin/redisLearningProject_hm-dianping 基于Session实现登录业务功能提交版本码&#xff1a;e34399f 基于Redis实现登录业务提交版本码&#xff1a;60bf740 一、导入黑马点评后端项目 项目架构图 1. 前期阶段2. 后续阶段导…...

2025年上海市“星光计划”第十一届职业院校技能大赛 网络安全赛项技能操作模块样题

2025年上海市“星光计划”第十一届职业院校技能大赛 网络安全赛项技能操作模块样题 &#xff08;二&#xff09;模块 A&#xff1a;安全事件响应、网络安全数据取证、应用安全、系统安全任务一&#xff1a;漏洞扫描与利用:任务二&#xff1a;Windows 操作系统渗透测试 :任务三&…...

window安装docker\docker-compose

安装前配置 打开控制面板,参照下图打开“启动或关闭windows功能”,Hyper-V 和容器需要启用 程序和功能 启动或关闭windows功能 勾选Hyper-V 安装路径配置 Docker在Windows上的默认安装路径为C:\Program Files\Docker。 以管理员身份运行CMD在D盘,dev文件夹下创建Docker文…...

模拟搭建私网访问外网、外网访问服务器服务的实践操作

目录 实验环境 实践要求 一、准备工作 1、准备四台虚拟机&#xff0c;分别标号 2、 防火墙额外添加两块网卡&#xff0c;自定义网络连接模式 3、 关闭虚拟机的图形管理工具 4、关闭防火墙 5、分别配置四台虚拟机的IP地址&#xff0c;此处举一个例子&#xff08;使用的临…...