在我的程序中,我需要查询元数据。
我从类似csv的文本文件**中将数据读入numpy
记录数组A
,没有重复行**。
var1|var2|var3|var4|var5|var6
'a1'|'b1'|'c1'|1.2|2.2|3.4
'a1'|'b1'|'c4'|3.2|6.2|3.2
'a2'|''|'c1'|1.4|5.7|3.8
'a2'|'b1'|'c2'|1.2|2.2|3.4
'a3'|''|'c2'|1.2|2.2|3.4
'a1'|'b2'|'c4'|7.2|6.2|3.2
...
数百万行,嵌套循环中的查询最多可达十亿次(大部分与前3列匹配),因此效率变得至关重要。< / p> 有3种类型的查询,第一种是最常见的。
获取与给定字符串匹配的前3列中的一个或多个列的行,例如
匹配var1='a2'
和var2='b1'
,
ind = np.logical_and(A['var1']=='a2', A['var2']=='b1')
要匹配var1='a2'
,var2='b1'
和var3='c1'
,
ind = np.logical_and(np.logical_and(A['var1']=='a2', A['var2']=='b1'), A['var3']=='c1')
正如我们所看到的,每次我们将列的所有元素与给定的字符串进行比较。
我认为映射可能是一种更有效的索引方式,因此我将重新排列A
转换为dict D = {'var1_var2_var3
:[var4,var5,var6],...} {{1} } fnmatch(keys,pat)`。我不确定这是一种更好的方式。
或者我可以创建分层词典, and search through the keys by
或内存中的hdf5 {'var1':{'var2':{'var3':[],...},...},...}
,并尝试获取该项目(如果存在)。这看起来是最快的方式吗?
后两种类型的查询不是很频繁,我可以接受numpy recarray比较的方式。
获取特定范围内后一列中数值的所有行,例如
获取行&#39; 1
/var1/var2/var3
上述两者的组合,例如,
获取ind = np.logical_and(1<A['var4']<3), 0<A['var5']<3)
,&#39; 1的行
var2='b1'
ind = np.logical_and(np.logical_and(A['var2']=='b1', 1<A['var4']<3), 0<A['var5']<3)
可能是一个好方法,但是对于这个小任务来说,使用数据库看起来太沉重了。而且我无权在任何地方安装数据库支持。
对快速内存查询的数据结构有何建议? (如果很难有一个简单的自定义实现,SQL
和sqlite
似乎是可能的解决方案,如建议的那样。)
答案 0 :(得分:0)
使用Pandas,它是为这样的任务而构建的:
# Import
import pandas as pd
# Read CSV
df = pd.read_csv('/path/to/file.csv')
# Selection criteria
# using `.query` method:
df.query('var1 == "a2" & var3 == "c1"')
df.query('var2 == "b1" & 1 < var4 < 3 & 0 < var5 < 3')
# using indexing:
df[(df['var1'] == 'a2') & (df['var3'] == 'c1')]
df[(df['var2'] == 'b1') & df['var4'].between(1,3) & df['var5'].between(0,3)]
# using `.where` method:
df.where((df['var1'] == 'a2') & (df['var3'] == 'c1'))
df.where(df['var2'] == 'b1') & df['var4'].between(1,3) & df['var5'].between(0,3))
答案 1 :(得分:0)
使用您的文件样本(&#39; b&#39; for py3)
In [51]: txt=b"""var1|var2|var3|var4|var5|var6
...: 'a1'|'b1'|'c1'|1.2|2.2|3.4
...: 'a1'|'b1'|'c4'|3.2|6.2|3.2
...: 'a2'|''|'c1'|1.4|5.7|3.8
...: 'a2'|'b1'|'c2'|1.2|2.2|3.4
...: 'a3'|''|'c2'|1.2|2.2|3.4
...: 'a1'|'b2'|'c4'|7.2|6.2|3.2"""
简单的阅读让我看到双层引用
data = np.genfromtxt(txt.splitlines(), names=True, delimiter='|', dtype=None)
array([(b"'a1'", b"'b1'", b"'c1'", 1.2, 2.2, 3.4), ...
dtype=[('var1', 'S4'), ('var2', 'S4'), ('var3', 'S4'), ('var4', '<f8'), ('var5', '<f8'), ('var6', '<f8')])
所以我要定义一个转换器来剥离它们(一个csv
读者也可以这样做):
def foo(astr):
return eval(astr)
In [55]: A = np.genfromtxt(txt.splitlines(), names=True, delimiter='|', dtype='U3,U3,U3,f8,f8,f8', converters={0:foo,1:foo,2:foo})
In [56]: A
Out[56]:
array([('a1', 'b1', 'c1', 1.2, 2.2, 3.4),
('a1', 'b1', 'c4', 3.2, 6.2, 3.2),
('a2', '', 'c1', 1.4, 5.7, 3.8),
('a2', 'b1', 'c2', 1.2, 2.2, 3.4),
('a3', '', 'c2', 1.2, 2.2, 3.4),
('a1', 'b2', 'c4', 7.2, 6.2, 3.2)],
dtype=[('var1', '<U3'), ('var2', '<U3'), ('var3', '<U3'), ('var4', '<f8'), ('var5', '<f8'), ('var6', '<f8')])
我可以编写像
这样的测试In [57]: (A['var1']=='a2')&(A['var2']=='b1')
Out[57]: array([False, False, False, True, False, False], dtype=bool)
In [58]: (1<A['var4'])&(A['var4']<3)
Out[58]: array([ True, False, True, True, True, False], dtype=bool)
A
的所有记录的测试都是在编译numpy
代码中完成的,因此它们不应该那么慢。
此数据也可以被视为2个多列字段
In [59]: dt = np.dtype([('labels', '<U3', (3,)), ('data', '<f8', (3,))])
In [60]: A1 = A.view(dt)
In [61]: A1
Out[61]:
array([(['a1', 'b1', 'c1'], [1.2, 2.2, 3.4]),
(['a1', 'b1', 'c4'], [3.2, 6.2, 3.2]),
(['a2', '', 'c1'], [1.4, 5.7, 3.8]),
(['a2', 'b1', 'c2'], [1.2, 2.2, 3.4]),
(['a3', '', 'c2'], [1.2, 2.2, 3.4]),
(['a1', 'b2', 'c4'], [7.2, 6.2, 3.2])],
dtype=[('labels', '<U3', (3,)), ('data', '<f8', (3,))])
或直接加载
A = np.genfromtxt(txt.splitlines(), skip_header=1, delimiter='|', dtype='(3)U3,(3)f8', converters={0:foo,1:foo,2:foo})
然后测试可以写成:
In [64]: (A1['labels'][:,0]=='a1') & (A1['labels'][:,1]=='b2') & ((A1['data']<6).any(axis=1))
Out[64]: array([False, False, False, False, False, True], dtype=bool)
In [65]: (A1['labels'][:,[0,1]]==['a1','b2']).all(axis=1)
Out[65]: array([False, False, False, False, False, True], dtype=bool)
有时可能更清楚的是为各列提供自己的ID:
var1 = A1['labels'][:,0] # or A['var1']
....
(var1=='a1')&(var2='b1')&...
可以保存重复的查询或组合。
我相信pandas
将其系列存储在numpy
数组中,每列的dtype不同(如果列中的类型不同,则为对象dtype)。但我还没有看到pandas
速度和速度技巧的讨论。除非它提供某种索引,否则我不会期望提高速度。
我可以想象将这些数据写入数据库。 sqlite3
已内置并具有memory
模式,因此您无需文件访问权限。但是,我已经完全没有使用我将通过演示的代码了。我也不了解进行这类查询的容易程度或速度。
https://mail.scipy.org/pipermail/scipy-user/2007-August/013350.html有一些代码可以将结构化数组保存到sqlite3数据库。它包含一个将dtype
转换为表创建语句的函数。
====================
我已将pipermail
示例与python3
一起使用。测试示例有11个字段。有5000条记录,
data[np.where(data['id']=='id2000')]
比相应的sqlite3
查询快6倍(现有cursor
):
cursor.execute('select * from data where id=?',('id2000',))
cursor.fetchone()