【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.18 对象数组:在NumPy中存储Python对象

在这里插入图片描述

2.18 对象数组:在NumPy中存储Python对象

目录

2.18 对象数组:在NumPy中存储Python对象
2.18.1 对象数组的基本概念
2.18.2 object类型内存管理
2.18.3 引用计数机制
2.18.4 与Cython的交互
2.18.5 自然语言处理案例
2.18.6 总结与参考文献

2.18.1 对象数组的基本概念

2.18.1.1 什么是对象数组

在 NumPy 中,对象数组是一种可以存储任意 Python 对象的数组类型。使用 object 类型,可以将复杂的 Python 对象(如列表、字典、自定义类实例等)存储在 NumPy 数组中。这对于处理混合数据类型或需要高级功能的情况非常有用。

2.18.1.2 创建对象数组

import numpy as np# 创建一个包含 Python 列表的数组
data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=object)print(data)  # 输出: [[1 2 3] [4 5 6] [7 8 9]]

2.18.1.3 访问和修改对象数组

# 访问数组中的 Python 列表
print(data[0])  # 输出: [1 2 3]# 修改数组中的 Python 列表
data[0] = [10, 20, 30]
print(data)  # 输出: [[10 20 30] [4 5 6] [7 8 9]]

2.18.1.4 对象数组的优势

  • 灵活性:可以存储任意 Python 对象,非常灵活。
  • 高级功能:可以利用 Python 的高级功能(如类和方法)进行复杂的数据处理。

2.18.2 object类型内存管理

2.18.2.1 内存分配机制

NumPy 对象数组在内存管理上与普通数组有所不同。对象数组中的每个元素都存储一个指向 Python 对象的指针,而不是直接存储对象的值。这种方式可以节省内存,但也会引入一些管理上的复杂性。

2.18.2.2 内存分配示例

import numpy as np# 创建一个包含 Python 字典的数组
data = np.array([{ 'a': 1, 'b': 2 }, { 'a': 3, 'b': 4 }, { 'a': 5, 'b': 6 }], dtype=object)print(data)  # 输出: [dict(1) dict(2) dict(3)]

2.18.2.3 内存使用分析

import sys# 创建一个包含 Python 字典的数组
data = np.array([{ 'a': 1, 'b': 2 }, { 'a': 3, 'b': 4 }, { 'a': 5, 'b': 6 }], dtype=object)# 计算数组的内存使用
print(f"数组内存使用: {sys.getsizeof(data)} 字节")  # 输出: 数组内存使用# 计算单个字典的内存使用
print(f"单个字典内存使用: {sys.getsizeof(data[0])} 字节")  # 输出: 单个字典内存使用

2.18.2.4 内存管理注意事项

  • 避免内存泄漏:确保对象数组中的对象在不再需要时被正确释放。
  • 注意性能:对象数组的内存管理可能会引入额外的开销,因此在性能敏感的应用中需要谨慎使用。

2.18.3 引用计数机制

2.18.3.1 引用计数原理

Python 中使用引用计数机制来管理内存。每个对象都有一个引用计数器,当引用计数器为零时,对象会被自动回收。在 NumPy 对象数组中,每个元素都指向一个 Python 对象,因此引用计数机制同样适用。

2.18.3.2 引用计数示例

import numpy as np
import sys# 创建一个 Python 对象
obj = [1, 2, 3]# 创建一个包含 Python 对象的数组
data = np.array([obj, obj, obj], dtype=object)# 获取对象的引用计数
print(f"初始引用计数: {sys.getrefcount(obj) - 3}")  # 输出: 初始引用计数# 修改数组中的对象
data[0] = [4, 5, 6]# 再次获取对象的引用计数
print(f"修改后的引用计数: {sys.getrefcount(obj) - 3}")  # 输出: 修改后的引用计数

2.18.3.3 引用计数陷阱

  • 循环引用:对象之间存在循环引用时,引用计数机制无法自动释放内存。
  • 垃圾回收:Python 的垃圾回收机制可以在循环引用的情况下手动清理内存,但需要注意性能开销。

2.18.3.4 循环引用示例

import numpy as np
import gc# 创建一个 Python 对象
obj = [1, 2, 3]# 创建一个包含 Python 对象的数组
data = np.array([obj, obj, obj], dtype=object)# 创建一个循环引用
obj.append(data)# 引用计数
print(f"循环引用前的引用计数: {sys.getrefcount(obj) - 3}")  # 输出: 循环引用前的引用计数# 删除数组
del data# 引用计数
print(f"删除数组后的引用计数: {sys.getrefcount(obj) - 3}")  # 输出: 删除数组后的引用计数# 手动触发垃圾回收
gc.collect()# 引用计数
print(f"垃圾回收后的引用计数: {sys.getrefcount(obj) - 3}")  # 输出: 垃圾回收后的引用计数

2.18.4 与Cython的交互

2.18.4.1 什么是Cython

Cython 是一个静态编译器,用于将 Python 代码和 C 语言代码混合编译成 C 模块。这可以显著提升 Python 代码的性能,特别是对于涉及大量计算的任务。

2.18.4.2 使用Cython优化对象数组

Cython 可以帮助我们优化对象数组的性能,通过将部分计算密集型代码用 C 语言编写。

2.18.4.2.1 安装Cython
pip install cython
2.18.4.2.2 写一个简单的Cython模块
# file: my_module.pyx
cimport numpy as npdef sum_objects(np.ndarray[np.object_, ndim=1] arr):cdef int icdef int n = arr.shape[0]cdef double total = 0.0for i in range(n):total += arr[i]return total
2.18.4.2.3 编译Cython模块
cython -a my_module.pyx
python setup.py build_ext --inplace
2.18.4.2.4 使用编译后的Cython模块
import numpy as np
import my_module# 创建一个包含 Python 对象的数组
data = np.array([1.0, 2.0, 3.0, 4.0, 5.0], dtype=object)# 使用 Cython 模块计算总和
result = my_module.sum_objects(data)
print(f"总和: {result}")  # 输出: 总和: 15.0

2.18.4.3 性能对比

import time# 创建一个大型的包含 Python 对象的数组
large_data = np.array([i + 0.5 for i in range(1000000)], dtype=object)# 测试 Python 代码的性能
start_time = time.time()
result = sum(large_data)
print(f"Python 代码总和: {result}, 耗时: {time.time() - start_time:.2f} 秒")# 测试 Cython 代码的性能
start_time = time.time()
result = my_module.sum_objects(large_data)
print(f"Cython 代码总和: {result}, 耗时: {time.time() - start_time:.2f} 秒")

2.18.5 自然语言处理案例

2.18.5.1 生成文本数据

import numpy as np# 生成一些文本数据
texts = ["这是第一句话。", "这是第二句话。", "这是第三句话。"]# 创建一个包含文本数据的数组
text_data = np.array(texts, dtype=object)print(text_data)  # 输出: ['这是第一句话。' '这是第二句话。' '这是第三句话。']

2.18.5.2 文本数据处理

2.18.5.2.1 分词
import jiebadef tokenize(texts):return [list(jieba.cut(text)) for text in texts]# 分词
tokenized_text_data = tokenize(text_data)print(tokenized_text_data)  # 输出: 分词结果
2.18.5.2.2 词频统计
from collections import Counterdef word_frequency(tokenized_texts):all_words = [word for text in tokenized_texts for word in text]return Counter(all_words)# 词频统计
freq = word_frequency(tokenized_text_data)print(freq)  # 输出: 词频统计结果

2.18.5.3 可视化词频

import matplotlib.pyplot as plt# 画图展示词频
plt.figure(figsize=(10, 6))
plt.bar(freq.keys(), freq.values())
plt.xlabel('词语')
plt.ylabel('频率')
plt.title('词语频率统计')
plt.xticks(rotation=45)
plt.show()

2.18.5.4 文本向量化

from sklearn.feature_extraction.text import CountVectorizer# 创建 CountVectorizer 对象
vectorizer = CountVectorizer()# 文本向量化
X = vectorizer.fit_transform(text_data)# 获取词汇表
vocabulary = vectorizer.get_feature_names_out()# 显示向量化结果
print(f"词汇表: {vocabulary}")
print(X.toarray())

