Python高维度大型气象矩阵存储策略分享

零、前情提要

最近需要分析全球范围多变量的数值预报数据,将grb格式的数据下载下来经过一通处理后需要将预处理数据先保存一遍,方便后续操作,处理完发现此时的数据维度很多,数据量巨大使用不同的保存策略的解析难度和储存大小可以相差很大,在此分享下不同存储方式的差异

对比发现,使用ZARR储存高维度大型气象矩阵的储存成本最低,相比于使用pkl存储字典数据小近十倍!

一、两种数据存储策略

1.1 预处理成字典存储

按日期读取各个模式数据,依次提取出各个变量,一个变量一个数组

{'20240701': {'ec': {'T': [],'rh': [],},'necp': {'T': [],'rh': [],}},'20240702': {'ec': {'T': [],'rh': [],},'necp': {'T': [],'rh': [],}},}

1.2 预处理为数组存储

预报数据维度
F ( T , m o d e l s , v a r i a b l s , p r e s s u r e s , l a t , l o n ) F(T, models, variabls, pressures, lat, lon) F(T,models,variabls,pressures,lat,lon)

观测场数据维度
O ( T , m o d e l s , p r e s s u r e s , l a t , l o n ) O(T, models, pressures, lat, lon) O(T,models,pressures,lat,lon)

T为时间数,models为模型数量,variables为变量,pressures为气压层,后面两者为经纬度,使用的0.25度分辨率的全球数据,数据量是相当大的

二、pkl储存

  • pkl的特点是可以直接储存python的字典,读取和存储都非常方便
  • 但是占用的文件大小相对很大

2.1 储存策略

pkl擅长储存python字典数据

res = {'20240701': {'ec': {'T': [],'rh': [],},'necp': {'T': [],'rh': [],}},'20240702': {'ec': {'T': [],'rh': [],},'necp': {'T': [],'rh': [],}},}

2.2 储存和读取方式

import pickle as pkl
# 存储pkl
def save2pkl(data, save_filepath):with open(save_filepath, 'wb') as file:pickle.dump(data, file)print('finish saving')def read_pkl(filepath):with open(filepath, 'rb') as file:data = pkl.load(file)return data

2.3 储存大小

结果是使用pkl储存出来的数据量巨大,两个时段的数据量达到3G,是无法接受的
在这里插入图片描述

三、HDF5存储

HDF5既可以通过group的形式储存字典,也可以直接存储numpy数组

3.1 储存策略1(存储大数组)

def save2hdf5(save_filepath, data, compression='gzip'):with h5py.File(save_filepath + '.hdf5', 'w') as hf:hf.create_dataset('data_name', data=data, compression=compression)print('finish saving')

3.2 储存策略2(存储字典)

以上面这个字典为例,通过遍历这个字典的k,v循环存储,需要不断创建group来形成字典的树状结构

data= {'20240701': {'ec': {'T': [],'rh': [],},'necp': {'T': [],'rh': [],}},'20240702': {'ec': {'T': [],'rh': [],},'necp': {'T': [],'rh': [],}},}
def save2hdf5(save_filepath, data, compression='gzip'):with h5py.File(save_filepath , 'w') as file:for date, models in data.items():date_group = file.create_group(date)for model, variables in models.items():model_group = date_group.create_group(model)for var_name, var_data in variables.items():model_group.create_dataset(var_name, data=var_data, compression=compression)print('finish saving')

这样是针对当前字典写死的代码,还可以用递归解决


def save_dict_to_hdf5(group, data_dict, compression):for key, value in data_dict.items():if isinstance(value, dict):# 创建一个新的 HDF5 组subgroup = group.create_group(key)# 递归调用DataReaderDict.save_dict_to_hdf5(subgroup, value, compression)else:# 直接保存数据到 HDF5 数据集中group.create_dataset(key, data=value, compression=compression)def save2hdf5(data, save_filepath , compression='gzip'):with h5py.File(save_filepath + 'hdf5', 'w') as hdf5_file:root_group = hdf5_file.create_group('root')save_dict_to_hdf5(root_group, data, compression)

