深入理解Python中的常用数据格式(如csv、json、pickle、npz、h5等):存储机制与性能解析

在数据科学与工程领域,数据的存储与读取是日常工作中不可或缺的一部分。选择合适的数据格式不仅影响数据处理的效率,还关系到存储空间的利用与后续分析的便捷性。本文将以通俗易懂的方式,深入探讨Python中几种常用的数据读写格式(如.csv.json.pickle.npz.h5等)的存储方式,并分析它们在速度与性能上的优劣。

1. 常用数据格式概览

在Python中,常见的数据读写格式包括但不限于:

  • CSV(Comma-Separated Values):简单的文本格式,广泛用于表格数据。
  • JSON(JavaScript Object Notation):灵活的文本格式,适合嵌套和复杂数据结构。
  • Pickle:Python原生的序列化格式,能够存储几乎所有Python对象。
  • NPZ(NumPy Zip):用于存储多个NumPy数组的压缩文件格式。
  • HDF5(Hierarchical Data Format version 5):支持大规模数据存储与复杂结构的二进制格式。
  • Parquet:列式存储格式,适合大规模数据分析与查询。
  • Feather:基于Apache Arrow的高性能列式存储格式,适合Python与R之间的数据传输。
  • SQLite:轻量级的嵌入式数据库,支持SQL查询。

接下来,我们将逐一详细解析这些格式的存储机制及其性能特点。

2. 详解存储机制与性能分析

CSV(Comma-Separated Values)

存储机制:

CSV是一种纯文本格式,每一行代表一条记录,字段之间使用逗号(或其他分隔符)分隔。例如:

csv


复制代码
id,value,category
1,0.123,A
2,0.456,B
...

性能分析:

  • 优点:
    • 简单易读:人类可读,便于查看与编辑。
    • 广泛支持:几乎所有数据处理工具和编程语言都支持CSV格式。
    • 轻量级:结构简单,适合存储结构化的表格数据。
  • 缺点:
    • 效率低下:纯文本格式导致文件体积较大,读写速度较慢,尤其在处理大规模数据时。
    • 缺乏数据类型信息:所有数据以字符串形式存储,需要额外解析以确定实际数据类型。
    • 不支持嵌套结构:无法直接表示复杂的嵌套数据,如列表或字典。

为什么速度较慢:

CSV作为纯文本格式,数据需要逐行解析,且每个字段都需要从字符串转换为相应的数据类型。这种逐行、逐字段的处理方式在数据量大时会显著降低读写速度。


JSON(JavaScript Object Notation)

存储机制:

JSON也是一种纯文本格式,使用键值对来表示数据,支持嵌套的对象和数组。例如:

json


复制代码
[
  {"id": 1, "value": 0.123, "category": "A"},
  {"id": 2, "value": 0.456, "category": "B"},
  ...
]

性能分析:

  • 优点:
    • 灵活性高:支持复杂的嵌套结构,适合存储多层次的数据。
    • 人类可读:易于理解与编辑。
    • 广泛支持:大多数编程语言和工具都支持JSON格式。
  • 缺点:
    • 较低效率:与二进制格式相比,JSON的读写速度较慢,文件体积较大。
    • 缺乏数据类型约束:需要额外解析来确定实际的数据类型。
    • 不适合大规模数据:在处理极大数据集时,性能和存储效率不佳。

为什么速度较慢:

类似于CSV,JSON也是纯文本格式,数据解析需要逐字符解析和解析嵌套结构,导致在处理大规模数据时效率较低。此外,复杂的嵌套结构增加了数据解析的复杂性,进一步影响了读写速度。


Pickle

存储机制:

Pickle是Python特有的序列化协议,用于将Python对象转化为字节流,并可将其恢复为原始对象。支持几乎所有Python数据类型,包括自定义对象。

性能分析:

  • 优点:
    • Python原生支持:能够序列化和反序列化几乎所有Python对象,使用方便。
    • 灵活性高:适合存储复杂的Python数据结构,如嵌套的列表、字典和自定义类实例。
  • 缺点:
    • 安全性低:不建议反序列化来自不可信来源的数据,可能导致代码执行漏洞。
    • 跨语言支持差:仅限于Python,其他编程语言难以读取或生成Pickle格式的数据。
    • 兼容性问题:不同Python版本之间可能存在不兼容性,尤其在主要版本升级时。

