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

【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 np

def sum_objects(np.ndarray[np.object_, ndim=1] arr):
    cdef int i
    cdef int n = arr.shape[0]
    cdef double total = 0.0

    for 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 jieba

def 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 Counter

def 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.kler.cn/a/531952.html

相关文章:

  • k8s二进制集群之ETCD集群证书生成
  • pytorch实现变分自编码器
  • 在线知识库的构建策略提升组织信息管理效率与决策能力
  • 玉米苗和杂草识别分割数据集labelme格式1997张3类别
  • 结构体DMA串口接收比特错位
  • 15 刚体变换模块(rigid.rs)
  • 记录 | 基于MaxKB的文字生成视频
  • Leetcode680:验证回文串 II
  • 物业管理平台系统为社区管理带来数字化转型与服务创新新机遇
  • 高阶开发基础——快速入门C++并发编程5 信号量的使用
  • 自定义数据集 使用paddlepaddle框架实现逻辑回归
  • 农历2025开始 笔记
  • 基于STM32的智能健康监测手环
  • Sqoop导入MySQL中含有回车换行符的数据
  • 【Deep Seek本地化部署】修改模型保存位置
  • (done) MIT6.S081 2023 学习笔记 (Day7: LAB6 Multithreading)
  • 【C++】继承(下)
  • 吴恩达深度学习——卷积神经网络基础
  • GESP2023年12月认证C++六级( 第三部分编程题(1)闯关游戏)
  • PyQt4学习笔记1】使用QWidget创建窗口
  • Kubernetes服务网格实战:从理论到落地
  • 经典本地影音播放器MPC-BE.
  • 动手学深度学习-3.1线性回归 问题汇总
  • 指导初学者使用Anaconda运行GitHub上One - DM项目的步骤
  • Python玄学
  • 【Jax和Flax介绍】