3.3 设置压缩策略

在 HDF5 中,压缩策略有几种常见的方法,可以用来减少数据存储空间的需求,通过compression参数设置(来自GPT):

  • gzip: 这是最常用的压缩方法,它使用 DEFLATE 算法进行压缩。Gzip 在压缩率和压缩速度之间提供了一个良好的平衡。可以通过设置压缩级别来调整压缩的强度。

  • szip: 这是 HDF5 提供的另一种压缩方法,特别适用于具有大的数据块的情况。Szip 能够提供更高的压缩比,但可能会比 Gzip 更慢。

  • lzf: 这种压缩算法提供了更快的压缩和解压缩速度,但压缩比通常不如 Gzip 或 Szip 高。它适用于需要快速访问压缩数据的场景。

  • None: 不进行任何压缩。这种策略适用于当压缩不必要或影响性能时的情况

3.4 读取HDF5返回字典

读取方式:通过递归遍历group形成一个dict

def read_hdf5_group(group):"""递归读取 HDF5 组及其所有子组和数据集"""result = {}for key, item in group.items():if isinstance(item, h5py.Group):# 如果是组,递归调用result[key] = read_hdf5_group(item)elif isinstance(item, h5py.Dataset):# 如果是数据集,直接读取数据result[key] = item[:]return resultdef read_hdf5(file_path):"""读取 HDF5 文件,返回字典表示的数据结构"""try:with h5py.File(file_path, 'r') as file:# 从根组开始递归读取数据data = read_hdf5_group(file)return dataexcept FileNotFoundError as e:print(e)return None
filepath = r'E:\pythonProject\superensemble\data\combined_data\20240721-20240722-00-24_dict.hdf5'
data = read_hdf5(filepath)
print("a")

3.5 储存大小

  • 使用gzip默认的压缩等级4进行存储,存储字典的大小为1.04GB
    在这里插入图片描述

  • 储存数组的大小为777MB
    在这里插入图片描述

  • 在相同的压缩方式下,直接存储数组的数据大小更小

四、ZARR存储

4.1 储存策略1(储存字典)

递归调用储存

import zarr
def save2zarr(data, save_filepath ):zarr_store = zarr.DirectoryStore(save_filepath)root = zarr.open(zarr_store, mode='w')self.store_dict_to_zarr(root, data)def store_dict_to_zarr(root, data_dict):for key, value in data_dict.items():if isinstance(value, dict):# 如果值是字典,则创建一个组if key not in root:root.create_group(key)DataReaderDict.store_dict_to_zarr(root[key], value)  # 递归处理子字典else:# 否则,假设值是数组,创建数据集root.create_dataset(key, data=value)

4.2 储存策略2(储存大数组)

直接保存一个数组的方式如下

import zarr
import numpy as np# 创建一个新的 Zarr 数组
zarr_array = zarr.open('data.zarr', mode='w', 
shape=(100, 100), dtype='f4', chunks=(10, 10))# 填充数据
data = np.random.random((100, 100))
zarr_array[:] = data

在参数中需要填写数组的维度,存储的数据类型以及分块,压缩策略等等

4.3 设置数据分块以及压缩

Zarr 支持多种压缩算法,如 zlib, gzip, bzip2, lz4, 和 zstd,可以在创建 Zarr 数组时指定压缩方式和参数

import zarr
import numpy as np# 创建一个带有分块和压缩的 Zarr 数组
compressor = zarr.Blosc(cname='zstd', clevel=3, shuffle=2)  # 使用 zstd 压缩zarr_array = zarr.open('compressed_data.zarr', mode='w', shape=(100, 100, 100), dtype='f4',chunks=(10, 10, 10), compressor=compressor)# 填充数据
data = np.random.random((100, 100, 100))
zarr_array[:] = data

4.4 读取zarr返回字典

与读取hdf5类似,通过递归遍历group返回字典