为什么速度适中:

Pickle使用二进制格式进行序列化,相较于纯文本格式,读写速度和存储效率更高。然而,由于其复杂的序列化机制和对Python对象的高度兼容,性能在某些情况下可能不如专门优化的二进制格式(如HDF5或Parquet)。


NPZ(NumPy Zip)

存储机制:

NPZ是NumPy提供的一种压缩文件格式,用于存储多个NumPy数组。它实际上是一个ZIP归档,包含多个.npy文件,每个.npy文件存储一个数组。

性能分析:

  • 优点:
    • 高效存储:专为NumPy数组设计,支持压缩,节省存储空间。
    • 快速读写:针对数值计算进行了优化,读写速度较快。
    • 支持多个数组:可以在一个文件中存储多个数组,便于管理。
  • 缺点:
    • 仅限于NumPy数组:不适合存储复杂的数据结构或非数值数据。
    • 可读性低:二进制格式,不易直接查看内容。
    • 缺乏元数据支持:与HDF5相比,NPZ在存储附加元数据方面功能有限。

为什么速度较快:

NPZ基于NumPy的.npy格式,直接存储内存中的数组数据,避免了中间的解析步骤。此外,支持压缩可以有效减少文件大小,进一步提升读写效率。然而,专注于数值数组的设计也限制了其应用范围。


HDF5(Hierarchical Data Format version 5)

存储机制:

HDF5是一种用于存储和管理大规模数据的二进制文件格式,支持分层结构。它允许在一个文件中存储多种类型的数据集和元数据,类似于文件系统中的目录和文件结构。

性能分析:

  • 优点:
    • 高效存储大规模数据:支持分块存储和压缩,适合处理超大数据集。
    • 支持复杂数据结构:能够存储多维数组、表格数据及其元数据。
    • 并行读写:支持并行I/O操作,适合高性能计算环境。
    • 跨语言支持:拥有广泛的语言绑定,如Python的h5pyPyTables
  • 缺点:
    • 学习曲线陡峭:API较为复杂,初学者需要花费时间学习。
    • 依赖库:需要安装第三方库(如h5pyPyTables)才能使用。
    • 文件管理复杂:文件结构复杂,管理和维护需要谨慎。

为什么速度高效:

HDF5采用分块存储和压缩技术,可以有效地管理和访问大规模数据。其底层使用二进制格式,减少了数据解析的开销。此外,支持并行I/O使其在多线程或分布式环境中具备显著的性能优势。


Parquet

存储机制:

Parquet是一种开源的列式存储格式,基于Apache Arrow项目开发,专为大规模数据处理和分析优化。它将数据按列而非按行存储,有利于高效的压缩和快速的列式查询。

性能分析:

  • 优点:
    • 列式存储:适合大规模数据分析和按列查询,提升查询性能。
    • 高效压缩:支持多种压缩算法(如Snappy、GZIP),节省存储空间。
    • 跨语言支持:被Apache Arrow等多种工具和编程语言支持。
    • 支持嵌套数据:能够有效地存储复杂的嵌套数据结构。
  • 缺点:
    • 复杂性:相较于CSV等格式,使用和理解较为复杂。
    • 写入速度:在某些情况下,写入速度可能较慢,尤其是在未优化的情况下。
    • 依赖库:需要安装如pyarrowfastparquet等第三方库。

为什么速度高效:

Parquet的列式存储方式使其在进行按列操作时无需读取整个数据集,显著提升了查询效率。高效的压缩算法减少了磁盘I/O的开销,加快了读写速度。此外,基于Apache Arrow的内存映射技术,使其在内存中处理数据时具备高效性。


Feather

存储机制:

Feather是基于Apache Arrow的高性能列式存储格式,旨在提供跨语言(主要是Python与R)之间的高效数据传输。它采用二进制格式,优化了读写速度和内存布局。

性能分析:

  • 优点:
    • 极快的读写速度:基于Apache Arrow的内存格式,避免了数据序列化和反序列化的开销。
    • 轻量级:设计简洁,适合快速数据传输。
    • 支持列式存储:优化了按列操作的性能。
    • 跨语言支持:特别适用于Python和R之间的数据交换。
  • 缺点:
    • 功能有限:不如Parquet那样支持复杂的压缩和分区功能。
    • 跨语言支持有限:主要针对Python和R,其他语言的支持较少。
    • 不适合长期存储:设计目标是高效传输,而非长期存储与管理。

