#!/usr/bin/env python # coding: utf-8 # # 数组读写 # ## 从文本中读取数组 # In[1]: import numpy as np # ### 空格(制表符)分割的文本 # 假设我们有这样的一个空白分割的文件: # In[2]: get_ipython().run_cell_magic('writefile', 'myfile.txt', '2.1 2.3 3.2 1.3 3.1\n6.1 3.1 4.2 2.3 1.8\n') # 为了生成数组,我们首先将数据转化成一个列表组成的列表,再将这个列表转换为数组: # In[3]: data = [] with open('myfile.txt') as f: # 每次读一行 for line in f: fileds = line.split() row_data = [float(x) for x in fileds] data.append(row_data) data = np.array(data) # In[4]: data # 不过,更简便的是使用 `loadtxt` 方法: # In[5]: data = np.loadtxt('myfile.txt') data # ### 逗号分隔文件 # In[6]: get_ipython().run_cell_magic('writefile', 'myfile.txt', '2.1, 2.3, 3.2, 1.3, 3.1\n6.1, 3.1, 4.2, 2.3, 1.8\n') # 对于逗号分隔的文件(通常为`.csv`格式),我们可以稍微修改之前繁琐的过程,将 `split` 的参数变成 `','`即可。 # # 不过,`loadtxt` 函数也可以读这样的文件,只需要制定分割符的参数即可: # In[7]: data = np.loadtxt('myfile.txt', delimiter=',') data # ### loadtxt 函数 # loadtxt(fname, dtype=, # comments='#', delimiter=None, # converters=None, skiprows=0, # usecols=None, unpack=False, ndmin=0) # # `loadtxt` 有很多可选参数,其中 `delimiter` 就是刚才用到的分隔符参数。 # # `skiprows` 参数表示忽略开头的行数,可以用来读写含有标题的文本 # In[8]: get_ipython().run_cell_magic('writefile', 'myfile.txt', 'X Y Z MAG ANG\n2.1 2.3 3.2 1.3 3.1\n6.1 3.1 4.2 2.3 1.8\n') # In[9]: np.loadtxt('myfile.txt', skiprows=1) # 此外,有一个功能更为全面的 `genfromtxt` 函数,能处理更多的情况,但相应的速度和效率会慢一些。 # # genfromtxt(fname, dtype=, comments='#', delimiter=None, # skiprows=0, skip_header=0, skip_footer=0, converters=None, # missing='', missing_values=None, filling_values=None, usecols=None, # names=None, excludelist=None, deletechars=None, replace_space='_', # autostrip=False, case_sensitive=True, defaultfmt='f%i', unpack=None, # usemask=False, loose=True, invalid_raise=True) # ### loadtxt 的更多特性 # 对于这样一个文件: # In[10]: get_ipython().run_cell_magic('writefile', 'myfile.txt', " -- BEGINNING OF THE FILE\n% Day, Month, Year, Skip, Power\n01, 01, 2000, x876, 13 % wow!\n% we don't want have Jan 03rd\n04, 01, 2000, xfed, 55\n") # In[11]: data = np.loadtxt('myfile.txt', skiprows=1, #忽略第一行 dtype=np.int, #数组类型 delimiter=',', #逗号分割 usecols=(0,1,2,4), #指定使用哪几列数据 comments='%' #百分号为注释符 ) data # ### loadtxt 自定义转换方法 # In[12]: get_ipython().run_cell_magic('writefile', 'myfile.txt', '2010-01-01 2.3 3.2\n2011-01-01 6.1 3.1\n') # 假设我们的文本包含日期,我们可以使用 `datetime` 在 `loadtxt` 中处理: # In[13]: import datetime def date_converter(s): return datetime.datetime.strptime(s, "%Y-%m-%d") data = np.loadtxt('myfile.txt', dtype=np.object, #数据类型为对象 converters={0:date_converter, #第一列使用自定义转换方法 1:float, #第二第三使用浮点数转换 2:float}) data # 移除 `myfile.txt`: # In[14]: import os os.remove('myfile.txt') # ### 读写各种格式的文件 # 如下表所示: # # 文件格式|使用的包|函数 # ----|----|---- # txt | numpy | loadtxt, genfromtxt, fromfile, savetxt, tofile # csv | csv | reader, writer # Matlab | scipy.io | loadmat, savemat # hdf | pytables, h5py| # NetCDF | netCDF4, scipy.io.netcdf | netCDF4.Dataset, scipy.io.netcdf.netcdf_file # **文件格式**|**使用的包**|**备注** # wav | scipy.io.wavfile | 音频文件 # jpeg,png,...| PIL, scipy.misc.pilutil | 图像文件 # fits | pyfits | 天文图像 # # 此外, `pandas` ——一个用来处理时间序列的包中包含处理各种文件的方法,具体可参见它的文档: # # http://pandas.pydata.org/pandas-docs/stable/io.html # ## 将数组写入文件 # `savetxt` 可以将数组写入文件,默认使用科学计数法的形式保存: # In[15]: data = np.array([[1,2], [3,4]]) np.savetxt('out.txt', data) # In[16]: with open('out.txt') as f: for line in f: print line, # 也可以使用类似**C**语言中 `printf` 的方式指定输出的格式: # In[17]: data = np.array([[1,2], [3,4]]) np.savetxt('out.txt', data, fmt="%d") #保存为整数 # In[18]: with open('out.txt') as f: for line in f: print line, # 逗号分隔的输出: # In[19]: data = np.array([[1,2], [3,4]]) np.savetxt('out.txt', data, fmt="%.2f", delimiter=',') #保存为2位小数的浮点数,用逗号分隔 # In[20]: with open('out.txt') as f: for line in f: print line, # 复数值默认会加上括号: # In[21]: data = np.array([[1+1j,2], [3,4]]) np.savetxt('out.txt', data, fmt="%.2f", delimiter=',') #保存为2位小数的浮点数,用逗号分隔 # In[22]: with open('out.txt') as f: for line in f: print line, # 更多参数: # savetxt(fname, # X, # fmt='%.18e', # delimiter=' ', # newline='\n', # header='', # footer='', # comments='# ') # 移除 `out.txt`: # In[23]: import os os.remove('out.txt') # ## Numpy 二进制格式 # 数组可以储存成二进制格式,单个的数组保存为 `.npy` 格式,多个数组保存为多个`.npy`文件组成的 `.npz` 格式,每个 `.npy` 文件包含一个数组。 # # 与文本格式不同,二进制格式保存了数组的 `shape, dtype` 信息,以便完全重构出保存的数组。 # # 保存的方法: # # - `save(file, arr)` 保存单个数组,`.npy` 格式 # - `savez(file, *args, **kwds)` 保存多个数组,无压缩的 `.npz` 格式 # - `savez_compressed(file, *args, **kwds)` 保存多个数组,有压缩的 `.npz` 格式 # # 读取的方法: # # - `load(file, mmap_mode=None)` 对于 `.npy`,返回保存的数组,对于 `.npz`,返回一个名称-数组对组成的字典。 # ### 单个数组的读写 # In[24]: a = np.array([[1.0,2.0], [3.0,4.0]]) fname = 'afile.npy' np.save(fname, a) # In[25]: aa = np.load(fname) aa # 删除生成的文件: # In[26]: import os os.remove('afile.npy') # ### 二进制与文本大小比较 # In[27]: a = np.arange(10000.) # 保存为文本: # In[28]: np.savetxt('a.txt', a) # 查看大小: # In[29]: import os os.stat('a.txt').st_size # 保存为二进制: # In[30]: np.save('a.npy', a) # 查看大小: # In[31]: os.stat('a.npy').st_size # 删除生成的文件: # In[32]: os.remove('a.npy') os.remove('a.txt') # 可以看到,二进制文件大约是文本文件的三分之一。 # ### 保存多个数组 # In[33]: a = np.array([[1.0,2.0], [3.0,4.0]]) b = np.arange(1000) # 保存多个数组: # In[34]: np.savez('data.npz', a=a, b=b) # 查看里面包含的文件: # In[35]: get_ipython().system('unzip -l data.npz') # 载入数据: # In[36]: data = np.load('data.npz') # 载入后可以像字典一样进行操作: # In[37]: data.keys() # In[38]: data['a'] # In[39]: data['b'].shape # 删除文件: # In[40]: # 要先删除 data,否则删除时会报错 del data os.remove('data.npz') # ### 压缩文件 # 当数据比较整齐时: # In[41]: a = np.arange(20000.) # 无压缩大小: # In[42]: np.savez('a.npz', a=a) os.stat('a.npz').st_size # 有压缩大小: # In[43]: np.savez_compressed('a2.npz', a=a) os.stat('a2.npz').st_size # 大约有 6x 的压缩效果。 # # 当数据比较混乱时: # In[44]: a = np.random.rand(20000.) # 无压缩大小: # In[45]: np.savez('a.npz', a=a) os.stat('a.npz').st_size # 有压缩大小: # In[46]: np.savez_compressed('a2.npz', a=a) os.stat('a2.npz').st_size # 只有大约 1.06x 的压缩效果。 # In[47]: os.remove('a.npz') os.remove('a2.npz')