Python學習(七)數組讀寫和保存


參考資料:

https://github.com/lijin-THU/notes-python(相應實體書為:《自學Python——編程基礎、科學計算及數據分析》)

1. 數組讀寫(注意bytes與str數據類型的相互轉換

(1)空格(制表符)分割的文本

 1 import numpy as np
 2 #生成目標文本
 3 %%writefile myfile.txt
 4 2.1 2.3 3.2 1.3 3.1
 5 6.1 3.1 4.2 2.3 1.8
 6 #常規讀取方式(繁瑣)
 7 data = []
 8 with open('myfile.txt') as f:
 9     # 每次讀一行
10     for line in f:
11         fileds = line.split()
12         row_data = [float(x) for x in fileds]
13         data.append(row_data)
14 
15 data = np.array(data)
16 #使用loadtxt方法(簡便)
17 data = np.loadtxt('myfile.txt')

(2)逗號分割文件(通常為.csv格式)

1 %%writefile myfile.txt
2 2.1, 2.3, 3.2, 1.3, 3.1
3 6.1, 3.1, 4.2, 2.3, 1.8
4 #常規方法,僅需將上述繁瑣過程中的split的參數變為','即可
5 data = np.loadtxt('myfile.txt', delimiter=',')  #指定分隔符參數

(3)loadtxt函數

loadtxt(fname, dtype=<type 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0)

skiprows 參數表示忽略開頭的行數,可以用來讀寫含有標題的文本

1 %%writefile myfile.txt
2 X Y Z MAG ANG
3 2.1 2.3 3.2 1.3 3.1
4 6.1 3.1 4.2 2.3 1.8
5 
6 np.loadtxt('myfile.txt', skiprows=1)  #忽略第一行

注:genfromtxt函數功能更加全面,但是處理速度和效率會慢一點

 1 %%writefile myfile.txt  #寫文件
 2  -- BEGINNING OF THE FILE
 3 % Day, Month, Year, Skip, Power
 4 01, 01, 2000, x876, 13 % wow!
 5 % we don't want have Jan 03rd
 6 04, 01, 2000, xfed, 55
 7 
 8 data = np.loadtxt('myfile.txt', 
 9                   skiprows=1,         #忽略第一行
10                   dtype=np.int,      #數組類型
11                   delimiter=',',     #逗號分割
12                   usecols=(0,1,2,4), #指定使用哪幾列數據
13                   comments='%'       #百分號為注釋符
14                  )

(4)自定義轉換方法

 1 %%writefile myfile.txt
 2 2010-01-01 2.3 3.2
 3 2011-01-01 6.1 3.1
 4 
 5 import datetime
 6 
 7 def date_converter(s):  #自定義的轉換方法
 8     return datetime.datetime.strptime(s.decode('ascii'), "%Y-%m-%d")  #保證輸入參數為字符串
 9 
10 data = np.loadtxt('myfile.txt',
11                   dtype=np.object, #數據類型為對象
12                   converters={0:date_converter,  #第一列使用自定義轉換方法
13                               1:float,           #第二第三使用浮點數轉換
14                               2:float})

(5)讀寫各種格式的文件

(6)將數組寫入文件

savetxt:將數組寫入文件,默認使用科學計數法的形式保存

savetxt(fname, X, fmt='%.18e'delimiter=' 'newline='\n', header='', footer='', comments='# ')  //格式fmt,分隔符delimiter

 1 data = np.array([[1,2], 
 2                  [3,4]])
 3 
 4 np.savetxt('out.txt', data)
 5 with open('out.txt') as f:
 6     for line in f:
 7         print(line, end='')
 8 
 9 data = np.array([[1,2], 
10                  [3,4]])
11 
12 np.savetxt('out.txt', data, fmt="%d") #保存為整數
13 np.savetxt('out.txt', data, fmt="%.2f", delimiter=',') #保存為2位小數的浮點數,用逗號分隔
14 
15 data = np.array([[1+1j,2], 
16                  [3,4]])  #復數值,默認會加上括號 17 
18 np.savetxt('out.txt', data, fmt="%.2f", delimiter=',') #保存為2位小數的浮點數,用逗號分隔

(7)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,返回一個名稱-數組對組成的字典。
1 a = np.array([[1.0,2.0], [3.0,4.0]])
2 #單個數組讀寫
3 fname = 'afile.npy'
4 np.save(fname, a)
5 aa = np.load(fname)

二進制與文本大小比較:

1 import os
2 a = np.arange(10000.)
3 
4 np.savetxt('a.txt', a)
5 os.stat('a.txt').st_size  #查看文件大小
6 
7 np.save('a.npy', a)
8 os.stat('a.npy').st_size

注:二進制文件較小

 1 a = np.array([[1.0,2.0], 
 2               [3.0,4.0]])
 3 b = np.arange(1000)
 4 #保存多個數組
 5 np.savez('data.npz', a=a, b=b)
 6 !unzip -l data.npz  #使用!執行系統命令unzip查看里面包含的文件
 7 
 8 data = np.load('data.npz')  #載入數據
 9 
10 data.keys()  #載入后可以像字典一樣進行操作
11 data['a']
12 data['b'].shape
13 
14 # 要先刪除 data,否則刪除時會報錯
15 del data
16 os.remove('data.npz')  

PermissionError
: [WinError 32] 另一個程序正在使用此文件,進程無法訪問。: 'data.npz'

壓縮文件

 #數據比較整齊時,壓縮率較大
1
a = np.arange(20000.) 2 np.savez('a.npz', a=a)  #無壓縮 3 os.stat('a.npz').st_size 4 np.savez_compressed('a2.npz', a=a)  #有壓縮 5 os.stat('a2.npz').st_size
#數據比較混亂時,壓縮率較小
6 a = np.random.rand(20000.) 7 np.savez('a.npz', a=a)  #無壓縮 8 os.stat('a.npz').st_size 9 np.savez_compressed('a2.npz', a=a)  #有壓縮 10 os.stat('a2.npz').st_size

2. 結構化數組

(1)可以使用 dtype 創造了自定義的結構類型,然后用自定義的結構來解釋數組所占的內存

 1 import numpy as np
 2 a = np.array([1.0,2.0,3.0,4.0], np.float32)
 3 a.view(np.complex64)  #使用view方法,將a對應的內存按照復數來解釋 
4
my_dtype = np.dtype([('mass', 'float32'), ('vol', 'float32')])
# 將第一個浮點數解釋為質量,第二個浮點數解釋為速度,這段內存還可以看成是包含兩個域(質量和速度)的結構體
5 a.view(my_dtype) 6 my_data = np.array([(1,1), (1,2), (2,1), (1,3)], my_dtype) 7 my_data[0]  #第一個元素 8 my_data[0]['vol']  #第一個元素的速度域 9 my_data['mass']  #所有元素的質量域 10 my_data.sort(order=('vol', 'mass'))  #自定義排序規則,先速度,后質量 11 person_dtype = np.dtype([('name', 'S10'), ('age', 'int'), ('weight', 'float')])
# 定義一個人的結構類型
12 people = np.empty((3,4), person_dtype)  #產生3*4的空結構體數組
# 根據屬性域,分別賦值
13 people['name'] = [['Brad', 'Jane', 'John', 'Fred'], 14 ['Henry', 'George', 'Brain', 'Amy'], 15 ['Ron', 'Susan', 'Jennife', 'Jill']] 16 people['age'] = [[33, 25, 47, 54], 17 [29, 61, 32, 27], 18 [19, 33, 18, 54]] 19 people['weight'] = [[135., 105., 255., 140.], 20 [154., 202., 137., 187.], 21 [188., 135., 88., 145.]]
22 people[-1, -1]  #值為:('Jill',54,145.0)

(2)從文本中讀取結構化數組

 1 %%writefile people.txt
 2 name age weight
 3 amy 11 38.2
 4 john 10 40.3
 5 bill 12 21.2
 6 #定義類型
 7 person_dtype = np.dtype([('name', 'S10'), ('age', 'int'), ('weight', 'float')])
 8 people = np.loadtxt('people.txt', 
 9                     skiprows=1,
10                     dtype=person_dtype)  #指定類型 11 people['name']  #查看name域
12 
13 %%writefile wood.csv
14 item,material,number
15 100,oak,33
16 110,maple,14
17 120,oak,7
18 145,birch,3
19    
20 tree_to_int = dict(oak = 1,
21                    maple=2,
22                    birch=3)
23 #定義轉換函數,使之對應於整數
24 def convert(s):
25     return tree_to_int.get(s.decode('utf-8'), 0)  #將bytes數據轉換成string類型;如僅使用s,則將都轉換成默認值0 26 
27 data = np.genfromtxt('wood.csv',
28                      delimiter=',', # 逗號分隔
29                      dtype=np.int, # 數據類型
30                      names=True,   # 從第一行讀入域名作為屬性名稱
31                      converters={1:convert}
32                     )
33 
34 data['material']  #查看域

(3)嵌套類型

 #定義嵌套類型:位置(x,y)、質量
1
particle_dtype = np.dtype([('position', [('x', 'float'), 2 ('y', 'float')]), 3 ('mass', 'float') 4 ]) 5 6 %%writefile data.txt 7 2.0 3.0 42.0 8 2.1 4.3 32.5 9 1.2 4.6 32.3 10 4.5 -6.4 23.3 11 12 data = np.loadtxt('data.txt', dtype=particle_dtype)  #讀取數據 13 data['position']['x']  #訪問位置中嵌套的x軸數據

 3. 記錄數組(record array)

 1 import numpy as np
 2 #定義質點類型
 3 partical_dtype = np.dtype([('mass', 'float'), 
 4                            ('velocity', 'float')])
 5 
 6 from numpy import rec  #生成記錄數組需要使用numpy.rec里的fromrecords  7 particals_rec = rec.fromrecords([(1,1), (1,2), (2,1), (1,3)], 
 8                                 dtype = partical_dtype)
 9 