为什么速度极快:

Feather利用Apache Arrow的内存映射和零拷贝技术,使得数据在内存与磁盘之间的传输几乎不需要额外的处理步骤。这大幅减少了读写时间,特别适用于需要频繁在不同编程环境之间传输数据的场景。


SQLite

存储机制:

SQLite是一个轻量级的嵌入式关系型数据库管理系统,使用单一的文件来存储整个数据库。它支持标准的SQL查询语句,具备事务支持和数据完整性保障。

性能分析:

  • 优点:
    • 嵌入式数据库:无需独立的数据库服务器,易于部署和管理。
    • 支持SQL查询:可以使用复杂的SQL语句进行数据查询和操作,灵活性高。
    • 事务支持:保证数据的一致性和完整性。
    • 广泛应用:被广泛应用于移动设备、嵌入式系统和小型应用中。
  • 缺点:
    • 性能瓶颈:对于极大规模的数据集,性能可能不如专用的数据库系统(如PostgreSQL、MySQL)。
    • 并发性能有限:虽然支持读写操作,但在高并发场景下表现不佳。
    • 学习成本:需要掌握SQL语法和数据库操作,增加了使用的复杂性。

为什么速度适中:

SQLite通过单一文件管理数据,适合轻量级应用。然而,其设计目标并非高性能的并发读写,而是提供一个简单可靠的嵌入式数据库解决方案。在处理大规模数据时,由于缺乏分布式架构和高级索引优化,性能可能受限。

3. 为什么不同格式速度快慢不一

不同数据格式在读写速度和性能上的差异,主要源于以下几个方面:

  1. 存储方式
    • 文本 vs 二进制:文本格式(如CSV、JSON)需要逐字符解析,速度较慢;二进制格式(如Pickle、HDF5、Parquet、Feather)直接存储内存数据,读写速度更快。
    • 行式 vs 列式:行式存储(如CSV、JSON)适合逐行读取,但在进行列操作时效率低下;列式存储(如Parquet、Feather)适合按列读取和操作,提升了分析效率。
  2. 压缩与编码
    • 有无压缩:支持压缩的格式(如HDF5、Parquet)可以显著减少文件大小,但可能增加读写时的压缩与解压开销。
    • 压缩算法:不同格式支持不同的压缩算法,影响存储效率与读写速度的平衡。
  3. 数据类型支持
    • 类型丰富度:支持丰富数据类型和结构的格式(如HDF5、Parquet)能够更高效地存储复杂数据,但可能导致解析过程更复杂。
    • 类型限制:如NPZ仅支持NumPy数组,优化了特定数据类型的存储与访问效率。
  4. 并行与并发支持
    • 并行读写:支持并行I/O操作的格式(如HDF5)在多线程或分布式环境中具备显著的性能优势。
    • 单线程限制:不支持并行操作的格式在高负载场景下可能成为瓶颈。
  5. 内存布局与访问模式
    • 内存映射:利用内存映射技术的格式(如Feather)减少了数据在内存与磁盘之间的拷贝,提升了读写速度。
    • 缓存优化:优化缓存访问模式的格式能够更高效地利用CPU缓存,提升性能。
  6. 元数据与索引
    • 丰富的元数据:支持存储和利用元数据(如HDF5、Parquet)的格式,可以优化数据访问路径,提升查询性能。
    • 缺乏索引:不支持索引的格式在进行复杂查询时需要全表扫描,影响性能。

4. 选择合适的数据格式的建议

根据上述分析,不同数据格式适用于不同的场景。以下是一些选择建议:

(1) 小规模数据或需要人类可读的场景

  • CSV:适用于简单的表格数据交换与存储,便于查看与编辑。
  • JSON:适用于需要存储嵌套结构或配置文件的场景。

(2) 需要高效读写和数值计算

  • NPZ:适合存储多个NumPy数组,尤其在科学计算与机器学习任务中常用。
  • HDF5:适合存储大规模、多维度的数据,支持高性能的读写操作。

(3) 大规模数据分析与按列查询

  • Parquet:适用于大数据分析平台(如Apache Spark),支持高效的列式存储和压缩。
  • Feather:适用于Python与R之间的快速数据传输,尤其在需要频繁交换数据的分析任务中。

(4) 需要数据库功能与复杂查询

  • SQLite:适用于嵌入式应用、小型项目或需要简单SQL查询的场景。

(5) 需要跨语言支持和高性能传输

  • Feather:在Python与R之间进行高效数据传输时表现优异。
  • Parquet:广泛的语言支持使其适用于多语言数据处理环境。

(6) 需要序列化复杂Python对象

  • Pickle:适用于内部Python应用的数据持久化,但需谨慎使用以避免安全风险。

5. 亿级数据量下常用数据格式的读写性能排名

在处理亿级(108)数据量时,选择合适的数据存储格式对于提升数据处理效率、节省存储空间以及优化内存使用至关重要。不同的数据格式在读写速度、文件大小和内存占用等方面表现各异。本文将基于综合读写性能,对常用的数据格式进行从优到差的排序,并解释其背后的原因。

5.1 综合读写性能排名

以下是常用数据格式在处理亿级数据量时,综合读写性能从优到差的排序:

  1. Feather
  2. Parquet
  3. HDF5 (.h5)
  4. NPZ (.npz)
  5. Pickle (.pkl)
  6. SQLite (.sqlite)
  7. JSON (.json)
  8. CSV (.csv)

5.2 排名详解

No.1 Feather

综合性能:最优

  • 读写速度:Feather基于Apache Arrow,采用列式存储和内存映射技术,实现了极高的读写速度,尤其适合在Python与R之间高效传输数据。
  • 文件大小:虽然主要优化速度,但文件大小通常也较为紧凑。
  • 内存占用:内存映射技术减少了数据在内存与磁盘之间的拷贝,优化了内存使用。

适用场景:需要在不同编程环境(如Python与R)之间快速传输大量数据,或者需要极高读写速度的分析任务。

No.2 Parquet

综合性能:极佳

  • 读写速度:Parquet采用列式存储,特别适合按列读取和分析,提升了读写效率。支持高效的压缩算法(如Snappy、GZIP),进一步加快了数据处理速度。
  • 文件大小:高效压缩显著减少了存储空间。
  • 内存占用:列式存储和压缩算法优化了内存使用,尤其在进行部分列读取时。

适用场景:大规模数据分析、数据仓库、需要高效列式查询的环境(如Apache Spark)。

No.3 HDF5 (.h5)

综合性能:优良

  • 读写速度:HDF5支持分块存储和并行I/O操作,适合处理超大数据集。优化的二进制存储格式减少了数据解析的开销。
  • 文件大小:支持多种压缩算法,有效节省存储空间。
  • 内存占用:高效的数据分块和压缩技术优化了内存使用,适合高性能计算环境。

适用场景:科学计算、工程应用、大规模多维数组存储、需要存储复杂数据结构的场景。

No.4 NPZ (.npz)

综合性能:良好

  • 读写速度:专为NumPy数组设计,直接存储内存中的数组数据,读写速度较快。支持压缩,进一步提升存储效率。
  • 文件大小:通过压缩技术显著减少文件体积。
  • 内存占用:优化的存储方式减少了内存使用,但仅限于数值数据。

适用场景:存储和共享多个NumPy数组,科学计算和机器学习任务中常用。

No.5 Pickle (.pkl)

综合性能:中等

  • 读写速度:Pickle使用二进制格式进行序列化,读写速度快于纯文本格式,但不及专门优化的二进制格式(如Parquet、Feather)。
  • 文件大小:相较于文本格式,文件体积较小,但不支持高效压缩。
  • 内存占用:灵活的序列化机制可能导致较高的内存使用,尤其在处理复杂对象时。

适用场景:序列化和反序列化复杂的Python对象,内部数据持久化(需注意安全性)。

No.6 SQLite (.sqlite)

综合性能:较好

  • 读写速度:作为嵌入式关系型数据库,SQLite在处理大量数据时表现良好,但不及专用的二进制格式。在支持复杂查询时具有优势。
  • 文件大小:合理的存储效率,支持索引优化查询性能。
  • 内存占用:适中的内存使用,支持事务和数据一致性。

适用场景:嵌入式应用、小型项目、需要使用SQL进行复杂查询的场景。

No.7 JSON (.json)

综合性能:较差

  • 读写速度:作为纯文本格式,JSON需要逐字符解析,读写速度较慢,尤其在处理亿级数据时效率低下。
  • 文件大小:文本格式导致文件体积较大,不利于存储和传输。
  • 内存占用:解析嵌套结构时可能导致较高的内存使用。

