在Python/PyTables中有效验证记录唯一性的方法

4 投票
3 回答
1681 浏览
提问于 2025-04-15 13:47

我在PyTables里有一个大约5000万条记录的表格。这里面有两个字段(具体来说是用户ID和日期)的组合应该是唯一的,也就是说,一个用户在一天内最多只能有一条记录。不过,我需要确认这点是否真的成立。

简单来说,我的表格长这样:

userID |   date
A      |    1
A      |    2
B      |    1
B      |    2
B      |    2   <- bad! Problem with the data!

一些额外的细节:

  • 这个表格现在“基本上”是排好序的。
  • 我只能勉强把一列数据加载到内存中作为numpy数组,但同时加载两列是不行的。
  • 用户ID和日期都是整数。

3 个回答

0

我对PyTables了解不多,但我会尝试这个方法。

  1. 对于每个用户ID,获取所有的 (用户ID, 日期) 组合。
  2. assert len(rows)==len(set(rows)) - 这个判断成立的前提是,rows 列表中的所有 (用户ID, 日期) 组合都是独一无二的。
1

多年后我还是有同样的问题,不过现在有了索引和查询的功能,这个问题就稍微好解决一些,具体还得看你的表有多大。使用 readWhere 或 getListWhere 的话,我觉得这个问题的复杂度大概是 O(n)。

我做了以下几件事……

1. 我创建了一个有两个索引的表。你可以在 PyTables 中使用多个索引:

http://pytables.github.com/usersguide/optimization.html#indexed-searches

一旦你的表被索引了,我还使用了 LZO 压缩,你可以这样做:

import tables
h5f = tables.openFile('filename.h5')
tbl = h5f.getNode('/data','data_table') # assumes group data and table data_table
counter += 0

for row in tbl:
    ts = row['date'] # timestamp (ts) or date
    uid = row['userID']
    query = '(date == %d) & (userID == "%s")' % (ts, uid)
    result = tbl.readWhere(query)
    if len(result) > 1:
        # Do something here
        pass
    counter += 1
    if counter % 1000 == 0: print '%d rows processed'

不过我写的这段代码其实有点慢。我相信有一些 PyTables 的高手能给你更好的答案。但我对性能的看法是:

如果你知道自己开始时的数据是干净的,也就是说没有重复数据,那么你只需要查询一次表,找出你感兴趣的键,这样你只需要做:

ts = row['date'] # timestamp (ts) or date
uid = row['userID']
query = '(date == %d) & (userID == "%s")' % (ts, uid)
result = tbl.getListWhere(query)
if len(result) == 0:
    # key pair is not in table
    # do what you were going to do
    pass
elif len(result) > 1:
    # Do something here, like get a handle to the row and update instead of append.
    pass

如果你有很多时间去检查重复数据,可以创建一个后台进程,遍历你的文件目录,寻找重复项。

希望这能对其他人有所帮助。

4

看起来在PyTables中,索引只能针对单一列。

我建议你可以添加一个哈希列,并在这个列上建立索引。你的唯一数据可以通过把数据库中的其他列连接起来定义。用分隔符可以确保不会有两行数据产生相同的唯一值。这个哈希列可以直接存放这个唯一字符串,但如果你的数据比较长,建议使用哈希函数。像md5或sha1这样的快速哈希函数非常适合这个用途。

计算出哈希后的数据,然后检查它是否在数据库中。如果在,那就说明你遇到了重复的数据。如果不在,那你就可以安全地添加这条数据。

撰写回答