import zarr
def read_zarr_group(group):"""递归读取 Zarr 组及其所有子组和数据集"""result = {}for key, item in group.items():if isinstance(item, zarr.Group):# 如果是组,递归调用result[key] = read_zarr_group(item)elif isinstance(item, zarr.Array):# 如果是数组,直接读取数据result[key] = item[:]return resultdef read_zarr(file_path):"""读取 Zarr 文件,返回字典表示的数据结构"""try:store = zarr.DirectoryStore(file_path)root_group = zarr.open(store, mode='r')# 从根组开始递归读取数据data = read_zarr_group(root_group)return dataexcept FileNotFoundError as e:print(e)return None
filepath = 'your filepath'
data = read_zarr(filepath)

4.5 储存大小

相同的数据,如果以字典存储,即使用zarr,也有882MB
在这里插入图片描述

但如果合理读取成一个大数组,则只有378MB,远远小于存储字典
在这里插入图片描述

五、小节

  • 对比发现使用zarr存储高纬度的网格数据占用的空间最小,容量为用pkl存储字典的1/10,一旦时间维度拉长使用字典存储的占用可能会大大增加
  • 对于时间序列的气象数据,预处理阶段处理成矩阵数组比处理成字典更加省空间且在下一阶段的操作更方便
  • 在下一阶段的计算方面,使用多维矩阵也可以方便选出各种数据,同时使用矩阵运算运用numpy的一些方法可以大大减少各种循环,非常高校
  • 因此,数据维度较为规整的情况下,尽量读取储存成矩阵数组的形式我认为更优

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

nowcoder bc49判断两个数的大小关系

描述 KiKi想知道从键盘输入的两个数的大小关系,请编程实现。 输入描述: 题目有多组输入数据,每一行输入两个整数(范围-231~231-1),用空格分隔。 输出描述: 针对每行输入,输出两…

zotfile基础配置详解

zotfile可以将自动移动pdf到指定文件夹中,那么应该如何配置呢? 遵循极简原则,只需配置两个地方即可。 一、路径配置 第一处是pdf附件存放的位置,可以指定自己想要的地方,我放在了C盘的文档文件夹下。 第二处是分类法…

由恶劣事件: CrowdStrike发布案例更新导致微软全球蓝屏事件的启示

前言 网络安全公司 CrowdStrike 周四发布软件更新后,机场、银行、证券交易所、911 服务、交通系统、酒店、新闻媒体、医院、紧急服务等开始出现臭名昭著的蓝屏死机 (BSOD)。在看似多年来最严重的 IT 中断中,大规模的网络安全软件问题正在全球范围内造成…

【七】Hadoop3.3.4基于ubuntu24的分布式集群安装

文章目录 1. 下载和准备工作1.1 安装包下载1.2 前提条件 2. 安装过程STEP 1: 解压并配置Hadoop选择环境变量添加位置的原则检查环境变量是否生效 STEP 2: 配置Hadoop2.1. 修改core-site.xml2.2. 修改hdfs-site.xml2.3. 修改mapred-site.xml2.4. 修改yarn-site.xml2.5. 修改hado…

C/C++大雪纷飞代码

目录 写在前面 C语言简介 EasyX简介 大雪纷飞 运行结果 写在后面 写在前面 本期博主给大家带来了C/C实现的大雪纷飞代码,一起来看看吧! 系列推荐 序号目录直达链接1爱心代码https://want595.blog.csdn.net/article/details/1363606842李峋同款跳…

Linux笔记 --- 程序入门

‘\n’换行符 通常来讲我们都是使用这个符号来进行换行的操作,但是这个符号不仅仅是用于换行 当标准输出文件中默认使用缓冲 ,也就是当遇到 \n 的时候会进行刷新缓冲区(把数据输 出) 当打印语句后面没有换行符时 , 需要…

强烈推荐这 3 款让你用一次就爱上,永不想删除的软件

IcecreamPDFEditor IcecreamPDFEditor是一款功能强大的PDF编辑工具,具备多种编辑和查看PDF文件的功能。这款软件不仅可以方便地阅读和查看各种PDF文件,还可以进行编辑操作。它拥有编辑文本、注释添加、页面管理以及PDF文件保护等功能。 用户可以通过下载…