适用场景:需要存储嵌套数据结构、配置文件或在不同系统间交换数据(但数据量不大时更为合适)。

No.8 CSV (.csv)

综合性能:最差

  • 读写速度:CSV作为纯文本格式,读写速度最慢。逐行解析和字符串转换在处理大规模数据时效率极低。
  • 文件大小:文本格式导致文件体积庞大,尤其在处理数值数据时更为明显。
  • 内存占用:高内存消耗,尤其在读取整个文件到内存中时。

适用场景:简单、轻量级的数据交换与存储,数据量较小或对可读性要求较高的场景。


5.3 排名总结

综合考虑亿级数据量下的读写速度、文件大小和内存占用,常用数据格式的性能从优到差排序如下:

  1. Feather:最快的读写速度,适合跨语言高效传输。
  2. Parquet:高效的列式存储与压缩,适合大规模数据分析。
  3. HDF5 (.h5):强大的数据管理能力,适用于科学计算和工程应用。
  4. NPZ (.npz):专为NumPy数组优化,适合数值计算任务。
  5. Pickle (.pkl):灵活的Python对象序列化,适合内部数据持久化。
  6. SQLite (.sqlite):嵌入式数据库,适合需要SQL查询的小型应用。
  7. JSON (.json):灵活的文本格式,适合嵌套数据和配置文件。
  8. CSV (.csv):最简单的文本格式,适合小规模、轻量级的数据交换。

5.4选择建议

  • 追求读写速度和存储效率:优先选择FeatherParquet
  • 需要存储复杂数据结构:选择HDF5
  • 主要处理NumPy数组:选择NPZ
  • 需要跨语言数据传输:选择Feather
  • 需要数据库功能和复杂查询:选择SQLite
  • 数据量较小且需要人类可读:选择CSVJSON

5.5 注意事项

  • 硬件限制:亿级数据量对硬件资源要求较高,确保有足够的内存和存储空间。
  • 依赖库:某些格式(如HDF5、Parquet、Feather)需要安装相应的Python库(如h5pypyarrow)。
  • 安全性:如使用Pickle进行序列化,需确保数据来源可信,避免反序列化不可信数据带来的安全风险。
  • 压缩与优化:合理选择压缩算法和优化参数,可以进一步提升性能和存储效率。

通过合理选择和应用上述数据格式,可以在处理亿级数据量时显著提升数据处理效率,优化存储和内存使用,为后续的数据分析和应用奠定坚实基础。

6. 千万级数据实验

​ 本节通过模拟千万级数据,验证各种数据格式:npy, npz, h5, pkl, csv, txt, feather, parquet 这八种数据格式在读取、写入和内存占用上的性能对比。

6.1 实验设计

Step1: 数据生成

​ 本节通过 data = np.random.rand(10**7, 5) 生成数据维度为 (1kw* 5) 的数据;

Step2: 读写和内存性能测评

​ 记录这批数据分别保存为各种格式的时间,以及读取保存后的数据的时间,记录内存占用;每测评完一个格式后,就进行缓存刷新,尽量保证公平性;共测试三轮,计算平均值。

​ 具体操作请看后面的完整代码。

6.2 效果展示

​ 读写性能对比:
在这里插入图片描述

​ 内存占用对比:

在这里插入图片描述

6.3 结果分析

​ 在千万级数据集上,除了csv和txt外,其余格式没有质的差别,感觉是数据量较小导致的,上述效果仅供参考!

​ 之所以不模拟亿级别的数据,因为我的电脑只能计算千万级的数据量,当我扩大到亿级时,直接崩了。代码在下面,有更好设备的朋友,可以尝试扩大规模,验证效果,要是乐于分享,也可以发给我,我进行补充。

6.4 实验代码
import numpy as np
import pandas as pd
import os
import time
import h5py
import pickle
import pyarrow as pa
import pyarrow.feather as feather
import pyarrow.parquet as pq
import matplotlib.pyplot as plt

def write_h5(file_path, data):
    with h5py.File(file_path, 'w') as f:
        f.create_dataset('data', data=data)