10 particals_rec.mass  #通過屬性訪問域 11 particals_rec['mass']  #直接查看域

注:記錄數組的運行效率要比結構化數組要慢一些

#定義結構化數組
1
particals = np.array([(1,1), (1,2), (2,1), (1,3)], 2 dtype = partical_dtype) 3 #使用view方法將結構化數組看成記錄數組 4 particals_rec = particals.view(np.recarray) 5 particals_rec.mass  #訪問域 6 particals_rec.velocity 7 particals.dtype.names  #對於自定義類型particals.dtype,通過names屬性查看有哪些域

4. 內存映射:內存映射文件與虛擬內存有些類似,通過內存映射文件可以保留一個地址空間的區域,同時將物理存儲器提交給此區域;內存文件映射的物理存儲器來自一個已經存在於磁盤上的文件,而且在對該文件進行操作之前必須首先對文件進行映射

使用內存映射文件處理存儲於磁盤上的文件時,將不必再對文件執行I/O操作(速度快),使得內存映射文件在處理大數據量的文件時能起到相當重要的作用。

主要函數有:

  • memmap
  • frombuffer
  • ndarray constructor

其中,memmap(filename, dtype=uint8, mode='r+', offset=0, shape=None, order=0)

mode表示文件被打開的類型:

  • r 只讀
  • c 復制+寫,但是不改變源文件
  • r+ 讀寫,使用 flush 方法會將更改的內容寫入文件
  • w+ 寫,如果存在則將數據覆蓋

offset表示從第幾個位置開始

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM