[Pandas] 04 - Efficient I/O
SQLITE3接口 to Arrary
——从数据库加载数据到dataframe/numpy中。
调动 SQLITE3数据库
import sqlite3 as sq3 query = 'CREATE TABLE numbs (Date date, No1 real, No2 real)' con = sq3.connect(path + 'numbs.db') con.execute(query) con.commit()
commit 命令
COMMIT 命令是用于把事务调用的更改保存到数据库中的事务命令。
COMMIT 命令把自上次 COMMIT 或 ROLLBACK 命令以来的所有事务保存到数据库
返回值处理
返回所有值,就用 fetchall()。
con.execute('SELECT * FROM numbs').fetchmany(10) pointer = con.execute('SELECT * FROM numbs') for i in range(3): print(pointer.fetchone())
Output:
------------------------------------------------- ('2017-11-18 11:18:51.443295', 0.12, 7.3) ('2017-11-18 11:18:51.466328', 0.9791, -0.01914) ('2017-11-18 11:18:51.466580', -0.88736, 0.19104)
保存到NumPy
第一步、通过初始化直接格式变换即可。
query = 'SELECT * FROM numbers WHERE No1 > 0 AND No2 < 0'
res = np.array( con.execute(query).fetchall() ).round(3)
第二步、可视化数据 by resampling,也就是少取一些点。
res = res[::100] # every 100th result
import matplotlib.pyplot as plt %matplotlib inline
plt.plot(res[:, 0], res[:, 1], 'ro')
plt.grid(True);
plt.xlim(-0.5, 4.5);
plt.ylim(-4.5, 0.5) # tag: scatter_query # title: Plot of the query result # size: 60
SQLITE3接口 to DataFrame
读取整个表
一张表通常内存可以搞定,全部读取也不是避讳的事情。
import sqlite3 as sq3
filename = path + 'numbs' con = sq3.Connection(filename + '.db') %time data = pd.read_sql('SELECT * FROM numbers', con) data.head()
表操作
其实已经演变为 ndarray操作。
“与” 条件
%time data[(data['No1'] > 0) & (data['No2'] < 0)].head()
“或” 条件
%%time res = data[['No1', 'No2']][((data['No1'] > 0.5) | (data['No1'] < -0.5)) & ((data['No2'] < -1) | (data['No2'] > 1))]
PyTable的快速I/O
HDF5数据库/文件标准。
"无压缩" 创建一个大表
表定义
import numpy as np import tables as tb import datetime as dt import matplotlib.pyplot as plt %matplotlib inline filename = './data/tab.h5' h5 = tb.open_file(filename, 'w') # 有几行:多搞几行,弄一个大表 rows = 2000000 # 有几列 row_des = { 'Date': tb.StringCol(26, pos=1), 'No1': tb.IntCol(pos=2), 'No2': tb.IntCol(pos=3), 'No3': tb.Float64Col(pos=4), 'No4': tb.Float64Col(pos=5) }
创建表
filters = tb.Filters(complevel=0) # no compression
tab = h5.create_table('/', 'ints_floats', row_des, title='Integers and Floats', expectedrows=rows, filters=filters)
新增数据
此时,表还在内存中,向这个表内添加数据。
(1) 一个关键的列表形式。
pointer = tab.row
(2) 生成随机数填充。
ran_int = np.random.randint(0, 10000, size=(rows, 2))
ran_flo = np.random.standard_normal((rows, 2)).round(5)
(3) 赋值给内存中的表。
传统策略,使用了繁琐的循环。
%%time for i in range(rows): pointer['Date'] = dt.datetime.now() pointer['No1'] = ran_int[i, 0] pointer['No2'] = ran_int[i, 1] pointer['No3'] = ran_flo[i, 0] pointer['No4'] = ran_flo[i, 1] pointer.append() # this appends the data and # moves the pointer one row forward
tab.flush() # 相当于SQLITE3中的commit命令
矩阵策略,省掉了循环。
%%time sarray['Date'] = dt.datetime.now() sarray['No1'] = ran_int[:, 0] sarray['No2'] = ran_int[:, 1] sarray['No3'] = ran_flo[:, 0] sarray['No4'] = ran_flo[:, 1]
“压缩” 创建一个大表
创建压缩表
因rows中其实已经有了数据,所以创建的同时就同步写入文件。
filename = './data/tab.h5c' h5c = tb.open_file(filename, 'w') filters = tb.Filters(complevel=4, complib='blosc') tabc = h5c.create_table('/', 'ints_floats', sarray, title='Integers and Floats', expectedrows=rows, filters=filters)
dnarray读取
读取内存数据,返回 numpy.ndarray。
%time arr_com = tabc.read()
h5c.close()
内存外计算
比如,处理一个若干GB的数组。
创建一个外存数组 EArray
filename = './data/array.h5' h5 = tb.open_file(filename, 'w') n = 100 ear = h5.create_earray(h5.root, 'ear', atom=tb.Float64Atom(), shape=(0, n)) %%time rand = np.random.standard_normal((n, n)) for i in range(750): ear.append(rand) ear.flush() ear.size_on_disk # 查看一下,这个E Array是个大数组
创建一个对应的 EArray
第一步、设置外存 workspace。
out = h5.create_earray(h5.root, 'out', atom=tb.Float64Atom(), shape=(0, n))
第二步、通过外存来计算ear大数组。
expr = tb.Expr('3 * sin(ear) + sqrt(abs(ear))') # 这里是 import tables as tb 中的 Expr,而不是import numexpr as ne # the numerical expression as a string object expr.set_output(out, append_mode=True) # target to store results is disk-based array %time expr.eval() # evaluation of the numerical expression # and storage of results in disk-based array
第三步、从外存读入内存,传的自然是“变量“,而非”workspace"。
%time imarray = ear.read() # read whole array into memory
End.