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

Python数值计算(1)——Numpy中数据的保存和加载

这里讨论一下在进行数值计算中,对计算数据的保存和加载。

1. 文本格式

这种方式可以采用文本的方式保存numpy数组,函数原型如下:

numpy.savetxt(fname, X, fmt='%.18e', delimiter=' ', 
newline='\n', header='', footer='', comments='# ', encoding=None)

其中fname是文件名称,如果文件名以.gz结尾,numpy会 自动将其作为gzip文件压缩,X是需要保存的数组,fmt是保存的格式,delimiter是数据之间的分隔符,newline是换行符,header和footer是放在数据之前和之后的注释,而comment则是注释的引导符,默认为#,这也是Python中的注释符。例如保存一个多维数组,代码如下:

a=np.linspace(1,2,5)np.savetxt('test.txt',a,header='header of array',footer='footer of array',encoding='utf-8')

输出文件test.txt内容为:

# header of array
1.000000000000000000e+00
1.250000000000000000e+00
1.500000000000000000e+00
1.750000000000000000e+00
2.000000000000000000e+00
# footer of array

加载这种保存的文档使用loadtxt,函数原型为:

numpy.loadtxt(fname, dtype=<class 'float'>, comments='#', 
delimiter=None, converters=None, skiprows=0, usecols=None, 
unpack=False, ndmin=0, encoding=None, max_rows=None, *, 
quotechar=None, like=None)

fname是文件名,如果后缀是.gz或者.bz2,文件会被先解压,另外需要注意的是加载时comments、delimiter和encoding务必要和前面存盘时保持一致,如果前面存盘时都保持默认值,可以只提供一个文件名,例如:

a=np.linspace(1,2,5)
np.savetxt('test.txt',a)
del a
na=np.loadtxt('test.txt')
print(na) # [1.   1.25 1.5  1.75 2.  ]

这种方式的优点是具有可读性,也便于和其他程序进行数据交互。

2. 二进制格式

第二种方式保存二进制格式,使用numpy.save函数,可以将数组保存为*.npy格式的文件,函数原型如下:

numpy.save(file, arr, allow_pickle=True, fix_imports=True)

前面两个参数分别是文件名和数组,后面两个选项通常保持默认值即可。例如,数据存盘:

a=np.linspace(1,2,5)
np.save('bin',a)

可以看到会生成一个名为bin.npy的文件(函数会自动添加后缀),所保存的文件已经不具有可读性:

加载使用numpy.load函数,其原型如下:

numpy.load(file, mmap_mode=None, allow_pickle=False, 
fix_imports=True, encoding='ASCII', *, max_header_size=10000)

加载时提供之前存盘的文件名即可,注意,必须显式提供后缀.npy。

a=np.linspace(1,2,5)
np.save('bin',a)
del a
na=np.load('bin.npy')
print(na) # [1.   1.25 1.5  1.75 2.  ]

save和load也支持多个数组的保存和加载,此时,提供给这两个函数的是文件,应该是一个使用二进制打开的文件标识符,例如,保存两个数组:

a=np.linspace(1,2,5)
b=np.arange(1,2,0.25)
with open('bin2.npy','wb') as f:np.save(f,a)np.save(f,b)

从这两个数组中加载数据:

na=nb=None
with open('bin2.npy','rb') as f:na=np.load(f)nb=np.load(f)
print(na) # [1.   1.25 1.5  1.75 2.  ]
print(nb) # [1.   1.25 1.5  1.75]

3. 多个数组的保存和加载

前面提到了使用save和load实现多个数组的保存和加载,针对这种需求,numpy中还有专门的savez函数,可以实现对多个.npy文件的打包形成*.npz文件,并且在加载后,可以像字典一样操作。

例如,同样保存前面两个数组:

a=np.linspace(1,2,5)
b=np.arange(1,2,0.25)
np.savez('zfile.npz',za=a,zb=b)

函数中za,zb是自定义的字符串,可以理解为是这个数组的别名,或者说是字典中的键。如果存盘时没有提供这些值,则savez函数会为存盘的数组依次取名arr_0,arr_1等。

加载依旧使用load函数,事实上,该函数返回一个NpzFile对象,可以通过类似访问字典的方式,获取其中的数据:

zf=np.load('zfile.npz')
aa=zf['za']
bb=zf['zb']
print(aa)
print(bb)

如果提供了一个不存在的键,会导致产生异常:raise KeyError("%s is not a file in the archive" % key),为了避免这样的问题,可以先通过Npzfile对象的属性files获取可用的数组名:

zf=np.load('zfile.npz')
print(zf.files) # ['za', 'zb']

4. 带数据压缩的存盘和加载

前面提到的.npz文件,只是做了归档,并未对数据进行压缩,在一些存储空间比较紧张的场合,还可以使用带压缩的存盘和加载,函数numpy.savez_compressed可以实现这一功能,其使用方式和savez一样,但是内部使用了压缩算法,缩减了数据的存盘空间。以下测试了空间的利用率:

import numpy as np
import os
'''
测试压缩率'''
for i in range(0,5):N=10**irng=np.random.rand(N,N)file1='z1.npz'file2='z2.npz'np.savez(file1,rng)np.savez_compressed(file2,rng)size1=os.path.getsize(file1)size2=os.path.getsize(file2)print(f'N={N},Size1={size1},Size2={size2},Ratio={size2/size1*100:5.2f}%')

某次的运行结果为:

N=1,Size1=272,Size2=215,Ratio=79.04%
N=10,Size1=1064,Size2=1024,Ratio=96.24%
N=100,Size1=80264,Size2=75632,Ratio=94.23%
N=1000,Size1=8000264,Size2=7544290,Ratio=94.30%
N=10000,Size1=800000264,Size2=754412539,Ratio=94.30%

可见对于这种稠密的数组,压缩效果并不明显,大概在95%左右

但是,如果是稀疏数组呢?效果如何?编写一个生成稀疏数组的函数:

def sparse_gen(m,n,ratio):ret=np.zeros((m,n))total=int(m*n*ratio)cnt=0while cnt<total:r=np.random.randint(m)c=np.random.randint(n)d=np.random.randint(1,10)if ret[r,c] ==0:ret[r,c]=dcnt+=1return ret

将原来代码中:

rng=np.random.rand(N,N)

替换为:

rng=sparse_gen(N,N,0.1)

再次运行,这次的结果如下:

N=1,Size1=272,Size2=209,Ratio=76.84%
N=10,Size1=1064,Size2=250,Ratio=23.50%
N=100,Size1=80264,Size2=2814,Ratio= 3.51%
N=1000,Size1=8000264,Size2=249132,Ratio= 3.11%
N=10000,Size1=800000264,Size2=24855059,Ratio= 3.11%

可见,在一个稠密度为10%的数组中,压缩率大概为3.1% ~ 3.5%,数据越多,压缩率越显著。

如果修改生成数组的稠密度为5%(这个通常是稀疏矩阵的临界值),则压缩率最终可以达到约2%的水平:

N=1,Size1=272,Size2=209,Ratio=76.84%
N=10,Size1=1064,Size2=236,Ratio=22.18%  
N=100,Size1=80264,Size2=1814,Ratio= 2.26%
N=1000,Size1=8000264,Size2=152801,Ratio= 1.91%
N=10000,Size1=800000264,Size2=15262699,Ratio= 1.91%

所以,总结下来就是,对于稠密数组而言,使用savez就足够了,只有在类似稀疏数组时,压缩存盘的空间效果才会比较显著。但是,对于稀疏矩阵而言,通常不会直接存储,而是用其他表示方式。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 芋道源码yudao-cloud 二开笔记(Feign服务调用,如何定义一个 API 接口)
  • 信息学奥赛初赛天天练-52-CSP-J2019基础题3-抽屉原理、鸽巢原理、乘法原理、二叉树遍历、前序遍历、中序遍历、后序遍历
  • 下属“软对抗”,工作阳奉阴违怎么办?4大权谋术,让他不敢造次
  • 复制列表(切片复制)
  • 前端:Vue学习 - 智慧商城项目
  • 数值分析——分段低次插值
  • 怎么给USER新增表空间文件
  • c语言指针中“数组名的理解”以及“一维数组传参”的本质
  • 攻击服务器100G流量多少钱?攻击服务器1小时价格多少?
  • 使用RabbitMQ在Spring Boot入门实现简单的消息的发送与接收
  • TwinCAT3 新建项目教程
  • 8.Redis的List类型
  • 说说什么是变频空调及其工作原理
  • 软测面试二十问(最新面试)
  • 报表系统之Cube.js
  • 30秒的PHP代码片段(1)数组 - Array
  • Computed property XXX was assigned to but it has no setter
  • Cookie 在前端中的实践
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • golang 发送GET和POST示例
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • JavaWeb(学习笔记二)
  • overflow: hidden IE7无效
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • Spring Cloud中负载均衡器概览
  • vue 配置sass、scss全局变量
  • vue的全局变量和全局拦截请求器
  • Vue实战(四)登录/注册页的实现
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 聚簇索引和非聚簇索引
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 实习面试笔记
  • 小程序开发之路(一)
  • 做一名精致的JavaScripter 01:JavaScript简介
  • #Z0458. 树的中心2
  • (1)(1.13) SiK无线电高级配置(五)
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (delphi11最新学习资料) Object Pascal 学习笔记---第14章泛型第2节(泛型类的类构造函数)
  • (function(){})()的分步解析
  • (定时器/计数器)中断系统(详解与使用)
  • (附源码)ssm高校志愿者服务系统 毕业设计 011648
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • (转)平衡树
  • (转)一些感悟
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .NET Core6.0 MVC+layui+SqlSugar 简单增删改查
  • .NET分布式缓存Memcached从入门到实战
  • .NET设计模式(11):组合模式(Composite Pattern)
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • .NET序列化 serializable,反序列化
  • .NET中的Exception处理(C#)
  • .one4-V-XXXXXXXX勒索病毒数据怎么处理|数据解密恢复
  • /usr/bin/env: node: No such file or directory
  • :not(:first-child)和:not(:last-child)的用法