def test_read_write(file_path, write_func, read_func):
    # 写入
    start_time = time.time()
    write_func()
    write_time = time.time() - start_time
    os.sync()  # 刷新缓存

    # 读取
    start_time = time.time()
    read_func()
    read_time = time.time() - start_time
    os.sync()  # 刷新缓存
    
    # 文件大小
    file_size = os.path.getsize(file_path) / (1024 * 1024)  # 转换为 MB
    
    return {'write_time': write_time, 'read_time': read_time, 'size': file_size}

def run_experiments(n=5):
    # 生成数据
    data = np.random.rand(10**7, 5)
    df = pd.DataFrame(data)

    # 文件路径
    file_paths = {
        'npy': 'data.npy',
        'npz': 'data.npz',
        'h5': 'data.h5',
        'pkl': 'data.pkl',
        'csv': 'data.csv',
        'txt': 'data.txt',
        'feather': 'data.feather',
        'parquet': 'data.parquet',
    }

    # 写入函数
    formats = {
        'npy': lambda: np.save(file_paths['npy'], data),
        'npz': lambda: np.savez(file_paths['npz'], data=data),
        'h5': lambda: write_h5(file_paths['h5'], data),
        'pkl': lambda: df.to_pickle(file_paths['pkl']),
        'csv': lambda: df.to_csv(file_paths['csv'], index=False),
        'txt': lambda: np.savetxt(file_paths['txt'], data),
        'feather': lambda: feather.write_feather(df, file_paths['feather']),
        'parquet': lambda: pq.write_table(pa.Table.from_pandas(df), file_paths['parquet']),
    }

    results = {fmt: {'write_time': [], 'read_time': [], 'size': []} for fmt in formats}

    # 执行N次实验
    for i in range(n):
        print(f"第 {i} 次执行开始")
        for fmt, writer in formats.items():
            read_func = None
            if fmt == 'npy':
                read_func = lambda: np.load(file_paths['npy'])
            elif fmt == 'npz':
                read_func = lambda: np.load(file_paths['npz'])
            elif fmt == 'h5':
                read_func = lambda: h5py.File(file_paths['h5'], 'r')['data'][:]
            elif fmt == 'pkl':
                read_func = lambda: pd.read_pickle(file_paths['pkl'])
            elif fmt == 'csv':
                read_func = lambda: pd.read_csv(file_paths['csv'])
            elif fmt == 'txt':
                read_func = lambda: np.loadtxt(file_paths['txt'])
            elif fmt == 'feather':
                read_func = lambda: feather.read_feather(file_paths['feather'])
            elif fmt == 'parquet':
                read_func = lambda: pq.read_table(file_paths['parquet']).to_pandas()
            
            res = test_read_write(file_paths[fmt], writer, read_func)
            results[fmt]['write_time'].append(res['write_time'])
            results[fmt]['read_time'].append(res['read_time'])
            results[fmt]['size'].append(res['size'])

    # 计算平均值,增强可信度
    avg_results = {}
    for fmt in results:
        avg_results[fmt] = {
            'avg_write_time': np.mean(results[fmt]['write_time']),
            'avg_read_time': np.mean(results[fmt]['read_time']),
            'avg_size': np.mean(results[fmt]['size']),
        }

    # 绘制结果
    df_avg_results = pd.DataFrame(avg_results).T

    plt.figure(figsize=(12, 6))
    # 绘制写入时间
    plt.plot(df_avg_results.index, df_avg_results['avg_write_time'], marker='o', label='Average Write Time', color='blue')
    for i, write_time in enumerate(df_avg_results['avg_write_time']):
        plt.annotate(f"{write_time:.2f}", (df_avg_results.index[i], write_time), textcoords="offset points", xytext=(0,10), ha='center')

    # 绘制读取时间
    plt.plot(df_avg_results.index, df_avg_results['avg_read_time'], marker='o', label='Average Read Time', color='green')
    for i, read_time in enumerate(df_avg_results['avg_read_time']):
        plt.annotate(f"{read_time:.2f}", (df_avg_results.index[i], read_time), textcoords="offset points", xytext=(0,-10), ha='center')

    plt.title('Average Read/Write Time Comparison')
    plt.xlabel('File Format')
    plt.ylabel('Time (seconds)')
    plt.xticks(rotation=45)
    plt.grid()
    plt.legend()
    plt.savefig('read_write_time_comparison.jpg', format='jpg', bbox_inches='tight')
    plt.close()  # 关闭图形以释放内存

    # 绘制文件大小
    plt.figure(figsize=(12, 6))
    plt.plot(df_avg_results.index, df_avg_results['avg_size'], marker='o', color='orange', label='Average Size (MB)')
    for i, size in enumerate(df_avg_results['avg_size']):
        plt.annotate(f"{size:.2f} MB", (df_avg_results.index[i], size), textcoords="offset points", xytext=(0,10), ha='center')

    plt.title('Average File Size Comparison')
    plt.xlabel('File Format')
    plt.ylabel('Size (MB)')
    plt.xticks(rotation=45)
    plt.grid()
    plt.legend()
    plt.savefig('file_size_comparison.jpg', format='jpg', bbox_inches='tight')
    plt.close()  # 关闭图形以释放内存

# 调用实验
run_experiments(n=3)

7. 结论

在Python的数据处理过程中,选择合适的数据读写格式至关重要。不同格式在存储机制、读写速度、存储效率和功能支持上各有千秋。理解各格式的存储原理和性能特点,可以帮助开发者在实际应用中做出更明智的选择,提升数据处理的效率与效果。

总结建议

  • 对于简单、轻量级的数据交换,选择CSVJSON
  • 需要高效存储和快速读写的大规模数值数据,选择HDF5Parquet
  • 在Python与R之间进行高性能数据传输,选择Feather
  • 需要序列化复杂Python对象,选择Pickle(注意安全性)。
  • 需要嵌入式数据库功能,选择SQLite

通过合理地选择和应用这些数据格式,可以显著优化数据处理流程,提升工作效率,满足不同应用场景的需求。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法 class 005 (对数器C语言实现)

对数器的概念: 用来测试你的算法是否正确。 怎么做呢? 1:比如,写个冒泡排序,作为对比的对象 2:生成一个随机数 数组,用来测试 3:用冒泡排序和你想要验证的那个排序算法,同…

基于AT89C51单片机的可暂停八路抢答器设计

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/90196607?spm1001.2014.3001.5503 C15 部分参考设计如下: 摘要 随着社会进步和科技发展,电子设备在各类活动中的应用日益普遍&#xff0c…

IoC设计模式详解:控制反转的核心思想

前言:在软件开发中,设计模式是一种经过验证的、在特定场景下能有效解决问题的解决方案。控制反转(Inversion of Control,IoC) 作为一种设计模式,通过让程序的控制流和对象管理反转,从而使得代码…

使用C#构建一个论文总结AI Agent

前言 我觉得将日常生活中一些简单重复的任务交给AI Agent,是学习构建AI Agent应用一个很不错的开始。本次分享我以日常生活中一个总结论文的简单任务出发进行说明,希望对大家了解AI Agent有所帮助。任务可以是多种多样的,真的帮助自己提升了…

[Qt] 常用控件 | QWidget | “表白程序2.0”

目录 一、控件概述 控件体系的发展阶段: 二、QWidget 核心属性 核心属性概览: 1、enabled 2、Geometry 实例 1: 控制按钮的位置 实例 2: 表白 程序 i、Window Frame 的影响 ii、API 设计理念 iii、Geometry 和 FrameGeometry 的区别 &#xf…

GAN对抗生成网络(二)——算法及Python实现

1 算法步骤 上一篇提到的GAN的最优化问题是,本文记录如何求解这一问题。 首先为了表示方便,记,这里让最大的可视作常量。 第一步,给定初始的,使用梯度上升找到 ,最大化。关于梯度下降,可以参考笔者另一篇…

JAVA(二)【未完】

数据类型与变量 数据类型:基本数据类型:整型:byte short int long 浮点型:float double char 布尔型:boolean 引用数据类型:数组 类 接口 枚举类型 long b 10l;System.out.println(b);System.out.printl…

C语言day5:shell脚本