JS逆向高级爬虫

JS逆向高级爬虫 JS逆向的目的是通过运行本地JS的文件或者代码,以实现脱离他的网站和浏览器,并且还能拿到和浏览器加密一样的效果。 10.1、编码算法 【1】摘要算法:一切从MD5开始 MD5是一个非常常见的摘要(hash)逻辑. 其特点就是小巧. 速度快. 极难被破解. 所以,…

ELK安装(Elasticsearch+Logstash+Kibana+Filebeat)

一、简介 1.1、软件简介 ELK其实是Elasticsearch,Logstash 和 Kibana三个产品的首字母缩写,这三款都是开源产品。 1.1.1、Elasticsearch简介 Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能很方便的使大量数据具有搜索、分析…

研究生选择学习Android开发的利与弊?

在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「Android的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!产品经理可以学学Axure快…

简单的CSS样式

样式分为三种 内部样式&#xff1a;写在html文件里的样式叫内部样式 内联样式&#xff1a;写在需要的标签中 外部样式&#xff1a;写在外部css文件里 可以通过不同的选择器来选择设置指定组件的样式&#xff1a; <style>/* 写在html文件里的样式叫内部样式 *//* 选择器 *…

6.3 面向对象技术-设计模式

设计模式 创建型模式 结构型模式

C++ unordered_map

1. unordered系列关联式容器 在C98 中&#xff0c; STL 提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到 &#xff0c;即最差情况下需要比较红黑树的高度次&#xff0c;当树中的节点非常多时&#xff0c;查询效率也不理想。最好的查询是&#xff0c…

我在百科荣创企业实践——简易函数信号发生器(6)

对于高职教师来说,必不可少的一个任务就是参加企业实践。这个暑假,本人也没闲着,报名参加了上海市电子信息类教师企业实践。7月8日到13日,有幸来到美丽的泉城济南,远离了上海的酷暑,走进了百科荣创科技发展有限公司。在这短短的一周时间里,我结合自己的教学经验和企业的…

Leetcode 剑指 Offer II 088.使用最小花费爬楼梯

题目难度: 简单 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 数组的每个下标作为一个阶梯&#xff0c;第 i 个阶梯对应着一个非…

5 Java的基本程序设计结构(基本语法4)- 集合之ArryList 和什么是包装类?

文章目录 前言一、集合二、基本数据类型的包装类三、ArryList1 ArryList对象的创建2 ArryList常见成员方法(1)boolean add(E e) : 添加元素,返回值表示是否添加成功(2)void add(int index, E e) :在指定索引位置插入元素。(3)boolean remove(E e) : 删除第一个指定元素…

从json到protobuf,接口效率的提升

在express开发的前后端调用中&#xff0c;express作为接收方是不二之选&#xff0c;它有一些很好用的body解析器来解析传入数据&#xff1b;而作为请求发起方&#xff0c;axios是非常方便的&#xff0c;这是一个很好的选择&#xff0c;它可以传输多种类型的数据给接收方。 通常…

Tekion 选择 ClickHouse Cloud 提升应用性能和指标监控

本文字数&#xff1a;4187&#xff1b;估计阅读时间&#xff1a;11 分钟 作者&#xff1a;ClickHouse team 本文在公众号【ClickHouseInc】首发 Tekion 由前 Tesla CIO Jay Vijayan 于 2016 年创立&#xff0c;利用大数据、人工智能和物联网等技术&#xff0c;为其汽车客户解决…

Week 3 DAY 6

Product C - Product (atcoder.jp) 一共N层&#xff0c;对于每一层的每个数&#xff0c;都遍历上一层更新过后的结果&#xff0c;更新为新的结果&#xff0c; 比如样例&#xff1a; 2 40 3 1 8 4 2 10 5动态数组a表示储存上一层除后留下来的数&#xff0c; 第一次a数组中只…

关于开源项目分享的通知

后续会逐步分享更多好用的开源项目&#xff0c;加入圈子&#xff1a; 圈子加入https://pc.fenchuan8.com/#/index?forum86631&yqm5EV39扫码加入&#xff1a;