我的数据如下:
"blue red"
"blue magenta cyan"
"yellow red"
"black"
每行中的最大元素数为10,但可能有数千个标签/类别/颜色。我想以某种方式在pytables列中插入这些数据,目的是以下列形式进行查询:
`label in row`
例如,返回包含blue
标签的所有文档(结果将是前两行)。考虑到Pytables没有set
数据类型这一事实,最有效的方法是什么?
答案 0 :(得分:3)
您只有最大N=10
的事实很棒。这意味着可以进行这些比较。你应该做的是有10个字符串列,其中每列是一个标签。如果一行的标签少于10个,则用空字符串填充。
这将允许您编写可在Table.where()
和Table.read_where()
命令[1]中使用的高效查询表达式。假设列具有愚蠢的名称'col0','col1'等。因为字符串比较在numexpr中是精确的,并且因为没有本机集类型,所以必须显式展开相等比较:
cond = ("col0 == 'blue' | col1 == 'blue' | col2 == 'blue' | col3 == 'blue' | "
"col4 == 'blue' | col5 == 'blue' | col6 == 'blue' | col7 == 'blue' | "
"col8 == 'blue' | col9 == 'blue'")
rows = [row[:] for row in table.where(cond)]
幸运的是,很容易以编程方式构造cond
字符串:
cond = " | ".join(["col{0} == 'blue'".format(i) for i in range(10)])
然而,你可以做的更多。字符串比较笨重而且速度慢。这是因为您的所有字符串都必须具有相同的大小,这意味着您的列大小由最长的标签决定。这导致了大量浪费的空间。相反,您应该与标签整数进行映射。然后你可以存储整数,快速比较这些。例如,使用列表索引:
labels = ['', 'blue', 'red', 'yellow', ...]
labels_to_idx = dict(zip(labels, range(len(labels))))
cond = " | ".join(["col{0} == '{1}'".format(i, labels_to_idx['blue'])
for i in range(10)])
rows = [[labels[x] for x in row[:]] for row in table.where(cond)]
您甚至可以将标签列表存储在PyTables中作为EArray,这样您就可以确保始终获得相同的索引顺序,同时还可以扩展允许标签列表。
此外,由于标签将被重复使用,特别是空字符串标签,我高度建议您启用压缩。
不幸的是,由于列是索引的(而不是表),因此您无法索引这些查询。
通过对整数进行压缩和映射,这可能是您获得的最快和最小的。