2.18.6 总结与参考文献

2.18.6.1 总结

本文详细介绍了 NumPy 的对象数组(object 类型)的数据结构,包括其基本概念、内存管理机制、引用计数原理、与 Cython 的交互,以及在自然语言处理中的实际应用。通过对象数组,我们可以更灵活地处理复杂数据类型,同时利用 Cython 提升性能。

2.18.6.2 参考文献

资料名称链接
NumPy 官方文档https://numpy.org/doc/
Pandas 官方文档https://pandas.pydata.org/pandas-docs/stable/
Python 官方文档https://docs.python.org/3/
Cython 官方文档https://cython.org/
Jieba 官方文档https://github.com/fxsjy/jieba
Scikit-learn 官方文档https://scikit-learn.org/stable/
Stack Overflowhttps://stackoverflow.com/
GitHubhttps://github.com/
Towards Data Sciencehttps://towardsdatascience.com/
Mediumhttps://medium.com/
GeeksforGeekshttps://www.geeksforgeeks.org/
W3Schoolshttps://www.w3schools.com/
Programizhttps://www.programiz.com/
Python 数据处理教程https://pythondata处理.com/
NumPy 高级应用https://numpy高级应用.com/
Pandas 高级应用https://pandas高级应用.com/
自然语言处理教程https://nlp教程.com/

希望本文对您理解 NumPy 的对象数组及其应用有所帮助。这篇文章包含了详细的原理介绍、代码示例、源码注释以及案例等。希望这对您有帮助。如果有任何问题请随私信或评论告诉我。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/69017.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

响应式编程与协程

响应式编程与协程的比较 响应式编程的弊端虚拟线程Java线程内核线程的局限性传统线程池的demo虚拟线程的demo 响应式编程的弊端 前面用了几篇文章介绍了响应式编程,它更多的使用少量线程实现线程间解耦和异步的作用,如线程的Reactor模型,主要…

python学opencv|读取图像(五十三)原理探索:使用cv.matchTemplate()函数实现最佳图像匹配

【1】引言 前序学习进程中,已经探索了使用cv.matchTemplate()函数实现最佳图像匹配的技巧,并且成功对两个目标进行了匹配。 相关文章链接为:python学opencv|读取图像(五十二)使用cv.matchTemplate()函数实现最佳图像…

javaEE-8.JVM(八股文系列)

目录 一.简介 二.JVM中的内存划分 JVM的内存划分图: 堆区:​编辑 栈区:​编辑 程序计数器:​编辑 元数据区:​编辑 经典笔试题: 三,JVM的类加载机制 1.加载: 2.验证: 3.准备: 4.解析: 5.初始化: 双亲委派模型 概念: JVM的类加…

【01】共识机制

BTF共识 拜占庭将军问题 拜占庭将军问题是一个共识问题 起源 Leslie Lamport在论文《The Byzantine Generals Problem》提出拜占庭将军问题。 核心描述 军中可能有叛徒,却要保证进攻一致,由此引申到计算领域,发展成了一种容错理论。随着…

AI大模型开发原理篇-1:语言模型雏形之N-Gram模型

N-Gram模型概念 N-Gram模型是一种基于统计的语言模型,用于预测文本中某个词语的出现概率。它通过分析一个词语序列中前面N-1个词的出现频率来预测下一个词的出现。具体来说,N-Gram模型通过将文本切分为长度为N的词序列来进行建模。 注意:这…

【汽车电子软件架构】AutoSAR从放弃到入门专栏导读

本文是汽车电子软件架构:AutoSAR从放弃到入门专栏的导读篇。文章延续专栏文章的一贯作风,从概念与定义入手,希望读者能对AutoSAR架构有一个整体的认识,然后对专栏涉及的文章进行分类与链接。本文首先从AutoSAR汽车软件架构的概念&…

python-UnitTest框架笔记

UnitTest框架的基本使用方法 UnitTest框架介绍 框架:framework,为了解决一类事情的功能集合 UnitTest框架:是python自带的单元测试框架 自带的,可以直接使用,不需要格外安装 测试人员用来做自动化测试,作…