一、练习题1 定义一个find函数,查找ubuntu和root的gid并使用变量接收结果 二、练习题2 定义一个数组,写一个函数完成对数组的冒泡排序 三、练习题3 使用break求1-100中的质数(质数:只能被1和它本身整除,如:…

R语言6种将字符转成数字的方法,写在新年来临之际

咱们临床研究中,拿到数据后首先要对数据进行清洗,把数据变成咱们想要的格式,才能进行下一步分析,其中数据中的字符转成数字是个重要的内容,因为字符中常含有特殊符号,不利于分析,转成数字后才能…

C语言面的向对象编程(OOP)

如果使用过C、C#、Java语言,一定知道面向对象编程,这些语言对面向对象编程的支持是语言级别的。C语言在语言级别不支持面向对象,那可以实现面向对象吗?其实面向对象是一种思想,而不是一种语言,很多初学者很…

C++ 基础思维导图(一)

目录 1、C基础 IO流 namespace 引用、const inline、函数参数 重载 2、类和对象 类举例 3、 内存管理 new/delete 对象内存分布 内存泄漏 4、继承 继承权限 继承中的构造与析构 菱形继承 1、C基础 IO流 #include <iostream> #include <iomanip> //…

聊聊前端框架中的process.env,env的来源及优先级(next.js、vue-cli、vite)

在平时开发中&#xff0c;常常使用vue、react相关脚手架创建项目&#xff0c;在项目根目录可以创建.env、.env.[mode]&#xff08;mode为development、production、test)、.env.local等文件&#xff0c;然后在项目中就可以通过process.env来访问相关的环境变量了。 下面针对如下…

基于云架构Web端的工业MES系统:赋能制造业数字化变革

基于云架构Web端的工业MES系统:赋能制造业数字化变革 在当今数字化浪潮席卷全球的背景下,制造业作为国家经济发展的重要支柱产业,正面临着前所未有的机遇与挑战。市场需求的快速变化、客户个性化定制要求的日益提高以及全球竞争的愈发激烈,都促使制造企业必须寻求更加高效、智…

LeetCode算法题——螺旋矩阵ll

题目描述 给你一个正整数n&#xff0c;生成一个包含1到n2所有元素&#xff0c;且元素按顺时针顺序螺旋排列的n x n正方形矩阵matrix 。 示例 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]]题解 思路&#xff1a; 将整个过程分解为逐圈填充的过程&#xf…

MySQL 01 02 章——数据库概述与MySQL安装篇

一、数据库概述 &#xff08;1&#xff09;为什么要使用数据库 数据库可以实现持久化&#xff0c;什么是持久化&#xff1a;数据持久化意味着将内存中的数据保存到硬盘上加以“固化”持久化的主要作用是&#xff1a;将内存中的数据存储在关系型数据库中&#xff0c;当然也可以…

GPU 进阶笔记(四):NVIDIA GH200 芯片、服务器及集群组网

大家读完觉得有意义记得关注和点赞&#xff01;&#xff01;&#xff01; 1 传统原厂 GPU 服务器&#xff1a;Intel/AMD x86 CPU NVIDIA GPU2 新一代原厂 GPU 服务器&#xff1a;NVIDIA CPU NVIDIA GPU 2.1 CPU 芯片&#xff1a;Grace (ARM)2.2 GPU 芯片&#xff1a;Hopper/B…

vite6+vue3+ts+prettier+eslint9配置前端项目(后台管理系统、移动端H5项目通用配置)

很多小伙伴苦于无法搭建一个规范的前端项目&#xff0c;导致后续开发不规范&#xff0c;今天给大家带来一个基于Vite6TypeScriptVue3ESlint9Prettier的搭建教程。 目录 一、基础配置1、初始化项目2、代码质量风格的统一2.1、配置prettier2.2、配置eslint2.3、配置typescript 3、…

ESLint+Prettier的配置

ESLintPrettier的配置 安装插件 ​​​​​​ 在settings.json中写下配置 {// tab自动转换标签"emmet.triggerExpansionOnTab": true,"workbench.colorTheme": "Default Dark","editor.tabSize": 2,"editor.fontSize": …

Cyber Security 101-Web Hacking-JavaScript Essentials(JavaScript 基础)

任务1&#xff1a;介绍 JavaScript &#xff08;JS&#xff09; 是一种流行的脚本语言&#xff0c;它允许 Web 开发人员向包含 HTML 和 CSS&#xff08;样式&#xff09;的网站添加交互式功能。创建 HTML 元素后&#xff0c;您可以通过 JS 添加交互性&#xff0c;例如验证、on…

《机器学习》从入门到实战——逻辑回归

目录 一、简介 二、逻辑回归的原理 1、线性回归部分 2、逻辑函数&#xff08;Sigmoid函数&#xff09; 3、分类决策 4、转换为概率的形式使用似然函数求解 5、对数似然函数 ​编辑 6、转换为梯度下降任务 三、逻辑回归拓展知识 1、数据标准化 &#xff08;1&#xf…