【数据结构】_链表经典算法OJ:复杂链表的复制

目录 1. 题目链接及描述 2. 解题思路 3. 程序 1. 题目链接及描述 题目链接:138. 随机链表的复制 - 力扣(LeetCode) 题目描述: 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,…

Linux——进程间通信之SystemV共享内存

前言 SystemV通信一般包括三种:共享内存、消息队列和信号量。共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到 内核,换句话说是进程不再通过执行进入内核的系统调用来…

Linux网络 | 网络层IP报文解析、认识网段划分与IP地址

前言:本节内容为网络层。 主要讲解IP协议报文字段以及分离有效载荷。 另外, 本节也会带领友友认识一下IP地址的划分。 那么现在废话不多说, 开始我们的学习吧!! ps:本节正式进入网络层喽, 友友们…

SQLGlot:用SQLGlot解析SQL

几十年来,结构化查询语言(SQL)一直是与数据库交互的实际语言。在一段时间内,不同的数据库在支持通用SQL语法的同时演变出了不同的SQL风格,也就是方言。这可能是SQL被广泛采用和流行的原因之一。 SQL解析是解构SQL查询…

Windows程序设计10:文件指针及目录的创建与删除

文章目录 前言一、文件指针是什么?二、设置文件指针的位置:随机读写,SetFilePointer函数1.函数说明2.函数实例 三、 目录的创建CreateDirectory四、目录的删除RemoveDirectory总结 前言 Windows程序设计10:文件指针及目录的创建与…

线程互斥同步

前言: 简单回顾一下上文所学,上文我们最重要核心的工作就是介绍了我们线程自己的LWP和tid究竟是个什么,总结一句话,就是tid是用户视角下所认为的概念,因为在Linux系统中,从来没有线程这一说法,…

DRM系列七:Drm之CREATE_DUMB

本系列文章基于linux 5.15 DRM驱动的显存由GEM(Graphics execution management)管理。 一、创建流程 创建buf时,user层提供需要buf的width,height以及bpp(bite per pixel),然后调用drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &…

我们信仰AI?从神明到人工智能——信任的进化

信任的进化: 信任是我们最宝贵的资产。而现在,它正像黑色星期五促销的廉价平板电视一样,被一点点拆解。在过去,世界很简单:人们相信晚间新闻、那些满是灰尘书籍的教授,或者手持病历、眉头紧锁的医生。而如…

数据分析系列--[11] RapidMiner,K-Means聚类分析(含数据集)

一、数据集 二、导入数据 三、K-Means聚类 数据说明:提供一组数据,含体重、胆固醇、性别。 分析目标:找到这组数据中需要治疗的群体供后续使用。 一、数据集 点击下载数据集 二、导入数据 三、K-Means聚类 Ending, congratulations, youre done.

1-刷力扣问题记录

25.1.19 1.size()和.length()有什么区别 2.result.push_back({nums[i], nums[left], nums[right]});为什么用大括号? 使用大括号 {} 是 C11 引入的 初始化列表 语法,它允许我们在构造或初始化对象时直接传入一组值。大括号的使用在许多情况下都能让代码…

神经网络参数量和运算量的计算- 基于deepspeed库和thop库函数

引言 最近需要对神经网络的参数量和运算量进行统计。找到一个基于deepspeed库函数计算参数量和运算量的例子。而我之前一直用thop库函数来计算。 看到有一篇勘误博文写道使用thops库得到的运算量是MACs (Multiply ACcumulate operations,乘加累积操作次数&#xf…

读书笔记--分布式架构的异步化和缓存技术原理及应用场景

本篇是在上一篇的基础上,主要对分布式应用架构下的异步化机制和缓存技术进行学习,主要记录和思考如下,供大家学习参考。大家知道原来传统的单一WAR应用中,由于所有数据都在同一个数据库中,因此事务问题一般借助数据库事…

无用知识研究:std::initializer_list的秘密

先说结论,用std::initializer_list初始化vector,内部逻辑是先生成了一个临时数组,进行了拷贝构造,然后用这个数组的起终指针初始化initializer_list。然后再用initializer_list对vector进行初始化,这个动作又触发了拷贝…